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.
This commit is contained in:
Kartik Agaram 2020-12-20 00:16:15 -08:00
parent 70bb19100e
commit 9b5b8471ca
2 changed files with 208 additions and 0 deletions

121
apps/bos/32bit.hex Normal file
View File

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

87
apps/bos/4.xxd Normal file
View File

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