Misc fixes to disk driver and real mode ints
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;
-
- size_t sectors_count = 1 + ((offset + count) / SECTOR_SIZE);
-
- while (sectors_count--) {
- if (cur_sector != last_sector)
- if ((res = read_sector(drive, sector_buf, cur_sector, 1)))
- return res;
-
- 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++;
+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;
+
+ int ret;
+ if ((ret = cache_sector(drive, sect)))
+ return ret;
+
+ uint64_t chunk = count - progress;
+ uint64_t offset = (loc + progress) % SECTOR_SIZE;
+ if (chunk > SECTOR_SIZE - offset)
+ chunk = SECTOR_SIZE - offset;
+
+ 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 <stddef.h>
#include <stdint.h>
-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;
