Ive been developing a Bootloader and when I attempt to load the GDT with the LGDT instruction it throws a General Protection Fault and I am unsure how to deal with it.
bootloader/gdt.asm
gdt_start: ; don't remove the labels, they're needed to compute sizes and jumps
gdt_null:
dq 0
; GDT for code segment. base = 0x00000000, length = 0xfffff
gdt_code:
dw 0xffff ; segment length, bits 0-15
dw 0x0 ; segment base, bits 0-15
db 0x0 ; segment base, bits 16-23
db 10011010b ; flags (8 bits)
db 11001111b ; flags (4 bits) + segment length, bits 16-19
db 0x0 ; segment base, bits 24-31
; GDT for data segment. base and length identical to code segment
gdt_data:
dw 0xffff
dw 0x0
db 0x0
db 10010010b
db 11001111b
db 0x0
gdt_end:
; GDT descriptor
gdt_descriptor:
dw gdt_end - gdt_start - 1 ; size (16 bit), always one less of its true size
dd gdt_start ; address (32 bit)
; define some constants for later use
CODE_SEG equ gdt_code - gdt_start
DATA_SEG equ gdt_data - gdt_start
[bits 16]
switch_to_pm:
cli
lgdt [gdt_descriptor] ; THIS is where the general protection fault occours
mov eax,0xff
mov [0xa006],eax
mov eax, cr0
or eax, 0x1 ; 3. set 32-bit mode bit in cr0
mov cr0, eax
jmp CODE_SEG:init_pm ; 4. far jump by using a different segment
; somehow forgot to copy this in
[bits 32]
init_pm: ; we are now using 32-bit instructions
mov ax, DATA_SEG ; 5. update the segment registers
mov ds, ax
mov ss, ax
mov es, ax
mov fs, ax
mov gs, ax
mov eax,0xee
mov [0xa000],eax
mov ebp, 0x90000 ; 6. update the stack right at the top of the free space
mov esp, ebp
call ready ; 7. Call a well-known label with useful code
bootloader.asm
[BITS 16]
[ORG 0x7c00]
jmp 0:start
%include "bootloader/gdt.asm"
[BITS 16]
start:
; setup video mode
mov ah,00h
mov al,13h
int 10h
mov dx,0
call print_dbg_x
; LOAD the system
mov ah,02h
mov al,20
mov ch,0
mov cl,02h
mov dh,0
mov dl,0
mov ebx,PROGRAM
int 13h
call print_dbg_x
; next setup the gdt
call print_dbg_x
cli
mov ax, 0x2401
int 0x15 ; enable A20 bit
call switch_to_pm
load_kern_err:
mov ah,0Ch
mov al,0xC
xor bh,bh
inc cx
int 10h
hlt
print_dbg_x:
mov ah,0Ch
mov al,0xF
xor bh,bh
inc cx
int 10h
ret
[BITS 32]
ready:
mov eax,0xff
mov [0xa000],eax
mov esp, 090000h
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 PROGRAM
jmp $
PROGRAM equ 0x1000
times 510 - ($ - $$) db 0
dw 0AA55h
switch_to_pm
is jumped to by the bootloader when it needs to load the GDT and switch to pmode. Before that it loads the kernel from the FDD and puts it into address 0x1000
. I dont load the IDT yet because the kernel in pmode will.
I use nasm and this is compiled into a binary (its an include on my main bootloader).
Bochs reports this before restarting as an exception, possibly the source of the #GPF
(0).[14992474] [0x000000007c40] 0000:0000000000007c40 (unk. ctxt): jmpf 0x0008:7c45 ; ea457c0800
Apparently the CPU gets into protected mode, so its something wrong with the jumpf.
00014992474i[CPU0 ] CPU is in protected mode (active)
00014992474i[CPU0 ] CS.mode = 16 bit
00014992474i[CPU0 ] SS.mode = 16 bit
00014992474i[CPU0 ] EFER = 0x00000000
00014992474i[CPU0 ] | EAX=60000011 EBX=00000000 ECX=00090004 EDX=00000000
00014992474i[CPU0 ] | ESP=0000ffd4 EBP=00000000 ESI=000e0000 EDI=0000ffac
00014992474i[CPU0 ] | IOPL=0 id vip vif ac vm RF nt of df if tf sf zf af PF cf
00014992474i[CPU0 ] | SEG sltr(index|ti|rpl) base limit G D
00014992474i[CPU0 ] | CS:0000( 0004| 0| 0) 00000000 0000ffff 0 0
00014992474i[CPU0 ] | DS:0010( 0005| 0| 0) 00000100 0000ffff 0 0
00014992474i[CPU0 ] | SS:0010( 0005| 0| 0) 00000100 0000ffff 0 0
00014992474i[CPU0 ] | ES:0010( 0005| 0| 0) 00000100 0000ffff 0 0
00014992474i[CPU0 ] | FS:0010( 0005| 0| 0) 00000100 0000ffff 0 0
00014992474i[CPU0 ] | GS:0010( 0005| 0| 0) 00000100 0000ffff 0 0
00014992474i[CPU0 ] | EIP=00007c40 (00007c40)
00014992474i[CPU0 ] | CR0=0x60000011 CR2=0x00000000
00014992474i[CPU0 ] | CR3=0x00000000 CR4=0x00000000
This is the code that the bootloader will load from the second sector, kernel is a C external linked with this code on compile time.
kentry.asm
[BITS 32]
global _start
_start:
mov ebp, 0x90000
mov esp, ebp
extern kernel
call kernel
ret
global idt_load
extern idtp
idt_load:
lidt [idtp]
ret
I put this code all together by compiling the bootloader then compiling the kernel, then I use cat to put the bootloader before the kernel in a binary file.
User contributions licensed under CC BY-SA 3.0