gdt and pmode problem

If you are new to OS Development, plan on spending some time here first before going into the other forums.

Moderator:Moderators

Post Reply
exor
Posts:13
Joined:Tue Mar 23, 2010 11:01 am
gdt and pmode problem

Post by exor » Tue Mar 23, 2010 11:36 am

hi
i have a problem while installing gdt and in far jmp to set cs.

i think my first problem is gdt install: this is my code

Stage2

Code: Select all

org 0x500			; loaded to first real mode unused address
bits 16

jmp main

;*******************************************
;	Global Description Table (GDT) Predef
;*******************************************

gdt_data_begin:

; first null desc
	dd 0x0
	dd 0x0

; Code Descriptor
	dw 0xffff
	dw 0x0
	db 0x0
	db 10011010b		; access byte
	db 11001111b		; granularity byte
	db 0x0
	
; Data Descriptor
	dw 0xffff
	dw 0x0
	db 0x0
	db 10010010b		; access byte
	db 11001111b		; granularity byte
	db 0x0
gdt_data_end:

lgdt_param:
	dw gdt_data_end - gdt_data_begin - 1		; gdt limit
	dd gdt_data_begin							; first descriptor addr


%include "includes\stdio.inc"
%include "includes\gdt.inc"

welcome.msg db 13,10,"Preparing to load operating system ...",13,10,0

main:
	cli
	;mov ax, 0x050
	;mov ds, ax
	;mov es, ax
	;mov fs, ax
	;mov gs, ax
	;;
        ; setting stack
	mov ax, 0x9000
	mov ss, ax
	mov sp, 0xffff
	sti
	
	mov si, welcome.msg
	call puts16
	
	call InstallGDT				; installing descriptors table
	
	cli
	;hlt
	mov eax, cr0
	or eax, 1
	mov cr0, eax				; PMODE
	
	jmp 8h:Stage3	;0x700 i have tried to far jmp directly to 0x700, without label and it didnt work			; jmp to fix cs 

times 512 - ($-$$)
	
;***********************************************
;	Stage3
;***********************************************

bits 32					; protected mode

Stage3:

	mov ax, 0x10			; data descriptor
	mov ds, ax
	mov es, ax
	mov ss, ax
	mov esp, 0x90000		; stack pointer 0x90000 to 0xFFFFF
	
	hlt
gdt.inc

Code: Select all

bits  16

InstallGDT:
	pusha
	cli
	lgdt [lgdt_param]			; loading gdt
	sti
	popa
	ret
i have tried bootldr with bochs.

first of all i'd like to know why setting segment at begin of stage2 it doesn't continue to execute the remaining code (i loaded stage2 to 0x500, but setting segments to 0x50, it does nothing. without set segments, it works normally)

about gdt i think there's an addressing problem with gdt code because trying to put gdt code directly in stage2 code, i get this from bochs:

Code: Select all

00015692314e[CPU0 ] check_cs(0x0008): not a valid code segment !
00015692314e[CPU0 ] interrupt(): gate descriptor is not valid sys seg (vector=0x0d)
00015692314e[CPU0 ] interrupt(): gate descriptor is not valid sys seg (vector=0x08)

and after

00015692314i[CPU0 ] 0x0000000000008195>> jmp far 0008:0700 : EA00070800
00015692314e[CPU0 ] exception(): 3rd (13) exception with no resolution, shutdown status is 00h, resetting
instead, putting gdt code to gdt.inc and including it in stage2

Code: Select all

bits 16

%ifndef
%define __GDT_INC_

;*******************************************
;	InstallGDT ()
;*******************************************

InstallGDT:
	pusha
	cli
	lgdt [lgdt_param]			; loading gdt
	sti
	popa
	ret
	
;*******************************************
;	Global Description Table (GDT) Predef
;*******************************************

; null desc
gdt_data_begin:
	dd 0x0
	dd 0x0

; Code Descriptor
	dw 0xffff
	dw 0x0
	db 0x0
	db 10011010b		; access byte
	db 11001111b
	db 0x0
	
; Data Descriptor
	dw 0xffff
	dw 0x0
	db 0x0
	db 10010010b		; access byte
	db 11001111b		; granularity byte
	db 0x0
gdt_data_end:

; Parametro per LGDT, una word con la dimensione del gdt e il gdt
lgdt_param:
	dw gdt_data_end - gdt_data_begin - 1		; gdt limit
	dd gdt_data_begin							; first descriptor addr

%endif
i get this:

Code: Select all

00015645378e[CPU0 ] jump_protected: gate type 0 unsupported
00015645378e[CPU0 ] interrupt(): gate descriptor is not valid sys seg (vector=0x0d)
00015645378e[CPU0 ] interrupt(): gate descriptor is not valid sys seg (vector=0x08)

