I've finished developing simple (Round-Robin) multitasking in the kernel, and threads can run only in the kernel mode (ring0). So, I've begun implementing switching to and from ring3. First, I've addded three segments into the GDT: ring3 code, ring3 data, 32-bit TSS. I've added a simple TSS setting up and loading function, but Bochs reboots and in the console there is:
Code: Select all
00089235313i[CPU0 ] 0x000000000010006e>> ltr ax : 0F00D8
00089235313e[CPU0 ] exception(): 3rd (13) exception with no resolution, shutdown status is 00h, resetting
The code for setting the TSS descriptor in the GDT (`tss' is defined in the same file, with no `static'):
Code: Select all
// Setup the TSS segment.
void setup_tss (void)
{
// Set the GDT entry.
uint32_t base = (uint32_t) &tss;
uint32_t limit = base + sizeof (tss_t); // Not sure here, it's different in the code I saw.
set_gdt_entry (5, base, limit, 0xE9, 0x00); // TSS
// Zero the TSS.
memset ((uint8_t *) &tss, 0, sizeof (tss_t));
// Fill the TSS (not the whole, only the used by the OS fields).
tss.esp0 = 0; // It is changed *somewhere* in the IRQ0 handler or somewhere else, I don't know.
// But actually, I change it nowhere, since the TSS isn't loaded anyway (see the above [code] tag).
tss.ss0 = 0x10; // Data segment.
}
// Change the TSS `esp0' field.
void set_kernel_stack (uint32_t esp0)
{
tss.esp0 = esp0;
}
Upd: And yeah, the `tss_t' structure is the same as in the above link. Also, I've a question about segment selectors. If the segment in the GDT is ring3, then do I need to set the "privilege level" bits to 3 (e.g. 0x1B for 0x18 ring3 code segment).
.... . .-.. .--.