From 761001dadc4fbbff674295f6bf0fd6c9026b107a Mon Sep 17 00:00:00 2001 From: Kartik Agaram Date: Sat, 26 Dec 2020 14:29:02 -0800 Subject: 7405 --- html/baremetal/boot0.hex.html | 404 ++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 404 insertions(+) create mode 100644 html/baremetal/boot0.hex.html (limited to 'html/baremetal/boot0.hex.html') diff --git a/html/baremetal/boot0.hex.html b/html/baremetal/boot0.hex.html new file mode 100644 index 00000000..e6ada4e7 --- /dev/null +++ b/html/baremetal/boot0.hex.html @@ -0,0 +1,404 @@ + + + + +Mu - baremetal/boot0.hex + + + + + + + + + + +https://github.com/akkartik/mu/blob/master/baremetal/boot0.hex +
+  1 # A minimal bootable image that:
+  2 #   - loads more sectors past the first boot sector (using BIOS primitives)
+  3 #   - switches to 32-bit mode (giving up access to BIOS primitives)
+  4 #   - sets up a handler for keyboard events
+  5 #   - as an example program, prints '1' to the top-left position on screen (by writing to memory-mapped VGA memory) when the '1' key is typed
+  6 #
+  7 # When it's ready to accept keys, it prints 'H' to the top-left of the screen.
+  8 #
+  9 # If the initial load fails, it prints 'D' to the top-left of the screen and
+ 10 # halts.
+ 11 #
+ 12 # To convert to a disk image, first prepare a realistically sized disk image:
+ 13 #   dd if=/dev/zero of=disk.img count=20160  # 512-byte sectors, so 10MB
+ 14 # Now fill in sectors:
+ 15 #   ./bootstrap run apps/hex < baremetal/boot0.hex > boot.bin
+ 16 #   dd if=boot.bin of=disk.img conv=notrunc
+ 17 # To run:
+ 18 #   qemu-system-i386 disk.img
+ 19 # Or:
+ 20 #   bochs -f baremetal/boot.bochsrc  # boot.bochsrc loads disk.img
+ 21 #
+ 22 # Since we start out in 16-bit mode, we need instructions SubX doesn't
+ 23 # support.
+ 24 # This file contains just lowercase hex bytes and comments. Zero
+ 25 # error-checking. Make liberal use of:
+ 26 #   - comments documenting expected offsets
+ 27 #   - size checks on the emitted file (currently: 512 bytes)
+ 28 #   - xxd to eyeball that offsets contain expected bytes
+ 29 
+ 30 ## 16-bit entry point
+ 31 
+ 32 # Upon reset, the IBM PC
+ 33 #   loads the first sector (512 bytes)
+ 34 #   from some bootable image (see the boot sector marker at the end of this file)
+ 35 #   to the address range [0x7c00, 0x7e00)
+ 36 
+ 37 # offset 00 (address 0x7c00):
+ 38   # disable interrupts for this initialization
+ 39   fa  # cli
+ 40 
+ 41   # initialize segment registers
+ 42   # this isn't always needed, but the recommendation is to not make assumptions
+ 43   b8 00 00  # ax <- 0
+ 44   8e d8  # ds <- ax
+ 45   8e d0  # ss <- ax
+ 46   8e c0  # es <- ax
+ 47   8e e0  # fs <- ax
+ 48   8e e8  # gs <- ax
+ 49 
+ 50   # We don't read or write the stack before we get to 32-bit mode. No function
+ 51   # calls, so we don't need to initialize the stack.
+ 52 
+ 53 # 0e:
+ 54   # load more sectors from disk
+ 55   b4 02  # ah <- 2  # read sectors from disk
+ 56   # dl comes conveniently initialized at boot time with the index of the device being booted
+ 57   b5 00  # ch <- 0  # cylinder 0
+ 58   b6 00  # dh <- 0  # track 0
+ 59   b1 02  # cl <- 2  # second sector, 1-based
+ 60   b0 01  # al <- 1  # number of sectors to read
+ 61   # address to write sectors to = es:bx = 0x7e00, contiguous with boot segment
+ 62   bb 00 00  # bx <- 0
+ 63   8e c3  # es <- bx
+ 64   bb 00 7e  # bx <- 0x7e00
+ 65   cd 13  # int 13h, BIOS disk service
+ 66   0f 82 76 00  # jump-if-carry disk-error
+ 67 
+ 68 # 26:
+ 69   # undo the A20 hack: https://en.wikipedia.org/wiki/A20_line
+ 70   # this is from https://github.com/mit-pdos/xv6-public/blob/master/bootasm.S
+ 71   # seta20.1:
+ 72   e4 64  # al <- port 0x64
+ 73   a8 02  # set zf if bit 1 (second-least significant) is not set
+ 74   75 fa  # if zf not set, goto seta20.1 (-6)
+ 75 
+ 76   b0 d1  # al <- 0xd1
+ 77   e6 64  # port 0x64 <- al
+ 78 
+ 79 # 30:
+ 80   # seta20.2:
+ 81   e4 64  # al <- port 0x64
+ 82   a8 02  # set zf if bit 1 (second-least significant) is not set
+ 83   75 fa  # if zf not set, goto seta20.2 (-6)
+ 84 
+ 85   b0 df  # al <- 0xdf
+ 86   e6 64  # port 0x64 <- al
+ 87 
+ 88 # 3a:
+ 89   # switch to 32-bit mode
+ 90   0f 01 16  # lgdt 00/mod/indirect 010/subop 110/rm/use-disp16
+ 91     80 7c  # *gdt_descriptor
+ 92 # 3f:
+ 93   0f 20 c0  # eax <- cr0
+ 94   66 83 c8 01  # eax <- or 0x1
+ 95   0f 22 c0  # cr0 <- eax
+ 96   ea c0 7c 08 00  # far jump to initialize_32bit_mode after setting cs to the record at offset 8 in the gdt (gdt_code)
+ 97 
+ 98 # padding
+ 99 # 4e:
+100                                           00 00
+101 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
+102 
+103 ## GDT: 3 records of 8 bytes each
+104 
+105 # 60:
+106 # gdt_start:
+107 # gdt_null:  mandatory null descriptor
+108   00 00 00 00 00 00 00 00
+109 # gdt_code:  (offset 8 from gdt_start)
+110   ff ff  # limit[0:16]
+111   00 00 00  # base[0:24]
+112   9a  # 1/present 00/privilege 1/descriptor type = 1001b
+113       # 1/code 0/conforming 1/readable 0/accessed = 1010b
+114   cf  # 1/granularity 1/32-bit 0/64-bit-segment 0/AVL = 1100b
+115       # limit[16:20] = 1111b
+116   00  # base[24:32]
+117 # gdt_data:  (offset 16 from gdt_start)
+118   ff ff  # limit[0:16]
+119   00 00 00  # base[0:24]
+120   92  # 1/present 00/privilege 1/descriptor type = 1001b
+121       # 0/data 0/conforming 1/readable 0/accessed = 0010b
+122   cf  # same as gdt_code
+123   00  # base[24:32]
+124 # gdt_end:
+125 
+126 # padding
+127 # 78:
+128                         00 00 00 00 00 00 00 00
+129 
+130 # 80:
+131 # gdt_descriptor:
+132   17 00  # final index of gdt = gdt_end - gdt_start - 1
+133   60 7c 00 00  # start = gdt_start
+134 
+135 # padding
+136 # 85:
+137                   00 00 00 00 00 00 00 00 00 00
+138 
+139 # 90:
+140 # disk_error:
+141   # print 'D' to top-left of screen to indicate disk error
+142   # *0xb8000 <- 0x0f44
+143   # bx <- 0xb800
+144   bb 00 b8
+145   # ds <- bx
+146   8e db  # 11b/mod 011b/reg/ds 011b/rm/bx
+147   # al <- 'D'
+148   b0 44
+149   # ah <- 0x0f  # white on black
+150   b4 0f
+151   # bx <- 0
+152   bb 00 00
+153   # *ds:bx <- ax
+154   89 07  # 00b/mod/indirect 000b/reg/ax 111b/rm/bx
+155 
+156 e9 fb ff  # loop forever
+157 
+158 # padding
+159 # a1:
+160    00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
+161 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
+162 
+163 ## 32-bit code from this point (still some instructions not in SubX)
+164 
+165 # c0:
+166 # initialize_32bit_mode:
+167   66 b8 10 00  # ax <- offset 16 from gdt_start
+168   8e d8  # ds <- ax
+169   8e d0  # ss <- ax
+170   8e c0  # es <- ax
+171   8e e0  # fs <- ax
+172   8e e8  # gs <- ax
+173 
+174   # load interrupt handlers
+175   0f 01 1d  # lidt 00/mod/indirect 011/subop 101/rm32/use-disp32
+176     00 7f 00 00  # *idt_descriptor
+177 
+178   # enable keyboard IRQ
+179   b0 fd  # al <- 0xfd  # enable just IRQ1
+180   e6 21  # port 0x21 <- al
+181 
+182   # initialization is done; enable interrupts
+183   fb
+184   e9 21 00 00 00  # jump to 0x7d00
+185 
+186 # padding
+187 # df:
+188                                              00
+189 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
+190 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
+191 
+192 ## 'application' SubX code: print one character to top-left of screen
+193 
+194 # offset 100 (address 0x7d00):
+195 # Entry:
+196   # eax <- *0x7ff4  # random address in second segment containing 'H'
+197   8b  # copy rm32 to r32
+198     05  # 00/mod/indirect 000/r32/eax 101/rm32/use-disp32
+199     # disp32
+200     f4 7f 00 00
+201   # *0xb8000 <- eax
+202   89  # copy r32 to rm32
+203     05  # 00/mod/indirect 000/r32/eax 101/rm32/use-disp32
+204     # disp32
+205     00 80 0b 00
+206 
+207 e9 fb ff ff ff  # loop forever
+208 
+209 # padding
+210 # 111:
+211    00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
+212 
+213 # 120:
+214 # null interrupt handler:
+215   cf  # iret
+216 
+217 # padding
+218 # 121:
+219    00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
+220 
+221 # 130:
+222 # keyboard interrupt handler:
+223   # prologue
+224   fa  # disable interrupts
+225   60  # push all registers to stack
+226   # acknowledge interrupt
+227   b0 20  # al <- 0x20
+228   e6 20  # port 0x20 <- al
+229   # read keyboard status (TODO: why bit 0? Doesn't line up with https://web.archive.org/web/20040604041507/http://panda.cs.ndsu.nodak.edu/~achapwes/PICmicro/keyboard/atkeyboard.html)
+230 #?   e4 64  # al <- port 0x64
+231 #?   a8 01  # set zf if bit 0 (least significant) is not set
+232 #?   74 11  # if bit 0 is not set, skip to epilogue
+233   # read keycode into eax
+234   31 c0  # eax <- xor eax;  11/direct 000/r32/eax 000/rm32/eax
+235   e4 60  # al <- port 0x60
+236   # map key '1' to ascii; if eax == 2, eax = 0x31
+237   3d 02 00 00 00  # compare eax with 0x02
+238   75 0b  # if not equal, goto epilogue
+239   b8 31 0f 00 00  # eax <- 0x0f31
+240   # print eax to top-left of screen (*0xb8000)
+241   89  # copy r32 to rm32
+242     05  # 00/mod/indirect 000/r32/eax 101/rm32/use-disp32
+243     # disp32
+244     00 80 0b 00
+245   # epilogue
+246   61  # pop all registers
+247   fb  # enable interrupts
+248   cf  # iret
+249 
+250 # padding
+251 # 14f
+252                                              00
+253 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
+254 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
+255 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
+256 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
+257 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
+258 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
+259 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
+260 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
+261 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
+262 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
+263 00 00 00 00 00 00 00 00 00 00 00 00 00 00
+264 
+265 # final 2 bytes of boot sector
+266 55 aa
+267 
+268 ## sector 2
+269 # loaded by load_disk, not automatically on boot
+270 
+271 # offset 200 (address 0x7e00): interrupt descriptor table
+272 # 32 entries * 8 bytes each = 256 bytes (0x100)
+273 # idt_start:
+274 
+275 00 00 00 00 00 00 00 00
+276 00 00 00 00 00 00 00 00
+277 00 00 00 00 00 00 00 00
+278 00 00 00 00 00 00 00 00
+279 00 00 00 00 00 00 00 00
+280 00 00 00 00 00 00 00 00
+281 00 00 00 00 00 00 00 00
+282 00 00 00 00 00 00 00 00
+283 
+284 # entry 8: clock
+285   20 7d  # target[0:16] = null interrupt handler
+286   08 00  # segment selector (gdt_code)
+287   00  # unused
+288   8e  # 1/p 00/dpl 0 1110/type/32-bit-interrupt-gate
+289   00 00  # target[16:32]
+290 
+291 # entry 9: keyboard
+292   30 7d  # target[0:16] = keyboard interrupt handler
+293   08 00  # segment selector (gdt_code)
+294   00  # unused
+295   8e  # 1/p 00/dpl 0 1110/type/32-bit-interrupt-gate
+296   00 00  # target[16:32]
+297 
+298 00 00 00 00 00 00 00 00
+299 00 00 00 00 00 00 00 00
+300 00 00 00 00 00 00 00 00
+301 00 00 00 00 00 00 00 00
+302 00 00 00 00 00 00 00 00
+303 00 00 00 00 00 00 00 00
+304 00 00 00 00 00 00 00 00
+305 00 00 00 00 00 00 00 00
+306 00 00 00 00 00 00 00 00
+307 00 00 00 00 00 00 00 00
+308 00 00 00 00 00 00 00 00
+309 00 00 00 00 00 00 00 00
+310 00 00 00 00 00 00 00 00
+311 00 00 00 00 00 00 00 00
+312 00 00 00 00 00 00 00 00
+313 00 00 00 00 00 00 00 00
+314 00 00 00 00 00 00 00 00
+315 00 00 00 00 00 00 00 00
+316 00 00 00 00 00 00 00 00
+317 00 00 00 00 00 00 00 00
+318 00 00 00 00 00 00 00 00
+319 00 00 00 00 00 00 00 00
+320 # idt_end:
+321 
+322 # offset 300 (address 0x7f00):
+323 # idt_descriptor:
+324   ff 00  # idt_end - idt_start - 1
+325   00 7e 00 00  # start = idt_start
+326 
+327 # padding
+328                   00 00 00 00 00 00 00 00 00 00
+329 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
+330 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
+331 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
+332 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
+333 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
+334 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
+335 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
+336 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
+337 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
+338 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
+339 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
+340 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
+341 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
+342 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
+343 00 00 00 00 48 0f 00 00 00 00 00 00 00 00 00 00  # spot the 'H' with attributes
+344 # offset 400 (address 0x8000)
+345 
+346 # vim:ft=conf
+
+ + + -- cgit 1.4.1-2-gfad0