From: Tulio A M Mendes Date: Thu, 5 Feb 2026 21:48:18 +0000 (-0300) Subject: x86: add flat GDT and minimal TSS; wire esp0 updates X-Git-Url: https://projects.tadryanom.me/?a=commitdiff_plain;h=2d84280e501bbac7d80c20099bc4a2109e28f5a2;p=AdrOS.git x86: add flat GDT and minimal TSS; wire esp0 updates --- diff --git a/include/arch/x86/gdt.h b/include/arch/x86/gdt.h new file mode 100644 index 0000000..d09969a --- /dev/null +++ b/include/arch/x86/gdt.h @@ -0,0 +1,10 @@ +#ifndef ARCH_X86_GDT_H +#define ARCH_X86_GDT_H + +#include +#include + +void gdt_init(void); +void tss_set_kernel_stack(uintptr_t esp0); + +#endif diff --git a/include/gdt.h b/include/gdt.h new file mode 100644 index 0000000..b2b7537 --- /dev/null +++ b/include/gdt.h @@ -0,0 +1,16 @@ +#ifndef GDT_H +#define GDT_H + +#if defined(__i386__) || defined(__x86_64__) +#include "arch/x86/gdt.h" +#else + +#include +#include + +static inline void gdt_init(void) { } +static inline void tss_set_kernel_stack(uintptr_t esp0) { (void)esp0; } + +#endif + +#endif diff --git a/src/arch/x86/gdt.c b/src/arch/x86/gdt.c new file mode 100644 index 0000000..79f1a23 --- /dev/null +++ b/src/arch/x86/gdt.c @@ -0,0 +1,107 @@ +#include "gdt.h" + +#include "uart_console.h" + +struct gdt_entry { + uint16_t limit_low; + uint16_t base_low; + uint8_t base_middle; + uint8_t access; + uint8_t granularity; + uint8_t base_high; +} __attribute__((packed)); + +struct gdt_ptr { + uint16_t limit; + uint32_t base; +} __attribute__((packed)); + +struct tss_entry { + uint32_t prev_tss; + uint32_t esp0; + uint32_t ss0; + uint32_t esp1; + uint32_t ss1; + uint32_t esp2; + uint32_t ss2; + uint32_t cr3; + uint32_t eip; + uint32_t eflags; + uint32_t eax; + uint32_t ecx; + uint32_t edx; + uint32_t ebx; + uint32_t esp; + uint32_t ebp; + uint32_t esi; + uint32_t edi; + uint32_t es; + uint32_t cs; + uint32_t ss; + uint32_t ds; + uint32_t fs; + uint32_t gs; + uint32_t ldt; + uint16_t trap; + uint16_t iomap_base; +} __attribute__((packed)); + +extern void gdt_flush(uint32_t gdt_ptr_addr); +extern void tss_flush(uint16_t tss_selector); + +static struct gdt_entry gdt[6]; +static struct gdt_ptr gp; +static struct tss_entry tss; + +static void gdt_set_gate(int num, uint32_t base, uint32_t limit, uint8_t access, uint8_t gran) { + gdt[num].base_low = (base & 0xFFFF); + gdt[num].base_middle = (base >> 16) & 0xFF; + gdt[num].base_high = (base >> 24) & 0xFF; + + gdt[num].limit_low = (limit & 0xFFFF); + gdt[num].granularity = ((limit >> 16) & 0x0F); + + gdt[num].granularity |= (gran & 0xF0); + gdt[num].access = access; +} + +static void tss_write(uint32_t idx, uint16_t kernel_ss, uint32_t kernel_esp) { + uintptr_t base = (uintptr_t)&tss; + uint32_t limit = (uint32_t)(sizeof(tss) - 1); + + gdt_set_gate((int)idx, (uint32_t)base, limit, 0x89, 0x00); + + for (size_t i = 0; i < sizeof(tss); i++) { + ((uint8_t*)&tss)[i] = 0; + } + + tss.ss0 = kernel_ss; + tss.esp0 = kernel_esp; + tss.iomap_base = (uint16_t)sizeof(tss); +} + +void tss_set_kernel_stack(uintptr_t esp0) { + tss.esp0 = (uint32_t)esp0; +} + +void gdt_init(void) { + uart_print("[GDT] Initializing GDT/TSS...\n"); + + gp.limit = (uint16_t)(sizeof(struct gdt_entry) * 6 - 1); + gp.base = (uint32_t)(uintptr_t)&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_set_gate(3, 0, 0xFFFFFFFF, 0xFA, 0xCF); + gdt_set_gate(4, 0, 0xFFFFFFFF, 0xF2, 0xCF); + + tss_write(5, 0x10, 0); + + gdt_flush((uint32_t)(uintptr_t)&gp); + tss_flush(0x28); + + uart_print("[GDT] Loaded.\n"); +} diff --git a/src/arch/x86/gdt_flush.S b/src/arch/x86/gdt_flush.S new file mode 100644 index 0000000..18adc31 --- /dev/null +++ b/src/arch/x86/gdt_flush.S @@ -0,0 +1,16 @@ +.section .text +.global gdt_flush +gdt_flush: + mov 4(%esp), %eax + lgdt (%eax) + + mov $0x10, %ax + mov %ax, %ds + mov %ax, %es + mov %ax, %fs + mov %ax, %gs + mov %ax, %ss + + ljmp $0x08, $flush_cs +flush_cs: + ret diff --git a/src/arch/x86/tss_flush.S b/src/arch/x86/tss_flush.S new file mode 100644 index 0000000..fd91165 --- /dev/null +++ b/src/arch/x86/tss_flush.S @@ -0,0 +1,6 @@ +.section .text +.global tss_flush +tss_flush: + mov 4(%esp), %ax + ltr %ax + ret diff --git a/src/kernel/main.c b/src/kernel/main.c index 5578fca..05d88bc 100644 --- a/src/kernel/main.c +++ b/src/kernel/main.c @@ -14,6 +14,8 @@ #include "initrd.h" #include "fs.h" +#include "gdt.h" + #include "syscall.h" /* Check if the compiler thinks we are targeting the wrong operating system. */ @@ -57,6 +59,9 @@ void kernel_main(unsigned long magic, unsigned long addr) { // 4. Initialize Kernel Heap kheap_init(); + + uart_print("[AdrOS] Initializing GDT/TSS...\n"); + gdt_init(); // 5. Initialize Interrupts (x86) uart_print("[AdrOS] Initializing IDT...\n"); diff --git a/src/kernel/scheduler.c b/src/kernel/scheduler.c index cc641c2..5a605db 100644 --- a/src/kernel/scheduler.c +++ b/src/kernel/scheduler.c @@ -4,6 +4,7 @@ #include "uart_console.h" #include "timer.h" // Need access to current tick usually, but we pass it in wake_check #include "spinlock.h" +#include "gdt.h" #include struct process* current_process = NULL; @@ -46,6 +47,11 @@ void process_init(void) { ready_queue_tail = kernel_proc; kernel_proc->next = kernel_proc; + // Best effort: set esp0 to current stack until we have a dedicated kernel stack for PID 0 + uintptr_t cur_esp; + __asm__ volatile("mov %%esp, %0" : "=r"(cur_esp)); + tss_set_kernel_stack(cur_esp); + spin_unlock_irqrestore(&sched_lock, flags); } @@ -153,6 +159,11 @@ void schedule(void) { current_process = next; current_process->state = PROCESS_RUNNING; + // For ring3->ring0 transitions, esp0 must point to the top of the kernel stack. + if (current_process->kernel_stack) { + tss_set_kernel_stack((uintptr_t)current_process->kernel_stack + 4096); + } + spin_unlock(&sched_lock); context_switch(&prev->esp, current_process->esp);