diff --git a/drivers/disk.c b/drivers/disk.c index b4f12e9a..8558d5e6 100644 --- a/drivers/disk.c +++ b/drivers/disk.c @@ -7,7 +7,7 @@ #define SECTOR_SIZE 512 -static uint64_t last_sector = -1; +static uint64_t cached_sector = -1; static uint8_t sector_buf[512]; static struct { @@ -18,25 +18,38 @@ static struct { uint64_t lba; } dap = { 16, 1, 0, 0, 0 }; -int read_sector(int drive, void *buffer, uint64_t lba, size_t count) { +static int cache_sector(int drive, uint64_t lba) { + if (lba == cached_sector) + return 0; + dap.offset = (uint16_t)(size_t)sector_buf; + dap.lba = lba; + struct rm_regs r = {0}; + r.eax = 0x4200; + r.edx = drive; + r.esi = (uint32_t)&dap; + + rm_int(0x13, &r, &r); + + if (r.eflags & EFLAGS_CF) { + int ah = (r.eax >> 8) & 0xff; + print("Disk error %x. Drive %x, LBA %x.\n", ah, drive, lba); + return ah; + } + + cached_sector = lba; + + return 0; +} + +int read_sector(int drive, void *buffer, uint64_t lba, uint64_t count) { while (count--) { - dap.lba = lba; - struct rm_regs r = {0}; - r.eax = 0x4200; - r.edx = drive; - r.esi = (unsigned int)&dap; - rm_int(0x13, &r, &r); - - int ah = (r.eax >> 8) & 0xFF; - if (ah) { - print("Disk error %x\n", ah); - return ah; - } + int ret; + if ((ret = cache_sector(drive, lba++))) + return ret; memcpy(buffer, sector_buf, SECTOR_SIZE); - last_sector = lba++; buffer += SECTOR_SIZE; } @@ -44,29 +57,22 @@ int read_sector(int drive, void *buffer, uint64_t lba, size_t count) { return 0; } -int read(int drive, void *buffer, int offset, size_t count) { - int res; - - if (last_sector == (uint64_t)-1) - if ((res = read_sector(drive, sector_buf, 0, 1))) - return res; - - uint64_t cur_sector = last_sector + (offset / SECTOR_SIZE); - offset %= SECTOR_SIZE; +int read(int drive, void *buffer, uint64_t loc, uint64_t count) { + uint64_t progress = 0; + while (progress < count) { + uint64_t sect = (loc + progress) / SECTOR_SIZE; - size_t sectors_count = 1 + ((offset + count) / SECTOR_SIZE); + int ret; + if ((ret = cache_sector(drive, sect))) + return ret; - while (sectors_count--) { - if (cur_sector != last_sector) - if ((res = read_sector(drive, sector_buf, cur_sector, 1))) - return res; + uint64_t chunk = count - progress; + uint64_t offset = (loc + progress) % SECTOR_SIZE; + if (chunk > SECTOR_SIZE - offset) + chunk = SECTOR_SIZE - offset; - size_t limited_count = ((offset + count) > SECTOR_SIZE) ? (size_t)(SECTOR_SIZE - offset) : count; - memcpy(buffer, §or_buf[offset], limited_count); - - offset = (offset + limited_count) % SECTOR_SIZE; - buffer += limited_count; - cur_sector++; + memcpy(buffer + progress, §or_buf[offset], chunk); + progress += chunk; } return 0; diff --git a/drivers/disk.h b/drivers/disk.h index 67cf9f35..4f9191e2 100644 --- a/drivers/disk.h +++ b/drivers/disk.h @@ -1,9 +1,10 @@ #ifndef __DISK_H__ #define __DISK_H__ +#include #include -int read_sector(int, void *, uint64_t, size_t); -int read(int, void *, int, size_t); +int read_sector(int, void *, uint64_t, uint64_t); +int read(int, void *, uint64_t, uint64_t); #endif diff --git a/lib/real.c b/lib/real.c index b5796656..ca41cbd2 100644 --- a/lib/real.c +++ b/lib/real.c @@ -23,6 +23,7 @@ void rm_int( "push esi\n\t" "push edi\n\t" "push ebp\n\t" + "pushf\n\t" // Jump to real mode "jmp 0x08:1f\n\t" @@ -48,6 +49,7 @@ void rm_int( // Load in_regs "mov dword ptr ds:[5f], esp\n\t" "mov esp, dword ptr ds:[7f]\n\t" + "popfd\n\t" "pop ebp\n\t" "pop edi\n\t" "pop esi\n\t" @@ -64,7 +66,7 @@ void rm_int( // Load out_regs "mov dword ptr ds:[5f], esp\n\t" "mov esp, dword ptr ds:[6f]\n\t" - "add esp, 7*4\n\t" + "lea esp, [esp + 8*4]\n\t" "push eax\n\t" "push ebx\n\t" "push ecx\n\t" @@ -72,6 +74,7 @@ void rm_int( "push esi\n\t" "push edi\n\t" "push ebp\n\t" + "pushfd\n\t" "mov esp, dword ptr ds:[5f]\n\t" // Jump back to pmode @@ -88,6 +91,7 @@ void rm_int( "mov ss, ax\n\t" // Restore non-scratch GPRs + "popf\n\t" "pop ebp\n\t" "pop edi\n\t" "pop esi\n\t" diff --git a/lib/real.h b/lib/real.h index 352bfdfe..6dcd37af 100644 --- a/lib/real.h +++ b/lib/real.h @@ -6,7 +6,10 @@ #define rm_seg(x) (unsigned short)(((int)x & 0xFFFF0) >> 4) #define rm_off(x) (unsigned short)(((int)x & 0x0000F) >> 0) +#define EFLAGS_CF (1 << 0) + struct rm_regs { + uint32_t eflags; uint32_t ebp; uint32_t edi; uint32_t esi;