and after

00015645378i[CPU0 ] 0x000000000000819d>> jmp far 0008:05a2 : EAA2050800
00015645378e[CPU0 ] exception(): 3rd (13) exception with no resolution, shutdown status is 00h, resetting
i think that when it tries to jmp to this segment, why gdt is not loaded, it triple faults...

thanks

exor
Posts:13
Joined:Tue Mar 23, 2010 11:01 am

Re: gdt and pmode problem

Post by exor » Thu Mar 25, 2010 4:24 pm

all right :D it was an addressing problem....
i've set segment registers to 0 and it has worked
but i would like to understand why it was wrong...

i loaded stage2 to 0:0x500 or 0x50:0 (i hope it's the same o.o), but i had to set segments to 0

why didnt it work setting org to 0x50 ?
i had to set segments to 0 too (maybe lgdt command uses any segment registers ?)

hoping for replies, tnx :)

Andyhhp
Moderator
Posts:387
Joined:Tue Oct 23, 2007 10:05 am
Location:127.0.0.1
Contact:

Re: gdt and pmode problem

Post by Andyhhp » Thu Mar 25, 2010 4:44 pm

I have explained the answer to that question on http://www.brokenthorn.com/forums/viewt ... =15&t=1356 so I wont repeat myself here :P
Image

exor
Posts:13
Joined:Tue Mar 23, 2010 11:01 am

Re: gdt and pmode problem

Post by exor » Thu Mar 25, 2010 5:04 pm

uhm .. i've read. but why i've to set segment registers to 0, if i loaded stage2 to 0x50:0...
if i set segments to 0x50 it should work, but it doesnt


EDIT: mmm.. could it be because floppy read sectors function loads stage in es:bx (0:500) ?
i'm confused ..

Andyhhp
Moderator
Posts:387
Joined:Tue Oct 23, 2007 10:05 am
Location:127.0.0.1
Contact:

Re: gdt and pmode problem

Post by Andyhhp » Thu Mar 25, 2010 10:18 pm

You clearly misunderstood my post.

In stage 2, you have an ORG 0x500 at the beginning which makes basically adds 0x500 to all absolute references.

This means that if you load it at 0x500, and set the segment registers to be 0, stage 2 will work correctly.

Take the following two cases, both using ORG 0x500

Case 1: segment registers at 0
linear address of cs:di is 0x0:(di+0x500) which is di+0x500

Case 2: segment registers at 0x50
linear address of cs:di is 0x50:(di+0x500) which is di+0x1000, which is 0x500 out.

The meaning of ORG is basically "assume the code that I am writing is 0xNNNN away from the segment register base values"

Now back to your specific case,

You start in stage2 having jumped to 0x0:0x500 (i assume, as the code works) which is correct.

You then set ds to be 0x50, making all absolute references in your code 0x500 out and wrong.
You then lgdt using an absolute reference (which is wrong), which loads garbage into the GDT.
You then attempt to jump to 0x8:stage3 which attempts to load the garbage entry from 0x8 which causes a GPF.


The way to fix it is to ensure that you jump from stage1 to stage 2 as 0x0:0x500 (if you arnt doing so already), and change

Code: Select all

main:
   cli
   mov ax, 0x050
   mov ds, ax
to

Code: Select all

main:
   cli
   mov ax, cs
   mov ds, ax
to ensure that cs and ds are the same

~Andrew
Image

Annie
Posts:14
Joined:Thu Feb 12, 2009 9:11 pm

Re: gdt and pmode problem

Post by Annie » Thu Apr 01, 2010 12:00 pm

hi Andyhhp,

Thanks for the explanation but I have a question, if the code (stage 2 is loaded at 0050:0000), Will the code segment (cs) is set to 0x0500 (or it is 0 and we need to have the org directive (0x500) to add to it?)

I remember in the stage 2 of the bootloader 4 (Tut 6), we set "org 0", and save value of cs to ds. (So I guess cs is set to 0x0500 automatically.)

I tried the same thing with the gdt code, instead of have "org 0x500", I set to 0, and save cs value to ds. But I got triple fault.

Do you happen to understand why?

Thank you

Annie
Posts:14
Joined:Thu Feb 12, 2009 9:11 pm

Re: gdt and pmode problem

Post by Annie » Thu Apr 01, 2010 12:07 pm

hi,

one more question (sorry for asking such a silly but I couldnt find it on google),

"org" directive add the given value to CS, DS, ES... DI, SI right?

Thanks

exor
Posts:13
Joined:Tue Mar 23, 2010 11:01 am

Re: gdt and pmode problem

Post by exor » Thu Apr 01, 2010 1:23 pm

