GDT help

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

Moderator:Moderators

Post Reply
afdgdhfrtewdszs
Posts:18
Joined:Tue Feb 01, 2011 6:25 pm
GDT help

Post by afdgdhfrtewdszs » Fri Nov 23, 2012 12:20 am

Hello, i have some questions about selectors. First of all i found that a selector(segment register) contains a 13-bit index,1-bit identification for GDT/LDT and 2-bits for protection level. After we entered protected mode and jump to Stage3, we loaded only descriptor index(0x10) in segments. Why we don't load identification for GDT/LDT and protection level? In addition, when we load ss(stack segment) with data selector, the segment type is data even there is type for stack segment,why is this happening? Thanks in advance.

User avatar
Mike
Site Admin
Posts:465
Joined:Sat Oct 20, 2007 7:58 pm
Contact:

Re: GDT help

Post by Mike » Sat Nov 24, 2012 10:07 pm

Hello,

When we load 0x10 into a segment register we are effectively setting the index to 3, ring 0, and clearing the gdt/ldt bit in the segment register (setting gdt type). The index 3 refers to the 3rd entry in the gdt at offset 0x10. In the design, we set ss to 0x10 to share the same kernel data segment; there is no separate selector type for stack. Of course, you can have a separate stack segment (using segmentation) but that isn't really needed and complicates the design (most real operating systems don't do this.)

afdgdhfrtewdszs
Posts:18
Joined:Tue Feb 01, 2011 6:25 pm

Re: GDT help

Post by afdgdhfrtewdszs » Sun Nov 25, 2012 10:25 am

Hi, thanks for the response but i still have a couple of questions. In number 0x10(0000000000010 0 00) index is 10(2), so null-descriptor is at index 0 and code-descriptor is at index 1? In addition 0x8 and 0x10 are not what they are because they are equal to the bytes from the start of the GDT, but instead because of the whole selector(index,gdt/ldt,ring) meaning that if,for example, wanted to be in ring-1 that number would be 0x11(10 0 01).Am i right? Thanks again, i appreciate your help!

User avatar
Mike
Site Admin
Posts:465
Joined:Sat Oct 20, 2007 7:58 pm
Contact:

Re: GDT help

Post by Mike » Sun Nov 25, 2012 6:38 pm

Hello,
In addition 0x8 and 0x10 are not what they are because they are equal to the bytes from the start of the GDT, but instead because of the whole selector(index,gdt/ldt,ring) meaning that if,for example, wanted to be in ring-1 that number would be 0x11(10 0 01).Am i right?
It is important to note that the segment registers only store a requested privileged level (RPL) not the descriptor privilege level (DPL) stored in the GDT. The segment registers are actually equal to the start of the GDT provided the low 3 bits are ignored: this is what the processor does when offsetting in the table.

If the requested privilege level (RPL) is greater then or equal to the current privilege level (CPL) then it can be used. 0x10 and 0x11 refer to the same GDT index (3) just different RPL's. If we have DS=0x10 with CPL=0 then DS=0x11 does set DS.RPL=1 (for ring 1.)
In number 0x10(0000000000010 0 00) index is 10(2), so null-descriptor is at index 0 and code-descriptor is at index 1?
That is correct.

afdgdhfrtewdszs
Posts:18
Joined:Tue Feb 01, 2011 6:25 pm

Re: GDT help

Post by afdgdhfrtewdszs » Mon Nov 26, 2012 11:57 pm

RPL is only for ds?How do we initially set CPL?

User avatar
Mike
Site Admin
Posts:465
Joined:Sat Oct 20, 2007 7:58 pm
Contact:

Re: GDT help

Post by Mike » Tue Nov 27, 2012 3:54 am

Hello,

The CPL is only set by the processor that controls it, you cannot set it directly. The software needs to request a new protection level change by setting the RPL bits in the segment registers. If the processor allows it, the RPL becomes the new CPL. This is a layer of protection: the processor can perform additional checks so only higher privilege software can set the CPL. Initially the processor(s) that are running are in CPL=0 (kernel mode) so you don't need to set it initially.

For example, you can enter user mode (ring 3) from kernel mode (ring 0) by setting CS.RPL=3 and performing a far call or return. The CPU compares the RPL with the respective DPL and CPL to see if the running program can do this (it can here; we assume CPL=0 and DPL=0 for kernel code in this example) so CPL is set to RPL (so we enter user mode.) If, on the other hand, the running program was user mode (ring 3) that requests RPL=0 for kernel mode, the CPU will not set CPL=RPL and issue a #GPF.

All segment selectors in protected mode have the same bit fields and so all have an RPL field.

afdgdhfrtewdszs
Posts:18
Joined:Tue Feb 01, 2011 6:25 pm

Re: GDT help

Post by afdgdhfrtewdszs » Wed Nov 28, 2012 9:09 am

Hi,
Thanks again for your valuable help. If the OS wants to give control to a program(and needs to go to user-mode), once program finishes its execution and want to give control back to OS, how will OS go to ring-0 since it can't go from ring-3 to ring-0?

Is 'jmp 0x8:Stage2' the same with the following?
mov cs,0x8
jmp Stage2


Keep up the good work!

User avatar
Mike
Site Admin
Posts:465
Joined:Sat Oct 20, 2007 7:58 pm
Contact:

Re: GDT help

Post by Mike » Wed Nov 28, 2012 8:54 pm

Hello,
If the OS wants to give control to a program(and needs to go to user-mode), once program finishes its execution and want to give control back to OS, how will OS go to ring-0 since it can't go from ring-3 to ring-0?
Typically the OS provides a kernel or executive API that user mode programs can call. One of these functions will be for terminating the current program: ExTerminateProcess on Windows or exit on Linux for some examples. User mode programs can call these functions (and go into kernel land) by using a trap instruction such as int, syscall, and sysenter. Modern operating systems use syscall or sysenter however most all support int.

Here is a more complete example. Lets say we are using int 0x80 for our system API. We want int 0x80 function 1 to be our exit function. The int 0x80 ISR might offset into a system call table and call the function _systemCalls [1] inside of the kernel which calls our TerminateProcess. The user mode program can then issue int 0x80, ax=1 to call the ISR. The CPU switches to ring 0 using the TSS to set the segment registers and kernel stack (recall that int is a trap instruction). We are now in the ISR in kernel land where TerminateProcess is called. The OS knows what the last program that executed was, so knows what program to terminate.

All of the user mode programs terminate by calling the operating system by either a trap instruction or, in worse case, exception.
Is 'jmp 0x8:Stage2' the same with the following?
mov cs,0x8
jmp Stage2
Sure, but the above is not technically valid code as CS cannot be set directly. An alternative method that is valid is to use a stack and perform a far return:

Code: Select all

push 0x8
push Stage2
retf

afdgdhfrtewdszs
Posts:18
Joined:Tue Feb 01, 2011 6:25 pm

Re: GDT help

Post by afdgdhfrtewdszs » Wed Nov 28, 2012 10:57 pm

Thanks a lot! Really helpful!

Post Reply