summaryrefslogtreecommitdiff
path: root/drive
diff options
context:
space:
mode:
Diffstat (limited to 'drive')
-rw-r--r--drive/+bios/drive.ha69
-rw-r--r--drive/README4
-rw-r--r--drive/drive.ha21
-rw-r--r--drive/errors.ha1
4 files changed, 74 insertions, 21 deletions
diff --git a/drive/+bios/drive.ha b/drive/+bios/drive.ha
new file mode 100644
index 0000000..da33740
--- /dev/null
+++ b/drive/+bios/drive.ha
@@ -0,0 +1,69 @@
+use bios;
+
+def sector_size: u32 = 512;
+
+// Converts lba to the CHS format
+fn lbatochs(lba: u32) (u16, u16, u16) = {
+ const temp = lba / bios::drive_sectors_per_track;
+ const sector = (lba % bios::drive_sectors_per_track) + 1;
+ const head = temp % bios::drive_heads;
+ const cylinder = temp / bios::drive_heads;
+
+ return (cylinder: u16, head: u16, sector: u16);
+};
+
+// Reads the sector at lba and place it into the workspace buffer
+fn bios_read(lba: u32) (void | error) = {
+ const chs = lbatochs(lba);
+ const readcount = len(bios::ws): u32 / sector_size;
+
+ // AH=0x2 (read disk) AL=1 (read 1 sector)
+ bios::regs.eax = 0x2 << 8 | readcount;
+
+ // CH=cylinder CL=sector
+ bios::regs.ecx = chs.0 << 8 | chs.2;
+
+ // DH=head DL=driveno
+ bios::regs.edx = chs.1 << 8 | bios::drive_number;
+
+ let ws = (&bios::ws): uintptr;
+ bios::regs.es = (ws / 16): u16;
+ bios::regs.ebx = (ws % 16): u32;
+
+ bios::call(0x13);
+
+ if (bios::regs.eax != readcount) {
+ return error;
+ };
+};
+
+export fn read(addr: u32, count: size, dest: *[*]u8) (void | error) = {
+ // the amount of sectors fitting in the workspace (cannot be make a global constant yet, an assertion fails)
+ const readcount = len(bios::ws): u32 / sector_size;
+
+ // the starting lba
+ let lba = addr / sector_size;
+ // the reading head (for starting to read bytes not aligned with the sector)
+ let head = addr % len(bios::ws);
+
+ let cursor = 0z;
+
+ for (true) {
+ bios_read(lba)?;
+
+ for (head < len(bios::ws)) {
+ // XXX: use memmove
+ dest[cursor] = bios::ws[head];
+
+ head += 1;
+ cursor += 1;
+ if (cursor >= count) {
+ return;
+ };
+ };
+
+ head = 0;
+ lba += readcount;
+ };
+
+};
diff --git a/drive/README b/drive/README
new file mode 100644
index 0000000..cd7a6f8
--- /dev/null
+++ b/drive/README
@@ -0,0 +1,4 @@
+drive contains various implementations of the drive reading interface
+
+Currently, it supports:
+ - BIOS (via the bios module). \ No newline at end of file
diff --git a/drive/drive.ha b/drive/drive.ha
deleted file mode 100644
index 259e7f5..0000000
--- a/drive/drive.ha
+++ /dev/null
@@ -1,21 +0,0 @@
-use bios;
-use bios::drive;
-
-fn lba_to_chs(lba: u16) (u16, u16, u16) = {
- //let temp = lba / bios::drive::drive_spt;
- //let sector = (lba % bios::drive::drive_spt) + 1;
- //let head = temp % bios::drive::drive_heads;
- //let cylinder = temp / bios::drive::drive_heads;
-
- //return (cylinder, head, sector);
- return (0, 0, 0);
-};
-
-export fn read(sector: u16, dest: uintptr) void = {
- let chs = lba_to_chs(sector);
-
- //bios::regs.eax = 1 | 0x2 << 8;
- //bios::regs.ebx = ws;
- //bios::regs.ecx = chs.2 | chs.0 << 8;
- //bios::regs.edx = bios::drive::drive_no | chs.1 << 8;
-};
diff --git a/drive/errors.ha b/drive/errors.ha
new file mode 100644
index 0000000..58742fb
--- /dev/null
+++ b/drive/errors.ha
@@ -0,0 +1 @@
+export type error = !void;