Added stage 1 bootloader
This commit is contained in:
parent
ede430390f
commit
6642ea76bb
14
.gdbinit
Normal file
14
.gdbinit
Normal file
@ -0,0 +1,14 @@
|
|||||||
|
define hook-stop
|
||||||
|
# Translate the segment:offset into a physical address
|
||||||
|
printf "[%4x:%4x] ", $cs, $eip
|
||||||
|
x/i $cs*16+$eip
|
||||||
|
end
|
||||||
|
|
||||||
|
set disassembly-flavor intel
|
||||||
|
set architecture i8086
|
||||||
|
|
||||||
|
layout asm
|
||||||
|
layout reg
|
||||||
|
|
||||||
|
target remote localhost:26000
|
||||||
|
break *0x7c00
|
1
bootloader/.gitignore
vendored
Normal file
1
bootloader/.gitignore
vendored
Normal file
@ -0,0 +1 @@
|
|||||||
|
build
|
83
bootloader/Makefile
Normal file
83
bootloader/Makefile
Normal file
@ -0,0 +1,83 @@
|
|||||||
|
# This compiles our bootloader as a static library,
|
||||||
|
# and wraps it in a multistage loader.
|
||||||
|
|
||||||
|
|
||||||
|
BUILD = ./build
|
||||||
|
|
||||||
|
|
||||||
|
.PHONY: all
|
||||||
|
all: $(BUILD)/mbr.bin $(BUILD)/512.bin $(BUILD)/stage2.bin
|
||||||
|
|
||||||
|
.PHONY: clean
|
||||||
|
clean:
|
||||||
|
rm -drf $(BUILD)
|
||||||
|
cd bootloader; cargo clean
|
||||||
|
|
||||||
|
# Compile bootloader as library
|
||||||
|
LIB_SRC = ./bootloader/Cargo.toml ./bootloader/Cargo.lock $(shell find ./bootloader/src -type f)
|
||||||
|
$(BUILD)/bootloader.lib: $(LIB_SRC)
|
||||||
|
@mkdir -p $(BUILD)
|
||||||
|
cd bootloader && \
|
||||||
|
env RUSTFLAGS="-C soft-float" \
|
||||||
|
cargo rustc \
|
||||||
|
--manifest-path="./Cargo.toml" \
|
||||||
|
-Z build-std=core,alloc \
|
||||||
|
-Z build-std-features=compiler-builtins-mem \
|
||||||
|
--target "./targets/x86-unknown-none.json" \
|
||||||
|
--lib \
|
||||||
|
--release \
|
||||||
|
-- \
|
||||||
|
--emit link="$(CURDIR)/$@"
|
||||||
|
|
||||||
|
# Link bootloader
|
||||||
|
BIOS_LD = ./bootloader/linkers/x86-unknown-none.ld
|
||||||
|
$(BUILD)/bootloader.elf: $(BUILD)/bootloader.lib $(BIOS_LD)
|
||||||
|
ld \
|
||||||
|
-m elf_i386 \
|
||||||
|
--gc-sections \
|
||||||
|
-z max-page-size=0x1000 \
|
||||||
|
-T "$(BIOS_LD)" \
|
||||||
|
-o "$@" \
|
||||||
|
"$<"
|
||||||
|
|
||||||
|
objcopy --only-keep-debug "$@" "$@.sym"
|
||||||
|
objcopy --strip-debug "$@"
|
||||||
|
|
||||||
|
# Wrap bootloader in three-stage BIOS loader
|
||||||
|
# Parameters:
|
||||||
|
# - BIOS_SRC: source directory of bios assembly
|
||||||
|
# - STAGE3: path to linked stage 3 binary
|
||||||
|
# - STAGE2_SECTOR: the index of the first sector of the stage 2 binary on the disk
|
||||||
|
BIOS_SRC = ./bios
|
||||||
|
STAGE2_SECTOR = 5
|
||||||
|
STAGE3 = $(BUILD)/bootloader.elf
|
||||||
|
$(BUILD)/bios.bin: $(wildcard $(BIOS_SRC)/*.asm) $(STAGE3)
|
||||||
|
@mkdir -p "$(BUILD)"
|
||||||
|
nasm \
|
||||||
|
-f bin \
|
||||||
|
-D STAGE3=$(STAGE3) \
|
||||||
|
-D STAGE2_SECTOR=$(STAGE2_SECTOR) \
|
||||||
|
-o "$@" \
|
||||||
|
-l "$@.lst" \
|
||||||
|
-i "$(BIOS_SRC)" \
|
||||||
|
"$(BIOS_SRC)/main.asm"
|
||||||
|
|
||||||
|
# Extract MBR code (first 440 bytes)
|
||||||
|
# This can be used to embed this mbr in gpt-partitioned disks
|
||||||
|
$(BUILD)/mbr.bin: $(BUILD)/bios.bin
|
||||||
|
@mkdir -p "$(BUILD)"
|
||||||
|
@echo ""
|
||||||
|
dd if="$<" bs=440 count=1 of="$@"
|
||||||
|
|
||||||
|
# Extract full mbr (first 512 bytes)
|
||||||
|
# This can be used to make raw boot disks
|
||||||
|
$(BUILD)/512.bin: $(BUILD)/bios.bin
|
||||||
|
@mkdir -p "$(BUILD)"
|
||||||
|
@echo ""
|
||||||
|
dd if="$<" bs=512 count=1 of="$@"
|
||||||
|
|
||||||
|
# Extract stage 2 (rest of file)
|
||||||
|
$(BUILD)/stage2.bin: $(BUILD)/bios.bin
|
||||||
|
@mkdir -p "$(BUILD)"
|
||||||
|
@echo ""
|
||||||
|
dd if="$<" bs=512 skip=1 of="$@"
|
176
bootloader/bios/cpuid.asm
Normal file
176
bootloader/bios/cpuid.asm
Normal file
@ -0,0 +1,176 @@
|
|||||||
|
SECTION .text
|
||||||
|
USE16
|
||||||
|
|
||||||
|
cpuid_required_features:
|
||||||
|
.edx equ cpuid_edx.fpu | cpuid_edx.pse | cpuid_edx.pge | cpuid_edx.fxsr
|
||||||
|
.ecx equ 0
|
||||||
|
|
||||||
|
cpuid_check:
|
||||||
|
; If bit 21 of EFLAGS can be changed, then CPUID is supported
|
||||||
|
pushfd ;Save EFLAGS
|
||||||
|
pushfd ;Store EFLAGS
|
||||||
|
xor dword [esp],0x00200000 ;Invert the ID bit in stored EFLAGS
|
||||||
|
popfd ;Load stored EFLAGS (with ID bit inverted)
|
||||||
|
pushfd ;Store EFLAGS again (ID bit may or may not be inverted)
|
||||||
|
pop eax ;eax = modified EFLAGS (ID bit may or may not be inverted)
|
||||||
|
xor eax,[esp] ;eax = whichever bits were changed
|
||||||
|
popfd ;Restore original EFLAGS
|
||||||
|
test eax,0x00200000 ;eax = zero if ID bit can't be changed, else non-zero
|
||||||
|
jz .no_cpuid
|
||||||
|
|
||||||
|
mov eax, 1
|
||||||
|
cpuid
|
||||||
|
|
||||||
|
and edx, cpuid_required_features.edx
|
||||||
|
cmp edx, cpuid_required_features.edx
|
||||||
|
jne .error
|
||||||
|
|
||||||
|
and ecx, cpuid_required_features.ecx
|
||||||
|
cmp ecx, cpuid_required_features.ecx
|
||||||
|
jne .error
|
||||||
|
|
||||||
|
ret
|
||||||
|
|
||||||
|
.no_cpuid:
|
||||||
|
mov si, .msg_cpuid
|
||||||
|
call print
|
||||||
|
|
||||||
|
mov si, .msg_line
|
||||||
|
call print
|
||||||
|
|
||||||
|
jmp .halt
|
||||||
|
|
||||||
|
.error:
|
||||||
|
push ecx
|
||||||
|
push edx
|
||||||
|
|
||||||
|
mov si, .msg_features
|
||||||
|
call print
|
||||||
|
|
||||||
|
mov si, .msg_line
|
||||||
|
call print
|
||||||
|
|
||||||
|
mov si, .msg_edx
|
||||||
|
call print
|
||||||
|
|
||||||
|
pop ebx
|
||||||
|
push ebx
|
||||||
|
shr ebx, 16
|
||||||
|
call print_hex
|
||||||
|
|
||||||
|
pop ebx
|
||||||
|
call print_hex
|
||||||
|
|
||||||
|
mov si, .msg_must_contain
|
||||||
|
call print
|
||||||
|
|
||||||
|
mov ebx, cpuid_required_features.edx
|
||||||
|
shr ebx, 16
|
||||||
|
call print_hex
|
||||||
|
|
||||||
|
mov ebx, cpuid_required_features.edx
|
||||||
|
call print_hex
|
||||||
|
|
||||||
|
mov si, .msg_line
|
||||||
|
call print
|
||||||
|
|
||||||
|
mov si, .msg_ecx
|
||||||
|
call print
|
||||||
|
|
||||||
|
pop ebx
|
||||||
|
push ebx
|
||||||
|
shr ebx, 16
|
||||||
|
call print_hex
|
||||||
|
|
||||||
|
pop ebx
|
||||||
|
call print_hex
|
||||||
|
|
||||||
|
mov si, .msg_must_contain
|
||||||
|
call print
|
||||||
|
|
||||||
|
mov ebx, cpuid_required_features.ecx
|
||||||
|
shr ebx, 16
|
||||||
|
call print_hex
|
||||||
|
|
||||||
|
mov ebx, cpuid_required_features.ecx
|
||||||
|
call print_hex
|
||||||
|
|
||||||
|
mov si, .msg_line
|
||||||
|
call print
|
||||||
|
|
||||||
|
.halt:
|
||||||
|
cli
|
||||||
|
hlt
|
||||||
|
jmp .halt
|
||||||
|
|
||||||
|
.msg_cpuid: db "CPUID not supported",0
|
||||||
|
.msg_features: db "Required CPU features are not present",0
|
||||||
|
.msg_line: db 13,10,0
|
||||||
|
.msg_edx: db "EDX ",0
|
||||||
|
.msg_ecx: db "ECX ",0
|
||||||
|
.msg_must_contain: db " must contain ",0
|
||||||
|
|
||||||
|
cpuid_edx:
|
||||||
|
.fpu equ 1 << 0
|
||||||
|
.vme equ 1 << 1
|
||||||
|
.de equ 1 << 2
|
||||||
|
.pse equ 1 << 3
|
||||||
|
.tsc equ 1 << 4
|
||||||
|
.msr equ 1 << 5
|
||||||
|
.pae equ 1 << 6
|
||||||
|
.mce equ 1 << 7
|
||||||
|
.cx8 equ 1 << 8
|
||||||
|
.apic equ 1 << 9
|
||||||
|
.sep equ 1 << 11
|
||||||
|
.mtrr equ 1 << 12
|
||||||
|
.pge equ 1 << 13
|
||||||
|
.mca equ 1 << 14
|
||||||
|
.cmov equ 1 << 15
|
||||||
|
.pat equ 1 << 16
|
||||||
|
.pse_36 equ 1 << 17
|
||||||
|
.psn equ 1 << 18
|
||||||
|
.clfsh equ 1 << 19
|
||||||
|
.ds equ 1 << 21
|
||||||
|
.acpi equ 1 << 22
|
||||||
|
.mmx equ 1 << 23
|
||||||
|
.fxsr equ 1 << 24
|
||||||
|
.sse equ 1 << 25
|
||||||
|
.sse2 equ 1 << 26
|
||||||
|
.ss equ 1 << 27
|
||||||
|
.htt equ 1 << 28
|
||||||
|
.tm equ 1 << 29
|
||||||
|
.ia64 equ 1 << 30
|
||||||
|
.pbe equ 1 << 31
|
||||||
|
|
||||||
|
cpuid_ecx:
|
||||||
|
.sse3 equ 1 << 0
|
||||||
|
.pclmulqdq equ 1 << 1
|
||||||
|
.dtes64 equ 1 << 2
|
||||||
|
.monitor equ 1 << 3
|
||||||
|
.ds_cpl equ 1 << 4
|
||||||
|
.vmx equ 1 << 5
|
||||||
|
.smx equ 1 << 6
|
||||||
|
.est equ 1 << 7
|
||||||
|
.tm2 equ 1 << 8
|
||||||
|
.ssse3 equ 1 << 9
|
||||||
|
.cnxt_id equ 1 << 10
|
||||||
|
.sdbg equ 1 << 11
|
||||||
|
.fma equ 1 << 12
|
||||||
|
.cmpxchg16b equ 1 << 13
|
||||||
|
.xtpr equ 1 << 14
|
||||||
|
.pdcm equ 1 << 15
|
||||||
|
.pcid equ 1 << 17
|
||||||
|
.dca equ 1 << 18
|
||||||
|
.sse4_1 equ 1 << 19
|
||||||
|
.sse4_2 equ 1 << 20
|
||||||
|
.x2apic equ 1 << 21
|
||||||
|
.movbe equ 1 << 22
|
||||||
|
.popcnt equ 1 << 23
|
||||||
|
.tsc_deadline equ 1 << 24
|
||||||
|
.aes equ 1 << 25
|
||||||
|
.xsave equ 1 << 26
|
||||||
|
.osxsave equ 1 << 27
|
||||||
|
.avx equ 1 << 28
|
||||||
|
.f16c equ 1 << 29
|
||||||
|
.rdrand equ 1 << 30
|
||||||
|
.hypervisor equ 1 << 31
|
4
bootloader/bios/defs.asm
Normal file
4
bootloader/bios/defs.asm
Normal file
@ -0,0 +1,4 @@
|
|||||||
|
; sector = 512 bytes
|
||||||
|
|
||||||
|
; first sector of stage 2, on disk.
|
||||||
|
%assign PARAM_STAGE2_SECTOR 34
|
134
bootloader/bios/gdt.asm
Normal file
134
bootloader/bios/gdt.asm
Normal file
@ -0,0 +1,134 @@
|
|||||||
|
SECTION .text ; cannot use .data
|
||||||
|
|
||||||
|
struc GDTEntry
|
||||||
|
.limitl resw 1
|
||||||
|
.basel resw 1
|
||||||
|
.basem resb 1
|
||||||
|
.attribute resb 1
|
||||||
|
.flags__limith resb 1
|
||||||
|
.baseh resb 1
|
||||||
|
endstruc
|
||||||
|
|
||||||
|
gdt_attr:
|
||||||
|
.present equ 1 << 7
|
||||||
|
.ring1 equ 1 << 5
|
||||||
|
.ring2 equ 1 << 6
|
||||||
|
.ring3 equ 1 << 5 | 1 << 6
|
||||||
|
.user equ 1 << 4
|
||||||
|
;user
|
||||||
|
.code equ 1 << 3
|
||||||
|
; code
|
||||||
|
.conforming equ 1 << 2
|
||||||
|
.readable equ 1 << 1
|
||||||
|
; data
|
||||||
|
.expand_down equ 1 << 2
|
||||||
|
.writable equ 1 << 1
|
||||||
|
.accessed equ 1 << 0
|
||||||
|
;system
|
||||||
|
; legacy
|
||||||
|
.tssAvailabe16 equ 0x1
|
||||||
|
.ldt equ 0x2
|
||||||
|
.tssBusy16 equ 0x3
|
||||||
|
.call16 equ 0x4
|
||||||
|
.task equ 0x5
|
||||||
|
.interrupt16 equ 0x6
|
||||||
|
.trap16 equ 0x7
|
||||||
|
.tssAvailabe32 equ 0x9
|
||||||
|
.tssBusy32 equ 0xB
|
||||||
|
.call32 equ 0xC
|
||||||
|
.interrupt32 equ 0xE
|
||||||
|
.trap32 equ 0xF
|
||||||
|
; long mode
|
||||||
|
.ldt32 equ 0x2
|
||||||
|
.tssAvailabe64 equ 0x9
|
||||||
|
.tssBusy64 equ 0xB
|
||||||
|
.call64 equ 0xC
|
||||||
|
.interrupt64 equ 0xE
|
||||||
|
.trap64 equ 0xF
|
||||||
|
|
||||||
|
gdt_flag:
|
||||||
|
.granularity equ 1 << 7
|
||||||
|
.available equ 1 << 4
|
||||||
|
;user
|
||||||
|
.default_operand_size equ 1 << 6
|
||||||
|
; code
|
||||||
|
.long_mode equ 1 << 5
|
||||||
|
; data
|
||||||
|
.reserved equ 1 << 5
|
||||||
|
|
||||||
|
gdtr:
|
||||||
|
dw gdt.end + 1 ; size
|
||||||
|
dq gdt ; offset
|
||||||
|
|
||||||
|
gdt:
|
||||||
|
.null equ $ - gdt
|
||||||
|
dq 0
|
||||||
|
|
||||||
|
.lm64_code equ $ - gdt
|
||||||
|
istruc GDTEntry
|
||||||
|
at GDTEntry.limitl, dw 0
|
||||||
|
at GDTEntry.basel, dw 0
|
||||||
|
at GDTEntry.basem, db 0
|
||||||
|
at GDTEntry.attribute, db gdt_attr.present | gdt_attr.user | gdt_attr.code
|
||||||
|
at GDTEntry.flags__limith, db gdt_flag.long_mode
|
||||||
|
at GDTEntry.baseh, db 0
|
||||||
|
iend
|
||||||
|
|
||||||
|
.lm64_data equ $ - gdt
|
||||||
|
istruc GDTEntry
|
||||||
|
at GDTEntry.limitl, dw 0
|
||||||
|
at GDTEntry.basel, dw 0
|
||||||
|
at GDTEntry.basem, db 0
|
||||||
|
; AMD System Programming Manual states that the writeable bit is ignored in long mode, but ss can not be set to this descriptor without it
|
||||||
|
at GDTEntry.attribute, db gdt_attr.present | gdt_attr.user | gdt_attr.writable
|
||||||
|
at GDTEntry.flags__limith, db 0
|
||||||
|
at GDTEntry.baseh, db 0
|
||||||
|
iend
|
||||||
|
|
||||||
|
; All GTD addresses are multiples of 8,
|
||||||
|
; and thus end in three zero bits.
|
||||||
|
;
|
||||||
|
; Also note that all segments overlap.
|
||||||
|
; We only need the GDT for a short time,
|
||||||
|
; so we use the simplest possible layout.
|
||||||
|
.pm32_code equ $ - gdt
|
||||||
|
istruc GDTEntry
|
||||||
|
at GDTEntry.limitl, dw 0xFFFF
|
||||||
|
at GDTEntry.basel, dw 0
|
||||||
|
at GDTEntry.basem, db 0
|
||||||
|
at GDTEntry.attribute, db gdt_attr.present | gdt_attr.user | gdt_attr.code | gdt_attr.readable
|
||||||
|
at GDTEntry.flags__limith, db 0xF | gdt_flag.granularity | gdt_flag.default_operand_size
|
||||||
|
at GDTEntry.baseh, db 0
|
||||||
|
iend
|
||||||
|
|
||||||
|
.pm32_data equ $ - gdt
|
||||||
|
istruc GDTEntry
|
||||||
|
at GDTEntry.limitl, dw 0xFFFF
|
||||||
|
at GDTEntry.basel, dw 0
|
||||||
|
at GDTEntry.basem, db 0
|
||||||
|
at GDTEntry.attribute, db gdt_attr.present | gdt_attr.user | gdt_attr.writable
|
||||||
|
at GDTEntry.flags__limith, db 0xF | gdt_flag.granularity | gdt_flag.default_operand_size
|
||||||
|
at GDTEntry.baseh, db 0
|
||||||
|
iend
|
||||||
|
|
||||||
|
.pm16_code equ $ - gdt
|
||||||
|
istruc GDTEntry
|
||||||
|
at GDTEntry.limitl, dw 0xFFFF
|
||||||
|
at GDTEntry.basel, dw 0
|
||||||
|
at GDTEntry.basem, db 0
|
||||||
|
at GDTEntry.attribute, db gdt_attr.present | gdt_attr.user | gdt_attr.code | gdt_attr.readable
|
||||||
|
at GDTEntry.flags__limith, db 0xF
|
||||||
|
at GDTEntry.baseh, db 0
|
||||||
|
iend
|
||||||
|
|
||||||
|
.pm16_data equ $ - gdt
|
||||||
|
istruc GDTEntry
|
||||||
|
at GDTEntry.limitl, dw 0xFFFF
|
||||||
|
at GDTEntry.basel, dw 0
|
||||||
|
at GDTEntry.basem, db 0
|
||||||
|
at GDTEntry.attribute, db gdt_attr.present | gdt_attr.user | gdt_attr.writable
|
||||||
|
at GDTEntry.flags__limith, db 0xF
|
||||||
|
at GDTEntry.baseh, db 0
|
||||||
|
iend
|
||||||
|
|
||||||
|
.end equ $ - gdt
|
56
bootloader/bios/long_mode.asm
Normal file
56
bootloader/bios/long_mode.asm
Normal file
@ -0,0 +1,56 @@
|
|||||||
|
SECTION .text
|
||||||
|
USE32
|
||||||
|
|
||||||
|
long_mode:
|
||||||
|
.func: dq 0
|
||||||
|
.page_table: dd 0
|
||||||
|
|
||||||
|
.entry:
|
||||||
|
; disable interrupts
|
||||||
|
cli
|
||||||
|
|
||||||
|
; disable paging
|
||||||
|
mov eax, cr0
|
||||||
|
and eax, 0x7FFFFFFF
|
||||||
|
mov cr0, eax
|
||||||
|
|
||||||
|
; enable FXSAVE/FXRSTOR, Page Global, Page Address Extension, and Page Size Extension
|
||||||
|
mov eax, cr4
|
||||||
|
or eax, 1 << 9 | 1 << 7 | 1 << 5 | 1 << 4
|
||||||
|
mov cr4, eax
|
||||||
|
|
||||||
|
; load long mode GDT
|
||||||
|
lgdt [gdtr]
|
||||||
|
|
||||||
|
; enable long mode
|
||||||
|
mov ecx, 0xC0000080 ; Read from the EFER MSR.
|
||||||
|
rdmsr
|
||||||
|
or eax, 1 << 11 | 1 << 8 ; Set the Long-Mode-Enable and NXE bit.
|
||||||
|
wrmsr
|
||||||
|
|
||||||
|
; set page table
|
||||||
|
mov eax, [.page_table]
|
||||||
|
mov cr3, eax
|
||||||
|
|
||||||
|
; enabling paging and protection simultaneously
|
||||||
|
mov eax, cr0
|
||||||
|
or eax, 1 << 31 | 1 << 16 | 1 ;Bit 31: Paging, Bit 16: write protect kernel, Bit 0: Protected Mode
|
||||||
|
mov cr0, eax
|
||||||
|
|
||||||
|
; far jump to enable Long Mode and load CS with 64 bit segment
|
||||||
|
jmp gdt.lm64_code:.inner
|
||||||
|
|
||||||
|
USE64
|
||||||
|
|
||||||
|
.inner:
|
||||||
|
; load all the other segments with 64 bit data segments
|
||||||
|
mov rax, gdt.lm64_data
|
||||||
|
mov ds, rax
|
||||||
|
mov es, rax
|
||||||
|
mov fs, rax
|
||||||
|
mov gs, rax
|
||||||
|
mov ss, rax
|
||||||
|
|
||||||
|
; jump to specified function
|
||||||
|
mov rax, [.func]
|
||||||
|
jmp rax
|
66
bootloader/bios/main.asm
Normal file
66
bootloader/bios/main.asm
Normal file
@ -0,0 +1,66 @@
|
|||||||
|
sectalign off
|
||||||
|
|
||||||
|
; This program expects two external macros:
|
||||||
|
; STAGE3, a path to the stage3 binary
|
||||||
|
; STAGE2_SECTOR, the location of stage 2
|
||||||
|
; on the disk, in 512-byte sectors.
|
||||||
|
; On a gpt disk, this is probably 34.
|
||||||
|
|
||||||
|
; Stage 1 is MBR code, and should fit in LBA 0
|
||||||
|
; (512 bytes). Layout is as follows:
|
||||||
|
; (Format is `offset, length: purpose`)
|
||||||
|
; 0, 424: x86 boot code
|
||||||
|
; 440, 4: Unique disk signature
|
||||||
|
; 444, 2: unknown
|
||||||
|
; 446, 16*4: Array of four legacy MBR records
|
||||||
|
; 510, 2: signature 0x55 0xAA
|
||||||
|
; 512 to end of logical block: reserved
|
||||||
|
;
|
||||||
|
; See https://uefi.org/specs/UEFI/2.10/05_GUID_Partition_Table_Format.html
|
||||||
|
|
||||||
|
ORG 0x7C00
|
||||||
|
SECTION .text
|
||||||
|
|
||||||
|
; stage 1 is sector 0, loaded into memory at 0x7C00
|
||||||
|
%include "stage1.asm"
|
||||||
|
|
||||||
|
; Stage 1 is at most 440 bytes
|
||||||
|
times 440-($-$$) db 0
|
||||||
|
db 0xee
|
||||||
|
|
||||||
|
; Pad until 512
|
||||||
|
times 510-($-$$) db 0
|
||||||
|
|
||||||
|
; MBR signature.
|
||||||
|
; This isn't loaded into memory, it's
|
||||||
|
; only here for debugging.
|
||||||
|
db 0x55
|
||||||
|
db 0xaa
|
||||||
|
|
||||||
|
stage2:
|
||||||
|
%include "stage2.asm"
|
||||||
|
align 512, db 0
|
||||||
|
stage2.end:
|
||||||
|
|
||||||
|
; TODO: why? Stage 1 read limit?
|
||||||
|
; Can we make this smaller?
|
||||||
|
; The maximum size of stage2 is 4 KiB,
|
||||||
|
; This fill will throw an error if the subtraction
|
||||||
|
; is negative.
|
||||||
|
times (4*1024)-($-stage2) db 0
|
||||||
|
|
||||||
|
; LEGACY
|
||||||
|
; Pad to 0x13000
|
||||||
|
; This needs to match the value configured
|
||||||
|
; in the stage3 linker script
|
||||||
|
times (0x13000 - 0x7c00)-($-$$) db 0
|
||||||
|
|
||||||
|
stage3:
|
||||||
|
%defstr STAGE3_STR %[STAGE3]
|
||||||
|
incbin STAGE3_STR
|
||||||
|
align 512, db 0
|
||||||
|
.end:
|
||||||
|
|
||||||
|
; TODO: why? Of the disk, or of memory?
|
||||||
|
; the maximum size of the boot loader portion is 384 KiB
|
||||||
|
times (384*1024)-($-$$) db 0
|
67
bootloader/bios/print.asm
Normal file
67
bootloader/bios/print.asm
Normal file
@ -0,0 +1,67 @@
|
|||||||
|
SECTION .text
|
||||||
|
USE16
|
||||||
|
|
||||||
|
; provide function for printing in x86 real mode
|
||||||
|
|
||||||
|
; print a string and a newline
|
||||||
|
; CLOBBER
|
||||||
|
; ax
|
||||||
|
print_line:
|
||||||
|
mov al, 13
|
||||||
|
call print_char
|
||||||
|
mov al, 10
|
||||||
|
jmp print_char
|
||||||
|
|
||||||
|
; print a string
|
||||||
|
; IN
|
||||||
|
; si: points at zero-terminated String
|
||||||
|
; CLOBBER
|
||||||
|
; si, ax
|
||||||
|
print:
|
||||||
|
pushf
|
||||||
|
cld
|
||||||
|
.loop:
|
||||||
|
lodsb
|
||||||
|
test al, al
|
||||||
|
jz .done
|
||||||
|
call print_char
|
||||||
|
jmp .loop
|
||||||
|
.done:
|
||||||
|
popf
|
||||||
|
ret
|
||||||
|
|
||||||
|
; print a character
|
||||||
|
; IN
|
||||||
|
; al: character to print
|
||||||
|
print_char:
|
||||||
|
pusha
|
||||||
|
mov bx, 7
|
||||||
|
mov ah, 0x0e
|
||||||
|
int 0x10
|
||||||
|
popa
|
||||||
|
ret
|
||||||
|
|
||||||
|
; print a number in hex
|
||||||
|
; IN
|
||||||
|
; bx: the number
|
||||||
|
; CLOBBER
|
||||||
|
; al, cx
|
||||||
|
print_hex:
|
||||||
|
mov cx, 4
|
||||||
|
.lp:
|
||||||
|
mov al, bh
|
||||||
|
shr al, 4
|
||||||
|
|
||||||
|
cmp al, 0xA
|
||||||
|
jb .below_0xA
|
||||||
|
|
||||||
|
add al, 'A' - 0xA - '0'
|
||||||
|
.below_0xA:
|
||||||
|
add al, '0'
|
||||||
|
|
||||||
|
call print_char
|
||||||
|
|
||||||
|
shl bx, 4
|
||||||
|
loop .lp
|
||||||
|
|
||||||
|
ret
|
46
bootloader/bios/protected_mode.asm
Normal file
46
bootloader/bios/protected_mode.asm
Normal file
@ -0,0 +1,46 @@
|
|||||||
|
SECTION .text
|
||||||
|
USE16
|
||||||
|
|
||||||
|
protected_mode:
|
||||||
|
|
||||||
|
.func: dd 0
|
||||||
|
|
||||||
|
.entry:
|
||||||
|
; disable interrupts
|
||||||
|
cli
|
||||||
|
|
||||||
|
; load protected mode GDT
|
||||||
|
lgdt [gdtr]
|
||||||
|
|
||||||
|
; set protected mode bit of cr0
|
||||||
|
mov eax, cr0
|
||||||
|
or eax, 1
|
||||||
|
mov cr0, eax
|
||||||
|
|
||||||
|
; far jump to load CS with 32 bit segment
|
||||||
|
; (we are in 32-bit mode, but instruction pipeline
|
||||||
|
; has 16-bit instructions.
|
||||||
|
jmp gdt.pm32_code:.inner
|
||||||
|
|
||||||
|
; gdt.pm32_code is a multiple of 8, so it always ends with three zero bits.
|
||||||
|
; The GDT spec abuses this fact, and uses these last three bits to store other
|
||||||
|
; data (table type and privilege). In this case, 000 is what we need anyway.
|
||||||
|
;
|
||||||
|
; Also note that CS isn't an address in protected mode---it's a GDT descriptor.
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
USE32
|
||||||
|
|
||||||
|
.inner:
|
||||||
|
; load all the other segments with 32 bit data segments
|
||||||
|
mov eax, gdt.pm32_data
|
||||||
|
mov ds, eax
|
||||||
|
mov es, eax
|
||||||
|
mov fs, eax
|
||||||
|
mov gs, eax
|
||||||
|
mov ss, eax
|
||||||
|
|
||||||
|
; jump to specified function
|
||||||
|
mov eax, [.func]
|
||||||
|
jmp eax
|
230
bootloader/bios/stage1.asm
Normal file
230
bootloader/bios/stage1.asm
Normal file
@ -0,0 +1,230 @@
|
|||||||
|
USE16
|
||||||
|
|
||||||
|
stage1: ; dl comes with disk
|
||||||
|
; initialize segment registers
|
||||||
|
xor ax, ax
|
||||||
|
mov ds, ax
|
||||||
|
mov es, ax
|
||||||
|
mov ss, ax
|
||||||
|
|
||||||
|
; initialize stack
|
||||||
|
mov sp, 0x7C00
|
||||||
|
|
||||||
|
; initialize CS
|
||||||
|
; far jump sets both CS and IP to a known-good state,
|
||||||
|
; we don't know where the BIOS put us at startup.
|
||||||
|
; (could be 0x00:0x7C00, could be 0x7C00:0x00.
|
||||||
|
; Not everybody follows spec.)
|
||||||
|
push ax
|
||||||
|
push word .set_cs
|
||||||
|
retf
|
||||||
|
|
||||||
|
.set_cs:
|
||||||
|
; save disk number
|
||||||
|
mov [disk], dl
|
||||||
|
|
||||||
|
mov si, stage_msg
|
||||||
|
call print
|
||||||
|
mov al, '1'
|
||||||
|
call print_char
|
||||||
|
call print_line
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
; read CHS gemotry
|
||||||
|
; CL (bits 0-5) = maximum sector number
|
||||||
|
; CL (bits 6-7) = high bits of max cylinder number
|
||||||
|
; CH = low bits of maximum cylinder number
|
||||||
|
; DH = maximum head number
|
||||||
|
mov ah, 0x08
|
||||||
|
mov dl, [disk]
|
||||||
|
xor di, di
|
||||||
|
int 0x13
|
||||||
|
jc error ; carry flag set on error
|
||||||
|
mov bl, ch
|
||||||
|
mov bh, cl
|
||||||
|
shr bh, 6
|
||||||
|
mov [chs.c], bx
|
||||||
|
shr dx, 8
|
||||||
|
inc dx ; returns heads - 1
|
||||||
|
mov [chs.h], dx
|
||||||
|
and cl, 0x3f
|
||||||
|
mov [chs.s], cl
|
||||||
|
|
||||||
|
; disk address of stage 2
|
||||||
|
; (start sector)
|
||||||
|
mov eax, STAGE2_SECTOR
|
||||||
|
|
||||||
|
; where to load stage 2
|
||||||
|
mov bx, stage2
|
||||||
|
|
||||||
|
; length of stage2 + stage3
|
||||||
|
; (on disk, in sectors)
|
||||||
|
mov cx, (stage3.end - stage2) / 512
|
||||||
|
mov dx, 0
|
||||||
|
|
||||||
|
call load
|
||||||
|
|
||||||
|
jmp stage2.entry
|
||||||
|
|
||||||
|
; load some sectors from disk to a buffer in memory
|
||||||
|
; buffer has to be below 1MiB
|
||||||
|
; IN
|
||||||
|
; ax: start sector
|
||||||
|
; bx: offset of buffer
|
||||||
|
; cx: number of sectors (512 Bytes each)
|
||||||
|
; dx: segment of buffer
|
||||||
|
; CLOBBER
|
||||||
|
; ax, bx, cx, dx, si
|
||||||
|
; TODO rewrite to (eventually) move larger parts at once
|
||||||
|
; if that is done increase buffer_size_sectors in startup-common to that (max 0x80000 - startup_end)
|
||||||
|
load:
|
||||||
|
; replaced 127 with 1.
|
||||||
|
; see https://stackoverflow.com/questions/58564895/problem-with-bios-int-13h-read-sectors-from-drive
|
||||||
|
; TODO: fix later
|
||||||
|
|
||||||
|
cmp cx, 1 ;127
|
||||||
|
jbe .good_size
|
||||||
|
|
||||||
|
pusha
|
||||||
|
mov cx, 1; 127
|
||||||
|
call load
|
||||||
|
popa
|
||||||
|
add eax, 1; 127
|
||||||
|
add dx, 1 * 512 / 16 ; 127
|
||||||
|
sub cx, 1;127
|
||||||
|
|
||||||
|
jmp load
|
||||||
|
.good_size:
|
||||||
|
mov [DAPACK.addr], eax
|
||||||
|
mov [DAPACK.buf], bx
|
||||||
|
mov [DAPACK.count], cx
|
||||||
|
mov [DAPACK.seg], dx
|
||||||
|
|
||||||
|
; This should be a subroutine,
|
||||||
|
; but we don't call/ret to save a few bytes.
|
||||||
|
; (we only use this once)
|
||||||
|
;
|
||||||
|
;call print_dapack
|
||||||
|
;print_dapack:
|
||||||
|
mov bx, [DAPACK.addr + 2]
|
||||||
|
call print_hex
|
||||||
|
|
||||||
|
mov bx, [DAPACK.addr]
|
||||||
|
call print_hex
|
||||||
|
|
||||||
|
mov al, '#'
|
||||||
|
call print_char
|
||||||
|
|
||||||
|
mov bx, [DAPACK.count]
|
||||||
|
call print_hex
|
||||||
|
|
||||||
|
mov al, ' '
|
||||||
|
call print_char
|
||||||
|
|
||||||
|
mov bx, [DAPACK.seg]
|
||||||
|
call print_hex
|
||||||
|
|
||||||
|
mov al, ':'
|
||||||
|
call print_char
|
||||||
|
|
||||||
|
mov bx, [DAPACK.buf]
|
||||||
|
call print_hex
|
||||||
|
|
||||||
|
call print_line
|
||||||
|
;ret
|
||||||
|
; End of print_dapack
|
||||||
|
|
||||||
|
|
||||||
|
cmp byte [chs.s], 0
|
||||||
|
jne .chs
|
||||||
|
;INT 0x13 extended read does not work on CDROM!
|
||||||
|
mov dl, [disk]
|
||||||
|
mov si, DAPACK
|
||||||
|
mov ah, 0x42
|
||||||
|
int 0x13
|
||||||
|
jc error ; carry flag set on error
|
||||||
|
ret
|
||||||
|
|
||||||
|
.chs:
|
||||||
|
; calculate CHS
|
||||||
|
xor edx, edx
|
||||||
|
mov eax, [DAPACK.addr]
|
||||||
|
div dword [chs.s] ; divide by sectors
|
||||||
|
mov ecx, edx ; move sector remainder to ecx
|
||||||
|
xor edx, edx
|
||||||
|
div dword [chs.h] ; divide by heads
|
||||||
|
; eax has cylinders, edx has heads, ecx has sectors
|
||||||
|
|
||||||
|
; Sector cannot be greater than 63
|
||||||
|
inc ecx ; Sector is base 1
|
||||||
|
cmp ecx, 63
|
||||||
|
ja error_chs
|
||||||
|
|
||||||
|
; Head cannot be greater than 255
|
||||||
|
cmp edx, 255
|
||||||
|
ja error_chs
|
||||||
|
|
||||||
|
; Cylinder cannot be greater than 1023
|
||||||
|
cmp eax, 1023
|
||||||
|
ja error_chs
|
||||||
|
|
||||||
|
; Move CHS values to parameters
|
||||||
|
mov ch, al
|
||||||
|
shl ah, 6
|
||||||
|
and cl, 0x3f
|
||||||
|
or cl, ah
|
||||||
|
shl dx, 8
|
||||||
|
|
||||||
|
; read from disk using CHS
|
||||||
|
mov al, [DAPACK.count]
|
||||||
|
mov ah, 0x02 ; disk read (CHS)
|
||||||
|
mov bx, [DAPACK.buf]
|
||||||
|
mov dl, [disk]
|
||||||
|
push es ; save ES
|
||||||
|
mov es, [DAPACK.seg]
|
||||||
|
int 0x13
|
||||||
|
pop es ; restore EC
|
||||||
|
jc error ; carry flag set on error
|
||||||
|
ret
|
||||||
|
|
||||||
|
error_chs:
|
||||||
|
mov ah, 0
|
||||||
|
|
||||||
|
error:
|
||||||
|
call print_line
|
||||||
|
|
||||||
|
mov bh, 0
|
||||||
|
mov bl, ah
|
||||||
|
call print_hex
|
||||||
|
|
||||||
|
mov si, stage1_error_msg
|
||||||
|
call print
|
||||||
|
call print_line
|
||||||
|
|
||||||
|
.halt:
|
||||||
|
cli
|
||||||
|
hlt
|
||||||
|
jmp .halt
|
||||||
|
|
||||||
|
%include "print.asm"
|
||||||
|
|
||||||
|
stage_msg: db "Stage ",0
|
||||||
|
stage1_error_msg: db " ERROR",0
|
||||||
|
|
||||||
|
disk: db 0
|
||||||
|
|
||||||
|
chs:
|
||||||
|
.c: dd 0
|
||||||
|
.h: dd 0
|
||||||
|
.s: dd 0
|
||||||
|
|
||||||
|
DAPACK:
|
||||||
|
db 0x10
|
||||||
|
db 0
|
||||||
|
.count: dw 0 ; int 13 resets this to # of blocks actually read/written
|
||||||
|
.buf: dw 0 ; memory buffer destination address (0:7c00)
|
||||||
|
.seg: dw 0 ; in memory page zero
|
||||||
|
.addr: dq 0 ; put the lba to read in this spot
|
||||||
|
|
||||||
|
db 0xff
|
141
bootloader/bios/stage2.asm
Normal file
141
bootloader/bios/stage2.asm
Normal file
@ -0,0 +1,141 @@
|
|||||||
|
SECTION .text
|
||||||
|
USE16
|
||||||
|
|
||||||
|
stage2.entry:
|
||||||
|
mov si, stage_msg
|
||||||
|
call print
|
||||||
|
mov al, '3'
|
||||||
|
call print_char
|
||||||
|
call print_line
|
||||||
|
|
||||||
|
|
||||||
|
; check for required features
|
||||||
|
call cpuid_check
|
||||||
|
|
||||||
|
; enable A20-Line via IO-Port 92, might not work on all motherboards
|
||||||
|
in al, 0x92
|
||||||
|
or al, 2
|
||||||
|
out 0x92, al
|
||||||
|
|
||||||
|
mov dword [protected_mode.func], stage3.entry
|
||||||
|
jmp protected_mode.entry
|
||||||
|
|
||||||
|
%include "cpuid.asm"
|
||||||
|
%include "gdt.asm"
|
||||||
|
%include "long_mode.asm"
|
||||||
|
%include "protected_mode.asm"
|
||||||
|
%include "thunk.asm"
|
||||||
|
|
||||||
|
USE32
|
||||||
|
|
||||||
|
stage3.entry:
|
||||||
|
; stage3 stack at 448 KiB (512KiB minus 64KiB disk buffer)
|
||||||
|
mov esp, 0x70000
|
||||||
|
|
||||||
|
; push arguments
|
||||||
|
mov eax, thunk.int16
|
||||||
|
push eax
|
||||||
|
mov eax, thunk.int15
|
||||||
|
push eax
|
||||||
|
mov eax, thunk.int13
|
||||||
|
push eax
|
||||||
|
mov eax, thunk.int10
|
||||||
|
push eax
|
||||||
|
xor eax, eax
|
||||||
|
mov al, [disk]
|
||||||
|
push eax
|
||||||
|
mov eax, kernel.entry
|
||||||
|
push eax
|
||||||
|
mov eax, [stage3 + 0x18]
|
||||||
|
call eax
|
||||||
|
.halt:
|
||||||
|
cli
|
||||||
|
hlt
|
||||||
|
jmp .halt
|
||||||
|
|
||||||
|
kernel:
|
||||||
|
.stack: dq 0
|
||||||
|
.func: dq 0
|
||||||
|
.args: dq 0
|
||||||
|
|
||||||
|
.entry:
|
||||||
|
; page_table: usize
|
||||||
|
mov eax, [esp + 4]
|
||||||
|
mov [long_mode.page_table], eax
|
||||||
|
|
||||||
|
; stack: u64
|
||||||
|
mov eax, [esp + 8]
|
||||||
|
mov [.stack], eax
|
||||||
|
mov eax, [esp + 12]
|
||||||
|
mov [.stack + 4], eax
|
||||||
|
|
||||||
|
; func: u64
|
||||||
|
mov eax, [esp + 16]
|
||||||
|
mov [.func], eax
|
||||||
|
mov eax, [esp + 20]
|
||||||
|
mov [.func + 4], eax
|
||||||
|
|
||||||
|
; args: *const KernelArgs
|
||||||
|
mov eax, [esp + 24]
|
||||||
|
mov [.args], eax
|
||||||
|
|
||||||
|
; long_mode: usize
|
||||||
|
mov eax, [esp + 28]
|
||||||
|
test eax, eax
|
||||||
|
jz .inner32
|
||||||
|
|
||||||
|
mov eax, .inner64
|
||||||
|
mov [long_mode.func], eax
|
||||||
|
jmp long_mode.entry
|
||||||
|
|
||||||
|
.inner32:
|
||||||
|
; disable paging
|
||||||
|
mov eax, cr0
|
||||||
|
and eax, 0x7FFFFFFF
|
||||||
|
mov cr0, eax
|
||||||
|
|
||||||
|
;TODO: PAE (1 << 5)
|
||||||
|
; enable FXSAVE/FXRSTOR, Page Global, and Page Size Extension
|
||||||
|
mov eax, cr4
|
||||||
|
or eax, 1 << 9 | 1 << 7 | 1 << 4
|
||||||
|
mov cr4, eax
|
||||||
|
|
||||||
|
; set page table
|
||||||
|
mov eax, [long_mode.page_table]
|
||||||
|
mov cr3, eax
|
||||||
|
|
||||||
|
; enabling paging and protection simultaneously
|
||||||
|
mov eax, cr0
|
||||||
|
; Bit 31: Paging, Bit 16: write protect kernel, Bit 0: Protected Mode
|
||||||
|
or eax, 1 << 31 | 1 << 16 | 1
|
||||||
|
mov cr0, eax
|
||||||
|
|
||||||
|
; enable FPU
|
||||||
|
;TODO: move to Rust
|
||||||
|
mov eax, cr0
|
||||||
|
and al, 11110011b ; Clear task switched (3) and emulation (2)
|
||||||
|
or al, 00100010b ; Set numeric error (5) monitor co-processor (1)
|
||||||
|
mov cr0, eax
|
||||||
|
fninit
|
||||||
|
|
||||||
|
mov esp, [.stack]
|
||||||
|
mov eax, [.args]
|
||||||
|
push eax
|
||||||
|
mov eax, [.func]
|
||||||
|
call eax
|
||||||
|
.halt32:
|
||||||
|
cli
|
||||||
|
hlt
|
||||||
|
jmp .halt32
|
||||||
|
|
||||||
|
USE64
|
||||||
|
|
||||||
|
.inner64:
|
||||||
|
mov rsp, [.stack]
|
||||||
|
mov rax, [.func]
|
||||||
|
mov rdi, [.args]
|
||||||
|
call rax
|
||||||
|
.halt64:
|
||||||
|
cli
|
||||||
|
hlt
|
||||||
|
jmp .halt64
|
149
bootloader/bios/thunk.asm
Normal file
149
bootloader/bios/thunk.asm
Normal file
@ -0,0 +1,149 @@
|
|||||||
|
SECTION .text
|
||||||
|
USE32
|
||||||
|
|
||||||
|
thunk:
|
||||||
|
.int10:
|
||||||
|
mov dword [.func], .int10_real
|
||||||
|
jmp .enter
|
||||||
|
|
||||||
|
.int13:
|
||||||
|
mov dword [.func], .int13_real
|
||||||
|
jmp .enter
|
||||||
|
|
||||||
|
.int15:
|
||||||
|
mov dword [.func], .int15_real
|
||||||
|
jmp .enter
|
||||||
|
|
||||||
|
.int16:
|
||||||
|
mov dword [.func], .int16_real
|
||||||
|
jmp .enter
|
||||||
|
|
||||||
|
.func: dd 0
|
||||||
|
.esp: dd 0
|
||||||
|
.cr0: dd 0
|
||||||
|
|
||||||
|
.enter:
|
||||||
|
; save flags
|
||||||
|
pushfd
|
||||||
|
|
||||||
|
; save registers
|
||||||
|
pushad
|
||||||
|
|
||||||
|
; save esp
|
||||||
|
mov [.esp], esp
|
||||||
|
|
||||||
|
; load gdt
|
||||||
|
lgdt [gdtr]
|
||||||
|
|
||||||
|
; far jump to protected mode 16-bit
|
||||||
|
jmp gdt.pm16_code:.pm16
|
||||||
|
|
||||||
|
.exit:
|
||||||
|
; set segment selectors to 32-bit protected mode
|
||||||
|
mov eax, gdt.pm32_data
|
||||||
|
mov ds, eax
|
||||||
|
mov es, eax
|
||||||
|
mov fs, eax
|
||||||
|
mov gs, eax
|
||||||
|
mov ss, eax
|
||||||
|
|
||||||
|
; restore esp
|
||||||
|
mov esp, [.esp]
|
||||||
|
|
||||||
|
; restore registers
|
||||||
|
popad
|
||||||
|
|
||||||
|
; restore flags
|
||||||
|
popfd
|
||||||
|
|
||||||
|
; return
|
||||||
|
ret
|
||||||
|
|
||||||
|
USE16
|
||||||
|
|
||||||
|
.int10_real:
|
||||||
|
int 0x10
|
||||||
|
ret
|
||||||
|
|
||||||
|
.int13_real:
|
||||||
|
int 0x13
|
||||||
|
ret
|
||||||
|
|
||||||
|
.int15_real:
|
||||||
|
int 0x15
|
||||||
|
ret
|
||||||
|
|
||||||
|
.int16_real:
|
||||||
|
int 0x16
|
||||||
|
ret
|
||||||
|
|
||||||
|
.pm16:
|
||||||
|
; set segment selectors to protected mode 16-bit
|
||||||
|
mov eax, gdt.pm16_data
|
||||||
|
mov ds, eax
|
||||||
|
mov es, eax
|
||||||
|
mov fs, eax
|
||||||
|
mov gs, eax
|
||||||
|
mov ss, eax
|
||||||
|
|
||||||
|
; save cr0
|
||||||
|
mov eax, cr0
|
||||||
|
mov [.cr0], eax
|
||||||
|
|
||||||
|
; disable paging and protected mode
|
||||||
|
and eax, 0x7FFFFFFE
|
||||||
|
mov cr0, eax
|
||||||
|
|
||||||
|
; far jump to real mode
|
||||||
|
jmp 0:.real
|
||||||
|
|
||||||
|
.real:
|
||||||
|
; set segment selectors to real mode
|
||||||
|
mov eax, 0
|
||||||
|
mov ds, eax
|
||||||
|
mov es, eax
|
||||||
|
mov fs, eax
|
||||||
|
mov gs, eax
|
||||||
|
mov ss, eax
|
||||||
|
|
||||||
|
; set stack
|
||||||
|
mov esp, 0x7C00 - 64
|
||||||
|
|
||||||
|
; load registers and ES
|
||||||
|
pop es
|
||||||
|
pop edi
|
||||||
|
pop esi
|
||||||
|
pop ebp
|
||||||
|
pop ebx
|
||||||
|
pop edx
|
||||||
|
pop ecx
|
||||||
|
pop eax
|
||||||
|
|
||||||
|
; enable interrupts
|
||||||
|
sti
|
||||||
|
|
||||||
|
; call real mode function
|
||||||
|
call [.func]
|
||||||
|
|
||||||
|
; disable interrupts
|
||||||
|
cli
|
||||||
|
|
||||||
|
; save registers and ES
|
||||||
|
push eax
|
||||||
|
push ecx
|
||||||
|
push edx
|
||||||
|
push ebx
|
||||||
|
push ebp
|
||||||
|
push esi
|
||||||
|
push edi
|
||||||
|
push es
|
||||||
|
|
||||||
|
; load gdt (BIOS sometimes overwrites this)
|
||||||
|
lgdt [gdtr]
|
||||||
|
|
||||||
|
; restore cr0, will enable protected mode
|
||||||
|
mov eax, [.cr0]
|
||||||
|
mov cr0, eax
|
||||||
|
|
||||||
|
; far jump to protected mode 32-bit
|
||||||
|
jmp gdt.pm32_code:.exit
|
Loading…
x
Reference in New Issue
Block a user