What is the use of defining a Global Descriptor Table?

Panther Coder picture Panther Coder · May 31, 2016 · Viewed 7.8k times · Source

I read a tutorial on GDT (Global Descriptor Table) which defines GDT as " the one that defines base access privileges for certain parts of memory ". That means GDT is used for memory protection.

Does it perform any other tasks other than the above?

Is it a must to implement a GDT in an Operating System?

In short it would be better if anyone could elaborate on GDT in a way easy to understand.

Thanks

Answer

Margaret Bloom picture Margaret Bloom · May 31, 2016

All the images have been taken from Intel Manual 3A, §5.1.
For further details the OP should read that manual, here I will expose just some concepts simplified for the sake of brevity and to avoid a link-only answer.


As the name suggests the Global Descriptor Table is an array of descriptors available to specify and define system wide resources (hence describe those resources).

More often than not the resource is an area of continuous memory but there are other kinds of very important resources too.

The taxonomy of the descriptors is

Descriptors
    Non system descriptors

        Code segment descriptor
        Data segment descriptor
        Stack segment descriptor (Alias of the previous)

    System descriptors

        System segment descriptors

            LDT segment descriptor
            TSS segment descriptor

        Gate descriptors
            Call gate descriptor
            Interrupt gate descriptor
            Trap gate descriptor
            Task gate descriptor

Other than the GDT there is another table, the Local Descriptor Table that describes resources made available by the OS to specific contexts only.

A descriptor is identified by its table (either GDT or LDT) and its position on the table, its index.

Such index is written into specific registers, called selector registers (previously known as segment registers).
Every instruction that accesses memory implicitly or explicitly uses one of the selectors.

xor eax, eax     ;eax is zero
xor esp, esp     ;esp is zero
xor ebx, ebx     ;ebx is zero

mov ecx, DWORD [eax]      ;Use DS selector (implicit)
mov ecx, DWORD [esp]      ;Use SS selector (implicit)
mov ecx, DWORD [fs:ebx]   ;Use FS selector (explicit)

All these instructions read the logical address 0 but the CPU uses the descriptor to compute a new address, called linear address and perform security checks.
So those three instructions may end up reading totally different addresses.

Each selector also specifies the privilege which should be used when carrying out an operation.
The cs selector is special because it cannot be longer changed (it has been a while actually) with a mov but only with a branch instruction (jmp, ret, call, ...).
Its purpose is not only to be used when fetching code, it also holds the code privilege level.
This privilege level is used by the CPU to check if a resource can be accessed (with the requested privilege), checks are not always trivial.

As you will see, every descriptor has a DPL field to set its privilege level.
So they are a form of protection.

Non system descriptors

Non system descriptors are used to define regions of memory intended to store code or data along with their attributes.

Non system descriptors

As you can see, the purpose of this kind of descriptors is to designate an area of memory and attach some attributes to it.
In particular the base address, the limit (size), the privilege needed to access it (the DPL field, checks are actually more involved than this), the size of the code (code only), if read/write is allowed and so on.

Long mode (64 bits) changed how the attributes are interpreted, beware of that.

System descriptors

System descriptors are used by the OS to control user mode programs.

System segment descriptors

These descriptors define the memory area used for storing the LDT and another structure called Task State Segment (a mechanism Intel provided for easing task switching).
There can be more than one of these structures on the system, the selected ones are indicated by the ldtr (LDT register) and tsr (TS register) registers.

System segment descriptors

Gate descriptors

These are used to transfer control to other (more or less privileged) code.

Call gates

Call gate

If you look at the picture you can see that a call gate is essentially a meta descriptor, it specifies a selector and an offset into the area designated by that descriptor along with privileges.
It is used to pass control to privileged routines.

call fs:0badbabeh

Assuming fs holds a gate's index, the CPU won't use the immediate address 0badbabeh at all, it will instead use the information on the gate itself.

Interrupt and Trap gates

These are used with interrupts, the difference between the two is that the former clear the if flag, the latter doesn't.

They are very similar to call gates.

Interrupt and Trap gates

These descriptors are actually placed into another table, the Interrupt Descriptor Table usually.
This other table is not indexed with selectors but with interrupt numbers.
If I recall correctly they can also be placed in the GDT/LDT and used like other gates.

A Task gate can be used to perform a task switch.

Task gates

Task gates

These are like the call gates but transfer control to a new task (task switching).

Some resources are not simple memory area, they can be gates