From: Tulio A M Mendes Date: Tue, 10 Feb 2026 05:42:24 +0000 (-0300) Subject: refactor: move x86 ATA PIO driver from src/drivers/ata_pio.c to src/hal/x86/ata_pio.c X-Git-Url: https://projects.tadryanom.me/sitemap.xml?a=commitdiff_plain;h=f6f684e125ed63ade43bdd526a03a3f77e8a18ca;p=AdrOS.git refactor: move x86 ATA PIO driver from src/drivers/ata_pio.c to src/hal/x86/ata_pio.c ATA PIO uses x86 I/O port instructions (inb/outb/inw/outw) for disk access. The full implementation now lives in src/hal/x86/ata_pio.c (no #if guards). src/drivers/ata_pio.c contains only weak stubs returning -ENOSYS, overridden at link time for x86. Passes: make, cppcheck, QEMU smoke test. --- diff --git a/src/drivers/ata_pio.c b/src/drivers/ata_pio.c index 6c33b93..d9197d6 100644 --- a/src/drivers/ata_pio.c +++ b/src/drivers/ata_pio.c @@ -1,151 +1,14 @@ #include "ata_pio.h" - #include "errno.h" -#include "io.h" - -#if defined(__i386__) - -// Primary ATA bus I/O ports -#define ATA_IO_BASE 0x1F0 -#define ATA_CTRL_BASE 0x3F6 - -#define ATA_REG_DATA 0x00 -#define ATA_REG_ERROR 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_CMD_READ_SECTORS 0x20 -#define ATA_CMD_WRITE_SECTORS 0x30 -#define ATA_CMD_CACHE_FLUSH 0xE7 -#define ATA_CMD_IDENTIFY 0xEC - -#define ATA_SR_BSY 0x80 -#define ATA_SR_DRDY 0x40 -#define ATA_SR_DF 0x20 -#define ATA_SR_DSC 0x10 -#define ATA_SR_DRQ 0x08 -#define ATA_SR_ERR 0x01 - -static inline void io_wait_400ns(void) { - (void)inb((uint16_t)ATA_CTRL_BASE); - (void)inb((uint16_t)ATA_CTRL_BASE); - (void)inb((uint16_t)ATA_CTRL_BASE); - (void)inb((uint16_t)ATA_CTRL_BASE); -} - -static int ata_wait_not_busy(void) { - for (int i = 0; i < 1000000; i++) { - uint8_t st = inb((uint16_t)(ATA_IO_BASE + ATA_REG_STATUS)); - if ((st & ATA_SR_BSY) == 0) return 0; - } - return -EIO; -} - -static int ata_wait_drq(void) { - for (int i = 0; i < 1000000; i++) { - uint8_t st = inb((uint16_t)(ATA_IO_BASE + ATA_REG_STATUS)); - if (st & ATA_SR_ERR) return -EIO; - if (st & ATA_SR_DF) return -EIO; - if ((st & ATA_SR_BSY) == 0 && (st & ATA_SR_DRQ)) return 0; - } - return -EIO; -} - -uint32_t ata_pio_sector_size(void) { - return 512; -} - -int ata_pio_init_primary_master(void) { - // Select drive: 0xA0 = master, CHS mode bits set, LBA bit cleared - outb((uint16_t)(ATA_IO_BASE + ATA_REG_HDDEVSEL), 0xA0); - io_wait_400ns(); - - if (ata_wait_not_busy() < 0) return -EIO; - - // IDENTIFY - outb((uint16_t)(ATA_IO_BASE + ATA_REG_SECCOUNT0), 0); - outb((uint16_t)(ATA_IO_BASE + ATA_REG_LBA0), 0); - outb((uint16_t)(ATA_IO_BASE + ATA_REG_LBA1), 0); - outb((uint16_t)(ATA_IO_BASE + ATA_REG_LBA2), 0); - outb((uint16_t)(ATA_IO_BASE + ATA_REG_COMMAND), ATA_CMD_IDENTIFY); - - uint8_t st = inb((uint16_t)(ATA_IO_BASE + ATA_REG_STATUS)); - if (st == 0) return -ENODEV; - - if (ata_wait_drq() < 0) return -EIO; - - // Read 256 words (512 bytes) identify data and discard. - for (int i = 0; i < 256; i++) { - (void)inw((uint16_t)(ATA_IO_BASE + ATA_REG_DATA)); - } - - return 0; -} - -int ata_pio_read28(uint32_t lba, uint8_t* buf512) { - if (!buf512) return -EFAULT; - if (lba & 0xF0000000U) return -EINVAL; - - if (ata_wait_not_busy() < 0) return -EIO; - - outb((uint16_t)(ATA_IO_BASE + ATA_REG_HDDEVSEL), (uint8_t)(0xE0 | ((lba >> 24) & 0x0F))); - io_wait_400ns(); - - outb((uint16_t)(ATA_IO_BASE + ATA_REG_SECCOUNT0), 1); - outb((uint16_t)(ATA_IO_BASE + ATA_REG_LBA0), (uint8_t)(lba & 0xFF)); - outb((uint16_t)(ATA_IO_BASE + ATA_REG_LBA1), (uint8_t)((lba >> 8) & 0xFF)); - outb((uint16_t)(ATA_IO_BASE + ATA_REG_LBA2), (uint8_t)((lba >> 16) & 0xFF)); - outb((uint16_t)(ATA_IO_BASE + ATA_REG_COMMAND), ATA_CMD_READ_SECTORS); - - if (ata_wait_drq() < 0) return -EIO; - - uint16_t* w = (uint16_t*)buf512; - for (int i = 0; i < 256; i++) { - w[i] = inw((uint16_t)(ATA_IO_BASE + ATA_REG_DATA)); - } - - io_wait_400ns(); - return 0; -} - -int ata_pio_write28(uint32_t lba, const uint8_t* buf512) { - if (!buf512) return -EFAULT; - if (lba & 0xF0000000U) return -EINVAL; - - if (ata_wait_not_busy() < 0) return -EIO; - - outb((uint16_t)(ATA_IO_BASE + ATA_REG_HDDEVSEL), (uint8_t)(0xE0 | ((lba >> 24) & 0x0F))); - io_wait_400ns(); - - outb((uint16_t)(ATA_IO_BASE + ATA_REG_SECCOUNT0), 1); - outb((uint16_t)(ATA_IO_BASE + ATA_REG_LBA0), (uint8_t)(lba & 0xFF)); - outb((uint16_t)(ATA_IO_BASE + ATA_REG_LBA1), (uint8_t)((lba >> 8) & 0xFF)); - outb((uint16_t)(ATA_IO_BASE + ATA_REG_LBA2), (uint8_t)((lba >> 16) & 0xFF)); - outb((uint16_t)(ATA_IO_BASE + ATA_REG_COMMAND), ATA_CMD_WRITE_SECTORS); - - if (ata_wait_drq() < 0) return -EIO; - - const uint16_t* w = (const uint16_t*)buf512; - for (int i = 0; i < 256; i++) { - outw((uint16_t)(ATA_IO_BASE + ATA_REG_DATA), w[i]); - } - - outb((uint16_t)(ATA_IO_BASE + ATA_REG_COMMAND), ATA_CMD_CACHE_FLUSH); - (void)ata_wait_not_busy(); - io_wait_400ns(); - return 0; -} - -#else +__attribute__((weak)) uint32_t ata_pio_sector_size(void) { return 512; } + +__attribute__((weak)) int ata_pio_init_primary_master(void) { return -ENOSYS; } + +__attribute__((weak)) int ata_pio_read28(uint32_t lba, uint8_t* buf512) { (void)lba; (void)buf512; return -ENOSYS; } -int ata_pio_write28(uint32_t lba, const uint8_t* buf512) { (void)lba; (void)buf512; return -ENOSYS; } -#endif +__attribute__((weak)) +int ata_pio_write28(uint32_t lba, const uint8_t* buf512) { (void)lba; (void)buf512; return -ENOSYS; } diff --git a/src/hal/x86/ata_pio.c b/src/hal/x86/ata_pio.c new file mode 100644 index 0000000..4406a47 --- /dev/null +++ b/src/hal/x86/ata_pio.c @@ -0,0 +1,140 @@ +#include "ata_pio.h" + +#include "errno.h" +#include "io.h" + +// Primary ATA bus I/O ports +#define ATA_IO_BASE 0x1F0 +#define ATA_CTRL_BASE 0x3F6 + +#define ATA_REG_DATA 0x00 +#define ATA_REG_ERROR 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_CMD_READ_SECTORS 0x20 +#define ATA_CMD_WRITE_SECTORS 0x30 +#define ATA_CMD_CACHE_FLUSH 0xE7 +#define ATA_CMD_IDENTIFY 0xEC + +#define ATA_SR_BSY 0x80 +#define ATA_SR_DRDY 0x40 +#define ATA_SR_DF 0x20 +#define ATA_SR_DSC 0x10 +#define ATA_SR_DRQ 0x08 +#define ATA_SR_ERR 0x01 + +static inline void io_wait_400ns(void) { + (void)inb((uint16_t)ATA_CTRL_BASE); + (void)inb((uint16_t)ATA_CTRL_BASE); + (void)inb((uint16_t)ATA_CTRL_BASE); + (void)inb((uint16_t)ATA_CTRL_BASE); +} + +static int ata_wait_not_busy(void) { + for (int i = 0; i < 1000000; i++) { + uint8_t st = inb((uint16_t)(ATA_IO_BASE + ATA_REG_STATUS)); + if ((st & ATA_SR_BSY) == 0) return 0; + } + return -EIO; +} + +static int ata_wait_drq(void) { + for (int i = 0; i < 1000000; i++) { + uint8_t st = inb((uint16_t)(ATA_IO_BASE + ATA_REG_STATUS)); + if (st & ATA_SR_ERR) return -EIO; + if (st & ATA_SR_DF) return -EIO; + if ((st & ATA_SR_BSY) == 0 && (st & ATA_SR_DRQ)) return 0; + } + return -EIO; +} + +uint32_t ata_pio_sector_size(void) { + return 512; +} + +int ata_pio_init_primary_master(void) { + // Select drive: 0xA0 = master, CHS mode bits set, LBA bit cleared + outb((uint16_t)(ATA_IO_BASE + ATA_REG_HDDEVSEL), 0xA0); + io_wait_400ns(); + + if (ata_wait_not_busy() < 0) return -EIO; + + // IDENTIFY + outb((uint16_t)(ATA_IO_BASE + ATA_REG_SECCOUNT0), 0); + outb((uint16_t)(ATA_IO_BASE + ATA_REG_LBA0), 0); + outb((uint16_t)(ATA_IO_BASE + ATA_REG_LBA1), 0); + outb((uint16_t)(ATA_IO_BASE + ATA_REG_LBA2), 0); + outb((uint16_t)(ATA_IO_BASE + ATA_REG_COMMAND), ATA_CMD_IDENTIFY); + + uint8_t st = inb((uint16_t)(ATA_IO_BASE + ATA_REG_STATUS)); + if (st == 0) return -ENODEV; + + if (ata_wait_drq() < 0) return -EIO; + + // Read 256 words (512 bytes) identify data and discard. + for (int i = 0; i < 256; i++) { + (void)inw((uint16_t)(ATA_IO_BASE + ATA_REG_DATA)); + } + + return 0; +} + +int ata_pio_read28(uint32_t lba, uint8_t* buf512) { + if (!buf512) return -EFAULT; + if (lba & 0xF0000000U) return -EINVAL; + + if (ata_wait_not_busy() < 0) return -EIO; + + outb((uint16_t)(ATA_IO_BASE + ATA_REG_HDDEVSEL), (uint8_t)(0xE0 | ((lba >> 24) & 0x0F))); + io_wait_400ns(); + + outb((uint16_t)(ATA_IO_BASE + ATA_REG_SECCOUNT0), 1); + outb((uint16_t)(ATA_IO_BASE + ATA_REG_LBA0), (uint8_t)(lba & 0xFF)); + outb((uint16_t)(ATA_IO_BASE + ATA_REG_LBA1), (uint8_t)((lba >> 8) & 0xFF)); + outb((uint16_t)(ATA_IO_BASE + ATA_REG_LBA2), (uint8_t)((lba >> 16) & 0xFF)); + outb((uint16_t)(ATA_IO_BASE + ATA_REG_COMMAND), ATA_CMD_READ_SECTORS); + + if (ata_wait_drq() < 0) return -EIO; + + uint16_t* w = (uint16_t*)buf512; + for (int i = 0; i < 256; i++) { + w[i] = inw((uint16_t)(ATA_IO_BASE + ATA_REG_DATA)); + } + + io_wait_400ns(); + return 0; +} + +int ata_pio_write28(uint32_t lba, const uint8_t* buf512) { + if (!buf512) return -EFAULT; + if (lba & 0xF0000000U) return -EINVAL; + + if (ata_wait_not_busy() < 0) return -EIO; + + outb((uint16_t)(ATA_IO_BASE + ATA_REG_HDDEVSEL), (uint8_t)(0xE0 | ((lba >> 24) & 0x0F))); + io_wait_400ns(); + + outb((uint16_t)(ATA_IO_BASE + ATA_REG_SECCOUNT0), 1); + outb((uint16_t)(ATA_IO_BASE + ATA_REG_LBA0), (uint8_t)(lba & 0xFF)); + outb((uint16_t)(ATA_IO_BASE + ATA_REG_LBA1), (uint8_t)((lba >> 8) & 0xFF)); + outb((uint16_t)(ATA_IO_BASE + ATA_REG_LBA2), (uint8_t)((lba >> 16) & 0xFF)); + outb((uint16_t)(ATA_IO_BASE + ATA_REG_COMMAND), ATA_CMD_WRITE_SECTORS); + + if (ata_wait_drq() < 0) return -EIO; + + const uint16_t* w = (const uint16_t*)buf512; + for (int i = 0; i < 256; i++) { + outw((uint16_t)(ATA_IO_BASE + ATA_REG_DATA), w[i]); + } + + outb((uint16_t)(ATA_IO_BASE + ATA_REG_COMMAND), ATA_CMD_CACHE_FLUSH); + (void)ata_wait_not_busy(); + io_wait_400ns(); + return 0; +}