int init_gdt() { /* initialize the pointer */ gdt_ptr.limit = (sizeof(gdt_entry_t) * NUM_GDT) -1; /* the size of our gdt entry is 5 gdt entries */ // gdt_ptr.base = (u32int)&gdt_entries; /* store the gdt register from where ever gdt_entries begins */ gdt_ptr.base = (unsigned int)&gdt_entries; /* store the gdt register from where ever gdt_entries begins */ /* set the gates */ /* from intel manuals : "The architecture also defines a set of special descriptors called gates (call gates, interrupt gates, trap gates, and task gates). These provide protected gateways to system procedures and handlers that may operate at a different privilege level than application programs and most procedures. For example, a CALL to a call gate can provide access to a procedure in a code segment that is at the same or a numerically lower privilege level (more privileged) than the current code segment. To access a procedure through a call gate, the calling procedure supplies the selector for the call gate. The processor then performs an access rights check on thecall gate, comparing the CPL with the privilege level of the call gate and the destination code segment pointed to by the call gate" */ /* TODO: understand why the segment bases and limits are allowed to overlap - is it physical or virtual memory? how binary and hexadecimal conversions, CF, 9A and so on work */ /* set the gates. Only the access byte changes. */ gdt_set_gate(NULL, NULL, NULL, NULL, NULL); // NULL segment, required for some reason gdt_set_gate(1, 0, 0xFFFFFFFF, 0x9A, 0xCF); // Ring 0 Code segment gdt_set_gate(2, 0, 0xFFFFFFFF, 0x92, 0xCF); // Ring 0 Data segment gdt_set_gate(3, 0, 0xFFFFFFFF, 0xFA, 0xCF); // Ring 3 (User mode) code segment gdt_set_gate(4, 0, 0xFFFFFFFF, 0xF2, 0xCF); // Ring 3 (User mode) data segment gdt_flush(); /* an asm routine to lgdt gdt_ptr and set up the segment registers */ return 1; }
/* Should be called by main. This will setup the special GDT * pointer, set up the first 3 entries in our GDT, and then * finally call gdt_flush() in our assembler file in order * to tell the processor where the new GDT is and update the * new segment registers */ void gdt_install() { /* Setup the GDT pointer and limit */ gp.limit = (sizeof(struct gdt_entry) * 3) - 1; gp.base = (unsigned int) &gdt; /* Our NULL descriptor */ gdt_set_gate(0, 0, 0, 0, 0); /* The second entry is our Code Segment. The base address * is 0, the limit is 4GBytes, it uses 4KByte granularity, * uses 32-bit opcodes, and is a Code Segment descriptor. * Please check the table above in the tutorial in order * to see exactly what each value means */ gdt_set_gate(1, 0, 0xFFFFFFFF, 0x9A, 0xCF); /* The third entry is our Data Segment. It's EXACTLY the * same as our code segment, but the descriptor type in * this entry's access byte says it's a Data Segment */ gdt_set_gate(2, 0, 0xFFFFFFFF, 0x92, 0xCF); //sys_tss.ss0 = 0x10; //sys_tss.iomap = (unsigned short) sizeof(struct tss_entry_struct); gdt_set_gate(3, 0, 0xFFFFFFFF, 0xFA, 0xCF); gdt_set_gate(4, 0, 0xFFFFFFFF, 0xF2, 0xCF); //unsigned long addr = &sys_tss; //int size = sizeof(struct tss_entry_struct)+1; //gdt_set_gate(5, addr, addr+size, 0x86, 0xCF); gdt_flush((uint32_t)&gp); }
void init_gdt() { //Sets up the gdt pointer gdtp.limit = (sizeof(struct gdt_entry)*GDT_LEN)-1; gdtp.base = (unsigned int)&gdt_table; /*the first NULL entry*/ gdt_set_gate(0, 0,0,0,0); // 0x9A, 0x92, 0xFA, 0xF2 gdt_set_gate(1, 0, 0xFFFFFFFF, 0x9A, 0xCF); gdt_set_gate(2, 0, 0xFFFFFFFF, 0x92, 0xCF); gdt_set_gate(3, 0, 0xFFFFFFFF, 0xFA, 0xCF); gdt_set_gate(4, 0, 0xFFFFFFFF, 0xF2, 0xCF); // Ok, add the tss set_tss(5, 0x10, 0x0); /*actually flushes gdt with lgdt code*/ gdt_flush((unsigned int)&gdtp); // now flush the TSS tss_flush(); }
/* Should be called by main. This will setup the special GDT * pointer, set up the first 3 entries in our GDT, and then * finally call gdt_flush() in our assembler file in order * to tell the processor where the new GDT is and update the * new segment registers */ void gdt_install() { kprintc(":: Installing ", BLACK, LIGHT_RED); kprintc("GDT\n", BLACK, LIGHT_CYAN); /* Setup the GDT pointer and limit */ gp.limit = (sizeof(struct gdt_entry) * 3) - 1; gp.base = (int)&gdt; /* Our NULL descriptor */ gdt_set_gate(0, 0, 0, 0, 0); /* The second entry is our Code Segment. The base address * is 0, the limit is 4GBytes, it uses 4KByte granularity, * uses 32-bit opcodes, and is a Code Segment descriptor. * Please check the table above in the tutorial in order * to see exactly what each value means */ gdt_set_gate(1, 0, 0xFFFFFFFF, 0x9A, 0xCF); /* The third entry is our Data Segment. It's EXACTLY the * same as our code segment, but the descriptor type in * this entry's access byte says it's a Data Segment */ gdt_set_gate(2, 0, 0xFFFFFFFF, 0x92, 0xCF); /* Flush out the old GDT and install the new changes! */ gdt_flush(); }
/** * @brief setup GDT * * Should be called by main. This will setup the special GDT * pointer, set up the first 3 entries in our GDT, and then * finally call gdt_flush() in our assembler file in order * to tell the processor where the new GDT is and update the * new segment registers */ void gdt_install() { /* Setup the GDT pointer and limit */ struct gdt_ptr gp; gp.limit = (sizeof(struct gdt_entry) * 10) - 1; gp.base = (unsigned int)&gdt; /* Our NULL descriptor */ gdt_set_gate(0, 0, 0, 0, 0); /* The second entry is our Code Segment. The base address * is 0, the limit is 4GBytes, it uses 4KByte granularity, * uses 32-bit opcodes, and is a Code Segment descriptor. * Please check the table above in the tutorial in order * to see exactly what each value means */ gdt_set_gate(1, 0, 0xFFFFFFFF, 0x9A, 0xCF); /* The third entry is our Data Segment. It's EXACTLY the * same as our code segment, but the descriptor type in * this entry's access byte says it's a Data Segment */ gdt_set_gate(2, 0, 0xFFFFFFFF, 0x92, 0xCF); /* The 4th entry is gdt_video: Descriptor 0B8000h, 0ffffh, DA_DRW | 0xcf00 ; VGA address */ gdt_set_gate(3, 0xB8000, 0xFFFFFFFF, 0x92, 0xCF); /* Flush out the old GDT and install the new changes! */ gdt_flush(gp); }
void gdt_flush(void) { asm("lgdtl (gdtptr)"); asm("movw $0x10, %ax\n \ movw %ax, %ds\n \ movw %ax, %es\n \ movw %ax, %fs\n \ movw %ax, %gs\n \ movw %ax, %ss\n \ ljmp $0x08, $next\n \ next: \n"); } void init_gdt(void) { gdtptr.limit = (sizeof(t_gdt_entry) * 5) - 1; gdtptr.base = (uint)&gdt_entries; gdt_set_gate(0, 0, 0, 0, 0); // Null segment gdt_set_gate(1, 0, 0xFFFFFFFF, 0x9A, 0xCF); // Code segment gdt_set_gate(2, 0, 0xFFFFFFFF, 0x92, 0xCF); // Data segment gdt_set_gate(3, 0, 0xFFFFFFFF, 0xFA, 0xCF); // User mode code segment gdt_set_gate(4, 0, 0xFFFFFFFF, 0xF2, 0xCF); // User mode data segment gdt_flush(); }
void gdt_install() { gp.limit = (sizeof(gdt_entry) * 3) - 1; gp.base = (int)&gdt; gdt_set_gate(0, 0, 0, 0, 0); gdt_set_gate(1, 0, 0xFFFFFFFF, 0x9A, 0xCF); gdt_set_gate(2, 0, 0xFFFFFFFF, 0x92, 0xCF); gdt_flush(); }
// Setup the GDT pointer and create the three entries (gates) we // want to use: // 1: Null descriptor (See Tutorial) // 2: Describes the code segment (Base address is 0, limit is 4GBytes, // use 4 KBytes granularity, 32bit coding and a Code Segment descriptor. // 3: Data segment which is the same as the data segment except the access // flag which tells it is a data segment. void gdt_install() { /* Setup the GDT pointer and limit */ gdt_p.limit = (sizeof(gdt_entry_t) * 3) - 1; gdt_p.base = (unsigned int)&gdt; // convert pointer to unsigned int gdt_set_gate(0, 0, 0, 0, 0); gdt_set_gate(1, 0, 0xFFFFFFFF, 0x9A, 0xCF); gdt_set_gate(2, 0, 0xFFFFFFFF, 0x92, 0xCF); // Flush the old GDT and install the new one. This code // can be found in start.asm. gdt_flush(); }
void gdt_init() { gdtp.limit = (sizeof(struct gdt_entry) * 3) - 1; gdtp.base = (uint32_t)&gdt; // 0x2000000 gdt_set_gate(0, 0, 0, 0, 0); gdt_set_gate(1, 0, 0xFFFFFFFF, 0x9A, 0xCF); gdt_set_gate(2, 0, 0xFFFFFFFF, 0x92, 0xCF); __gdt_flush(); }
void gdt_install() /// Initiates our GDT with flat 32-bit addresses. { gp.limit = (sizeof(struct gdt_entry) * 3) - 1; // Set up the Pointer gp.base = (unsigned int)&gdt; // To the Table gdt_set_gate(0, 0, 0, 0, 0); // 1st Descriptor is null gdt_set_gate(1, 0, 0xFFFFFFFF, 0x9A, 0xCF); // Code Segment, Kernel Mode gdt_set_gate(2, 0, 0xFFFFFFFF, 0x92, 0xCF); // Data Segment, Kernel Mode gdt_flush(); // Tell CPU we have a new GDT }
static void init_gdt(void){ _gdt_ptr.limit = sizeof(gdt_entry_t)*5 - 1; _gdt_ptr.base = (uint32_t)&_gdt; gdt_set_gate(0, 0, 0, 0, 0); // Null segment gdt_set_gate(1, 0, 0xFFFFFFFF, 0x9A, 0xCF); // Code segment gdt_set_gate(2, 0, 0xFFFFFFFF, 0x92, 0xCF); // Data segment gdt_set_gate(3, 0, 0xFFFFFFFF, 0xFA, 0xCF); // User mode code segment gdt_set_gate(4, 0, 0xFFFFFFFF, 0xF2, 0xCF); // User mode data segment __flush_gdt((uint32_t)&_gdt_ptr); }
void gdt_install ( void ) { gp.limit = ( sizeof ( struct gdt_entry ) * 3 ) - 1; gp.base = (unsigned int) &gdt; gdt_set_gate ( 0, 0, 0, 0, 0 ); //NULL descriptor gdt_set_gate ( 1, 0, 0xFFFFFFFF, 0x9A, 0xCF); //Code segment gdt_set_gate(2, 0, 0xFFFFFFFF, 0x92, 0xCF); //Data segment gdt_flush(); printline ("Installed GDT"); }
void init_gdt() { terminal_writestring("Initiating GDT... "); gdt_ptr.limit = (sizeof(gdt_entry_t) * 3) - 1; gdt_ptr.base = (uint32_t)&gdt_entries; gdt_set_gate(0, 0, 0, 0, 0); // Null segment gdt_set_gate(1, 0, 0xFFFFFFFF, 0x9A, 0xCF); // Kernel code segment gdt_set_gate(2, 0, 0xFFFFFFFF, 0x92, 0xCF); // Kernel data segment gdt_flush((uint32_t)&gdt_ptr); terminal_writestring("DONE\n"); }
void gdt_init(void) { gdt_set_gdtr(&gdt_ptr, gdt); gdt_set_gate(0, 0, 0, 0, 0); /* NULL Descriptor */ gdt_set_gate(GDT_ENTRY_KERNEL_CS, 0, 0xFFFFFFFF, 0x9A, 0xCF); gdt_set_gate(GDT_ENTRY_KERNEL_DS, 0, 0xFFFFFFFF, 0x92, 0xCF); gdt_set_gate(GDT_ENTRY_USER_CS, 0, 0xFFFFFFFF, 0xFA, 0xCF); gdt_set_gate(GDT_ENTRY_USER_DS, 0, 0xFFFFFFFF, 0xF2, 0xCF); /* TSS is filled in usermode (if we have) */ gdt[GDT_ENTRY_TSS].access &= ~GDT_BUSY_FLAG; gdt_flush(&gdt_ptr); }
static void init_gdt() { gdt_ptr.limit = (sizeof(gdt_entry_t) * 5) - 1; gdt_ptr.base = (u32int) &gdt_entries; gdt_set_gate(0, 0, 0, 0, 0); gdt_set_gate(1, 0, 0xFFFFFFFF, 0x9A, 0xCF); // code seg gdt_set_gate(2, 0, 0xFFFFFFFF, 0x92, 0xCF); // data seg gdt_set_gate(3, 0, 0xFFFFFFFF, 0xFA, 0xCF); // user code seg gdt_set_gate(4, 0, 0xFFFFFFFF, 0xF2, 0xCF); // user data seg gdt_flush((u32int) &gdt_ptr); }
// Init the GDT by setting its values static void init_gdt() { gdt_ptr.limit = (sizeof(gdt_entry_t) * 5) - 1; gdt_ptr.base = (u32int)&gdt_entries; gdt_set_gate(0, 0, 0, 0, 0); gdt_set_gate(1, 0, 0xFFFFFFFF, 0X9A, 0XCF); gdt_set_gate(2, 0, 0xFFFFFFFF, 0X92, 0XCF); gdt_set_gate(3, 0, 0xFFFFFFFF, 0XFA, 0XCF); gdt_set_gate(4, 0, 0xFFFFFFFF, 0XF2, 0XCF); gdt_flush((u32int)&gdt_ptr); }
static void init_gdt() { gdt_ptr.limit = (sizeof(gdt_entry_t) * 5) - 1; gdt_ptr.base = (u32int)&gdt_entries; gdt_set_gate(0, 0, 0, 0, 0); // Null segment gdt_set_gate(1, 0, 0xFFFFFFFF, 0x9A, 0xCF); // CS gdt_set_gate(2, 0, 0xFFFFFFFF, 0x92, 0xCF); // DS gdt_set_gate(3, 0, 0xFFFFFFFF, 0xFA, 0xCF); // User CS gdt_set_gate(4, 0, 0xFFFFFFFF, 0xF2, 0xCF); // User DS gdt_flush((u32int)&gdt_ptr); }
static void init_gdt() { gdt_ptr.limit = (sizeof(gdt_entry_t) * 5) - 1; gdt_ptr.base = (uint32)&gdt_entries; gdt_set_gate(0, 0, 0, 0, 0); // Null segment gdt_set_gate(1, 0, 0xFFFFFFFF, 0x9A, 0xCF); // Code segment gdt_set_gate(2, 0, 0xFFFFFFFF, 0x92, 0xCF); // Data segment gdt_set_gate(3, 0, 0xFFFFFFFF, 0xFA, 0xCF); // User mode code segment gdt_set_gate(4, 0, 0xFFFFFFFF, 0xF2, 0xCF); // User mode data segment gdt_flush((uint32)&gdt_ptr); }
static void init_gdt() { gdt_ptr.limit = (sizeof(gdt_entry_t) * GDT_ENTRIES) - 1; gdt_ptr.base = (uint32_t)&gdt_entries; gdt_set_gate(0, 0, 0, 0, 0); // Null segment gdt_set_gate(1, SEGMENT_BASE, SEGMENT_LIMIT, 0x9A, 0xCF); // Kernel Code segment gdt_set_gate(2, SEGMENT_BASE, SEGMENT_LIMIT, 0x92, 0xCF); // Kernel Data segment gdt_set_gate(3, SEGMENT_BASE, SEGMENT_LIMIT, 0xFA, 0xCF); // User mode code segment gdt_set_gate(4, SEGMENT_BASE, SEGMENT_LIMIT, 0xF2, 0xCF); // User mode data segment gdt_flush((uint32_t)&gdt_ptr); }
static void init_gdt() { gdt_ptr.limit = (sizeof(gdt_entry) * 5) - 1; gdt_ptr.base = (unsigned int)&gdt_entries; gdt_set_gate(0, 0, 0, 0, 0); gdt_set_gate(1, 0, 0xFFFFFFFF, 0x9A, 0xCF); gdt_set_gate(2, 0, 0xFFFFFFFF, 0x92, 0xCF); gdt_set_gate(3, 0, 0xFFFFFFFF, 0xFA, 0xCF); gdt_set_gate(4, 0, 0xFFFFFFFF, 0xF2, 0xCF); gdt_flush((unsigned int)&gdt_ptr); }
/* * static function implementation */ static void gdt_init() { log(LOG_TAG_INFO, "Init global descriptor tables"); gdt_ptr.limit = (sizeof(gdt_entry_t) * 5) - 1; gdt_ptr.base = (u32int)&gdt_entries; gdt_set_gate(0, 0, 0, 0, 0); //Null segment gdt_set_gate(1, 0, 0xFFFFFFFF, 0x9A, 0xCF); //Code segemnt gdt_set_gate(2, 0, 0xFFFFFFFF, 0x92, 0xCF); //Data segment gdt_set_gate(3, 0, 0xFFFFFFFF, 0xFA, 0xCF); //User mode code segment gdt_set_gate(4, 0, 0xFFFFFFFF, 0xF2, 0xCF); //User mode data segment gdt_flush((u32int)& gdt_ptr); }
static void init_gdt() { gdt_ptr.limit = (sizeof(gdt_entry_t)*5)-1; // forgive me gdt_ptr.base = (u32int)&gdt_entries; gdt_set_gate(0,0,0,0,0); //null segment gdt_set_gate(1,0,LIMIT,0x9A,0xCF); // kernel code segment gdt_set_gate(2,0,LIMIT,0x92,0xCF); // kernel data segment gdt_set_gate(3,0,LIMIT,0xFA,0xCF); // user code segment gdt_set_gate(4,0,LIMIT,0xF2,0xCF); // user data segment gdt_flush((u32int)&gdt_ptr); }
static void init_gdt() { gdt_ptr.limit = (sizeof(gdt_entry_t) * 5) - 1; gdt_ptr.base = (uint32_t)&gdt_entries; gdt_set_gate(0, 0, 0, 0, 0); // Null segment gdt_set_gate(1, 0, 0xFFFFFFFF, 0x9A, 0xCF); // Code segment gdt_set_gate(2, 0, 0xFFFFFFFF, 0x92, 0xCF); // Data segment gdt_set_gate(3, 0, 0xFFFFFFFF, 0xFA, 0xCF); // User mode code segment gdt_set_gate(4, 0, 0xFFFFFFFF, 0xF2, 0xCF); // User mode data segment gdt_flush((uint32_t)&gdt_ptr); kprintf("GDT:: Finished init of GDT AND it's in memory! :D\n"); }
void gdt_install() { gp.limit = (sizeof(struct gdt_entry) * 3) - 1; // Limit of GDT gp.base = (int)&gdt; // Base address of GDT gdt_set_gate(0, 0, 0, 0, 0); // GDT must start with a NULL descriptor /* Base Address = 0, limit = 4GB, Granularity = 4KB, 32 bit opcodes, type = Code Segment */ gdt_set_gate(1, 0, 0xFFFFFFFF, 0x9A, 0xCF); // 0x9A = 10011010, 0xCF = 11001111 /* Base Address = 0, limit = 4GB, Granularity = 4KB, 32 bit opcodes, type = Data Segment */ gdt_set_gate(2, 0, 0xFFFFFFFF, 0x92, 0xCF); // 0x92 = 10010010, 0xCF = 11001111 gdt_flush(); // Gets rid of the old GDT and installs the changes }
void gdt_init() { //Setup GDT pointer gdtp.limit=(sizeof(struct gdt_entry)*GDT_COUNT)-1; gdtp.base=(unsigned int)&gdt; //NULL Descriptor gdt_set_gate(0,0,0,0,0); //Code segment gdt_set_gate(1,0,0xFFFFFFFF,0x9A,0xCF); //Data segment gdt_set_gate(2,0,0xFFFFFFFF,0x92,0xCF); //Code segment gdt_set_gate(3,0,0xFFFFFFFF,0xFA,0xCF); //Data segment gdt_set_gate(4,0,0xFFFFFFFF,0xF2,0xCF); //Task state segment gdt_set_gate(5,(unsigned int)&mt_task_state_segment,(unsigned int)&mt_task_state_segment + sizeof(mt_task_state_segment) + 1,0x89,0x40); //16-bit Code segment gdt_set_gate(6,0,0xFFFF,0x9A,0x00); //16-bit Data segment gdt_set_gate(7,0,0xFFFF,0x92,0x00); //Setup GDT gdt_setup(); }
/* * 初始化GDT */ void init_gdt() { // 设置GDT指针 gdt_ptr.limit = (sizeof(struct gdt_entry_struct) * 5) - 1; gdt_ptr.base = (u_int32)&gdt_entries; // 设置全局描述符 gdt_set_gate(0, 0, 0, 0, 0); // 第一个为全0 gdt_set_gate(1, 0, 0xFFFFFFFF, 0x9A, 0xCF); // 代码段 gdt_set_gate(2, 0, 0xFFFFFFFF, 0x92, 0xCF); // 数据段 gdt_set_gate(3, 0, 0xFFFFFFFF, 0xFA, 0xCF); // 用户模式代码段 gdt_set_gate(4, 0, 0xFFFFFFFF, 0xF2, 0xCF); // 用户模式数据段 // 将GDT写到GDTR gdt_flush((u_int32)&gdt_ptr); }
/* gdt_install * * Set up our GDT. */ void gdt_install() { gp.limit = (sizeof(struct gdt_entry) * 3) - 1; gp.base = (unsigned int)&gdt; /* Set up the null descriptor. */ gdt_set_gate(0, 0, 0, 0, 0); /* Set up the text segment descriptor. */ gdt_set_gate(1, 0, 0xFFFFFFFF, 0x9A, 0xCF); /* Set up the data segment descriptor. */ gdt_set_gate(2, 0, 0xFFFFFFFF, 0x92, 0xCF); gdt_flush(); }
static void write_tss(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_entry; uint32_t limit = base + sizeof(tss_entry); // Now, add our TSS descriptor's address to the GDT. gdt_set_gate(num, base, limit, 0xE9, 0x00); // Ensure the descriptor is initially zero. memset(&tss_entry, 0, sizeof(tss_entry)); tss_entry.ss0 = ss0; // set the kernel stack segment tss_entry.esp0 = esp0; // set the kernel stack pointer // Here we set the cs, ss, ds, es, fs and gs entries in the TSS. // These specify what segments should be loaded when the processor // switches to kernel mode. Therefore they are just our normal // kernel code/data segments - 0x08 and 0x10 respectively, // but with the last two bits set, making 0x0b and 0x13. // The setting of these bits sets the RPL (requested privilege level) // to 3, meaning that this TSS can be used to switch to // kernel mode from ring 3. tss_entry.cs = 0x0b; tss_entry.ss = tss_entry.ds = tss_entry.es = tss_entry.fs = tss_entry.gs = 0x13; }
/** * Write a TSS (we only do this once) */ static void write_tss( int32_t num, uint16_t ss0, uint32_t esp0 ) { uintptr_t base = (uintptr_t)&tss_entry; uintptr_t limit = base + sizeof(tss_entry); /* Add the TSS descriptor to the GDT */ gdt_set_gate(num, base, limit, 0xE9, 0x00); memset(&tss_entry, 0x0, sizeof(tss_entry)); tss_entry.ss0 = ss0; tss_entry.esp0 = esp0; /* Zero out the descriptors */ tss_entry.cs = 0x0b; tss_entry.ss = tss_entry.ds = tss_entry.es = tss_entry.fs = tss_entry.gs = 0x13; tss_entry.iomap_base = sizeof(tss_entry); }
/* Init the task state segment structure */ static void tss_write(int32_t num, uint16_t ss0, uint32_t esp0) { uint32_t base, limit; /* Firstly, let's compute the base and limit of our entry into the GDT */ base = (uint32_t) &tss_entry; limit = base + sizeof(tss_entry); /* Now add the TSS descriptor's address to the GDT */ gdt_set_gate(num, base, limit, 0xE9, 0x00); /* Ensure the descriptor is initially zero */ memset(&tss_entry, 0, sizeof(tss_entry)); tss_entry.ss0 = ss0; /* Set the kernel stack segment */ tss_entry.esp0 = esp0; /* Set the kernel stack pointer */ /* Here we set the cs, ss, ds, es, fs and gs entries in the TSS. The specify * what segments should be loaded when the processor switches to kernel mode. * Therefore they are just the normal kernel code/data segments - 0x08 and * 0x10 respectively, but with the last two bits set, making 0x0b and 0x13. * The setting of these bits sets the RP (Requested Privilege Level) to 3, * meaning that this TSS can be used to switch to kernel mode from ring 3 */ tss_entry.cs = 0x0b; tss_entry.ss = tss_entry.ds = tss_entry.es = tss_entry.fs = tss_entry.gs = 0x13; }