ATA add write and some test

This commit is contained in:
Mathieu Maret 2021-10-05 23:55:15 +02:00
parent 1a337881f3
commit 19714126d1
4 changed files with 129 additions and 20 deletions

View File

@ -12,6 +12,11 @@ static inline void outb(uint16_t port, uint8_t val)
* number a wider C type */ * 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) static inline uint8_t inb(uint16_t port)
{ {
uint8_t ret; uint8_t ret;

View File

@ -379,23 +379,24 @@ struct _IDENTIFY_DEVICE_DATA {
} __attribute__((packed)); } __attribute__((packed));
static struct ata_controller controllers[MAX_ATA_CONTROLLER] = {{ static struct ata_controller controllers[MAX_ATA_CONTROLLER] = {{
.id = 0, .id = 0,
.base = 0x1F0, .base = 0x1F0,
.dev_ctl = 0x3F6, .dev_ctl = 0x3F6,
.present = 0, .present = 0,
.last_device_used = -1, .last_device_used = -1,
}, },
{ {
.id = 1, .id = 1,
.base = 0x170, .base = 0x170,
.dev_ctl = 0x376, .dev_ctl = 0x376,
.present = 0, .present = 0,
.last_device_used = -1, .last_device_used = -1,
}}; }};
int ATADetectDevice(struct ata_device *dev) int ATADetectDevice(struct ata_device *dev)
{ {
struct ata_controller *ctl = dev->ctl; 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); unsigned st = inb(ctl->base + ATA_PIO_STATUS);
if (st & ATA_PIO_STATUS_DRIVE_BUSY) if (st & ATA_PIO_STATUS_DRIVE_BUSY)
goto no_disk; goto no_disk;
@ -427,7 +428,8 @@ int ATAGetDeviceInfo(struct ata_device *dev)
struct ata_controller *ctl = dev->ctl; struct ata_controller *ctl = dev->ctl;
struct _IDENTIFY_DEVICE_DATA *deviceInfo; 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); outb(ctl->base + ATA_PIO_CMD, ATA_PIO_CMD_IDENTIFY);
/* Wait for command completion (wait while busy bit is set) */ /* 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) int ATADetectController(struct ata_controller *controller)
{ {
mutexInit(&controller[0].mutex);
mutexInit(&controller[1].mutex);
controller->devices[0].id = 0; controller->devices[0].id = 0;
controller->devices[0].isSlave = 0; controller->devices[0].isSlave = 0;
controller->devices[0].ctl = controller; controller->devices[0].ctl = controller;
controller->devices[0].type = ATADetectDevice(&controllers->devices[0]); controller->devices[0].type = ATADetectDevice(&controllers->devices[0]);
if (controller->devices[0].type == ATA_DEV_PATA || if (controller->devices[0].type == ATA_DEV_PATA ||
controller->devices[0].type == ATA_DEV_SATA) { controller->devices[0].type == ATA_DEV_SATA) {
ATAGetDeviceInfo(&controller->devices[0]); ATAGetDeviceInfo(&controller->devices[0]);
@ -491,35 +494,111 @@ int ATAInit()
return 0; 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; struct ata_controller *ctl = dev->ctl;
uint nb_block = DIV_ROUND_UP(size, DISK_SECTOR_SIZE);
mutexLock(&ctl->mutex); mutexLock(&ctl->mutex);
if (ctl->last_device_used != dev->id) { if (ctl->last_device_used != dev->id) {
outb(ctl->base + ATA_PIO_DRIVE, ATA_PIO_DRIVE_IBM | dev->isSlave << 4); 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; 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_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_LBALO, lba & 0xff);
outb(ctl->base + ATA_PIO_LBAMID, (lba >> 8) & 0xff); outb(ctl->base + ATA_PIO_LBAMID, (lba >> 8) & 0xff);
outb(ctl->base + ATA_PIO_LBAHI, (lba >> 16) & 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; uint16_t *ptr = (uint16_t *)buf;
for(uint block = 0; block < nb_block ; block ++){ for (uint sector = 0; sector < nb_sector; sector++) {
while(inb(ctl->base +ATA_PIO_STATUS)&ATA_PIO_STATUS_DRIVE_BUSY); 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); 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++; ptr++;
} }
} }
mutexUnlock(&ctl->mutex); mutexUnlock(&ctl->mutex);
return 0; 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];
}

View File

@ -84,3 +84,6 @@ struct ata_controller {
}; };
int ATAInit(); 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);

View File

@ -1,4 +1,5 @@
#include "alloc.h" #include "alloc.h"
#include "ata.h"
#include "assert.h" #include "assert.h"
#include "cpu_context.h" #include "cpu_context.h"
#include "klibc.h" #include "klibc.h"
@ -338,8 +339,29 @@ void testKthread()
kthreadCreate("mtest3", mutThread, "mut3"); 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) void run_test(void)
{ {
testATA();
testMemcpyPerf(); testMemcpyPerf();
{ {
int test = 1000; int test = 1000;