]> Projects (at) Tadryanom (dot) Me - AdrOS.git/commitdiff
x86: add flat GDT and minimal TSS; wire esp0 updates
authorTulio A M Mendes <[email protected]>
Thu, 5 Feb 2026 21:48:18 +0000 (18:48 -0300)
committerTulio A M Mendes <[email protected]>
Thu, 5 Feb 2026 21:48:18 +0000 (18:48 -0300)
include/arch/x86/gdt.h [new file with mode: 0644]
include/gdt.h [new file with mode: 0644]
src/arch/x86/gdt.c [new file with mode: 0644]
src/arch/x86/gdt_flush.S [new file with mode: 0644]
src/arch/x86/tss_flush.S [new file with mode: 0644]
src/kernel/main.c
src/kernel/scheduler.c

diff --git a/include/arch/x86/gdt.h b/include/arch/x86/gdt.h
new file mode 100644 (file)
index 0000000..d09969a
--- /dev/null
@@ -0,0 +1,10 @@
+#ifndef ARCH_X86_GDT_H
+#define ARCH_X86_GDT_H
+
+#include <stdint.h>
+#include <stddef.h>
+
+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 (file)
index 0000000..b2b7537
--- /dev/null
@@ -0,0 +1,16 @@
+#ifndef GDT_H
+#define GDT_H
+
+#if defined(__i386__) || defined(__x86_64__)
+#include "arch/x86/gdt.h"
+#else
+
+#include <stdint.h>
+#include <stddef.h>
+
+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 (file)
index 0000000..79f1a23
--- /dev/null
@@ -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 (file)
index 0000000..18adc31
--- /dev/null
@@ -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 (file)
index 0000000..fd91165
--- /dev/null
@@ -0,0 +1,6 @@
+.section .text
+.global tss_flush
+tss_flush:
+    mov 4(%esp), %ax
+    ltr %ax
+    ret
index 5578fcaebd82216d167ea9b9b5a9a8760ac56f4b..05d88bcdd97e0edcbce763c78b2a038d2842f519 100644 (file)
@@ -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");
index cc641c2a35d14649e1c7dec990eec7a25e9af06c..5a605db90eb9578034829c79b293a93b59c45922 100644 (file)
@@ -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 <stddef.h>
 
 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);