Page 1 of 1

Global Descriptor Table -- whoa

Posted: Tue Apr 12, 2005 4:50 pm
by Warrior
Hello again. I have gotten a little farther since my last posts (Hello World C Kernel after using GRUB) . Now I want to setup a GDT for my OS. This is good. Well I'm writing my C code to be more in assembly as opposed to C (don't ask why my coding style)

Something like this

Code: Select all

void init_gdt()
{
???/* We want to jump to our Assembly code for the GDT */
???
???gdt_install();
???notify_kernel("The Global Descriptor Table has been loaded");???
??????return; /* Return Back to main() */
}
gdt_install() refrencing code in my assembly stub .

Now I know that you must have a Dummy, Code, and Data entry and that you must you use the lgdt instruction to load the GDT. (Pointing it to a block of code with the length of the GDT and pointer to the GDT's memory address ) Good fine.

Now, I don't like writing code when I don't know how it will help me and what it's uses are. So can someone please enlighten me on this? Thanks.

I also need to know if it's needed to make a GDT for the user space as well (Dunno, saw it in a kernel once)


All help is appreciated.

Regards,
Warrior

Re:Global Descriptor Table -- whoa

Posted: Tue Apr 12, 2005 7:29 pm
by Brendan
Hi,
Warrior wrote:Now, I don't like writing code when I don't know how it will help me and what it's uses are. So can someone please enlighten me on this? Thanks.
The GDT (Global Descriptor Table), and the optional LDT/s (Local Descriptor Tables) define the segments that software can (or is) using. Each segment consists of a base address, a limit and access rights. For example, you could create a segment with a base address of 0x1000 and a limit of 3 that can only by used by system code.

You'd need to describe each segment by creating a "descriptor", which is an 8 byte entry in the GDT (or LDT). Descriptors can be used to describe more than just segments though - there's also TSS descriptors (used for task switching) and call gates.

Most modern OS's use paging instead of segmentation by setting the base address of all segments to 0x00000000, and the limit to 0xFFFFFFFF. This effectively disables segmentation.

However, how you want to setup your GDT is up to you...

I'd recommend studying the Intel System Programmer's Guide and becoming familiar with all of the facilities supported by the CPU. Then you'd be able to design the environment your OS will provide, and use this design as a guide when creating/initializing your GDT, LDT/s (if any), paging (if used), etc. This is because things that seem simple can make a significant difference. For example, if you want to support SYSENTER and/or SYSCALL you'll need GDT entries to be in a specific order (and this little decision can force you to forget about a fully segmentated OS).
Warrior wrote:I also need to know if it's needed to make a GDT for the user space as well (Dunno, saw it in a kernel once)
Normally people use a single GDT with descriptors for both system code and user code (and one or more TSS's). You could use multiple GDT's if you want, or use LDT's, or use a different number of privilege levels (e.g. "kernel", "system" and "user"), or use a minimal number of GDT descriptors and change them dynamically, or perhaps you'll have different requirements or invent other ways to use the GDT...


Cheers,

Brendan

Re:Global Descriptor Table -- whoa

Posted: Tue Apr 12, 2005 7:35 pm
by Warrior
Thanks, Brendan. This just defines and protects locations in memory.

Also: Is there any recommended way to make use of the GDT? I was thinking of writing it in assembly just with the hardcoded descriptors.

Code: Select all

gdt_start:

; Kernel GDT
gdt_krnl_null:
gdt_krnl_code:
gdt_krnl_data:

; User GDT
gdt_user_null:
gdt_user_code:
gdt_user_data:

gdt_end:
Or something of the sorts but then again, what about writing it in C with an ASM stublet for the lgdt instruction but with the ability to dynamicly add descriptors with permissions, etc etc..? I'm not sure what advantages one has over the other :p .

One last question: Just for my sanity, is it okay to think as a GDT as a roadmap ?

Re:Global Descriptor Table -- whoa

Posted: Tue Apr 12, 2005 9:40 pm
by Brendan
Hi,
Warrior wrote:Also: Is there any recommended way to make use of the GDT?
I'd recommend using the GDT in a way that suits the overall design of the OS (without knowing the overall design of the OS I can't be more specific).
Warrior wrote:I was thinking of writing it in assembly just with the hardcoded descriptors.
Warrior wrote:Or something of the sorts but then again, what about writing it in C with an ASM stublet for the lgdt instruction but with the ability to dynamicly add descriptors with permissions, etc etc..? I'm not sure what advantages one has over the other :p .
Will your OS design require the ability to dynamically create GDT entries? If you're using flat segments and doing everything with paging, then possibly not. You could have a different descriptor for each process' CS (so that they can't execute their data), or have an OS that uses segmentation (with or without paging). Perhaps your OS compiles everything from a strict/secure language during boot, and doesn't need privilege levels, paging or segmentation (in this case you wouldn't need any GDT after boot)?

My OS uses paging for almost everything, a single GDT (and no LDTs). GDT entries below 0x800 are created statically, while the rest are created dynamically (but remain unchanged after the GDT is created). The GDT is initialized/created by boot code (third stage) before the kernel is started.

My GDT goes like this:

[tt]0x0000 NULL descriptor
0x0008 System code descriptor, base = 0, limit = 0xC01FF000
0x0010 System data descriptor, base = 0, limit =4GB
0x0018 User code descriptor, base = 0, limit = 0xC0000000
0x0020 User data descriptor, base = 0, limit = 4GB
0x0028 System code descriptor, base = 0, limit = 0xC01FF000 (for SYSCALL only)
0x0030 System data descriptor, base = 0, limit = 4GB (for SYSCALL only)
0x0038 User data descriptor, base = 0, limit = 4GB (for SYSCALL only)
0x0040 Kernel API call gate
0x0048 to 0x07F8 Unused (reserved for future use)
0x0800 First CPU's data, base = list entry address, limit = entry structure size (used by GS only)
0x0808 to 0x0FF8 Reserved for more CPU's data (up to 256 CPUs supported)
0x1000 First CPU's TSS descriptor
0x1008 to 0x17F8 Reserved for more CPU's TSSs (one TSS per CPU)
0x17FF GDT limit (8 KB only)[/tt]
Warrior wrote:One last question: Just for my sanity, is it okay to think as a GDT as a roadmap ?
I'm neither a therapist nor a judge, so it's ok with me if you choose to think of the GDT as anything you like :). Whether or not I'd consider it appropriate to use the term "roadmap" within documentation intended for other developers is another matter entirely, and would depend on the answer to following question: In what way is the GDT like a roadmap for your OS?


Cheers,

Brendan

Re:Global Descriptor Table -- whoa

Posted: Tue Apr 12, 2005 9:53 pm
by Warrior
Well it sort of maps out where everything will be, what priviledges it will have, etc.


I don't really understand call gates or SYSCALL or anything like that :| , is there a link containing information on that?

My OS will most likely use paging for everything (provided I investigate more on paging :p)


Also what about the TSS I know it has to do with task switching just don't know what it does in depth.

Thanks!

Re:Global Descriptor Table -- whoa

Posted: Wed Apr 13, 2005 2:46 am
by Pype.Clicker
as we are about segments and sysenter and all ...

iirc, SYSENTER/SYSEXIT or the amd counterpart enforces restrictions on segments' content but not their selectors, right (i mean, it may require base == 0, size == 0xFFFFFFFF, but it doesn't require user_code == 0x30 or anything alike ...)

I was thinking, if it fit one's need, nothing should prevent the use of SYSENTER in some cpu-intensive process that has lot of syscalls to do and keep a segmented model for some "less trusted" application or plugin and have the full power of segments to keep an eye on what's going on ...