]> Projects (at) Tadryanom (dot) Me - AdrOS.git/commitdiff
refactor: move x86 ATA PIO driver from src/drivers/ata_pio.c to src/hal/x86/ata_pio.c
authorTulio A M Mendes <[email protected]>
Tue, 10 Feb 2026 05:42:24 +0000 (02:42 -0300)
committerTulio A M Mendes <[email protected]>
Tue, 10 Feb 2026 05:42:24 +0000 (02:42 -0300)
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.

src/drivers/ata_pio.c
src/hal/x86/ata_pio.c [new file with mode: 0644]

index 6c33b9380faf02c6ea3a3928a873fe6b5764561c..d9197d6ba96b6dd9a8335a495980c7d849ba9719 100644 (file)
 #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 (file)
index 0000000..4406a47
--- /dev/null
@@ -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;
+}