Practical Application For the GDT

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.
brodeur235
Member
Member
Posts: 86
Joined: Sat Jun 06, 2009 11:55 am

Practical Application For the GDT

Post by brodeur235 »

I am somewhat confused as to what the purpose of the GDT is. Yes, I have read the entire wiki tutorial on it, and you'd think that was enough, but I still am not positive what the thing is used for. Here's what I ->think<- I understand about the GDT:

The table itself is defined by two attributes (base and size), which can be created and loaded into the gdt regster in asm with:

Code: Select all

lgdt [gdt]
gdt:
    limit dw 0x0000 ; ...some hex val
    base dd 0x00000000  ;     "
I have to fill this table with 8 byte entries that organize memory... This statement is very vague and lacking in specifics, yet it is the extent to which many explanations attempt to describe the GDT. It "organizes memory" simply isn't enough to get the ball rolling for me. Also, HOW do I load an entry into the GDT (technically, as in asm code)?

The first entry must be a null entry. I guess that means I add an entry (however I do that) of 8 bits all zeroed out. Okay, that sounds like it will be simple enough to do as soon as I learn how to add an entry, but again, what is the point? I don't want to do things "just because." WHY is it necessary to have a null entry first? I suppose I might better understand the answer to that if I at least understood the general prupose that the GDT serves.

Next, I need to add a code segment descriptor.

Next, I need to add a data segment descriptor.

Finally, as soon as I enter protected mode, I must jump to the first byte in the described code segment.

Okay, after having received these points about the GDT other questions come to mind... Let me organize them so they don't seem like a jumble of irrecoverable confusion

Is the code segment that I am required to set up and jump to akin to my Protected mode's "main" function?

Do I add two new descriptors (code and data) for every running process?

An well documented example of the GDT being used for something would be great help.

There are a lot of questions in there and probably a lot of statements made about the GDT that I thought were right but are actually flat out wrong. Again, I'm sorry if this is something that shouldn't be this hard to grasp, but I guess I'm just that slow.

All help is appreciated,

Brodeur235
xiphias
Posts: 7
Joined: Mon Jul 23, 2007 5:45 am
Location: Sweden

Re: Practical Application For the GDT

Post by xiphias »

brodeur235
Member
Member
Posts: 86
Joined: Sat Jun 06, 2009 11:55 am

Re: Practical Application For the GDT

Post by brodeur235 »

There is an exceedingly small amount of information in those manuals concerning the GDT. Thanks for taking the time to reply, but I'm still looking for help with this subject,

Brodeur235
geppyfx
Member
Member
Posts: 87
Joined: Tue Apr 28, 2009 4:58 pm

Re: Practical Application For the GDT

Post by geppyfx »

descriptor is an entry in GDT,LDT or IDT. And its not always 8 baits.
GDT(LDT,IDT) itself resides in RAM. Starting physical address of GDT and GDT limit(size) need to be put into gdtr register. The register is very similar to eax,ebx... except it has specific purpose - to let CPU know where GDT is.
This statement is very vague and lacking in specifics, yet it is the extent to which many explanations attempt to describe the GDT. It "organizes memory" simply isn't enough to get the ball rolling for me. Also, HOW do I load an entry into the GDT (technically, as in asm code)?
starting with long mode GDT is needed a lot more to define permissions rather than organize memory. Still organization is present.
Finally, as soon as I enter protected mode, I must jump to the first byte in the described code segment.
you must do that from 16bit real mode. There are several ways to jump but most common to use if 'far jump' x86 instruction. In Fasm it is encoded at "jmp segment:address", where segment is offset in in GDT table for the code descriptor which is 8

memory
+00 | dq 0 ;null descriptor
+08 | .code dq 0
+16 | .data dq 0

