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.
This commit is contained in:
Kartik K. Agaram 2021-03-21 22:10:17 -07:00
parent 89db4ec100
commit fba2146593
3 changed files with 216 additions and 0 deletions

View File

@ -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.

214
boot.subx
View File

@ -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

View File

@ -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