about summary refs log tree commit diff stats
diff options
context:
space:
mode:
authorKartik Agaram <vc@akkartik.com>2020-12-20 00:16:15 -0800
committerKartik Agaram <vc@akkartik.com>2020-12-20 00:16:15 -0800
commit9b5b8471caf0a41b6d4c3445590a19643e97d546 (patch)
treee83f7e237eb3cd2786174517c326ff57ad84374f
parent70bb19100eaa979c58a5513f29fec1b4a00634f6 (diff)
downloadmu-9b5b8471caf0a41b6d4c3445590a19643e97d546.tar.gz
7358
Snapshot: first draft of a boot image that switches to 32-bit mode as quickly
as possible (~70 bytes)

Doesn't work yet. Gets stuck in an infinite reset loop.
-rw-r--r--apps/bos/32bit.hex121
-rw-r--r--apps/bos/4.xxd87
2 files changed, 208 insertions, 0 deletions
diff --git a/apps/bos/32bit.hex b/apps/bos/32bit.hex
new file mode 100644
index 00000000..0d7a294c
--- /dev/null
+++ b/apps/bos/32bit.hex
@@ -0,0 +1,121 @@
+# Bootable image demonstrating printing to screen in 32-bit mode.
+# Must have exactly 512 bytes.
+#
+# To convert to a disk image:
+#   ./bootstrap run apps/hex < apps/bos/32bit.hex > boot.bin
+# To run:
+#   qemu-system-i386 boot.bin
+# Or:
+#   bochs -f apps/bos/bochsrc  # bochsrc loads boot.bin
+#
+# Expected output inside emulator:
+#   H
+
+## 16-bit entry point
+
+# Boot image starts executing at address 0x7c00,
+# and so occupies [0x7c00, 0x7e00).
+# We don't read or write the stack before we get to 32-bit mode.
+
+# 00:
+  fa
+  0f 01 16  # lgdt 00/mod/indirect 010/subop 110/rm32/TODO
+    2c 7c  # *gdt_descriptor
+  0f 20 c0  # eax <- cr0
+  66 83 c8 01  # eax <- or 0x1
+  0f 22 c0  # cr0 <- eax
+  ea 32 7c 08 00  # far jump to CODE_SEG:initialize_32bit_mode (TODO: why the 08? something to do with segment selector; only first 16 bits are used in the jump address)
+
+## GDT: 3 records of 8 bytes each
+
+# 14:
+# gdt_start:
+# gdt_null:  mandatory null descriptor
+  00 00 00 00 00 00 00 00
+# gdt_code:  (offset 8 from gdt_start)
+  ff ff  # limit[0:16]
+  00 00 00  # base[0:24]
+  9a  # 1/present 00/privilege 1/descriptor type = 1001b
+      # 1/code 0/conforming 1/readable 0/accessed = 1010b
+  cf  # 1/granularity 1/32-bit 0/64-bit-segment 0/AVL = 1100b
+      # limit[16:20] = 1111b
+  00  # base[24:32]
+# gdt_data:  (offset 16 from gdt_start)
+  ff ff  # limit[0:16]
+  00 00 00  # base[0:24]
+  92  # 1/present 00/privilege 1/descriptor type = 1001b
+      # 0/data 0/conforming 1/readable 0/accessed = 0010b
+  cf  # same as gdt_code
+  00  # base[24:32]
+# gdt_end:
+
+# 2c:
+# gdt_descriptor:
+  17 00  # final index of gdt = gdt_end - gdt_start - 1
+  14 7c 00 00  # start = gdt_start
+
+## 32-bit code from this point (still some instructions not in SubX)
+
+# 32:
+# initialize_32bit_mode:
+  66 b8 10 00  # ax <- offset 16 from gdt_start
+  8e d8  # ds <- ax
+  8e d0  # ss <- ax
+  8e c0  # es <- ax
+  8e e0  # fs <- ax
+  8e e8  # gs <- ax
+# 40:
+  e9 0a 00 00 00  # jump to 0x7c50, leaving some extra padding
+
+# padding
+# 45:
+                  00 00 00 00 00 00 00 00 00 00
+
+## 'application' SubX code: print one character to top-left of screen
+
+# 50:
+# *0xb8000 <- 0x0f48
+c7  # opcode
+  # modrm
+  05  # 00/mod/indirect 000/subop/copy 101/rm32/use-disp32
+  # disp32
+  00 80 0b 00
+  # imm32
+  48  # 'H'
+  0f  # white on black
+  00 00
+
+e9 fd ff  # loop forever
+
+# more padding to 512 bytes
+                                       00 00 00
+00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00 00 00 00 00 00 00
+
+55 aa  # final 2 bytes: boot sector marker
+
+# vim:ft=subx
diff --git a/apps/bos/4.xxd b/apps/bos/4.xxd
new file mode 100644
index 00000000..be677134
--- /dev/null
+++ b/apps/bos/4.xxd
@@ -0,0 +1,87 @@
+## 16-bit code
+
+# Entry:
+00:
+  bd 00 90  # bp <- 0x9000
+  89 ec  # sp <- bp
+
+  bb 8f 7c  # bx <- MSG_REAL_MODE
+  e8 38 00  # call print_string
+
+  e8 02 00  # call switch_to_pm
+  eb fe  # jump $  (should never get here)
+
+# switch_to_pm:
+10:
+  fa  # cli
+  0f 01 16 3d 7c  # lgdt [gdt_descriptor]
+  0f 20 c0  # eax <- cr0
+  66 83 c8 01  # eax <- or 0x1
+  0f 22 c0  # cr0 <- eax
+20:
+  ea 53 7c 08 00  # jmp CODE_SEG:init_pm
+
+# gdt_start:
+# gdt_null:  mandatory null descriptor
+  00 00 00 00 00 00 00 00
+# gdt_code:
+  ff ff 00
+30:
+  00 00 9a cf 00
+# gdt_data:
+  ff ff 00 00 00 92 cf 00
+# gdt_end:
+
+# gdt_descriptor:
+3d:
+  17 00  # limit
+  25 7c 00 00  # start
+
+# print_string:
+43:
+  60  # pusha
+  b4 0e  # ah <- 0x0e
+# loop:
+  8a 07  # al <- *bx
+  cd 10  # int 10h
+  83 c3 01  # add bx, 1
+  3c 00  # cmp al, 0
+  75 f5  # jne loop
+  61  # popa
+  c3  # ret
+
+## 32-bit code
+
+# init_pm:
+53:
+  66 b8 10 00  # ax <- DATA_SEG
+  8e d8  # ds <- ax
+  8e d0  # ss <- ax
+  8e c0  # es <- ax
+  8e e0  # fs <- ax
+  8e e8  # gs <- ax
+61:
+  bd 00 00 09 00  # ebp <- 0x90000
+  89 ec  # esp <- ebp
+  bb ab 7c 00 00  # ebx <- MSG_PROT_MODE
+  e8 02 00 00 00  # call print_string_pm
+  eb fe  # hang
+
+# print_string_pm:
+74:
+  60  # pusha
+  ba 00 80 0b 00 8a 03 b4 0f 3c 00
+80:
+  74 0b 66 89 02 83 c3 01 83 c2 02 eb ed 61 c3 53
+90:
+  74 61 72 74 65 64 20 69 6e 20 31 36 2d 62 69 74
+a0:
+  20 52 65 61 6c 20 4d 6f 64 65 00 53 75 63 63 65
+b0:
+  73 73 66 75 6c 6c 79 20 6c 61 6e 64 65 64 20 69
+c0:
+  6e 20 33 32 2d 62 69 74 20 50 72 6f 74 65 63 74
+d0:
+  65 64 20 4d 6f 64 65
+
+# vim:ft=conf