E
in PrettyOS sieht das so aus am Anfang:
// "Segment Present" bit 7
#define VALID 0x80
// "Deskriptor Privilege Level" bit 6:5
#define RING_0 0x00
#define RING_1 0x20
#define RING_2 0x40
#define RING_3 0x60
// "Segment" bit 4
#define SYSTEM 0x00
#define CODE_DATA_STACK 0x10
// "Descriptor Type" bit 3:1
#define DATA_READ_ONLY 0x0 // ....000.
#define DATA_READ_WRITE 0x2 // ....001.
#define STACK_READ_ONLY 0x4 // ....010.
#define STACK_READ_WRITE 0x6 // ....011.
#define CODE_EXEC_ONLY 0x8 // ....100.
#define CODE_EXEC_READ 0xA // ....101.
#define CODE_EXEC_ONLY_CONF 0xC // ....110.
#define CODE_EXEC_READ_CONF 0xE // ....111.
// "Segment Accessed" bit 0
#define SEGM_ACCESSED 0x1
/**********************/
/* Parameter "gran" */
/**********************/
// "granularity" bit 7
#define _BYTE_ 0x00
#define _4KB_ 0x80
// "Default Operation Size" bit 6
#define USE16 0x00
#define USE32 0x40
// Defines a GDT entry
typedef struct
{
uint16_t limit_low;
uint16_t base_low;
uint8_t base_middle;
uint8_t access;
uint8_t granularity;
uint8_t base_high;
} __attribute__((packed)) GDTentry_t;
typedef struct
{
uint16_t limit;
uint32_t base;
} __attribute__((packed)) GDTptr_t;
void gdt_install(void)
{
GDTptr_t gdt_register;
// Setup the GDT pointer and limit
gdt_register.limit = (sizeof(GDTentry_t) * NUMBER_GDT_GATES)-1;
gdt_register.base = (uint32_t)&gdt;
// GDT GATES - desriptors with pointers to the linear memory address
gdt_setGate(0,0,0,0,0); // NULL descriptor
// num base limit access gran
gdt_setGate(1, 0, 0xFFFFF, VALID | RING_0 | CODE_DATA_STACK | CODE_EXEC_READ, _4KB_ | USE32);
gdt_setGate(2, 0, 0xFFFFF, VALID | RING_0 | CODE_DATA_STACK | DATA_READ_WRITE, _4KB_ | USE32);
gdt_setGate(3, 0, 0xFFFFF, VALID | RING_3 | CODE_DATA_STACK | CODE_EXEC_READ, _4KB_ | USE32);
gdt_setGate(4, 0, 0xFFFFF, VALID | RING_3 | CODE_DATA_STACK | DATA_READ_WRITE, _4KB_ | USE32);
tss_write(5, 0x10, 0x0); // num, ss0, esp0
gdt_flush(&gdt_register);
tss_flush();
}
void gdt_setGate(int32_t num, uint32_t base, uint32_t limit, uint8_t access, uint8_t gran)
{
// Setup the descriptor base address
gdt[num].base_low = base & 0xFFFF;
gdt[num].base_middle = (base >> 16) & 0xFF;
gdt[num].base_high = (base >> 24) & 0xFF;
// Setup the descriptor limits
gdt[num].limit_low = limit & 0xFFFF;
gdt[num].granularity = (limit >> 16) & 0x0F;
// Finally, set up the granularity and access flags
gdt[num].granularity |= (gran & 0xF0);
gdt[num].access = access;
}
// Initialise our task state segment structure.
void tss_write(int32_t num, uint16_t ss0, uint32_t esp0)
{
// Firstly, let's compute the base and limit of our entry into the GDT.
uint32_t base = (uint32_t)&tss;
uint32_t limit = sizeof(tss); //http://forum.osdev.org/viewtopic.php?f=1&t=19819&p=155587&hilit=tss_entry#p155587
// Now, add our TSS descriptor's address to the GDT.
gdt_setGate(num, base, limit, 0xE9, 0x00);
tss.ss0 = ss0; // Set the kernel stack segment.
tss.esp0 = esp0; // Set the kernel stack pointer.
tss.cs = 0x08;
tss.ss = tss.ds = tss.es = tss.fs = tss.gs = 0x10;
#ifdef _DIAGNOSIS_
tss_log(&tss);
#endif
}