From d1024d77939eae636f10a01a4af1eb29e8e02f27 Mon Sep 17 00:00:00 2001 From: Lucia Ceionia Date: Fri, 10 Feb 2023 01:06:42 -0600 Subject: [PATCH] Disk does very basic read caching --- disk.c | 78 +++++++++++++++++++++++++++++++++++++++++++++++++--- handler.nasm | 1 + kernel.c | 3 +- 3 files changed, 77 insertions(+), 5 deletions(-) diff --git a/disk.c b/disk.c index 1b7d2fc..c1eb06f 100644 --- a/disk.c +++ b/disk.c @@ -5,6 +5,13 @@ extern void *memcpy(void *restrict dest, const void *restrict src, uintptr_t n); +uintptr_t DiskCacheBlockSize = 0x1000; // 512 * 4 +uintptr_t DiskCacheSectorMask = 7; +uintptr_t DiskCacheSectorSize = 8; +uint8_t (*DiskCache)[128][0x1000] = (uint8_t (*)[128][0x1000])0x280000; +uint32_t DiskCacheLastRead[128]; +uint32_t DiskCacheSector[128]; + extern uint32_t _gpf_eax_save; extern uint32_t _gpf_eflags_save; extern uint16_t error_screen[80*50]; // defined in kernel.c @@ -14,6 +21,7 @@ uint32_t numHead; uint32_t secPerTrack; uint32_t maxCylinder; char useCHS = -1; +// TODO This function also inits cache, make that go somewhere else void Disk_SetupCHS() { union V86Regs_t regs; // Check for INT 13 Extensions support @@ -39,25 +47,77 @@ void Disk_SetupCHS() { maxCylinder = ((_gpf_eax_save & 0xff0000) >> 16) | ((_gpf_eax_save & 0xc0) << 2); useCHS = 1; } + + // Init Cache + for (int i = 0; i < 128; i++) { + DiskCacheLastRead[i] = 0; + DiskCacheSector[i] = -1; + } } + +extern uint32_t TIMERVAL; +uint8_t *FindInCache(uint32_t sector) { + uint32_t maskedSector = sector & ~DiskCacheSectorMask; + for (int i = 0; i < 128; i++) { + // Found + if (DiskCacheSector[i] == maskedSector) { + DiskCacheLastRead[i] = TIMERVAL; + return &(*DiskCache)[i][(sector & DiskCacheSectorMask) << 9]; + } + } + // Not Found + return 0; +} + +void AddToCache(uint32_t sector, uint8_t *buffer) { + uintptr_t lowestFoundTime = DiskCacheLastRead[0]; + uintptr_t lowestFoundIdx = 0; + for (int i = 1; i < 32; i++) { + if (DiskCacheLastRead[i] < lowestFoundTime) { + lowestFoundTime = DiskCacheLastRead[i]; + lowestFoundIdx = i; + } + } + for (int i = 0; i < DiskCacheBlockSize / sizeof(uint32_t); i++) + ((uint32_t *)((*DiskCache)[lowestFoundIdx]))[i] = ((uint32_t*)buffer)[i]; + DiskCacheLastRead[lowestFoundIdx] = TIMERVAL; + DiskCacheSector[lowestFoundIdx] = sector; +} + +// NOTE Only updates one sector (512B) +void UpdateCache(uint32_t sector, uint8_t *buffer) { + uint8_t *cache = FindInCache(sector); + // Not in cache, nothing to update + if (!cache) return; + for (int i = 0; i < SECTOR_SIZE/sizeof(uint32_t); i++) + ((uint32_t*)cache)[i] = ((uint32_t*)buffer)[i]; +} + uint32_t DFS_ReadSector(uint8_t unit, uint8_t *buffer, uint32_t sector, uint32_t count) { // NOTE If the buffer provided is outside the 0x20000-0x2FE00 range, // the function will use that buffer for the Virtual 8086 process // and copy to the other buffer after uint8_t *v86buf = buffer; - if ((uintptr_t)v86buf < 0x20000 || (uintptr_t)v86buf > 0x2FE00) - v86buf = (uint8_t *)0x20000; + if ((uintptr_t)v86buf >= 0x20000 && (uintptr_t)v86buf < 0x28000) + v86buf = (uint8_t *)0x28000; + else v86buf = (uint8_t *)0x20000; // TODO This check should probably happen at the kernel level if (useCHS == -1) { Disk_SetupCHS(); } + uint8_t *cache = FindInCache(sector); + if (cache) { + memcpy(buffer, cache, count * SECTOR_SIZE); + return 0; + } + // TODO Do error handling if (!useCHS) { // LBA Read - v86disk_addr_packet.start_block = sector; - v86disk_addr_packet.blocks = count; + v86disk_addr_packet.start_block = sector & ~DiskCacheSectorMask; + v86disk_addr_packet.blocks = DiskCacheSectorSize; v86disk_addr_packet.transfer_buffer = (uintptr_t)v86buf & 0x000F | (((uintptr_t)v86buf & 0xFFFF0) << 12); @@ -65,6 +125,15 @@ uint32_t DFS_ReadSector(uint8_t unit, uint8_t *buffer, uint32_t sector, uint32_t regs.h.ah = 0x42; FARPTR v86_entry = i386LinearToFp(v86DiskOp); enter_v86(0x8000, 0xFF00, FP_SEG(v86_entry), FP_OFF(v86_entry), ®s); + if (v86disk_addr_packet.blocks != DiskCacheSectorSize) { + uint16_t *vga = error_screen; + vga += printStr("INT13 Read Secs: ", vga); + vga += printDec(v86disk_addr_packet.blocks, vga); + error_environment(); + for(;;); + } + AddToCache(sector & ~DiskCacheSectorMask, v86buf); + v86buf = &v86buf[(sector & DiskCacheSectorMask) << 9]; } else { uint32_t tmp = sector / secPerTrack; uint32_t sec = (sector % (secPerTrack)) + 1; @@ -110,6 +179,7 @@ uint32_t DFS_WriteSector(uint8_t unit, uint8_t *buffer, uint32_t sector, uint32_ regs.w.ax = 0x4300; FARPTR v86_entry = i386LinearToFp(v86DiskOp); enter_v86(0x8000, 0xFF00, FP_SEG(v86_entry), FP_OFF(v86_entry), ®s); + UpdateCache(sector, buffer); } else { uint16_t *vga = error_screen; vga += printStr("CHS Write Unimplemented", vga); diff --git a/handler.nasm b/handler.nasm index 366379d..7598156 100644 --- a/handler.nasm +++ b/handler.nasm @@ -50,6 +50,7 @@ test eax, eax jz .loop ret +global TIMERVAL TIMERVAL: dd 0 global timerHandler timerHandler: diff --git a/kernel.c b/kernel.c index de29253..f637b63 100644 --- a/kernel.c +++ b/kernel.c @@ -174,7 +174,8 @@ Protected Only (1MB+) 100000 - 200000 Kernel Code (1mB) 200000 - 200080 TSS (128B) 200080 - 202080 TSS IOMAP (8kB) -202080 - 300000 Free (~1mB) +202080 - 300000 Free (~1/2mB) +280000 - 300000 Disk Cache (512kB) 300000 - 310000 Task Stack (64kB) 310000 - 320000 Interrupt Stack (64kB) 320000 - 400000 Kernel Stack (896kB)