GDT Tutorial: Difference between revisions
Jump to navigation
Jump to search
[unchecked revision] | [unchecked revision] |
Content deleted Content added
m fix typos, missing verb |
m clean up |
||
Line 1: | Line 1: | ||
{{Rating|1}} |
{{Rating|1}} |
||
{{FirstPerson}} |
|||
In the [[:Category:x86|Intel Architecture]], and more precisely in [[protected mode]], most of the [[memory management]] and [[Interrupt Service Routines]] are controlled through tables of descriptors. Each descriptor stores information about a single object (e.g. a service routine, a task, a chunk of code or data, whatever) the CPU might need at some time. If you try, for instance, to load a new value into a [[Segment|segment register]], the CPU needs to perform safety and access control checks to see whether you're actually entitled to access that specific memory area. Once the checks are performed, useful values (such as the lowest and highest addresses) are cached in invisible registers of the CPU. |
In the [[:Category:x86|Intel Architecture]], and more precisely in [[protected mode]], most of the [[memory management]] and [[Interrupt Service Routines]] are controlled through tables of descriptors. Each descriptor stores information about a single object (e.g. a service routine, a task, a chunk of code or data, whatever) the CPU might need at some time. If you try, for instance, to load a new value into a [[Segment|segment register]], the CPU needs to perform safety and access control checks to see whether you're actually entitled to access that specific memory area. Once the checks are performed, useful values (such as the lowest and highest addresses) are cached in invisible registers of the CPU. |
||
Line 16: | Line 15: | ||
: a memory structure (part of a table) that tells the CPU the attributes of a given segment |
: a memory structure (part of a table) that tells the CPU the attributes of a given segment |
||
== What |
== What to put in a GDT == |
||
=== Basics === |
=== Basics === |
||
Line 69: | Line 68: | ||
That means whatever you load at physical address 4 MiB will appear as code at <tt>CS:0</tt> and what you load at physical address 8 MiB will appear as data at <tt>DS:0</tt>. However it might not be the best design. |
That means whatever you load at physical address 4 MiB will appear as code at <tt>CS:0</tt> and what you load at physical address 8 MiB will appear as data at <tt>DS:0</tt>. However it might not be the best design. |
||
== How |
== How to do that == |
||
=== Disable interrupts === |
=== Disable interrupts === |
||
Line 77: | Line 76: | ||
=== Filling the table === |
=== Filling the table === |
||
The above structure of <tt>GDT[]</tt> isn't complete. The actual structure of descriptors is a little messy for backwards compatibility with the 286's GDT. Base address are split on 3 different fields and you cannot encode any limit you want. Plus, here and there, you have flags that you need to set up properly if you want things to work. |
|||
<source lang="c"> |
<source lang="c"> |
||
Line 114: | Line 113: | ||
</source> |
</source> |
||
You can hard-code that rather than convert it at runtime, of course. This code assumes that you only want 32-bit segments. |
|||
=== Telling the CPU where the table stands === |
=== Telling the CPU where the table stands === |
||
Line 122: | Line 121: | ||
==== From real mode ==== |
==== From real mode ==== |
||
The linear address should here be computed as <tt>segment * 16 + offset</tt>. |
The linear address should here be computed as <tt>segment * 16 + offset</tt>. <tt>GDT</tt> and <tt>GDT_end</tt> are assumed to be symbols in the current data segment. |
||
<source lang="asm"> |
<source lang="asm"> |
||
Line 143: | Line 142: | ||
==== From flat, protected mode ==== |
==== From flat, protected mode ==== |
||
"Flat" meaning the base of your data segment is 0 (regardless of whether paging is on or off). This is the case if you're just been booted by [[GRUB]], for instance. |
"Flat" meaning the base of your data segment is 0 (regardless of whether paging is on or off). This is the case if you're just been booted by [[GRUB]], for instance. You should call this as <tt>setGdt(GDT, sizeof(GDT))</tt>. |
||
<source lang="asm"> |
<source lang="asm"> |
||
Line 183: | Line 182: | ||
An explanation of the above code can be found [http://stackoverflow.com/questions/23978486/far-jump-in-gdt-in-bootloader here]. |
An explanation of the above code can be found [http://stackoverflow.com/questions/23978486/far-jump-in-gdt-in-bootloader here]. |
||
== |
== The LDT == |
||
Much like the GDT (global descriptor table), the LDT (''local'' descriptor table) contains descriptors for memory segments description, call gates, etc. The good thing with the LDT is that each task can have its own LDT and that the processor will automatically switch to the right LDT when you use hardware task switching. |
Much like the GDT (global descriptor table), the LDT (''local'' descriptor table) contains descriptors for memory segments description, call gates, etc. The good thing with the LDT is that each task can have its own LDT and that the processor will automatically switch to the right LDT when you use hardware task switching. |
||
Line 200: | Line 199: | ||
Note that with 386+ processors, the paging has made LDT almost obsolete, and there's no longer need for multiple LDT descriptors, so you can almost safely ignore the LDT for OS developing, unless you have by design many different segments to store. |
Note that with 386+ processors, the paging has made LDT almost obsolete, and there's no longer need for multiple LDT descriptors, so you can almost safely ignore the LDT for OS developing, unless you have by design many different segments to store. |
||
== |
== The IDT and why it's needed == |
||
As said above, the IDT (Interrupt Descriptor Table) loads much the same way as the GDT and its structure is roughly the same except that it only contains gates and not segments. Each gate gives a full reference to a piece of code (code segment, privilege level and offset to the code in that segment) that is now bound to a number between 0 and 255 (the slot in the IDT). |
As said above, the IDT (Interrupt Descriptor Table) loads much the same way as the GDT and its structure is roughly the same except that it only contains gates and not segments. Each gate gives a full reference to a piece of code (code segment, privilege level and offset to the code in that segment) that is now bound to a number between 0 and 255 (the slot in the IDT). |
||
The IDT will be one of the first things to be enabled in your kernel sequence, so that you can catch hardware exceptions, listen to external events, etc. See [[Interrupts |
The IDT will be one of the first things to be enabled in your kernel sequence, so that you can catch hardware exceptions, listen to external events, etc. See [[Interrupts]] for more information about the interrupts of X86 family. |
||
==Some stuff to make your life easy== |
== Some stuff to make your life easy == |
||
Tool for easily creating GDT entries. |
Tool for easily creating GDT entries. |