From c3621a33dcbbf619c8a1a54b707b6dc85b4885e6 Mon Sep 17 00:00:00 2001 From: kamkow1 Date: Sun, 19 Oct 2025 15:46:56 +0200 Subject: [PATCH] Support up to 4 ATA drives (primary and secondary bus) --- base/scripts/mount.tb | 1 + kernel/storedev/atasd.c | 211 +++++++++++++++++++++++++------------ kernel/storedev/atasd.h | 4 + kernel/storedev/storedev.c | 5 +- 4 files changed, 155 insertions(+), 66 deletions(-) diff --git a/base/scripts/mount.tb b/base/scripts/mount.tb index c9fa816..f65dd1b 100644 --- a/base/scripts/mount.tb +++ b/base/scripts/mount.tb @@ -1,2 +1,3 @@ print 'Mounting filesystems...\n' +setlogcmds yes $fs mount -mp system -fs LittleFS -dev atasd-ch0-M -fmt no diff --git a/kernel/storedev/atasd.c b/kernel/storedev/atasd.c index 6e5ffb0..6d055a3 100644 --- a/kernel/storedev/atasd.c +++ b/kernel/storedev/atasd.c @@ -10,16 +10,15 @@ #include "hshtb.h" #include "vfs/vfs.h" -#define ATA_REG_DATA 0x1f0 -#define ATA_REG_ERROR 0x1f1 -#define ATA_REG_SECCOUNT0 0x1f2 -#define ATA_REG_LBA0 0x1f3 -#define ATA_REG_LBA1 0x1f4 -#define ATA_REG_LBA2 0x1f5 -#define ATA_REG_DRIVE 0x1f6 -#define ATA_REG_STATUS 0x1f7 -#define ATA_REG_COMMAND 0x1f7 -#define ATA_REG_CTRL 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_DRIVE 0x06 +#define ATA_REG_STATUS 0x07 +#define ATA_REG_COMMAND 0x07 #define ATA_BSY 0x80 #define ATA_DRDY 0x40 @@ -35,11 +34,11 @@ #define ATA_MASTER 0x00 #define ATA_SLAVE 0x01 -int ata_wait(uint32_t timeout, bool require_drq, int checkerr) { +int ata_wait(uint16_t iobase, uint32_t timeout, bool require_drq, int checkerr) { uint32_t i = 0; uint8_t st; for(;;) { - st = io_in8(ATA_REG_STATUS); + st = io_in8(iobase + ATA_REG_STATUS); if (!(st & ATA_BSY)) break; if (++i >= timeout) @@ -50,7 +49,7 @@ int ata_wait(uint32_t timeout, bool require_drq, int checkerr) { while (!(st & ATA_DRQ)) { if (st & ATA_ERR) return -1; - st = io_in8(ATA_REG_STATUS); + st = io_in8(iobase + ATA_REG_STATUS); if (++i >= timeout) return -1; } @@ -60,38 +59,38 @@ int ata_wait(uint32_t timeout, bool require_drq, int checkerr) { return 0; } -void ata_delay400ns(void) { - io_in8(ATA_REG_CTRL); - io_in8(ATA_REG_CTRL); - io_in8(ATA_REG_CTRL); - io_in8(ATA_REG_CTRL); +void ata_delay400ns(uint16_t ctrlbase) { + io_in8(ctrlbase); + io_in8(ctrlbase); + io_in8(ctrlbase); + io_in8(ctrlbase); } // caller must synchronize -uint64_t ata_probesize_bytes(int devno) { +uint64_t ata_probesize_bytes(uint16_t iobase, uint16_t ctrlbase, int devno) { uint16_t identifydata[0x100]; - io_out8(ATA_REG_DRIVE, 0xA0 | (devno << 4)); - ata_delay400ns(); + io_out8(iobase + ATA_REG_DRIVE, 0xA0 | (devno << 4)); + ata_delay400ns(ctrlbase); - io_out8(ATA_REG_SECCOUNT0, 0); - io_out8(ATA_REG_LBA0, 0); - io_out8(ATA_REG_LBA1, 0); - io_out8(ATA_REG_LBA2, 0); + io_out8(iobase + ATA_REG_SECCOUNT0, 0); + io_out8(iobase + ATA_REG_LBA0, 0); + io_out8(iobase + ATA_REG_LBA1, 0); + io_out8(iobase + ATA_REG_LBA2, 0); - io_out8(ATA_REG_COMMAND, ATA_CMD_IDENTIFY); + io_out8(iobase + ATA_REG_COMMAND, ATA_CMD_IDENTIFY); - if (ata_wait(100000, false, 0) < 0) + if (ata_wait(iobase, 100000, false, 0) < 0) return 0; - uint8_t st = io_in8(ATA_REG_STATUS); + uint8_t st = io_in8(iobase + ATA_REG_STATUS); if (st == 0) return 0; - if (ata_wait(100000, true, 1) < 0) + if (ata_wait(iobase, 100000, true, 1) < 0) return 0; - io_ins16(ATA_REG_DATA, identifydata, 256); + io_ins16(iobase + ATA_REG_DATA, identifydata, 256); bool lba48 = (identifydata[83] & (1<<10)) != 0; if (lba48) { @@ -107,53 +106,135 @@ uint64_t ata_probesize_bytes(int devno) { } } -bool ata_probe1(int drive) { - io_out8(ATA_REG_DRIVE, 0xA0 | (drive << 4)); - for (int i = 0; i < 1000; i++) { - uint8_t status = io_in8(ATA_REG_STATUS); - if (status != 0 && status != 0xFF) - return true; // got something - } - return false; -} +/* bool ata_probe1(uint16_t iobase, uint16_t ctrlbase, int drive) { */ +/* /1* io_out8(iobase + ATA_REG_DRIVE, 0xA0 | (drive << 4)); *1/ */ +/* /1* for (int i = 0; i < 1000; i++) { *1/ */ +/* /1* uint8_t status = io_in8(iobase + ATA_REG_STATUS); *1/ */ +/* /1* if (status != 0 && status != 0xFF) *1/ */ +/* /1* return true; // got something *1/ */ +/* /1* } *1/ */ +/* /1* return false; *1/ */ + +/* uint8_t cl, ch; */ + +/* io_out8(iobase + ATA_REG_DRIVE, 0xA0 | (drive << 4)); */ +/* ata_delay400ns(ctrlbase); */ + +/* io_out8(iobase + ATA_REG_SECCOUNT0, 0x55); */ +/* io_out8(iobase + ATA_REG_LBA0, 0xAA); */ +/* io_out8(iobase + ATA_REG_SECCOUNT0, 0xAA); */ +/* io_out8(iobase + ATA_REG_LBA0, 0x55); */ + +/* cl = io_in8(iobase + ATA_REG_SECCOUNT0); */ +/* ch = io_in8(iobase + ATA_REG_LBA0); */ + +/* if (cl != 0x55 || ch != 0xAA) */ +/* return false; */ + +/* io_out8(iobase + ATA_REG_COMMAND, ATA_CMD_IDENTIFY); */ +/* ata_delay400ns(ctrlbase); */ + +/* uint8_t st = io_in8(iobase + ATA_REG_STATUS); */ +/* if (st == 0) */ +/* return false; */ + +/* while ((st & (ATA_BSY | ATA_DRQ | ATA_ERR)) == ATA_BSY) */ +/* st = io_in8(iobase + ATA_REG_STATUS); */ + +/* if (st & ATA_ERR) */ +/* return false; */ + +/* if (!(st & ATA_DRQ)) */ +/* return false; */ + +/* return true; */ +/* } */ void ata_probe(void) { - if (ata_probe1(ATA_MASTER)) { - uint64_t probesize = ata_probesize_bytes(ATA_MASTER); + uint64_t probesize; + + probesize = ata_probesize_bytes(0x1F0, 0x3F6, ATA_MASTER); + if (probesize > 0) { char hs[20]; - LOG("ata", "found ATA Master, size = %s\n", human_size(probesize, hs, sizeof(hs))); + LOG("ata", "found ATA primary bus master, size = %s\n", human_size(probesize, hs, sizeof(hs))); AtaSdInitExtra extra = { .devno = ATA_MASTER, .capacity = probesize, + .iobase = 0x1F0, + .ctrlbase = 0x3F6, + }; + storedev_create(STOREDEV_ATASD, (void *)&extra); + } + + probesize = ata_probesize_bytes(0x1F0, 0x3F6, ATA_SLAVE); + if (probesize > 0) { + char hs[20]; + LOG("ata", "found ATA primary bus slave, size = %s\n", human_size(probesize, hs, sizeof(hs))); + + AtaSdInitExtra extra = { + .devno = ATA_SLAVE, + .capacity = probesize, + .iobase = 0x1F0, + .ctrlbase = 0x3F6, + }; + storedev_create(STOREDEV_ATASD, (void *)&extra); + } + + probesize = ata_probesize_bytes(0x170, 0x376, ATA_MASTER); + if (probesize > 0) { + char hs[20]; + LOG("ata", "found ATA secondary bus master, size = %s\n", human_size(probesize, hs, sizeof(hs))); + + AtaSdInitExtra extra = { + .devno = ATA_MASTER, + .capacity = probesize, + .iobase = 0x170, + .ctrlbase = 0x376, + }; + storedev_create(STOREDEV_ATASD, (void *)&extra); + } + + probesize = ata_probesize_bytes(0x170, 0x376, ATA_SLAVE); + if (probesize > 0) { + char hs[20]; + LOG("ata", "found ATA secondary bus slave, size = %s\n", human_size(probesize, hs, sizeof(hs))); + + AtaSdInitExtra extra = { + .devno = ATA_SLAVE, + .capacity = probesize, + .iobase = 0x170, + .ctrlbase = 0x376, }; storedev_create(STOREDEV_ATASD, (void *)&extra); } } -void ata_setup(int devno, uint16_t sectors, uint64_t lba) { - io_out8(ATA_REG_CTRL, 0x02); +void ata_setup(uint16_t iobase, uint16_t ctrlbase, int devno, uint16_t sectors, uint64_t lba) { + io_out8(ctrlbase, 0x02); - io_out8(ATA_REG_DRIVE, 0x40 | (devno << 4)); - ata_delay400ns(); + io_out8(iobase + ATA_REG_DRIVE, 0x40 | (devno << 4)); + ata_delay400ns(ctrlbase); - io_out8(ATA_REG_SECCOUNT0, (sectors >> 8) & 0xFF); - io_out8(ATA_REG_LBA0, (lba >> 24) & 0xFF); - io_out8(ATA_REG_LBA1, (lba >> 32) & 0xFF); - io_out8(ATA_REG_LBA2, (lba >> 40) & 0xFF); + io_out8(iobase + ATA_REG_SECCOUNT0, (sectors >> 8) & 0xFF); + io_out8(iobase + ATA_REG_LBA0, (lba >> 24) & 0xFF); + io_out8(iobase + ATA_REG_LBA1, (lba >> 32) & 0xFF); + io_out8(iobase + ATA_REG_LBA2, (lba >> 40) & 0xFF); - io_out8(ATA_REG_SECCOUNT0, sectors & 0xFF); - io_out8(ATA_REG_LBA0, (uint8_t)(lba & 0xFF)); - io_out8(ATA_REG_LBA1, (uint8_t)((lba >> 8) & 0xFF)); - io_out8(ATA_REG_LBA2, (uint8_t)((lba >> 16) & 0xFF)); + io_out8(iobase + ATA_REG_SECCOUNT0, sectors & 0xFF); + io_out8(iobase + ATA_REG_LBA0, (uint8_t)(lba & 0xFF)); + io_out8(iobase + ATA_REG_LBA1, (uint8_t)((lba >> 8) & 0xFF)); + io_out8(iobase + ATA_REG_LBA2, (uint8_t)((lba >> 16) & 0xFF)); } int32_t atasd_init(struct StoreDev *sd, void *extra) { AtaSdInitExtra *e = (AtaSdInitExtra *)extra; - sd->sd.atasd.devno = e->devno; + sd->sd.atasd.devno = e->devno; sd->sd.atasd.capacity = e->capacity; + sd->sd.atasd.iobase = e->iobase; + sd->sd.atasd.ctrlbase = e->ctrlbase; return E_OK; } @@ -167,12 +248,12 @@ int32_t atasd_read(struct StoreDev *sd, uint8_t *const buffer, ptrdiff_t sector, size_t sectors = size / STOREDEV_ATASD_SECTORSIZE; if (size % STOREDEV_ATASD_SECTORSIZE) sectors++; - ata_setup(ata->devno, sectors, lba); - io_out8(ATA_REG_COMMAND, ATA_CMD_READ_PIO_EXT); + ata_setup(ata->iobase, ata->ctrlbase, ata->devno, sectors, lba); + io_out8(ata->iobase + ATA_REG_COMMAND, ATA_CMD_READ_PIO_EXT); for (size_t s = 0; s < sectors; s++) { - if (ata_wait(100000, true, 1) < 0) { ret = E_BADIO; goto done; } - io_ins16(ATA_REG_DATA, (uint16_t *)(buffer + s * STOREDEV_ATASD_SECTORSIZE), STOREDEV_ATASD_SECTORSIZE/2); + if (ata_wait(ata->iobase, 100000, true, 1) < 0) { ret = E_BADIO; goto done; } + io_ins16(ata->iobase + ATA_REG_DATA, (uint16_t *)(buffer + s * STOREDEV_ATASD_SECTORSIZE), STOREDEV_ATASD_SECTORSIZE/2); } ret = E_OK; @@ -192,16 +273,16 @@ int32_t atasd_write(struct StoreDev *sd, const uint8_t *const buffer, ptrdiff_t size_t sectors = size / STOREDEV_ATASD_SECTORSIZE; if (size % STOREDEV_ATASD_SECTORSIZE) sectors++; - ata_setup(ata->devno, sectors, lba); - io_out8(ATA_REG_COMMAND, ATA_CMD_WRITE_PIO_EXT); + ata_setup(ata->iobase, ata->ctrlbase, ata->devno, sectors, lba); + io_out8(ata->iobase + ATA_REG_COMMAND, ATA_CMD_WRITE_PIO_EXT); for (size_t s = 0; s < sectors; s++) { - if (ata_wait(100000, true, 1) < 0) { ret = E_BADIO; goto done; } - io_outs16(ATA_REG_DATA, (uint16_t *)(buffer + s * STOREDEV_ATASD_SECTORSIZE), STOREDEV_ATASD_SECTORSIZE/2); + if (ata_wait(ata->iobase, 100000, true, 1) < 0) { ret = E_BADIO; goto done; } + io_outs16(ata->iobase + ATA_REG_DATA, (uint16_t *)(buffer + s * STOREDEV_ATASD_SECTORSIZE), STOREDEV_ATASD_SECTORSIZE/2); } - io_out8(ATA_REG_COMMAND, ATA_CMD_CACHE_FLUSH_EXT); - if (ata_wait(100000, false, 1) < 0) { ret = E_BADIO; goto done; } + io_out8(ata->iobase + ATA_REG_COMMAND, ATA_CMD_CACHE_FLUSH_EXT); + if (ata_wait(ata->iobase, 100000, false, 1) < 0) { ret = E_BADIO; goto done; } ret = E_OK; diff --git a/kernel/storedev/atasd.h b/kernel/storedev/atasd.h index 60650f3..864c6e5 100644 --- a/kernel/storedev/atasd.h +++ b/kernel/storedev/atasd.h @@ -12,11 +12,15 @@ struct StoreDev; typedef struct { int devno; size_t capacity; + uint16_t iobase; + uint16_t ctrlbase; } AtaSdInitExtra; typedef struct { int devno; size_t capacity; + uint16_t iobase; + uint16_t ctrlbase; } AtaSd; int32_t atasd_init(struct StoreDev *sd, void *extra); diff --git a/kernel/storedev/storedev.c b/kernel/storedev/storedev.c index 6d95555..a7cd339 100644 --- a/kernel/storedev/storedev.c +++ b/kernel/storedev/storedev.c @@ -32,7 +32,10 @@ void storedev_register_dev_entry(StoreDev *sd, int32_t sdtype) { if (sdtype == STOREDEV_RAMSD) { ksprintf(key, "ramsd-%zu", ramsd_counter++); } else if (sdtype == STOREDEV_ATASD) { - ksprintf(key, "atasd-ch0-%c", sd->sd.atasd.devno == 0x00 ? 'M' : 'S'); + ksprintf(key, "atasd-ch%d-%c", + sd->sd.atasd.iobase == 0x1F0 ? 0 : 1, + sd->sd.atasd.devno == 0x00 ? 'M' : 'S' + ); } spinlock_acquire(&DEVTABLE.spinlock);