Keep in mind that #8 has lowest 3 bits cleared to 0. They are only zero for ring0(read manual).
After(or during I don't know) far jump CPU will put 'segment' into CS register. Now CS will reference code descriptor and CPU will watch that you don't violate any boundaries.
Is the code segment that I am required to set up and jump to akin to my Protected mode's "main" function?
your function has to be within code segment memory boundaries. Code segment doesn't have to start where you function(read memory address or label) does
Do I add two new descriptors (code and data) for every running process?
people normally don't do that and I don't advise either. One code descriptor for 32bit ring0, one for 32bit ring3(user). One 32bit data descriptor for ring0, one for ring3. TSS descriptor for 32bit ring0. That should be enough right now.
TSS descriptor is required to create processes(called software task switch, search)
The first entry must be a null entry. I guess that means I add an entry (however I do that) of 8 bits all zeroed out. Okay, that sounds like it will be simple enough to do as soon as I learn how to add an entry, but again, what is the point? I don't want to do things "just because." WHY is it necessary to have a null entry first? I suppose I might better understand the answer to that if I at least understood the general prupose that the GDT serves.
The 'null descriptor' is probably called this way because its offset is zero. Don't know. Ask Intel. Its purpose? Don't know, ask Intel, but the null descriptor is not used. You can keep any data in those 8 baits. You can even put 0(referencing null descriptor) into DS,SS or CS(careful here) and nothing will happen. Unless you use DS(like mov eax,[memory]) or SS(like push eax). Loading CS with 0 will result in error right away because CS is used to execute instructions.
Last edited by geppyfx on Thu Jun 11, 2009 4:46 pm, edited 1 time in total.
geppyfx
Member
Member
Posts: 87
Joined: Tue Apr 28, 2009 4:58 pm

Re: Practical Application For the GDT

Post by geppyfx »

geppyfx wrote:
Finally, as soon as I enter protected mode, I must jump to the first byte in the described code segment.
you must do than from 16bit real mode.
correction: you can jump to any byte in code segment from real mode. That byte has to contain valid x86 instruction. Jump is only required to change CS

LGDT and SGDT instruction are used to manipulate gdtr register. INtel Manual Vol 2A/2B
xiphias
Posts: 7
Joined: Mon Jul 23, 2007 5:45 am
Location: Sweden

Re: Practical Application For the GDT

Post by xiphias »

To understand what the GDT is used for you need to understand how the cpu works. In the IA-32 architecture, memory is referenced using addresses. The CPU uses a segmented memory model to get the linear address using a logical address which is a segment and an offset. All this can be found in the manuals from Intel. You need to specify a segment if you want to access memory. The cpu then adds the base address of the segment together with the offset to form the linear address. In real mode where you do not have a GDT, a segment is specified as a 16 bit value which is multiplied by 16 and added to the offset to form the memory address. In protected mode you specify a segment selector and an offset. The segment selector (which is the value you put in your segment registers like CS and DS) holds an index into the GDT or LDT and a privelige level. The index is 0, 1, 2, 3, 4 and so on where 0 is invalid since it points to the null descriptor. The descriptor in the GDT holds, among other things, the base address of the segment which is added to the offset to form the linear address. The currently executing instruction is always CS:EIP, therefore you need to setup the CS to point to a real segment descriptor. SS and DS are used implicitly in instructions like push and mov, therefore you should set them aswell.

Processes can share the same descriptors in the GDT or have their own, it is up to you. Most people uses a flat memory model without segments, but since the CPU still uses segments we need atleast two (code and data). So basically you can set the base of your segment descriptors to 0, which will make the offset == linear address.

Another important thing about segment descriptors is the default address and operand size which is specified in a bit in the descriptor. Depending on this bit, code is executed as 32 bit or 16 bit instructions. That's why you need a seperate segment descriptor when jumping into 32 bit protected mode. The reason for the far jmp when switching to protected mode is that you want to update the CS register. And you do not have to jmp to the first byte of your code segment.

Most of the times you do not need to dynamically add things to your gdt, instead you can have it statically defined within your program.
(Assuming your binary is loaded at 0x7C00):

Code: Select all

mov ax, 0x7C00
add eax, gdt
mov dword [gdt_desc+2], eax   ; set gdt base address
lgdt [gdt_desc]
mov eax, cr0
or eax, 1
mov cr0, eax  ; enter pm
jmp 0x8:0x7C00+pmode_entry  ; We are now in pm performing a jmp in a 16 bit code segment

[BITS32]
pmode_entry:
jmp  $

gdt: dd 0, 0
; entry 1
dw 0xffff, 0x00
db 0x00, 10011010b
db 11001111b, 0x00
; entry 2
dw 0xffff, 0x00
db 0x00, 10010010b
db 11001111b, 0x00

gdt_desc: dw $-gdt-1
dd 0
User avatar
Troy Martin
Member
Member
Posts: 1686
Joined: Fri Apr 18, 2008 4:40 pm
Location: Langley, Vancouver, BC, Canada
Contact:

Re: Practical Application For the GDT

Post by Troy Martin »

Image
Image
Solar wrote:It keeps stunning me how friendly we - as a community - are towards people who start programming "their first OS" who don't even have a solid understanding of pointers, their compiler, or how a OS is structured.
I wish I could add more tex
User avatar
kop99
Member
Member
Posts: 120
Joined: Fri May 15, 2009 2:58 am

Re: Practical Application For the GDT

Post by kop99 »

There is an exceedingly small amount of information in those manuals concerning the GDT. Thanks for taking the time to reply, but I'm still looking for help with this subject,
If you're going to understand GDT, first thing you have to do is understanding IA mauals fully...
And you should analyze some sample code and read some tutorials.
http://wiki.osdev.org/GDT_Tutorial
brodeur235
Member
Member
Posts: 86
Joined: Sat Jun 06, 2009 11:55 am

Re: Practical Application For the GDT

Post by brodeur235 »

Thank you Xiphia. That assembly helped a ton. The only question I have is this: it looks there like you defined both segment discriptors from 0-4gb... If that's the case, how does the processor know where in memory to apply the code descriptor rules and where in memory to apply the data descriptor rules. I realize you included the 0x8: in your protected mode jmp, but couldn't you do the same thing with another jmp, accept using 0x10: to specify that your using the data descriptor? Thanks for your help, I now have a really good understanding of the GDT's basic purpose and it's technicalities. The above question is the only one I have left. To anybody else having the same problem I did, I recommend these two pages:

http://wiki.osdev.org/Segmentation
http://wiki.osdev.org/GDT
And this thread, especially Xiphia's asm.

Brodeur235
User avatar
Troy Martin
Member
Member
Posts: 1686
Joined: Fri Apr 18, 2008 4:40 pm
Location: Langley, Vancouver, BC, Canada
Contact:

Re: Practical Application For the GDT

Post by Troy Martin »

Code descriptors are read/execute and data descriptors are read/write or read only. Therefore, to use the data descriptors, you jump using the 0x08:x and then mov ax,0x10 and mov ax into ds, es, fs, and gs.
Image
Image
Solar wrote:It keeps stunning me how friendly we - as a community - are towards people who start programming "their first OS" who don't even have a solid understanding of pointers, their compiler, or how a OS is structured.
I wish I could add more tex
xiphias
Posts: 7
Joined: Mon Jul 23, 2007 5:45 am
Location: Sweden

Re: Practical Application For the GDT

Post by xiphias »

brodeur235 wrote:Thank you Xiphia. That assembly helped a ton. The only question I have is this: it looks there like you defined both segment discriptors from 0-4gb... If that's the case, how does the processor know where in memory to apply the code descriptor rules and where in memory to apply the data descriptor rules.
It is the other way around; it's not 'where in memory you are' that tells the cpu which rules to apply. You tell the cpu which segment descriptor to use by using a segment selector and put it in CS or DS. Then, when you try to access data, the cpu will by default use the descriptor pointed to by the selector in DS. You can also override the segment selector when specifying an effective address like this: (nasm syntax)

Code: Select all

mov eax, dword [ES:0x400]
Mark139
Member
Member
Posts: 39
Joined: Mon Jan 15, 2007 2:32 pm

Re: Practical Application For the GDT

Post by Mark139 »

The GDT and the LDT (local) are tables of configuration data used by the CPU. The tables are used for various settings including code & data segments, task segments, gate descriptors, etc etc. The CPU will look up the settings in the tables at various points - i/e looking up memory, interupts etc.
It's a very flexible idea to have these tables and a little confusing at first. Stick with it, read the manuals and follow some tutorials.
brodeur235
Member
Member
Posts: 86
Joined: Sat Jun 06, 2009 11:55 am

Re: Practical Application For the GDT

Post by brodeur235 »

For some reason VBox aborts the OS somewhere around this part of my boatloader:

Code: Select all

mov eax, cr0
or eax, 1
mov cr0, eax

jmp 0x8:kernel
If i comment all that out, and just write:

Code: Select all

jmp kernel
it makes the jmp in real mode.

Here's the entire bootloader:

Code: Select all

[ORG 0x7C00]

;procedures

main:
	xor ax,ax
	mov ds,ax
	
	mov si,bl_loaded_msg
	call print_si
	
	call load_kernel
	mov si,kl_loaded_msg
	call print_si
	
	lgdt [gdt_head]
	mov si,gdt_loaded_msg
	call print_si
	
	mov eax, cr0
	or eax, 1
	mov cr0, eax
	
	jmp 0x8:kernel

print_si:
	mov bh,0x00
	mov bl,0x07
	mov ah,0x0E
	.next_char
		lodsb
		cmp al,0x00
		jz .done
		int 0x10
		jmp .next_char
	.done
		ret

load_kernel:
	mov dh,0x00
	mov dl,0x00
	mov ch,0x00
	mov cl,0x02
	xor bx,bx
	mov es,bx
	mov bx,kernel
	mov ah,0x02
	mov al,0x01
	int 0x13
	ret
	
;gdt

gdt_entries:
	
	;null entry
	dd 0x0,0x0
	
	;code segment descriptor: OFFESET = 0x8
	dw 0xFFFF,0x0000
	db 0x00, 10011010b
	
	;data segment descriptor: OFFSET = 0x10
	dw 0xFFFF,0x0000
	db 0x00, 10010010b
	
gdt_head:
	size dw ($-gdt_entries)
	offset dd gdt_entries

;data

bl_loaded_msg db "Bootloader loaded.",0xA,0xD,0
kl_loaded_msg db "Kernel loaded.",0xA,0xD,0
gdt_loaded_msg db "GDT setup.",0xA,0xD,0
pm_loaded_msg db "Protected mode entered.",0xA,0xD,0

;padding

times 512-2-($-$$) db 0x0000
bootable db 0xAA, 0x55
Brodeur235
User avatar
Troy Martin
Member
Member
Posts: 1686
Joined: Fri Apr 18, 2008 4:40 pm
Location: Langley, Vancouver, BC, Canada
Contact:

Re: Practical Application For the GDT

Post by Troy Martin »

Yeah, your GDT entries are only 6 bytes long. Here's the GDT I use for reference:

Code: Select all

gdt_data: 
    dd 0			; Null descriptor
    dd 0

    dw 0FFFFh		; Code descriptor
    dw 0
    db 0
    db 10011010b
    db 11001111b
    db 0

    dw 0FFFFh		; Data descriptor
    dw 0
    db 0
    db 10010010b
    db 11001111b
    db 0
Image
Image
Solar wrote:It keeps stunning me how friendly we - as a community - are towards people who start programming "their first OS" who don't even have a solid understanding of pointers, their compiler, or how a OS is structured.
I wish I could add more tex
User avatar
kop99
Member
Member
Posts: 120
Joined: Fri May 15, 2009 2:58 am

Re: Practical Application For the GDT

Post by kop99 »

Code: Select all

   dw 0xFFFF,0x0000
   db 0x00, 10011010b
   
   ;data segment descriptor: OFFSET = 0x10
   dw 0xFFFF,0x0000
   db 0x00, 10010010b
Are you sure this gdt table is all right?

Segment Descriptor is 8 byte aligned. But your SD seems like 6 byte aligned.
Post Reply