I've done my fair share of researching and have had a look at similar questions, but I can't seem to find anything useful. I'm pretty new to this, but I have a decent understanding of what's going on in the assembly code and why.
Basically, the boot sector here runs just fine in QEMU but my PC can't boot into it. It seems to get stuck in a loop, with just the blinking underscore on screen.
Neither MSG_REAL_MODE
nor MSG_PROT_MODE
get printed to screen (or if they do, they get cleared instantly).
There are a few different files with this one. I know it's a lot, sorry about that! If you need any clarification about anything, let me know :)
boot.asm (the main boot file)
[org 0x7c00]
mov bp, 0x9000
mov sp, bp
mov bx, MSG_REAL_MODE
call print_string
call switch_to_pm
jmp $
%include "f_print_string.asm"
%include "f_print_string_pm.asm"
%include "gdt.asm"
%include "f_switch_to_pm.asm"
[bits 32]
BEGIN_PM:
mov ebx, MSG_PROT_MODE
call print_string_pm
jmp $
MSG_REAL_MODE: db "Started in 16-bit Real Mode", 0
MSG_PROT_MODE: db "Successfully landed in 32-bit Protected Mode", 0
times 510-($-$$) db 0
dw 0xaa55
f_print_string.asm (for printing strings in 16-bit Real Mode)
print_string:
pusha
string_loop:
mov al, [bx]
cmp al, 0
jne print_char
popa
ret
print_char:
mov ah, 0x0e
int 0x10
add bx, 1
jmp string_loop
f_print_string_pm.asm (for printing strings in 32-bit Protected Mode)
[bits 32]
VIDEO_MEMORY equ 0xb8000
WHITE_ON_BLACK equ 0x0f
print_string_pm:
pusha
mov edx, VIDEO_MEMORY
print_string_pm_loop:
mov al, [ebx]
mov ah, WHITE_ON_BLACK
cmp al, 0
je print_string_pm_done
mov [edx], ax
add ebx, 1
add edx, 2
jmp print_string_pm_loop
print_string_pm_done:
popa
ret
gdt.asm (for setting up the GDT and GDT descriptor, commented for better understanding)
; GDT
gdt_start:
gdt_null:
dd 0x0
dd 0x0
gdt_code:
; base=0x0, limit=0xfffff
; 1st flags: (present)1 (privilege)00 (descriptor type)1 -> 1001b
; type flags: (code)1 (conforming)0 (readable)1 (accessed)0 -> 1010b
; 2nd flags: (granularity)1 (32-bit default)1 (64-bit seg)0 (AVL)0 -> 1100b
dw 0xffff ; Limit (bits 0-15)
dw 0x0 ; Base (bits 0-15)
db 0x0 ; Base (bits 16-23)
db 10011010b ; 1st flags (4 bits) and type flags (4 bits)
db 11001111b ; 2nd flags (4 bits) and limit (4 bits)
db 0x0 ; Base (bits 24-31)
gdt_data:
; Same as code segment except for the type flags:
; type flags: (code)0 (expand down)0 (writable)1 (accessed)0 -> 0010b
dw 0xffff ; Limit (bits 0-15)
dw 0x0 ; Base (bits 0-15)
db 0x0 ; Base (bits 16-23)
db 10010010b ; 1st flags (4 bits) and type flags (4 bits)
db 11001111b ; 2nd flags (4 bits) and limit (4 bits)
db 0x0 ; Base (bits 24-31)
gdt_end:
; GDT descriptor
gdt_descriptor:
dw gdt_end - gdt_start - 1
dd gdt_start
CODE_SEG equ gdt_code - gdt_start
DATA_SEG equ gdt_data - gdt_start
f_switch_to_pm.asm (for switching to 32-bit Protected Mode)
[bits 16]
switch_to_pm:
cli
lgdt [gdt_descriptor]
mov eax, cr0
or eax, 0x1
mov cr0, eax
jmp CODE_SEG:init_pm
[bits 32]
init_pm:
mov ax, DATA_SEG
mov ds, ax
mov ss, ax
mov es, ax
mov fs, ax
mov gs, ax
mov ebp, 0x90000
mov esp, ebp
call BEGIN_PM