I'm writing my own boot loader for i386 in NASM for education purposes. But when I'm running qemu with this it starts blinking and do anything but what I want. Here's my code:
; defs.asm
%define STACK_SEGMENT_REAL_MODE 0x9000
%define STACK_SEGMENT_PROT_MODE 0xFFFFFFFE
; head.asm
[bits 16]
[org 0x7C00]
%include "defs.asm"
start:
cli
xor ax, ax ; AX = 0
mov ds, ax ; DS = 0
mov es, ax ; ES = 0
mov ss, ax ; SS = 0
mov esp, STACK_SEGMENT_REAL_MODE
mov ebp, esp
sti
call switch_real_to_prot
; at this point interrupts are diabled
; infinite loop
jmp $
%include "protection.asm"
times 510-($-$$) db 0
db 0x55
db 0xAA
; protection.asm
; ----------------- Global Descriptor Table -----------------
;
; Segment Descriptor
; 31 23 15 7 0
; +---------------+-+-+-+----------+-+-----+-+-----+-+---------------+
; | | | |A| | | | | | | |
; | BASE 31..24 |G|X|V| LIMIT |P| DPL |1| TYPE|A| BASE 21..16 |
; | | | |L| 19..16 | | | | | | |
; +---------------+-+-+-+----------+-+-----+-+-----+-+---------------+
; | | |
; | SEGMENT BASE 15..0 | SEGMENT LIMIT 15..0 |
; | | |
; +--------------------------------+---------------------------------+
%include "defs.asm"
%define GDT_CS_PROT 0x08
%define GDT_DS_PROT 0x10
gdt:
; NULL Segment Descriptor
dq 0
; Code Segment Descriptor
;
; BASE = 0x00000000
; LIMIT = 0xFFFFF (4GB), 4KiB GRANULARITY,
; PRESENT TYPE = 32 bit, EXECUTE/READ, DPL = 0
dw 0xFFFF
dw 0
db 0
db 0x9A
db 0xCF
db 0
; Data Segment Descriptor
;
; BASE = 0x00000000
; LIMIT = 0xFFFFF (4GB), 4KiB GRANULARITY,
; PRESENT TYPE = 32 bit, READ/WRITE, DPL = 0
dw 0xFFFF
dw 0
db 0
db 0x92
db 0xCF
db 0
gdt_end:
gdt_desc: ; Func | Bits
; --------+------
db gdt_end - gdt ; Limit | 0-15
dw gdt ; Address | 16-47
switch_real_to_prot:
[bits 16]
cli
xor ax, ax
mov ds, ax
lgdt [gdt_desc]
; switch to protected mode
mov eax, cr0
or eax, 1
mov cr0, eax
jmp GDT_CS_PROT:init_prot
[bits 32]
init_prot:
; Since this moment all data segment registers
; point to the same data segment in GDT:0x10
mov ax, GDT_DS_PROT
mov es, ax
mov fs, ax
mov gs, ax
mov ds, ax
mov ss, ax
; move return address to the real stack
mov eax, [esp]
mov [STACK_SEGMENT_REAL_MODE], eax
; get protected mode stack
mov eax, [STACK_SEGMENT_PROT_MODE]
mov esp, eax
mov ebp, eax
; put the return address to the correct stack
mov eax, [STACK_SEGMENT_REAL_MODE]
mov [esp], eax
xor eax, eax
ret
I build it using nasm:
$ nasm -f bin head.asm -o boot
and run qemu like:
$ qemu-system-i386 boot
and then I see something weird. Can anybody explain what I'm doing wrong?