From 9b5b8471caf0a41b6d4c3445590a19643e97d546 Mon Sep 17 00:00:00 2001 From: Kartik Agaram Date: Sun, 20 Dec 2020 00:16:15 -0800 Subject: 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. --- apps/bos/32bit.hex | 121 +++++++++++++++++++++++++++++++++++++++++++++++++++++ apps/bos/4.xxd | 87 ++++++++++++++++++++++++++++++++++++++ 2 files changed, 208 insertions(+) create mode 100644 apps/bos/32bit.hex create mode 100644 apps/bos/4.xxd 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 -- cgit 1.4.1-2-gfad0