Annie wrote:hi Andyhhp,
I remember in the stage 2 of the bootloader 4 (Tut 6), we set "org 0", and save value of cs to ds. (So I guess cs is set to 0x0500 automatically.)
cs isnt set automatically, but by retf function in stage1 code, which sets cs to 0x50

Code: Select all

          push    WORD 0x0050
          push    WORD 0x0000
          retf
Annie wrote: I tried the same thing with the gdt code, instead of have "org 0x500", I set to 0, and save cs value to ds. But I got triple fault.
in gdt code you can't to do this, because pmode uses not segment:offset memory model, but descriptor:linear_address, so org must be set always to linear_address and cs has to be set to code descriptor in use (0x8)
Annie wrote: "org" directive add the given value to CS, DS, ES... DI, SI right?
org adds address to offset, not to segment, so as Andyhhp explained to me (really understandable), these are new references:

cs:(di+orgaddress)

Andyhhp
Moderator
Posts:387
Joined:Tue Oct 23, 2007 10:05 am
Location:127.0.0.1
Contact:

Re: gdt and pmode problem

Post by Andyhhp » Thu Apr 01, 2010 1:43 pm

When you are loading stage2 from disk into memory, the segment and offset are independent of the cs:ip pair used to execute stage2. It appears that you are getting mixed up between the two.


When loading stage2 from disk, you are saying "please copy stage2 from disk to the memory location xx:yy" where xx:yy is the segment:offset pair. This does nothing to affect the code - all it does is copy to the linear addres represented. Remember that there are 4096 unique ways to address every possible linear address in this way. As a result, it doesnt matter if you 0x50:0x0 or 0x0:0x500 for loading stage2 - they both mean the same thing.

As for compiling and executing, thats a different matter.

the ORG statement means "This source code file starts at offset 0xnnnn". The assembler will ensure that all references are adjusted to fit.

As a result, if you use ORG 0x500, you must ensure that the offset register (in this case, ip as its the offset half of cs:ip) is set to 0x500 to execute the first instruction in stage2. As the offset is 0x500 and the code is loaded at linear address 0x500, the only working segment value will be 0x0.

On the other hand, if you use ORG 0x0, the offset register must be 0x0. Once again, the code is loaded to linear 0x500, meaning that the segment register must be 0x50.

(Along the lines of having 4096 unique ways to address every byte in memory, it would work to use ORG 0x4F0 and jump to 0x01:0x4F0 to execute stage2 loaded at 0x500)


@exor: "descriptor:linear_address"

the GDT uses descriptor:offset, not linear_address as the linear_address is only equal to the offset if the base address of the descriptor is 0. For Page Address Extensions, this is most likely not the case.

~Andrew
Image

Annie
Posts:14
Joined:Thu Feb 12, 2009 9:11 pm

Re: gdt and pmode problem

Post by Annie » Fri Apr 02, 2010 9:43 am

HI,

Thanks I think I kind of understand. Now I understand why we need to set those segment and org in gdt. Just one more question regarding the ip and cs (an example Andyhhp showed)

so if we set ORG to 0x500, our ip value will be added to 0x500.
Our code stage2 is loaded at 0x500. and as exor said, the retf instruction actually set cs to 0x500.

That if we have cs:ip (0x500:0x500). Aren't we out by 0x500?

Andyhhp
Moderator
Posts:387
Joined:Tue Oct 23, 2007 10:05 am
Location:127.0.0.1
Contact:

Re: gdt and pmode problem

Post by Andyhhp » Fri Apr 02, 2010 10:09 am

You are correct that the result is wrong.

However, you are actually out by 0x5000 not 0x500.

0x500:0x500 = 0x5500 (linear address) which is supposed to be going to 0x500 linear.


As basic rules:

If ORG is the same as the linear address where it is loaded, the segment registers must be 0

If ORG is 0, the segment registers must be the linear address where stage2 is loaded, divided by 16

Does this help?

~Andrew
Image

Annie
Posts:14
Joined:Thu Feb 12, 2009 9:11 pm

Re: gdt and pmode problem

Post by Annie » Fri Apr 02, 2010 9:31 pm

hi thanks, the basic rules help.

Just to make sure I understand thing correctly

if we are actually out by 0x5000, how could the codes still run fine?

why 0x5500 (linear address) is going to 0x500 linear?

Thanks

Andyhhp
Moderator
Posts:387
Joined:Tue Oct 23, 2007 10:05 am
Location:127.0.0.1
Contact:

Re: gdt and pmode problem

Post by Andyhhp » Fri Apr 02, 2010 11:49 pm

if we are actually out by 0x5000, how could the codes still run fine?

why 0x5500 (linear address) is going to 0x500 linear?
They really arnt - The code will definatly not run fine. I was attempting to emphasise that the example given was wrong

~Andrew
Image

Post Reply