ata: deal in pages, not sectors

This commit is contained in:
K. Lange 2021-11-16 08:56:14 +09:00
parent 32e99ff897
commit 7c0f882178

View File

@ -197,6 +197,7 @@ static spin_lock_t atapi_cmd_lock = { 0 };
/* TODO support other sector sizes */
#define ATA_SECTOR_SIZE 512
#define ATA_CACHE_SIZE 4096
static void ata_device_read_sector(struct ata_device * dev, uint64_t lba, uint8_t * buf);
static void ata_device_read_sector_atapi(struct ata_device * dev, uint64_t lba, uint8_t * buf);
@ -283,8 +284,8 @@ static off_t atapi_max_offset(struct ata_device * dev) {
static ssize_t read_ata(fs_node_t *node, off_t offset, size_t size, uint8_t *buffer) {
struct ata_device * dev = (struct ata_device *)node->device;
unsigned int start_block = offset / ATA_SECTOR_SIZE;
unsigned int end_block = (offset + size - 1) / ATA_SECTOR_SIZE;
unsigned int start_block = offset / ATA_CACHE_SIZE;
unsigned int end_block = (offset + size - 1) / ATA_CACHE_SIZE;
unsigned int x_offset = 0;
@ -297,13 +298,13 @@ static ssize_t read_ata(fs_node_t *node, off_t offset, size_t size, uint8_t *buf
size = i;
}
if (offset % ATA_SECTOR_SIZE || size < ATA_SECTOR_SIZE) {
unsigned int prefix_size = (ATA_SECTOR_SIZE - (offset % ATA_SECTOR_SIZE));
if (offset % ATA_CACHE_SIZE || size < ATA_CACHE_SIZE) {
unsigned int prefix_size = (ATA_CACHE_SIZE - (offset % ATA_CACHE_SIZE));
if (prefix_size > size) prefix_size = size;
char * tmp = malloc(ATA_SECTOR_SIZE);
char * tmp = malloc(ATA_CACHE_SIZE);
ata_device_read_sector(dev, start_block, (uint8_t *)tmp);
memcpy(buffer, (void *)((uintptr_t)tmp + ((uintptr_t)offset % ATA_SECTOR_SIZE)), prefix_size);
memcpy(buffer, (void *)((uintptr_t)tmp + ((uintptr_t)offset % ATA_CACHE_SIZE)), prefix_size);
free(tmp);
@ -311,9 +312,9 @@ static ssize_t read_ata(fs_node_t *node, off_t offset, size_t size, uint8_t *buf
start_block++;
}
if ((offset + size) % ATA_SECTOR_SIZE && start_block <= end_block) {
unsigned int postfix_size = (offset + size) % ATA_SECTOR_SIZE;
char * tmp = malloc(ATA_SECTOR_SIZE);
if ((offset + size) % ATA_CACHE_SIZE && start_block <= end_block) {
unsigned int postfix_size = (offset + size) % ATA_CACHE_SIZE;
char * tmp = malloc(ATA_CACHE_SIZE);
ata_device_read_sector(dev, end_block, (uint8_t *)tmp);
memcpy((void *)((uintptr_t)buffer + size - postfix_size), tmp, postfix_size);
@ -325,7 +326,7 @@ static ssize_t read_ata(fs_node_t *node, off_t offset, size_t size, uint8_t *buf
while (start_block <= end_block) {
ata_device_read_sector(dev, start_block, (uint8_t *)((uintptr_t)buffer + x_offset));
x_offset += ATA_SECTOR_SIZE;
x_offset += ATA_CACHE_SIZE;
start_block++;
}
@ -389,8 +390,8 @@ static ssize_t read_atapi(fs_node_t *node, off_t offset, size_t size, uint8_t *b
static ssize_t write_ata(fs_node_t *node, off_t offset, size_t size, uint8_t *buffer) {
struct ata_device * dev = (struct ata_device *)node->device;
unsigned int start_block = offset / ATA_SECTOR_SIZE;
unsigned int end_block = (offset + size - 1) / ATA_SECTOR_SIZE;
unsigned int start_block = offset / ATA_CACHE_SIZE;
unsigned int end_block = (offset + size - 1) / ATA_CACHE_SIZE;
unsigned int x_offset = 0;
@ -403,13 +404,13 @@ static ssize_t write_ata(fs_node_t *node, off_t offset, size_t size, uint8_t *bu
size = i;
}
if (offset % ATA_SECTOR_SIZE) {
unsigned int prefix_size = (ATA_SECTOR_SIZE - (offset % ATA_SECTOR_SIZE));
if (offset % ATA_CACHE_SIZE) {
unsigned int prefix_size = (ATA_CACHE_SIZE - (offset % ATA_CACHE_SIZE));
char * tmp = malloc(ATA_SECTOR_SIZE);
char * tmp = malloc(ATA_CACHE_SIZE);
ata_device_read_sector(dev, start_block, (uint8_t *)tmp);
memcpy((void *)((uintptr_t)tmp + ((uintptr_t)offset % ATA_SECTOR_SIZE)), buffer, prefix_size);
memcpy((void *)((uintptr_t)tmp + ((uintptr_t)offset % ATA_CACHE_SIZE)), buffer, prefix_size);
ata_device_write_sector(dev, start_block, (uint8_t *)tmp);
free(tmp);
@ -417,10 +418,10 @@ static ssize_t write_ata(fs_node_t *node, off_t offset, size_t size, uint8_t *bu
start_block++;
}
if ((offset + size) % ATA_SECTOR_SIZE && start_block <= end_block) {
unsigned int postfix_size = (offset + size) % ATA_SECTOR_SIZE;
if ((offset + size) % ATA_CACHE_SIZE && start_block <= end_block) {
unsigned int postfix_size = (offset + size) % ATA_CACHE_SIZE;
char * tmp = malloc(ATA_SECTOR_SIZE);
char * tmp = malloc(ATA_CACHE_SIZE);
ata_device_read_sector(dev, end_block, (uint8_t *)tmp);
memcpy(tmp, (void *)((uintptr_t)buffer + size - postfix_size), postfix_size);
@ -433,7 +434,7 @@ static ssize_t write_ata(fs_node_t *node, off_t offset, size_t size, uint8_t *bu
while (start_block <= end_block) {
ata_device_write_sector(dev, start_block, (uint8_t *)((uintptr_t)buffer + x_offset));
x_offset += ATA_SECTOR_SIZE;
x_offset += ATA_CACHE_SIZE;
start_block++;
}
@ -613,7 +614,7 @@ static void ata_device_init(struct ata_device * dev) {
dev->dma_prdt = (void *)kvmalloc_p(sizeof(prdt_t) * 1, &dev->dma_prdt_phys);
dev->dma_start = (void *)kvmalloc_p(4096, &dev->dma_start_phys);
dev->dma_prdt[0].offset = dev->dma_start_phys;
dev->dma_prdt[0].bytes = 512;
dev->dma_prdt[0].bytes = ATA_CACHE_SIZE;
dev->dma_prdt[0].last = 0x8000;
uint16_t command_reg = pci_read_field(ata_pci, PCI_COMMAND, 4);
@ -794,12 +795,12 @@ static int ata_device_detect(struct ata_device * dev) {
static void ata_device_read_sector(struct ata_device * dev, uint64_t lba, uint8_t * buf) {
/* Submit request */
struct DataRequest req;
ata_enqueue_request(&req, dev,lba,1,NULL);
ata_enqueue_request(&req, dev, lba * 8, 1, NULL);
if (!req.resolved) {
dprintf("ata: Unresolved request?\n");
} else {
memcpy(buf, req.buf, 512);
memcpy(buf, req.buf, ATA_CACHE_SIZE);
free(req.buf);
}
}
@ -839,7 +840,7 @@ static void ata_device_read_sector_actual(struct ata_device * dev, uint64_t lba)
outportb(bus + ATA_REG_LBA1, (lba & 0xff00000000) >> 32);
outportb(bus + ATA_REG_LBA2, (lba & 0xff0000000000) >> 40);
outportb(bus + ATA_REG_SECCOUNT0, 1);
outportb(bus + ATA_REG_SECCOUNT0, 8);
outportb(bus + ATA_REG_LBA0, (lba & 0x000000ff) >> 0);
outportb(bus + ATA_REG_LBA1, (lba & 0x0000ff00) >> 8);
outportb(bus + ATA_REG_LBA2, (lba & 0x00ff0000) >> 16);
@ -957,10 +958,10 @@ atapi_timeout:
static void ata_device_write_sector(struct ata_device * dev, uint64_t lba, uint8_t * buf) {
/* Submit request */
char * tmp = malloc(512);
memcpy(tmp, buf, 512);
char * tmp = malloc(ATA_CACHE_SIZE);
memcpy(tmp, buf, ATA_CACHE_SIZE);
struct DataRequest req;
ata_enqueue_request(&req, dev,lba,2,tmp);
ata_enqueue_request(&req, dev,lba * 8, 2, tmp);
if (!req.resolved) {
dprintf("ata: Unresolved write request?\n");
@ -995,7 +996,7 @@ static void ata_device_write_sector_actual(struct ata_device * dev, uint64_t lba
outportb(bus + ATA_REG_LBA1, (lba & 0xff00000000) >> 32);
outportb(bus + ATA_REG_LBA2, (lba & 0xff0000000000) >> 40);
outportb(bus + ATA_REG_SECCOUNT0, 1);
outportb(bus + ATA_REG_SECCOUNT0, 8);
outportb(bus + ATA_REG_LBA0, (lba & 0x000000ff) >> 0);
outportb(bus + ATA_REG_LBA1, (lba & 0x0000ff00) >> 8);
outportb(bus + ATA_REG_LBA2, (lba & 0x00ff0000) >> 16);
@ -1033,13 +1034,13 @@ struct CacheEntry {
uint64_t flags;
};
#define CACHE_COUNT 10240
#define CACHE_COUNT 4096
static void ata_scheduler(void * data) {
/* Allocate some cache space */
struct CacheEntry * cache_entries = malloc(sizeof(struct CacheEntry) * CACHE_COUNT);
memset(cache_entries, 0, sizeof(struct CacheEntry) * CACHE_COUNT);
char * cache_blocks = mmu_map_module(CACHE_COUNT * 512);
char * cache_blocks = mmu_map_module(CACHE_COUNT * ATA_CACHE_SIZE);
uint64_t counter = 1;
while (1) {
@ -1055,6 +1056,7 @@ static void ata_scheduler(void * data) {
/* Is it in the cache? */
int found = 0;
int oldest = 0;
uint64_t lu = -1;
for (int i = 0; i < CACHE_COUNT; ++i) {
if (cache_entries[i].dev == req->dev && cache_entries[i].lba == req->lba) {
//dprintf("ata: cache hit\n");
@ -1065,32 +1067,34 @@ static void ata_scheduler(void * data) {
} else if (cache_entries[i].dev == NULL) {
oldest = i;
break;
} else if (cache_entries[i].last_use < cache_entries[oldest].last_use) {
} else if (cache_entries[i].last_use < lu) {
oldest = i;
lu = cache_entries[oldest].last_use;
}
}
if (!found) {
miss_count++;
if (cache_entries[oldest].dev && cache_entries[oldest].flags & 1) {
eviction_count++;
memcpy(cache_entries[oldest].dev->dma_start, cache_blocks + oldest * 512, 512);
memcpy(cache_entries[oldest].dev->dma_start, cache_blocks + oldest * ATA_CACHE_SIZE, ATA_CACHE_SIZE);
ata_device_write_sector_actual(cache_entries[oldest].dev, cache_entries[oldest].lba);
}
ata_device_read_sector_actual(req->dev, req->lba);
cache_entries[oldest].dev = req->dev;
cache_entries[oldest].lba = req->lba;
cache_entries[oldest].flags = 0;
memcpy(cache_blocks + oldest * 512, req->dev->dma_start, 512);
memcpy(cache_blocks + oldest * ATA_CACHE_SIZE, req->dev->dma_start, ATA_CACHE_SIZE);
}
cache_entries[oldest].last_use = counter++;
req->buf = malloc(512);
memcpy(req->buf, cache_blocks + 512 * oldest, 512);
req->buf = malloc(ATA_CACHE_SIZE);
memcpy(req->buf, cache_blocks + ATA_CACHE_SIZE * oldest, ATA_CACHE_SIZE);
ata_respond(req);
break;
}
case 2: {
int found = 0;
int oldest = 0;
uint64_t lu = -1;
for (int i = 0; i < CACHE_COUNT; ++i) {
if (cache_entries[i].dev == req->dev && cache_entries[i].lba == req->lba) {
//dprintf("ata: cache hit\n");
@ -1101,15 +1105,16 @@ static void ata_scheduler(void * data) {
} else if (cache_entries[i].dev == NULL) {
oldest = i;
break;
} else if (cache_entries[i].last_use < cache_entries[oldest].last_use) {
} else if (cache_entries[i].last_use < lu) {
oldest = i;
lu = cache_entries[oldest].last_use;
}
}
if (!found) {
miss_count++;
if (cache_entries[oldest].dev && cache_entries[oldest].flags & 1) {
eviction_count++;
memcpy(cache_entries[oldest].dev->dma_start, cache_blocks + oldest * 512, 512);
memcpy(cache_entries[oldest].dev->dma_start, cache_blocks + oldest * ATA_CACHE_SIZE, ATA_CACHE_SIZE);
ata_device_write_sector_actual(cache_entries[oldest].dev, cache_entries[oldest].lba);
}
cache_entries[oldest].dev = req->dev;
@ -1117,7 +1122,7 @@ static void ata_scheduler(void * data) {
}
write_count++;
cache_entries[oldest].last_use = counter++;
memcpy(cache_blocks + oldest * 512, req->buf, 512);
memcpy(cache_blocks + oldest * ATA_CACHE_SIZE, req->buf, ATA_CACHE_SIZE);
cache_entries[oldest].flags = 1;
free(req->buf);
ata_respond(req);
@ -1127,7 +1132,7 @@ static void ata_scheduler(void * data) {
for (int i = 0; i < CACHE_COUNT; ++i) {
if (cache_entries[i].dev == req->dev && cache_entries[i].flags & 1) {
eviction_count++;
memcpy(cache_entries[i].dev->dma_start, cache_blocks + i * 512, 512);
memcpy(cache_entries[i].dev->dma_start, cache_blocks + i * ATA_CACHE_SIZE, ATA_CACHE_SIZE);
ata_device_write_sector_actual(cache_entries[i].dev, cache_entries[i].lba);
cache_entries[i].flags = 0;
}