From fde9fe87536257eded087bf7f810d87e5669ca9d Mon Sep 17 00:00:00 2001 From: "K. Lange" Date: Sun, 14 Nov 2021 10:49:01 +0900 Subject: [PATCH] ext2: Try to make this less broken --- modules/ata.c | 53 ++++++++++++++++++++++++++++++++++++++++++-------- modules/ext2.c | 44 +++++++++++++++++++++++++++++++---------- 2 files changed, 79 insertions(+), 18 deletions(-) diff --git a/modules/ata.c b/modules/ata.c index 58b6e3e7..3cf0daf8 100644 --- a/modules/ata.c +++ b/modules/ata.c @@ -144,6 +144,8 @@ static int cdrom_number = 0; static uint32_t ata_pci = 0x00000000; static list_t * atapi_waiter; +#define yield_lock(lock) do { while (__sync_lock_test_and_set((lock).latch, 0x01)) { switch_task(0); } (lock).owner = this_core->cpu_id+1; (lock).func = __func__; } while (0) + typedef union { uint8_t command_bytes[12]; uint16_t command_words[6]; @@ -700,7 +702,7 @@ static void ata_device_read_sector(struct ata_device * dev, uint64_t lba, uint8_ if (dev->is_atapi) return; - spin_lock(ata_lock); + yield_lock(ata_lock); ata_wait(dev, 0); @@ -740,11 +742,13 @@ static void ata_device_read_sector(struct ata_device * dev, uint64_t lba, uint8_ uint8_t status = inportb(dev->io_base + ATA_REG_STATUS); if (!(status & ATA_SR_BSY) && (status & ATA_SR_DRDY)) break; } + spin_lock(atapi_cmd_lock); outportb(bus + ATA_REG_COMMAND, ATA_CMD_READ_DMA_EXT); ata_io_wait(dev); outportb(dev->bar4, 0x08 | 0x01); + sleep_on_unlocking(atapi_waiter, &atapi_cmd_lock); while (1) { int status = inportb(dev->bar4 + 0x02); @@ -771,7 +775,7 @@ static void ata_device_read_sector_atapi(struct ata_device * dev, uint64_t lba, if (!dev->is_atapi) return; uint16_t bus = dev->io_base; - spin_lock(ata_lock); + yield_lock(ata_lock); outportb(dev->io_base + ATA_REG_HDDEVSEL, 0xA0 | dev->slave << 4); ata_io_wait(dev); @@ -842,14 +846,26 @@ static void ata_device_write_sector(struct ata_device * dev, uint64_t lba, uint8 uint16_t bus = dev->io_base; uint8_t slave = dev->slave; - spin_lock(ata_lock); + yield_lock(ata_lock); + + ata_wait(dev, 0); + outportb(dev->bar4, 0x00); + outportl(dev->bar4 + 0x04, dev->dma_prdt_phys); + outportb(dev->bar4 + 0x2, inportb(dev->bar4 + 0x02) | 0x04 | 0x02); + + /* set write */ + outportb(dev->bar4, 0x00); + + while (1) { + uint8_t status = inportb(dev->io_base + ATA_REG_STATUS); + if (!(status & ATA_SR_BSY)) break; + } + + memcpy(dev->dma_start, buf, 512); outportb(bus + ATA_REG_CONTROL, 0x02); - - ata_wait(dev, 0); outportb(bus + ATA_REG_HDDEVSEL, 0xe0 | slave << 4); ata_wait(dev, 0); - outportb(bus + ATA_REG_FEATURES, 0x00); outportb(bus + ATA_REG_SECCOUNT0, 0); @@ -862,12 +878,31 @@ static void ata_device_write_sector(struct ata_device * dev, uint64_t lba, uint8 outportb(bus + ATA_REG_LBA1, (lba & 0x0000ff00) >> 8); outportb(bus + ATA_REG_LBA2, (lba & 0x00ff0000) >> 16); - outportb(bus + ATA_REG_COMMAND, ATA_CMD_WRITE_PIO_EXT); + while (1) { + uint8_t status = inportb(dev->io_base + ATA_REG_STATUS); + if (!(status & ATA_SR_BSY) && (status & ATA_SR_DRDY)) break; + } + spin_lock(atapi_cmd_lock); + outportb(bus + ATA_REG_COMMAND, ATA_CMD_WRITE_DMA_EXT); + + ata_io_wait(dev); + + outportb(dev->bar4, 0x00 | 0x01); + sleep_on_unlocking(atapi_waiter, &atapi_cmd_lock); + + #if 0 ata_wait(dev, 0); int size = ATA_SECTOR_SIZE / 2; outportsm(bus,buf,size); + #endif + + outportb(dev->bar4 + 0x2, inportb(dev->bar4 + 0x02) | 0x04 | 0x02); + +#if 0 outportb(bus + 0x07, ATA_CMD_CACHE_FLUSH); ata_wait(dev, 0); +#endif + spin_unlock(ata_lock); } @@ -889,7 +924,9 @@ static void ata_device_write_sector_retry(struct ata_device * dev, uint64_t lba, do { ata_device_write_sector(dev, lba, buf); ata_device_read_sector(dev, lba, read_buf); - } while (buffer_compare((uint32_t *)buf, (uint32_t *)read_buf, ATA_SECTOR_SIZE)); + if (!buffer_compare((uint32_t *)buf, (uint32_t *)read_buf, ATA_SECTOR_SIZE)) break; + switch_task(1); + } while (1); free(read_buf); } diff --git a/modules/ext2.c b/modules/ext2.c index 1bbd9274..83b3cf62 100644 --- a/modules/ext2.c +++ b/modules/ext2.c @@ -246,6 +246,30 @@ static int write_inode(ext2_fs_t * this, ext2_inodetable_t *inode, size_t index) static fs_node_t * finddir_ext2(fs_node_t *node, char *name); static size_t allocate_block(ext2_fs_t * this); +static void yield_lock_acquire(spin_lock_t * lock) { + size_t spin_count = 0; + while (__sync_lock_test_and_set(lock->latch, 0x01)) { + if (spin_count == 10) { + unsigned long s, ss; + relative_time(0, 10, &s, &ss); + sleep_until((process_t *)this_core->current_process, s, ss); + switch_task(0); + spin_count = 0; + } else { + switch_task(1); + spin_count++; + } + } + lock->owner = this_core->cpu_id + 1; + lock->func = "yield_lock_acquire"; +} + +static void yield_lock_release(spin_lock_t * lock) { + lock->func = NULL; + lock->owner = -1; + __sync_lock_release(lock->latch); +} + /** * ext2->get_cache_time Increment and return the current cache time * @@ -296,14 +320,14 @@ static int read_block(ext2_fs_t * this, unsigned int block_no, uint8_t * buf) { } /* This operation requires the filesystem lock to be obtained */ - spin_lock(this->lock); + yield_lock_acquire(&this->lock); /* We can make reads without a cache in place. */ if (!DC) { /* In such cases, we read directly from the block device */ read_fs(this->block_device, block_no * this->block_size, this->block_size, (uint8_t *)buf); /* We are done, release the lock */ - spin_unlock(this->lock); + yield_lock_release(&this->lock); /* And return SUCCESS */ return E_SUCCESS; } @@ -321,7 +345,7 @@ static int read_block(ext2_fs_t * this, unsigned int block_no, uint8_t * buf) { /* Read the block */ memcpy(buf, DC[i].block, this->block_size); /* Release the lock */ - spin_unlock(this->lock); + yield_lock_release(&this->lock); /* Success! */ return E_SUCCESS; } @@ -354,7 +378,7 @@ static int read_block(ext2_fs_t * this, unsigned int block_no, uint8_t * buf) { DC[oldest].dirty = 0; /* Release the lock */ - spin_unlock(this->lock); + yield_lock_release(&this->lock); /* And return success */ return E_SUCCESS; @@ -375,11 +399,11 @@ static int write_block(ext2_fs_t * this, unsigned int block_no, uint8_t *buf) { } /* This operation requires the filesystem lock */ - spin_lock(this->lock); + yield_lock_acquire(&this->lock); if (!DC) { write_fs(this->block_device, block_no * this->block_size, this->block_size, buf); - spin_unlock(this->lock); + yield_lock_release(&this->lock); return E_SUCCESS; } @@ -392,7 +416,7 @@ static int write_block(ext2_fs_t * this, unsigned int block_no, uint8_t *buf) { DC[i].last_use = get_cache_time(this); DC[i].dirty = 1; memcpy(DC[i].block, buf, this->block_size); - spin_unlock(this->lock); + yield_lock_release(&this->lock); return E_SUCCESS; } if (DC[i].last_use < oldest_age) { @@ -415,7 +439,7 @@ static int write_block(ext2_fs_t * this, unsigned int block_no, uint8_t *buf) { DC[oldest].dirty = 1; /* Release the lock */ - spin_unlock(this->lock); + yield_lock_release(&this->lock); /* We're done. */ return E_SUCCESS; @@ -425,7 +449,7 @@ static unsigned int ext2_sync(ext2_fs_t * this) { if (!this->disk_cache) return 0; /* This operation requires the filesystem lock */ - spin_lock(this->lock); + yield_lock_acquire(&this->lock); /* Flush each cache entry. */ for (unsigned int i = 0; i < this->cache_entries; ++i) { @@ -435,7 +459,7 @@ static unsigned int ext2_sync(ext2_fs_t * this) { } /* Release the lock */ - spin_unlock(this->lock); + yield_lock_release(&this->lock); return 0; }