diff --git a/core/io.h b/core/io.h index 2f766f2..f153d3b 100644 --- a/core/io.h +++ b/core/io.h @@ -12,6 +12,11 @@ static inline void outb(uint16_t port, uint8_t val) * number a wider C type */ } +static inline void outw(uint16_t port, int16_t val) +{ + asm volatile("outw %w0, %w1" :: "a"(val), "Nd"(port)); +} + static inline uint8_t inb(uint16_t port) { uint8_t ret; diff --git a/drivers/ata.c b/drivers/ata.c index fd48c64..ca9ad20 100644 --- a/drivers/ata.c +++ b/drivers/ata.c @@ -379,23 +379,24 @@ struct _IDENTIFY_DEVICE_DATA { } __attribute__((packed)); static struct ata_controller controllers[MAX_ATA_CONTROLLER] = {{ - .id = 0, - .base = 0x1F0, - .dev_ctl = 0x3F6, - .present = 0, + .id = 0, + .base = 0x1F0, + .dev_ctl = 0x3F6, + .present = 0, .last_device_used = -1, }, { - .id = 1, - .base = 0x170, - .dev_ctl = 0x376, - .present = 0, + .id = 1, + .base = 0x170, + .dev_ctl = 0x376, + .present = 0, .last_device_used = -1, }}; int ATADetectDevice(struct ata_device *dev) { struct ata_controller *ctl = dev->ctl; - outb(ctl->base + ATA_PIO_DRIVE, ATA_PIO_DRIVE_IBM | dev->isSlave? ATA_PIO_DRIVE_SLAVE: ATA_PIO_DRIVE_MASTER); + outb(ctl->base + ATA_PIO_DRIVE, + ATA_PIO_DRIVE_IBM | dev->isSlave ? ATA_PIO_DRIVE_SLAVE : ATA_PIO_DRIVE_MASTER); unsigned st = inb(ctl->base + ATA_PIO_STATUS); if (st & ATA_PIO_STATUS_DRIVE_BUSY) goto no_disk; @@ -427,7 +428,8 @@ int ATAGetDeviceInfo(struct ata_device *dev) struct ata_controller *ctl = dev->ctl; struct _IDENTIFY_DEVICE_DATA *deviceInfo; - outb(ctl->base + ATA_PIO_DRIVE, ATA_PIO_DRIVE_IBM | dev->isSlave? ATA_PIO_DRIVE_SLAVE: ATA_PIO_DRIVE_MASTER); + outb(ctl->base + ATA_PIO_DRIVE, + ATA_PIO_DRIVE_IBM | (dev->isSlave ? ATA_PIO_DRIVE_SLAVE : ATA_PIO_DRIVE_MASTER)); outb(ctl->base + ATA_PIO_CMD, ATA_PIO_CMD_IDENTIFY); /* Wait for command completion (wait while busy bit is set) */ @@ -459,12 +461,13 @@ int ATAGetDeviceInfo(struct ata_device *dev) int ATADetectController(struct ata_controller *controller) { + mutexInit(&controller[0].mutex); + mutexInit(&controller[1].mutex); controller->devices[0].id = 0; controller->devices[0].isSlave = 0; controller->devices[0].ctl = controller; controller->devices[0].type = ATADetectDevice(&controllers->devices[0]); - if (controller->devices[0].type == ATA_DEV_PATA || controller->devices[0].type == ATA_DEV_SATA) { ATAGetDeviceInfo(&controller->devices[0]); @@ -491,35 +494,111 @@ int ATAInit() return 0; } -int ATARead(struct ata_device *dev, int lba, int size, void *buf) +int ATAReadSector(struct ata_device *dev, int lba, uint nb_sector, void *buf) { struct ata_controller *ctl = dev->ctl; - uint nb_block = DIV_ROUND_UP(size, DISK_SECTOR_SIZE); mutexLock(&ctl->mutex); if (ctl->last_device_used != dev->id) { outb(ctl->base + ATA_PIO_DRIVE, ATA_PIO_DRIVE_IBM | dev->isSlave << 4); - while(inb(ctl->base +ATA_PIO_STATUS)&ATA_PIO_STATUS_DRIVE_BUSY); + while (inb(ctl->base + ATA_PIO_STATUS) & ATA_PIO_STATUS_DRIVE_BUSY) { + } ctl->last_device_used = dev->id; } outb(ctl->base + ATA_PIO_DRIVE, lba >> 24 | ATA_PIO_DRIVE_IBM | ATA_PIO_DRIVE_LBA); - outb(ctl->base + ATA_PIO_SEC_COUNT, nb_block); + outb(ctl->base + ATA_PIO_SEC_COUNT, nb_sector); outb(ctl->base + ATA_PIO_LBALO, lba & 0xff); outb(ctl->base + ATA_PIO_LBAMID, (lba >> 8) & 0xff); outb(ctl->base + ATA_PIO_LBAHI, (lba >> 16) & 0xff); + outb(ctl->base + ATA_PIO_CMD, ATA_PIO_CMD_READ); uint16_t *ptr = (uint16_t *)buf; - for(uint block = 0; block < nb_block ; block ++){ - while(inb(ctl->base +ATA_PIO_STATUS)&ATA_PIO_STATUS_DRIVE_BUSY); - for(int i = 0; i< 256 && size >0; i++, size --){ - *ptr = inw(ctl->base +ATA_PIO_DATA); + for (uint sector = 0; sector < nb_sector; sector++) { + while (inb(ctl->base + ATA_PIO_STATUS) & ATA_PIO_STATUS_DRIVE_BUSY) { + } + if (inb(ctl->base + ATA_PIO_STATUS) & ATA_PIO_STATUS_REG_ERR) { + mutexUnlock(&ctl->mutex); + printf("ATA read error\n"); + return -1; + } + for (uint i = 0; i < (DISK_SECTOR_SIZE / sizeof(uint16_t)); i++) { + *ptr = inw(ctl->base + ATA_PIO_DATA); ptr++; } - } mutexUnlock(&ctl->mutex); return 0; } + +int ATAWriteSector(struct ata_device *dev, int lba, uint nb_sector, void *buf) +{ + struct ata_controller *ctl = dev->ctl; + + mutexLock(&ctl->mutex); + + if (ctl->last_device_used != dev->id) { + outb(ctl->base + ATA_PIO_DRIVE, ATA_PIO_DRIVE_IBM | dev->isSlave << 4); + while (inb(ctl->base + ATA_PIO_STATUS) & ATA_PIO_STATUS_DRIVE_BUSY) { + } + ctl->last_device_used = dev->id; + } + outb(ctl->base + ATA_PIO_DRIVE, lba >> 24 | ATA_PIO_DRIVE_IBM | ATA_PIO_DRIVE_LBA); + outb(ctl->base + ATA_PIO_SEC_COUNT, nb_sector); + outb(ctl->base + ATA_PIO_LBALO, lba & 0xff); + outb(ctl->base + ATA_PIO_LBAMID, (lba >> 8) & 0xff); + outb(ctl->base + ATA_PIO_LBAHI, (lba >> 16) & 0xff); + outb(ctl->base + ATA_PIO_CMD, ATA_PIO_CMD_WRITE); + + uint16_t *ptr = (uint16_t *)buf; + for (uint sector = 0; sector < nb_sector; sector++) { + while (inb(ctl->base + ATA_PIO_STATUS) & ATA_PIO_STATUS_DRIVE_BUSY) { + } + if (inb(ctl->base + ATA_PIO_STATUS) & ATA_PIO_STATUS_REG_ERR) { + mutexUnlock(&ctl->mutex); + printf("ATA write error\n"); + return -1; + } + while (1) { + int status = inb(ctl->base + ATA_PIO_STATUS); + if (status & ATA_PIO_STATUS_REG_ERR) { + mutexUnlock(&ctl->mutex); + printf("ATA write error\n"); + return -1; + } + if ((status & ATA_PIO_STATUS_DRQ) && + !(status & ATA_PIO_STATUS_DRIVE_BUSY)) + break; + } + for (uint i = 0; i < (DISK_SECTOR_SIZE / sizeof(uint16_t)); i++) { + outw(ctl->base + ATA_PIO_DATA, *ptr++); + } + // Wait for the device to receive the data + while (1) { + int status = inb(ctl->base + ATA_PIO_STATUS); + if (status & ATA_PIO_STATUS_REG_ERR) { + mutexUnlock(&ctl->mutex); + printf("ATA write error\n"); + return -1; + } + if (!(status & ATA_PIO_STATUS_DRQ) && + !(status & ATA_PIO_STATUS_DRIVE_BUSY)) + break; + } + } + + mutexUnlock(&ctl->mutex); + + return 0; +} + +struct ata_device *ATAGetDevice(int ctlId, int devId) +{ + if (ctlId >= MAX_ATA_CONTROLLER) + return NULL; + if (devId >= MAX_ATA_DEVICES) + return NULL; + return &controllers[ctlId].devices[devId]; +} diff --git a/drivers/ata.h b/drivers/ata.h index 2afbc80..c1b6e08 100644 --- a/drivers/ata.h +++ b/drivers/ata.h @@ -84,3 +84,6 @@ struct ata_controller { }; int ATAInit(); +int ATAReadSector(struct ata_device *dev, int lba, uint nbSector, void *buf); +int ATAWriteSector(struct ata_device *dev, int lba, uint nbSector, void *buf); +struct ata_device *ATAGetDevice(int ctlId, int devId); diff --git a/tests/test.c b/tests/test.c index b1a11c1..4c0af66 100644 --- a/tests/test.c +++ b/tests/test.c @@ -1,4 +1,5 @@ #include "alloc.h" +#include "ata.h" #include "assert.h" #include "cpu_context.h" #include "klibc.h" @@ -338,8 +339,29 @@ void testKthread() kthreadCreate("mtest3", mutThread, "mut3"); } +void testATAThread(){ + uint16_t buf[DISK_SECTOR_SIZE/2]; + struct ata_device *dev = ATAGetDevice(0, 0); + if(dev != NULL){ + ATAReadSector(dev, 0, 1, buf); + printf("Reading from disk 0x%x 0x%x 0x%x 0x%x\n", buf[0], buf[1], buf[2], buf[3]); + memset(buf, 0, sizeof(buf)); + buf[0]= 0x1; + buf[1]= 0x2; + buf[2]= 0x3; + buf[3]= 0x4; + ATAWriteSector(dev, 0, 1, buf); + } +} + +void testATA(){ + kthreadCreate("ATA_TEST", testATAThread, NULL); + //testATAThread(); +} + void run_test(void) { + testATA(); testMemcpyPerf(); { int test = 1000;