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; }; };