I've got a few issues with my code. In theory, it opens Gate A20, sets up a GDT, and switches to Protected Mode.
Practically, it generates a General Protection Fault when attemping to do a far jump.
boot.asm
Code: Select all
[BITS 16]
org 0x7C00
mov ax, 0x2000
mov ss, ax
xor sp, sp
xor ax, ax
xor bx, bx
xor cx, cx
xor dx, dx
retry:
mov ah, 0
mov dl, [boot_device]
int 0x13
jc retry
mov ax, 0x3000
mov es, ax
mov ah, 0x02
mov al, [sectors_to_load] ;Sectors to Load
mov dl, [boot_device] ;Drive Number (1st Floppy: 0, 2nd Floppy: 1, 1st Harddisk: 0x80)
mov dh, 0x00 ;Head 0
mov cx, 0x0002 ;Cylinder 0, Sector 2
int 0x13
jc retry
jmp 0x3000:0x0000
boot_device db 0
sectors_to_load db 2
times 510-($-$$) db 0
db 0x55
db 0xAA
Code: Select all
org 0x3000
;section .text
;[BITS 16]
init:
mov ax, 0x3000
mov ds, ax
mov es, ax
xor ax, ax
xor bx, bx
xor cx, cx
xor dx, dx
mainloop:
call enable_A20 ;enable A20
cli
lgdt [GDT_ADDR] ;load GDT
xchg bx, bx
mov eax, cr0 ;switch to Protected Mode
or eax, 0x0001
mov cr0, eax
xchg bx, bx
jmp 0x3000:asm_pm_main ;far jump to assembly kernel
cli ;if anything fails, suspend CPU forever
hlt
;;;;;;;;;;;;;;;;
;; A20 Gate ;;
;;;;;;;;;;;;;;;;
enable_A20:
cli
call wait65k
mov al,0xAD
out 0x64,al
call wait65k
mov al,0xD0
out 0x64,al
call wait65k
in al,0x60
push ax
call wait65k
mov al,0xD1
out 0x64,al
call wait65k
pop ax
or al,2
out 0x60,al
call wait65k
mov al,0xAE
out 0x64,al
call wait65k
sti
ret
;;;;;;;;;;;;;;;;
;; AUX CALLS ;;
;;;;;;;;;;;;;;;;
print_hex_byte:
push ax
shr al, 4
cmp al, 10
sbb al, 69h
das
mov ah, 0Eh
int 10h
pop ax
ror al, 4
shr al, 4
cmp al, 10
sbb al, 69h
das
mov ah, 0Eh
int 10h
ret
wait65k:
mov ax, 0xFFFF
.loop:
dec ax
jnz .loop
ret
[BITS 32]
asm_pm_main:
xor eax, eax
mov ax, 0x10
mov ds, ax
mov es, ax
mov ss, ax
xor eax, eax
mov fs, ax
mov gs, ax
mov esp, 0x200000
mov esi, message1
mov edi, 0xb8000
call memcpy
cli
hlt
memcpy:
lodsb
cmp eax, 0
je .done
stosb
jmp memcpy
.done:
ret
message1 db "Hello World", 0x0D, 0x0A, 0
;;;;;;;;;;;;;;;;;;;
;; GDT ;;
;;;;;;;;;;;;;;;;;;;
GDT_NULL:
dq 0 ;NULL-Descriptor
GDT_KERNEL_CODE:
dw 0x0400 ;Word 0: Limit 0:15
dw 0x0000 ;Word 1: Base 0:15
dw 0x9A00 ;Word 2: Access Byte [1001 1010: Present, Ring 0, Executable(Code Segment), own Level Only, Readable, Accessed] (High Byte) and Base 16:23 (Low Byte)
dw 0x00C0 ;Word 3: Base Addr 24:31 (High Byte) and FLAGS [Granularity 4kiB (Paging Size), 32-Bit Protected Mode] (Low Byte, High Nibble) + Limit 16:19 (Low Byte, Low Nibble)
GDT_KERNEL_DATA:
dw 0x0400 ;Word 0: Limit 0:15
dw 0x0000 ;Word 1: Base 0:15
dw 0x9A00 ;Word 2: Access Byte [1001 1010: Present, Ring 0, Executable(Code Segment), own Level Only, Readable, Accessed] (High Byte) and Base 16:23 (Low Byte)
dw 0x00C0 ;Word 3: Base Addr 24:31 (High Byte) and FLAGS [Granularity 4kiB (Paging Size), 32-Bit Protected Mode] (Low Byte, High Nibble) + Limit 16:19 (Low Byte, Low Nibble)
GDT_ADDR:
dw GDT_ADDR - GDT_NULL - 1
dd GDT_NULL
times 1024-($-$$) db 0
As far as i can tell, there are no faulty offsets, but i'm not sure (im not a hardcore assembly programmer).
What I KNOW is that the bootloader, and enabling of Gate A20 works (testet in Bochs and Qemu, apart from that A20 is always enabled in bochs (at least in my version))
I already disassembled the code, viewed at the memory dump (Bochs), went through the code step by step, but i'm still stuck.