GPF in Simple Bootloader

Question about which tools to use, bugs, the best way to implement a function, etc should go here. Don't forget to see if your question is answered in the wiki first! When in doubt post here.
Post Reply
singerng
Posts: 21
Joined: Sun Jan 20, 2013 6:27 pm

GPF in Simple Bootloader

Post by singerng »

I'm starting to write a simple 3-stage bootloader. I've already successfully written stage 1, which loads stage 2 (found in the reserved sectors of the hard drive). Stage 2 is responsible for (right now) only switching into a stable protected mode environment (stage 3 will enable higher half and actually start my kernel). The trouble is, I've been following the OSDev Babystep tutorial as a model and no matter how I manipulate the code of my bootloader, it still doesn't seem to work (I hope I'm not missing something obvious). I consistently get a GPF (triple fault, of course) when executing the instruction

Code: Select all

jmp 0x08:pm_start
.

Here is my stage 2 code:

Code: Select all

[ORG 0x4000]
[BITS 16]

lgdt [gdtr]	; load gdt register
mov ebx, 0xBEEF0000

mov eax, cr0	; switch to protected mode by
or al,1			; setting the protected mode bit
mov cr0, eax	; in CR0

jmp 0x08:flush_gdt

[BITS 32]

flush_gdt:
	mov ebx, 0xBEEF0001
	mov ax, 0x10
	mov ebx, 0xBEEF0002
	mov ds, ax
	mov es, ax
	mov fs, ax
	mov gs, ax
	mov ss, ax
	mov bx, 0xBEE2
	ret

mov eax, 0xDEADBEEF
mov ebx, 0xDEADBEEF

jmp $

[BITS 16]

; GDT

gdtr:
	dw gdt_end - gdt - 1	; last byte in table
	dd gdt					; start of table
 
gdt					dd 0,0	; entry 0 is always unused
flatdesc			db 0xff, 0xff, 0, 0, 0, 10010010b, 11001111b, 0
gdt_end:
Here is the register dump/error report from Bochs:

Code: Select all

CPU is in protected mode (active)
00017825947i[CPU0 ] CS.mode = 16 bit
00017825947i[CPU0 ] SS.mode = 16 bit
00017825947i[CPU0 ] EFER   = 0x00000000
00017825947i[CPU0 ] | EAX=60000011  EBX=beef0000  ECX=00090010  EDX=00000080
00017825947i[CPU0 ] | ESP=0000ffd6  EBP=00000000  ESI=000e0000  EDI=0000ffac
00017825947i[CPU0 ] | IOPL=0 id vip vif ac vm RF nt of df if tf sf zf af PF cf
00017825947i[CPU0 ] | SEG sltr(index|ti|rpl)     base    limit G D
00017825947i[CPU0 ] |  CS:4000( 0004| 0|  0) 00040000 0000ffff 0 0
00017825947i[CPU0 ] |  DS:0000( 0005| 0|  0) 00000000 0000ffff 0 0
00017825947i[CPU0 ] |  SS:0000( 0005| 0|  0) 00000000 0000ffff 0 0
00017825947i[CPU0 ] |  ES:4000( 0005| 0|  0) 00040000 0000ffff 0 0
00017825947i[CPU0 ] |  FS:0000( 0005| 0|  0) 00000000 0000ffff 0 0
00017825947i[CPU0 ] |  GS:0000( 0005| 0|  0) 00000000 0000ffff 0 0
00017825947i[CPU0 ] | EIP=00000013 (00000013)
00017825947i[CPU0 ] | CR0=0x60000011 CR2=0x00000000
00017825947i[CPU0 ] | CR3=0x00000000 CR4=0x00000000
(0).[17825947] [0x0000000000040013] 4000:0000000000000013 (unk. ctxt): jmp far 0008:4018         ; ea18400800
UPDATE: I added the code to enable the A20 line and it still doesn't work.

Code: Select all

in al, 0x92
or al, 2
out 0x92, al
User avatar
Combuster
Member
Member
Posts: 9301
Joined: Wed Oct 18, 2006 3:45 am
Libera.chat IRC: [com]buster
Location: On the balcony, where I can actually keep 1½m distance
Contact:

Re: GPF in Simple Bootloader

Post by Combuster »

Watch your segment registers. You are loading code somewhere different than where you are trying to load data from - a difference of four bits to be precise:

Code: Select all

[ORG 0x4000]
(...)
CS: (...) 00040000
"Certainly avoid yourself. He is a newbie and might not realize it. You'll hate his code deeply a few years down the road." - Sortie
[ My OS ] [ VDisk/SFS ]
singerng
Posts: 21
Joined: Sun Jan 20, 2013 6:27 pm

Re: GPF in Simple Bootloader

Post by singerng »

I'm not sure I understand... I changed the [ORG] directive to 0x40000, but it still doesn't work. I'm sorry if this seems noobish, but I'm bad with segmentation :(.

Can you explain more clearly what I have to do to fix this problem?
User avatar
Nessphoro
Member
Member
Posts: 308
Joined: Sat Apr 30, 2011 12:50 am

Re: GPF in Simple Bootloader

Post by Nessphoro »

Address = segment * 16
singerng
Posts: 21
Joined: Sun Jan 20, 2013 6:27 pm

Re: GPF in Simple Bootloader

Post by singerng »

I've made a few modifications, but it still isn't working. I noticed that the address of the code was above 16-bits so I moved it down. I also recognized there may have been problems with the GDT given in the tutorial so I rewrote it, but it's still not working (failing on the jmp instruction). Here's the new code:

Code: Select all

[ORG 0x6000]
[BITS 16]

mov ax, 0x600
mov ds, ax

in al, 0x92
or al, 2
out 0x92, al

lgdt [gdtr]	; load gdt register
mov ebx, 0xBEEF0000

mov eax, cr0	; switch to protected mode by
or al,1			; setting the protected mode bit
mov cr0, eax	; in CR0

jmp 0x08:flush_gdt

gdtr:
	dw gdt_end - null_seg - 1	; last byte in table
	dd null_seg					; start of table
 
null_seg					db 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00	; entry 0 (null seg) is always unused
code_seg					db 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x9A, 0xCF, 0x00	; entry 1 (code seg)
data_seg					db 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x92, 0xCF, 0x00	; entry 2 (data seg)
gdt_end:

[BITS 32]

flush_gdt:
	mov ebx, 0xBEEF0001
	mov ax, 0x10
	mov ebx, 0xBEEF0002
	mov ds, ax
	mov es, ax
	mov fs, ax
	mov gs, ax
	mov ss, ax
	mov bx, 0xBEE2
	ret

mov eax, 0xDEADBEEF
mov ebx, 0xDEADBEEF

jmp $
Mikemk
Member
Member
Posts: 409
Joined: Sat Oct 22, 2011 12:27 pm

Re: GPF in Simple Bootloader

Post by Mikemk »

Nessphoro wrote:Address = segment * 16
Address = segment * 16 + offset
Programming is 80% Math, 20% Grammar, and 10% Creativity <--- Do not make fun of my joke!
If you're new, check this out.
User avatar
Nessphoro
Member
Member
Posts: 308
Joined: Sat Apr 30, 2011 12:50 am

Re: GPF in Simple Bootloader

Post by Nessphoro »

m12 wrote:
Nessphoro wrote:Address = segment * 16
Address = segment * 16 + offset
That was unnecessary.
User avatar
Combuster
Member
Member
Posts: 9301
Joined: Wed Oct 18, 2006 3:45 am
Libera.chat IRC: [com]buster
Location: On the balcony, where I can actually keep 1½m distance
Contact:

Re: GPF in Simple Bootloader

Post by Combuster »

[ORG 0x6000]
[BITS 16]

mov ax, 0x600
mov ds, ax
So now your code runs at 0x00006000 and expects itself to be at base+offset = 16 * 0x600 + 0x6000 = 2 * 0x6000 = 0x0000C000 ?

There are only constants involved in loading the GDT. You can calculate every value and every address for all accessed bytes in memory by hand and see if it works out before you even try running the code. After all, OSDev isn't about guesswork, so don't turn it into that.
"Certainly avoid yourself. He is a newbie and might not realize it. You'll hate his code deeply a few years down the road." - Sortie
[ My OS ] [ VDisk/SFS ]
Post Reply