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/boot.hex.html | 396 +++++++++++++++++++++++++++++++++++++++++ html/baremetal/boot0.hex.html | 404 ++++++++++++++++++++++++++++++++++++++++++ html/baremetal/ex1.hex.html | 75 ++++++++ 3 files changed, 875 insertions(+) create mode 100644 html/baremetal/boot.hex.html create mode 100644 html/baremetal/boot0.hex.html create mode 100644 html/baremetal/ex1.hex.html (limited to 'html') diff --git a/html/baremetal/boot.hex.html b/html/baremetal/boot.hex.html new file mode 100644 index 00000000..0e2909f3 --- /dev/null +++ b/html/baremetal/boot.hex.html @@ -0,0 +1,396 @@ + + + + +Mu - baremetal/boot.hex + + + + + + + + + + +https://github.com/akkartik/mu/blob/master/baremetal/boot.hex +
+  1 # Code for the first 2 disk sectors, that all programs in this directory need:
+  2 #   - load sectors past the first (using BIOS primitives) since only the first is available by default
+  3 #     - if this fails, print 'D' at top-left of screen and halt
+  4 #   - initialize a minimal graphics mode
+  5 #   - switch to 32-bit mode (giving up access to BIOS primitives)
+  6 #   - set up a handler for keyboard events
+  7 #   - jump to start of program
+  8 #
+  9 # To convert to a disk image, first prepare a realistically sized disk image:
+ 10 #   dd if=/dev/zero of=disk.img count=20160  # 512-byte sectors, so 10MB
+ 11 # Create initial sectors from this file:
+ 12 #   ./bootstrap run apps/hex < baremetal/boot.hex > boot.bin
+ 13 # Translate other sectors into a file called a.img
+ 14 # Load all sectors into the disk image:
+ 15 #   cat boot.bin a.img > disk.bin
+ 16 #   dd if=disk.bin of=disk.img conv=notrunc
+ 17 # To run:
+ 18 #   qemu-system-i386 disk.img
+ 19 # Or:
+ 20 #   bochs -f apps/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 # Programs using this initialization:
+ 31 #   - can't use any syscalls
+ 32 #   - can't print text to video memory (past these boot sectors)
+ 33 #   - must only print raw pixels (256 colors) to video memory (resolution 1280x1024)
+ 34 #   - must store their entry-point at address 0x8000
+ 35 
+ 36 ## 16-bit entry point
+ 37 
+ 38 # Upon reset, the IBM PC:
+ 39 # - loads the first sector (512 bytes)
+ 40 #   from some bootable image (see the boot sector marker at the end of this file)
+ 41 #   to the address range [0x7c00, 0x7e00)
+ 42 # - starts executing code at address 0x7c00
+ 43 
+ 44 # offset 00 (address 0x7c00):
+ 45   # disable interrupts for this initialization
+ 46   fa  # cli
+ 47 
+ 48   # initialize segment registers
+ 49   # this isn't always needed, but the recommendation is to not make assumptions
+ 50   b8 00 00  # ax <- 0
+ 51   8e d8  # ds <- ax
+ 52   8e d0  # ss <- ax
+ 53   8e c0  # es <- ax
+ 54   8e e0  # fs <- ax
+ 55   8e e8  # gs <- ax
+ 56 
+ 57   # We don't read or write the stack before we get to 32-bit mode. No function
+ 58   # calls, so we don't need to initialize the stack.
+ 59 
+ 60 # 0e:
+ 61   # load second sector from disk
+ 62   b4 02  # ah <- 2  # read sectors from disk
+ 63   # dl comes conveniently initialized at boot time with the index of the device being booted
+ 64   b5 00  # ch <- 0  # cylinder 0
+ 65   b6 00  # dh <- 0  # track 0
+ 66   b1 02  # cl <- 2  # second sector, 1-based
+ 67   b0 04  # al <- 4  # number of sectors to read
+ 68   # address to write sectors to = es:bx = 0x7e00, contiguous with boot segment
+ 69   bb 00 00  # bx <- 0
+ 70   8e c3  # es <- bx
+ 71   bb 00 7e  # bx <- 0x7e00
+ 72   cd 13  # int 13h, BIOS disk service
+ 73   0f 82 76 00  # jump-if-carry disk-error
+ 74 
+ 75 # 26:
+ 76   # undo the A20 hack: https://en.wikipedia.org/wiki/A20_line
+ 77   # this is from https://github.com/mit-pdos/xv6-public/blob/master/bootasm.S
+ 78   # seta20.1:
+ 79   e4 64  # al <- port 0x64
+ 80   a8 02  # set zf if bit 1 (second-least significant) is not set
+ 81   75 fa  # if zf not set, goto seta20.1 (-6)
+ 82 
+ 83   b0 d1  # al <- 0xd1
+ 84   e6 64  # port 0x64 <- al
+ 85 
+ 86 # 30:
+ 87   # seta20.2:
+ 88   e4 64  # al <- port 0x64
+ 89   a8 02  # set zf if bit 1 (second-least significant) is not set
+ 90   75 fa  # if zf not set, goto seta20.2 (-6)
+ 91 
+ 92   b0 df  # al <- 0xdf
+ 93   e6 64  # port 0x64 <- al
+ 94 
+ 95 # 3a:
+ 96   # adjust video mode
+ 97   b4 4f  # ah <- 4f (VBE)
+ 98   b0 02  # al <- 02 (set video mode)
+ 99   bb 07 01  # bx <- 0x0107 (graphics 1280x1024x256)
+100             # fallback: 0x0101 (640x480x256)
+101             # for other choices see http://www.ctyme.com/intr/rb-0069.htm
+102   cd 10  # int 10h, Vesa BIOS extensions
+103 
+104 # 43:
+105   # switch to 32-bit mode
+106   0f 01 16  # lgdt 00/mod/indirect 010/subop 110/rm/use-disp16
+107     80 7c  # *gdt_descriptor
+108   0f 20 c0  # eax <- cr0
+109   66 83 c8 01  # eax <- or 0x1
+110   0f 22 c0  # cr0 <- eax
+111   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)
+112 
+113 # padding
+114 # 57:
+115                      00 00 00 00 00 00 00 00 00
+116 
+117 ## GDT: 3 records of 8 bytes each
+118 
+119 # 60:
+120 # gdt_start:
+121 # gdt_null:  mandatory null descriptor
+122   00 00 00 00 00 00 00 00
+123 # gdt_code:  (offset 8 from gdt_start)
+124   ff ff  # limit[0:16]
+125   00 00 00  # base[0:24]
+126   9a  # 1/present 00/privilege 1/descriptor type = 1001b
+127       # 1/code 0/conforming 1/readable 0/accessed = 1010b
+128   cf  # 1/granularity 1/32-bit 0/64-bit-segment 0/AVL = 1100b
+129       # limit[16:20] = 1111b
+130   00  # base[24:32]
+131 # gdt_data:  (offset 16 from gdt_start)
+132   ff ff  # limit[0:16]
+133   00 00 00  # base[0:24]
+134   92  # 1/present 00/privilege 1/descriptor type = 1001b
+135       # 0/data 0/conforming 1/readable 0/accessed = 0010b
+136   cf  # same as gdt_code
+137   00  # base[24:32]
+138 # gdt_end:
+139 
+140 # padding
+141 # 78:
+142                         00 00 00 00 00 00 00 00
+143 
+144 # 80:
+145 # gdt_descriptor:
+146   17 00  # final index of gdt = gdt_end - gdt_start - 1
+147   60 7c 00 00  # start = gdt_start
+148 
+149 # padding
+150 # 85:
+151                   00 00 00 00 00 00 00 00 00 00
+152 
+153 # 90:
+154 # disk_error:
+155   # print 'D' to top-left of screen to indicate disk error
+156   # *0xb8000 <- 0x0f44
+157   # bx <- 0xb800
+158   bb 00 b8
+159   # ds <- bx
+160   8e db  # 11b/mod 011b/reg/ds 011b/rm/bx
+161   # al <- 'D'
+162   b0 44
+163   # ah <- 0x0f  # white on black
+164   b4 0f
+165   # bx <- 0
+166   bb 00 00
+167   # *ds:bx <- ax
+168   89 07  # 00b/mod/indirect 000b/reg/ax 111b/rm/bx
+169 
+170 e9 fb ff  # loop forever
+171 
+172 # padding
+173 # a1:
+174    00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
+175 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
+176 
+177 ## 32-bit code from this point (still some instructions not in SubX)
+178 
+179 # c0:
+180 # initialize_32bit_mode:
+181   66 b8 10 00  # ax <- offset 16 from gdt_start
+182   8e d8  # ds <- ax
+183   8e d0  # ss <- ax
+184   8e c0  # es <- ax
+185   8e e0  # fs <- ax
+186   8e e8  # gs <- ax
+187 
+188   # load interrupt handlers
+189   0f 01 1d  # lidt 00/mod/indirect 011/subop 101/rm32/use-disp32
+190     00 7f 00 00  # *idt_descriptor
+191 
+192   # enable keyboard IRQ
+193   b0 fd  # al <- 0xfd  # enable just IRQ1
+194   e6 21  # port 0x21 <- al
+195 
+196   # initialization is done; enable interrupts
+197   fb
+198   e9 21 03 00 00  # jump to 0x8000
+199 
+200 # padding
+201 # df:
+202                                              00
+203 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
+204 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
+205 
+206 # 100:
+207 # null interrupt handler:
+208   cf  # iret
+209 
+210 # padding
+211 # 101:
+212    00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
+213 
+214 # 110:
+215 # keyboard interrupt handler:
+216   # prologue
+217   fa  # disable interrupts
+218   60  # push all registers to stack
+219   # acknowledge interrupt
+220   b0 20  # al <- 0x20
+221   e6 20  # port 0x20 <- al
+222   # TODO: perhaps we should check keyboard status
+223   # read keycode into eax
+224   31 c0  # eax <- xor eax;  11/direct 000/r32/eax 000/rm32/eax
+225   e4 60  # al <- port 0x60
+226   # map key '1' to ascii; if eax == 2, eax = 0x31
+227   3d 02 00 00 00  # compare eax with 0x02
+228   75 0b  # if not equal, goto epilogue
+229   b8 31 0f 00 00  # eax <- 0x0f31
+230   # print eax to top-left of screen (*0xb8000)
+231   89  # copy r32 to rm32
+232     05  # 00/mod/indirect 000/r32/eax 101/rm32/use-disp32
+233     # disp32
+234     00 80 0b 00
+235   # epilogue
+236   61  # pop all registers
+237   fb  # enable interrupts
+238   cf  # iret
+239 
+240 # padding
+241 # 12f
+242                                              00
+243 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
+244 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
+245 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
+246 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
+247 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
+248 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
+249 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
+250 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
+251 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
+252 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 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
+256 
+257 # final 2 bytes of boot sector
+258 55 aa
+259 
+260 ## sector 2
+261 # loaded by load_disk, not automatically on boot
+262 
+263 # offset 200 (address 0x7e00): interrupt descriptor table
+264 # 32 entries * 8 bytes each = 256 bytes (0x100)
+265 # idt_start:
+266 
+267 00 00 00 00 00 00 00 00
+268 00 00 00 00 00 00 00 00
+269 00 00 00 00 00 00 00 00
+270 00 00 00 00 00 00 00 00
+271 00 00 00 00 00 00 00 00
+272 00 00 00 00 00 00 00 00
+273 00 00 00 00 00 00 00 00
+274 00 00 00 00 00 00 00 00
+275 
+276 # entry 8: clock
+277   00 7d  # target[0:16] = null interrupt handler
+278   08 00  # segment selector (gdt_code)
+279   00  # unused
+280   8e  # 1/p 00/dpl 0 1110/type/32-bit-interrupt-gate
+281   00 00  # target[16:32]
+282 
+283 # entry 9: keyboard
+284   10 7d  # target[0:16] = keyboard interrupt handler
+285   08 00  # segment selector (gdt_code)
+286   00  # unused
+287   8e  # 1/p 00/dpl 0 1110/type/32-bit-interrupt-gate
+288   00 00  # target[16:32]
+289 
+290 00 00 00 00 00 00 00 00
+291 00 00 00 00 00 00 00 00
+292 00 00 00 00 00 00 00 00
+293 00 00 00 00 00 00 00 00
+294 00 00 00 00 00 00 00 00
+295 00 00 00 00 00 00 00 00
+296 00 00 00 00 00 00 00 00
+297 00 00 00 00 00 00 00 00
+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 # idt_end:
+313 
+314 # offset 300 (address 0x7f00):
+315 # idt_descriptor:
+316   ff 00  # idt_end - idt_start - 1
+317   00 7e 00 00  # start = idt_start
+318 
+319 # padding
+320                   00 00 00 00 00 00 00 00 00 00
+321 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
+322 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
+323 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
+324 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
+325 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
+326 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
+327 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
+328 00 00 00 00 00 00 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 # offset 400 (address 0x8000)
+337 
+338 # vim:ft=subx
+
+ + + 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
+
+ + + diff --git a/html/baremetal/ex1.hex.html b/html/baremetal/ex1.hex.html new file mode 100644 index 00000000..bdfb696f --- /dev/null +++ b/html/baremetal/ex1.hex.html @@ -0,0 +1,75 @@ + + + + +Mu - baremetal/ex1.hex + + + + + + + + + + +https://github.com/akkartik/mu/blob/master/baremetal/ex1.hex +
+ 1 # The simplest possible program: just an infinite loop.
+ 2 # All is well if your computer clears screen and hangs without restarting.
+ 3 # On an emulator the window may get bigger to accomodate the 1280x1024 graphics mode.
+ 4 #
+ 5 # To convert to a disk image, first prepare a realistically sized disk image:
+ 6 #   dd if=/dev/zero of=disk.img count=20160  # 512-byte sectors, so 10MB
+ 7 # Load the disk image:
+ 8 #   cat baremetal/boot.hex baremetal/ex1.hex  |./bootstrap run apps/hex  > a.bin
+ 9 #   dd if=a.bin of=disk.img conv=notrunc
+10 # To run:
+11 #   qemu-system-i386 disk.img
+12 # Or:
+13 #   bochs -f apps/boot.bochsrc  # boot.bochsrc loads disk.img
+14 
+15 # address 0x8000
+16 e9 fb ff ff ff  # jump to address 0x8000
+17 
+18 # vim:ft=subx
+
+ + + -- cgit 1.4.1-2-gfad0