From b28301d7cbab81ecb9021a99551410fffcf2ff94 Mon Sep 17 00:00:00 2001 From: babywolf Date: Wed, 2 Oct 2024 21:23:11 +0100 Subject: [PATCH] - ATA? --- .gitignore | 1 + build.ninja | 5 +- src/arch/i386/kernel/acpi.c | 3 + src/arch/i386/kernel/drivers/ata.c | 182 +++++++++++++++++++++ src/arch/i386/kernel/include/drivers/ata.h | 59 +++++++ src/arch/i386/kernel/include/io.h | 2 + src/arch/i386/kernel/io.c | 4 + src/arch/i386/kernel/kernel.c | 4 +- 8 files changed, 257 insertions(+), 3 deletions(-) create mode 100644 src/arch/i386/kernel/drivers/ata.c create mode 100644 src/arch/i386/kernel/include/drivers/ata.h diff --git a/.gitignore b/.gitignore index 915b14d..0e19203 100644 --- a/.gitignore +++ b/.gitignore @@ -2,6 +2,7 @@ *.a *.bin *.iso +*.img *.elf /.dccache /.ninja_deps diff --git a/build.ninja b/build.ninja index 89cf9e7..74ada6f 100644 --- a/build.ninja +++ b/build.ninja @@ -24,16 +24,17 @@ build ./build/i386/cmos.o: gcc ./src/arch/i386/kernel/drivers/cmos.c build ./build/i386/keyboard.o: gcc ./src/arch/i386/kernel/drivers/keyboard.c build ./build/i386/fpu.o: gcc ./src/arch/i386/kernel/drivers/fpu.c build ./build/i386/pit.o: gcc ./src/arch/i386/kernel/drivers/pit.c +build ./build/i386/ata.o: gcc ./src/arch/i386/kernel/drivers/ata.c build ./build/i386/console.o: gcc ./src/arch/i386/kernel/console.c build ./build/i386/acpi.o: gcc ./src/arch/i386/kernel/acpi.c build ./build/i386/madt.o: gcc ./src/arch/i386/kernel/madt.c build ./build/i386/kernel.o: gcc ./src/arch/i386/kernel/kernel.c -build ./isodir/boot/piriquitOS-i386.bin: ld ./build/i386/acpi.o ./build/i386/madt.o ./build/libc/string.o ./build/i386/boot.o ./build/i386/gdt.asm.o ./build/i386/gdt.c.o ./build/i386/idt.c.o ./build/i386/idt.asm.o ./build/i386/irq.o ./build/i386/exceptions.o ./build/i386/isr.o ./build/i386/io.o ./build/i386/vga.o ./build/i386/pic.o ./build/i386/cmos.o ./build/i386/keyboard.o ./build/i386/pit.o ./build/i386/console.o ./build/i386/fpu.o ./build/i386/kernel.o +build ./isodir/boot/piriquitOS-i386.bin: ld ./build/i386/ata.o ./build/i386/acpi.o ./build/i386/madt.o ./build/libc/string.o ./build/i386/boot.o ./build/i386/gdt.asm.o ./build/i386/gdt.c.o ./build/i386/idt.c.o ./build/i386/idt.asm.o ./build/i386/irq.o ./build/i386/exceptions.o ./build/i386/isr.o ./build/i386/io.o ./build/i386/vga.o ./build/i386/pic.o ./build/i386/cmos.o ./build/i386/keyboard.o ./build/i386/pit.o ./build/i386/console.o ./build/i386/fpu.o ./build/i386/kernel.o build ./build/piriquitOS-i386.iso: iso ./isodir #phony build libc: phony ./build/libc/string.o ./libs/libc.a -build i386: phony ./libs/libc.a ./build/i386/acpi.o ./build/i386/madt.o ./build/i386/boot.o ./build/i386/gdt.asm.o ./build/i386/idt.asm.o ./build/i386/irq.o ./build/i386/exceptions.o ./build/i386/isr.o ./build/i386/io.o ./build/i386/vga.o ./build/i386/pic.o ./build/i386/cmos.o ./build/i386/keyboard.o ./build/i386/console.o ./build/i386/fpu.o ./build/i386/pit.o ./build/i386/kernel.o ./isodir/boot/piriquitOS-i386.bin ./build/piriquitOS-i386.iso +build i386: phony ./libs/libc.a ./build/i386/ata.o ./build/i386/acpi.o ./build/i386/madt.o ./build/i386/boot.o ./build/i386/gdt.asm.o ./build/i386/idt.asm.o ./build/i386/irq.o ./build/i386/exceptions.o ./build/i386/isr.o ./build/i386/io.o ./build/i386/vga.o ./build/i386/pic.o ./build/i386/cmos.o ./build/i386/keyboard.o ./build/i386/console.o ./build/i386/fpu.o ./build/i386/pit.o ./build/i386/kernel.o ./isodir/boot/piriquitOS-i386.bin ./build/piriquitOS-i386.iso default help diff --git a/src/arch/i386/kernel/acpi.c b/src/arch/i386/kernel/acpi.c index 2d0725f..d6ced49 100644 --- a/src/arch/i386/kernel/acpi.c +++ b/src/arch/i386/kernel/acpi.c @@ -1,6 +1,7 @@ #include "include/acpi.h" #include "libc/include/string.h" #include "libc/include/stdio.h" +#include "include/isr.h" static acpi_rsdp_t *rsdp = NULL; static acpi_xsdt_t *xsdt = NULL; @@ -14,6 +15,8 @@ static bool validate_table(acpi_sdt_header_t *table_header) { } bool acpi_init(void) { + //TODO: ACPI IRQ/ISR + // Search for the RSDP for (u8 *addr = (u8 *)0x000E0000; addr < (u8 *)0x00100000; addr += 16) { if (memcmp(addr, "RSD PTR ", 8) == 0) { diff --git a/src/arch/i386/kernel/drivers/ata.c b/src/arch/i386/kernel/drivers/ata.c new file mode 100644 index 0000000..4e0b122 --- /dev/null +++ b/src/arch/i386/kernel/drivers/ata.c @@ -0,0 +1,182 @@ +#include "../include/drivers/ata.h" +#include "../include/io.h" +#include "../include/drivers/pic.h" +#include "../include/console.h" + +void ata_wait_bsy() { + while (inportb(ATA_PRIMARY_IO + ATA_REG_STATUS) & 0x80); +} + +void ata_wait_drq() { + while (!(inportb(ATA_PRIMARY_IO + ATA_REG_STATUS) & 0x08)); +} + +bool ata_read_sector(u8 *buffer, u32 lba) { + ata_wait_bsy(); + + outportb(ATA_PRIMARY_IO + ATA_REG_HDDEVSEL, 0xE0 | ((lba >> 24) & 0x0F)); + outportb(ATA_PRIMARY_IO + ATA_REG_FEATURES, 0); + outportb(ATA_PRIMARY_IO + ATA_REG_SECCOUNT0, 1); + outportb(ATA_PRIMARY_IO + ATA_REG_LBA0, (u8)lba); + outportb(ATA_PRIMARY_IO + ATA_REG_LBA1, (u8)(lba >> 8)); + outportb(ATA_PRIMARY_IO + ATA_REG_LBA2, (u8)(lba >> 16)); + outportb(ATA_PRIMARY_IO + ATA_REG_COMMAND, ATA_CMD_READ_PIO); + + ata_wait_bsy(); + ata_wait_drq(); + + for (int i = 0; i < 256; i++) { + u16 data = *(u16*)(ATA_PRIMARY_IO + ATA_REG_DATA); + buffer[i*2] = (u8)data; + buffer[i*2+1] = (u8)(data >> 8); + } + + ata_wait_bsy(); + + return true; +} + +bool ata_write_sector(u8 *buffer, u32 lba) { + ata_wait_bsy(); + + outportb(ATA_PRIMARY_IO + ATA_REG_HDDEVSEL, 0xE0 | ((lba >> 24) & 0x0F)); + outportb(ATA_PRIMARY_IO + ATA_REG_FEATURES, 0); + outportb(ATA_PRIMARY_IO + ATA_REG_SECCOUNT0, 1); + outportb(ATA_PRIMARY_IO + ATA_REG_LBA0, (u8)lba); + outportb(ATA_PRIMARY_IO + ATA_REG_LBA1, (u8)(lba >> 8)); + outportb(ATA_PRIMARY_IO + ATA_REG_LBA2, (u8)(lba >> 16)); + outportb(ATA_PRIMARY_IO + ATA_REG_COMMAND, ATA_CMD_WRITE_PIO); + + ata_wait_bsy(); + ata_wait_drq(); + + for (int i = 0; i < 256; i++) { + u16 data = buffer[i*2] | (buffer[i*2+1] << 8); + *(u16*)(ATA_PRIMARY_IO + ATA_REG_DATA) = data; + io_wait(); + } + + ata_wait_bsy(); + + return true; +} + +void ata_read_identify(u16 io_port, ata_device_t* device) { + u16 identify_data[256]; + for (int i = 0; i < 256; i++) { + identify_data[i] = *(u16*)(io_port + ATA_REG_DATA); + } + + device->present = true; + device->signature = identify_data[0]; + device->capabilities = identify_data[49]; + device->command_sets = identify_data[82] | ((u32)identify_data[83] << 16); + device->size = identify_data[60] | ((u32)identify_data[61] << 16); + + for (int i = 0; i < 20; i++) { + u16 data = identify_data[27 + i]; + device->model[i*2] = (data >> 8) & 0xFF; + device->model[i*2 + 1] = data & 0xFF; + } + device->model[40] = '\0'; + + for (int i = 39; i >= 0 && device->model[i] == ' '; i--) { + device->model[i] = '\0'; + } +} + +int ata_software_reset(u16 io_base) { + outportb(io_base + ATA_REG_COMMAND, 4); + io_wait(); + outportb(io_base + ATA_REG_COMMAND, 0); + io_wait(); + + for (int i = 0; i < 1000; i++) { + if ((inportb(io_base + ATA_REG_STATUS) & 0x80) == 0) { + return 0; + } + io_wait(); + } + + return -1; +} + +void ata_probe_devices() { + outportb(ATA_PRIMARY_IO + ATA_REG_HDDEVSEL, 0xA0); + io_wait(); + if (ata_software_reset(ATA_PRIMARY_IO) == 0) { + ata_read_identify(ATA_PRIMARY_IO, &ata_primary_master); + } + + outportb(ATA_PRIMARY_IO + ATA_REG_HDDEVSEL, 0xB0); + io_wait(); + if (ata_software_reset(ATA_PRIMARY_IO) == 0) { + ata_read_identify(ATA_PRIMARY_IO, &ata_primary_slave); + } + + outportb(ATA_SECONDARY_IO + ATA_REG_HDDEVSEL, 0xA0); + io_wait(); + if (ata_software_reset(ATA_SECONDARY_IO) == 0) { + ata_read_identify(ATA_SECONDARY_IO, &ata_secondary_master); + } + + outportb(ATA_SECONDARY_IO + ATA_REG_HDDEVSEL, 0xB0); + io_wait(); + if (ata_software_reset(ATA_SECONDARY_IO) == 0) { + ata_read_identify(ATA_SECONDARY_IO, &ata_secondary_slave); + } +} + +ata_status_t ata_read_status(u16 io_base) { + u8 status = inportb(io_base + ATA_REG_STATUS); + return (ata_status_t) { + .busy = (status & 0x80) != 0, + .data_ready = (status & 0x08) != 0, + .error = (status & 0x01) != 0 + }; +} + +void ata_interrupt_handler(registers_t *regs) { + ata_status_t primary_status = ata_read_status(ATA_PRIMARY_IO); + ata_status_t secondary_status = ata_read_status(ATA_SECONDARY_IO); + + if (!primary_status.busy) { + ata_primary_status = primary_status; + if (primary_status.error) { + u8 error = inportb(ATA_PRIMARY_IO + ATA_REG_ERROR); + } else if (primary_status.data_ready) { + } + } + + if (!secondary_status.busy) { + ata_secondary_status = secondary_status; + if (secondary_status.error) { + u8 error = inportb(ATA_SECONDARY_IO + ATA_REG_ERROR); + } else if (secondary_status.data_ready) { + } + } + + inportb(ATA_PRIMARY_IO + ATA_REG_STATUS); + inportb(ATA_SECONDARY_IO + ATA_REG_STATUS); +} + +bool ata_init() { + printf("Initializing ATA...\n"); + isr_register_interrupt_handler(IRQ_ATA1, ata_interrupt_handler); + isr_register_interrupt_handler(IRQ_ATA2, ata_interrupt_handler); + + ata_primary_status = (ata_status_t){0}; + ata_secondary_status = (ata_status_t){0}; + + ata_probe_devices(); + + ata_software_reset(ATA_PRIMARY_IO); + ata_software_reset(ATA_SECONDARY_IO); + + ata_probe_devices(); + + unmask(IRQ_ATA1 - IRQ_BASE); + unmask(IRQ_ATA2 - IRQ_BASE); + + return true; +} diff --git a/src/arch/i386/kernel/include/drivers/ata.h b/src/arch/i386/kernel/include/drivers/ata.h new file mode 100644 index 0000000..0fa8315 --- /dev/null +++ b/src/arch/i386/kernel/include/drivers/ata.h @@ -0,0 +1,59 @@ +#ifndef ATA_H +#define ATA_H + +#include "../libc/include/types.h" +#include "../isr.h" + +#define ATA_PRIMARY_IO 0x1F0 +#define ATA_SECONDARY_IO 0x170 + +#define ATA_REG_DATA 0x00 +#define ATA_REG_ERROR 0x01 +#define ATA_REG_FEATURES 0x01 +#define ATA_REG_SECCOUNT0 0x02 +#define ATA_REG_LBA0 0x03 +#define ATA_REG_LBA1 0x04 +#define ATA_REG_LBA2 0x05 +#define ATA_REG_HDDEVSEL 0x06 +#define ATA_REG_COMMAND 0x07 +#define ATA_REG_STATUS 0x07 +#define ATA_REG_CONTROL 0x0C + +#define ATA_CMD_READ_PIO 0x20 +#define ATA_CMD_WRITE_PIO 0x30 + +typedef struct { + bool present; + bool is_atapi; + u16 signature; + u16 capabilities; + u32 command_sets; + u32 size; + char model[41]; +} ata_device_t; + +typedef struct { + bool busy; + bool data_ready; + bool error; +} ata_status_t; + +static ata_device_t ata_primary_master; +static ata_device_t ata_primary_slave; +static ata_device_t ata_secondary_master; +static ata_device_t ata_secondary_slave; +static ata_status_t ata_primary_status; +static ata_status_t ata_secondary_status; + +void ata_wait_bsy(); +void ata_wait_drq(); +bool ata_read_sector(u8 *buf, u32 sector); +bool ata_write_sector(u8 *buf, u32 sector); +void ata_read_identify(u16 io_port, ata_device_t* device); +int ata_software_reset(u16 io_base); +void ata_probe_devices(); +ata_status_t ata_read_status(u16 io_base); +void ata_interrupt_handler(registers_t *regs); +bool ata_init(); + +#endif // !ATA_H diff --git a/src/arch/i386/kernel/include/io.h b/src/arch/i386/kernel/include/io.h index a9cc1e4..440d3e4 100644 --- a/src/arch/i386/kernel/include/io.h +++ b/src/arch/i386/kernel/include/io.h @@ -11,4 +11,6 @@ void outportb(u16 port, u8 data); void outportw(u16 port, u16 data); void outportl(u16 port, u32 data); +void io_wait(); + #endif diff --git a/src/arch/i386/kernel/io.c b/src/arch/i386/kernel/io.c index 0f5fbbe..5f9b50b 100644 --- a/src/arch/i386/kernel/io.c +++ b/src/arch/i386/kernel/io.c @@ -31,3 +31,7 @@ u32 inportl(u16 port) { void outportl(u16 port, u32 data) { asmv("outl %%eax, %%dx" : : "dN"(port), "a"(data)); } + +void io_wait(){ + outportb(0x80, 0); +} diff --git a/src/arch/i386/kernel/kernel.c b/src/arch/i386/kernel/kernel.c index 076135c..c6814f2 100644 --- a/src/arch/i386/kernel/kernel.c +++ b/src/arch/i386/kernel/kernel.c @@ -2,12 +2,13 @@ #include "include/console.h" #include "include/drivers/vga.h" #include "include/gdt.h" +#include "include/madt.h" #include "include/drivers/pic.h" #include "include/drivers/keyboard.h" #include "include/drivers/cmos.h" #include "include/drivers/fpu.h" #include "include/drivers/pit.h" -#include "include/madt.h" +#include "include/drivers/ata.h" void cpuid(u32 type, u32 *eax, u32 *ebx, u32 *ecx, u32 *edx) { @@ -76,6 +77,7 @@ void kmain() init_pit(); init_keyboard(); init_cmos(); + ata_init(); while (1) {