diff options
author | Kartik K. Agaram <vc@akkartik.com> | 2021-03-21 22:10:17 -0700 |
---|---|---|
committer | Kartik K. Agaram <vc@akkartik.com> | 2021-03-21 22:29:24 -0700 |
commit | fba2146593b077829845efcfe4b343ce809f5d88 (patch) | |
tree | 5cda18c98876967530105ab95757fede599685f9 | |
parent | 89db4ec10001f08742be78596ef41f07ed5b124c (diff) | |
download | mu-fba2146593b077829845efcfe4b343ce809f5d88.tar.gz |
snapshot: reading from disk without BIOS!!
Both LBA and CHS coordinates are now working for the primary disk on the primary bus. Failure modes I ran into: - ATA ports are 16-bit values. Using instructions with 8-bit immediates will yield strange results. (I had to debug this twice because I missed poll-ata-primary-bus-primary-drive-regular-status-word the first time around.) Mu's toolchain has been found out here. bootstrap has good errors but doesn't support the instructions I need in boot.subx. The self-hosted phases support the instructions but provide no error-checking. Might be worth starting to add error-checking as I encounter the need. In this case, a vote for validating metadata sizes even if we don't validate that instructions pass in the right metadata sizes. - Can't poll readiness first thing. Maybe we need to always select the drive first. - Reading 8-bit values from a 16-bit port (data port 0x1f0) returns garbage. Reading 32-bit values however works totally fine; go figure. (Maybe it won't work on real hardware?) https://forum.osdev.org/viewtopic.php?t=36415 - Passing in a 0 segment will never return data.
-rw-r--r-- | bochsrc | 1 | ||||
-rw-r--r-- | boot.subx | 214 | ||||
-rw-r--r-- | mu-init.subx | 1 |
3 files changed, 216 insertions, 0 deletions
diff --git a/bochsrc b/bochsrc index a1c8a4bc..f70d7906 100644 --- a/bochsrc +++ b/bochsrc @@ -9,6 +9,7 @@ display_library: sdl2 +#ata0: enabled=1, ioaddr1=0x1f0, ioaddr2=0x3f0, irq=14 ata0-master: type=disk, path="disk.img", mode=flat, cylinders=20, heads=16, spt=63 # 10MB, 512 bytes per sector boot: disk # PS/2 mouse requires black magic that I don't know how to explain. diff --git a/boot.subx b/boot.subx index 5cf7ee7d..1a2a6e64 100644 --- a/boot.subx +++ b/boot.subx @@ -914,5 +914,219 @@ Font: # }}} # offset 1800 (address 0x9400) +== code 0x9400 + +# Use 28-bit PIO mode to transfer one sector from the primary drive on the +# primary bus. +# Inspired by https://colorforth.github.io/ide.html +# +# Resources: +# https://wiki.osdev.org/ATA_PIO_Mode +# https://forum.osdev.org/viewtopic.php?f=1&p=167798 +# read-sector, according to https://www.scs.stanford.edu/11wi-cs140/pintos/specs/ata-3-std.pdf +read-a-sector: + # . prologue + 55/push-ebp + 89/<- %ebp 4/r32/esp + # . save registers + 50/push-eax + 52/push-edx + # check for floating bus + { + 31/xor %eax 0/r32/eax + ba/copy-to-edx 0x1f7/imm32 + ec/read-port-dx-into-al + 81 7/subop/compare %eax 0xff/imm32 + 75/jump-if-!= break/disp8 + (abort "primary bus has no drives") + } + # kick off read + (ata-drive-select 0xe0) # primary drive; 4 LSBs contain 4 upper bits of LBA (here 0) +#? (ata-drive-select 0xa0) # primary drive in CHS + head number + (ata-error 0) + (ata-sector-count 1) + (ata-lba 0 0 0) # lower 24 bits of LBA +#? (ata-cyl-sector 1 0 0) + (ata-command 0x20) # read sectors with retries + # poll for results + (poll-ata-primary-bus-primary-drive-regular-status-word) + # print out results + ba/copy-to-edx 0x1f0/imm32 + b9/copy-to-ecx 0x10/imm32 + { + 81 7/subop/compare %ecx 0/imm32 + 74/jump-if-= break/disp8 + ed/read-port-dx-into-eax + (draw-int32-hex-wrapping-right-then-down-from-cursor-over-full-screen 0 %eax) + (move-cursor-to-left-margin-of-next-line 0) # 0=screen + 49/decrement-ecx + eb/jump loop/disp8 + } + (abort "success") +$read-256-sectors:end: + # . restore registers + 5a/pop-to-edx + 58/pop-to-eax + # . epilogue + 89/<- %esp 5/r32/ebp + 5d/pop-to-ebp + c3/return + +ata-drive-select: # n: byte + # . prologue + 55/push-ebp + 89/<- %ebp 4/r32/esp + # . save registers + 50/push-eax + 52/push-edx + # + 8b/-> *(ebp+8) 0/r32/eax + ba/copy-to-edx 0x1f6/imm32 + ee/write-al-into-port-dx +$ata-drive-select:end: + # . restore registers + 5a/pop-to-edx + 58/pop-to-eax + # . epilogue + 89/<- %esp 5/r32/ebp + 5d/pop-to-ebp + c3/return + +ata-error: # n: byte + # . prologue + 55/push-ebp + 89/<- %ebp 4/r32/esp + # . save registers + 50/push-eax + 52/push-edx + # + 8b/-> *(ebp+8) 0/r32/eax + ba/copy-to-edx 0x1f1/imm32 + ee/write-al-into-port-dx +$ata-error:end: + # . restore registers + 5a/pop-to-edx + 58/pop-to-eax + # . epilogue + 89/<- %esp 5/r32/ebp + 5d/pop-to-ebp + c3/return + +ata-sector-count: # n: byte + # . prologue + 55/push-ebp + 89/<- %ebp 4/r32/esp + # . save registers + 50/push-eax + 52/push-edx + # + 8b/-> *(ebp+8) 0/r32/eax + ba/copy-to-edx 0x1f2/imm32 + ee/write-al-into-port-dx +$ata-sector-count:end: + # . restore registers + 5a/pop-to-edx + 58/pop-to-eax + # . epilogue + 89/<- %esp 5/r32/ebp + 5d/pop-to-ebp + c3/return + +ata-lba: # lo: byte, mid: byte, hi: byte + # . prologue + 55/push-ebp + 89/<- %ebp 4/r32/esp + # . save registers + 50/push-eax + 52/push-edx + # lo + 8b/-> *(ebp+8) 0/r32/eax + ba/copy-to-edx 0x1f3/imm32 + ee/write-al-into-port-dx + # mid + 8b/-> *(ebp+0xc) 0/r32/eax + ba/copy-to-edx 0x1f4/imm32 + ee/write-al-into-port-dx + # hi + 8b/-> *(ebp+0x10) 0/r32/eax + ba/copy-to-edx 0x1f5/imm32 + ee/write-al-into-port-dx +$ata-lba:end: + # . restore registers + 5a/pop-to-edx + 58/pop-to-eax + # . epilogue + 89/<- %esp 5/r32/ebp + 5d/pop-to-ebp + c3/return + +# sector: [1, 63] +# cylinder: [0, 1023] +ata-cyl-sector: # sector: byte, cyl-lo: byte, cyl-hi: byte + # . prologue + 55/push-ebp + 89/<- %ebp 4/r32/esp + # . save registers + 50/push-eax + 52/push-edx + # sector + 8b/-> *(ebp+8) 0/r32/eax + ba/copy-to-edx 0x1f3/imm32 + ee/write-al-into-port-dx + # cyl-lo + 8b/-> *(ebp+0xc) 0/r32/eax + ba/copy-to-edx 0x1f4/imm32 + ee/write-al-into-port-dx + # cyl-hi + 8b/-> *(ebp+0x10) 0/r32/eax + ba/copy-to-edx 0x1f5/imm32 + ee/write-al-into-port-dx +$ata-lba:end: + # . restore registers + 5a/pop-to-edx + 58/pop-to-eax + # . epilogue + 89/<- %esp 5/r32/ebp + 5d/pop-to-ebp + c3/return + +ata-command: # cmd: byte + # . prologue + 55/push-ebp + 89/<- %ebp 4/r32/esp + # . save registers + 50/push-eax + 52/push-edx + # + 8b/-> *(ebp+8) 0/r32/eax + ba/copy-to-edx 0x1f7/imm32 + ee/write-al-into-port-dx +$ata-command:end: + # . restore registers + 5a/pop-to-edx + 58/pop-to-eax + # . epilogue + 89/<- %esp 5/r32/ebp + 5d/pop-to-ebp + c3/return + +poll-ata-primary-bus-primary-drive-regular-status-word: + # . save registers + 50/push-eax + 52/push-edx + { + ba/copy-to-edx 0x1f7/imm32 + ec/read-port-dx-into-al + a8/test-bits-in-al 0x80/imm8/bsy # set zf if bit 7 (most significant) is not set + 75/jump-if-zf-not-set-and-bit-7-set loop/disp8 + a8/test-bits-in-al 8/imm8/drq # set zf if bit 3 is not set + 74/jump-if-zf-set-and-bit-3-not-set loop/disp8 + } +$poll-ata-primary-bus-primary-drive-regular-status-word:end: + # . restore registers + 5a/pop-to-edx + 58/pop-to-eax + # . epilogue + c3/return # vim:ft=subx diff --git a/mu-init.subx b/mu-init.subx index bf9e5b0d..7857a8a1 100644 --- a/mu-init.subx +++ b/mu-init.subx @@ -10,6 +10,7 @@ Entry: # initialize stack bd/copy-to-ebp 0/imm32 + (read-a-sector) # always first run tests (run-tests) (num-test-failures) # => eax |