Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 2 additions & 3 deletions arch/x86_64/cpu/Cpu.c
Original file line number Diff line number Diff line change
Expand Up @@ -20,9 +20,8 @@ void CpuInit(void) {
cpuid(7, &eax, &ebx, &ecx, &edx);
cpu_features.avx2 = (ebx >> 5) & 1;

if (cpu_features.sse) {
EnableSse();
}
// SSE/SSE2 are already enabled by the bootloader (pxs.asm)
// No need to call EnableSse() here.
}

void EnableSse(void) {
Expand Down
66 changes: 53 additions & 13 deletions arch/x86_64/gdt/Gdt.c
Original file line number Diff line number Diff line change
@@ -1,32 +1,72 @@
#include "Gdt.h"
#include "Panic.h"
// GDT with user mode segments
static struct GdtEntry gdt[5];

// GDT with 7 entries: null, kcode, kdata, ucode, udata, tss_low, tss_high
static struct GdtEntry gdt[7];
static struct GdtPtr gdt_ptr;
static struct TssEntry tss;

extern void GdtFlush(uint64_t gdt_ptr_addr);
extern void TssFlush(void);

static void SetGdtGate(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;
}

int GdtInit(void) {
gdt_ptr.limit = (sizeof(struct GdtEntry) * 5) - 1;
// A cleaner way to set up the 64-bit TSS descriptor
static void SetTssGate(int num, uint64_t base, uint64_t limit) {
// Set up the lower 8 bytes (standard system segment descriptor)
gdt[num].limit_low = (limit & 0xFFFF);
gdt[num].base_low = (base & 0xFFFF);
gdt[num].base_middle = (base >> 16) & 0xFF;
gdt[num].access = GDT_ACCESS_TSS; // Access byte for 64-bit TSS
gdt[num].granularity = (limit >> 16) & 0x0F; // No granularity bits (G=0, AVL=0)
gdt[num].base_high = (base >> 24) & 0xFF;

// The second GDT entry for a 64-bit TSS holds the upper 32 bits of the base address.
// We can cast the pointer to make this clearer.
uint32_t* base_high_ptr = (uint32_t*)&gdt[num + 1];
*base_high_ptr = (base >> 32);

// The second 4 bytes of the second entry should be zero.
// If gdt is a global static, it's already zero-initialized, but being explicit is good.
*((uint32_t*)base_high_ptr + 1) = 0;
}


void GdtInit(void) {
// The GDT limit is the size of the table in bytes, minus one.
// We now have 7 entries.
gdt_ptr.limit = (sizeof(struct GdtEntry) * 7) - 1;
gdt_ptr.base = (uint64_t)&gdt;

SetGdtGate(0, 0, 0, 0, 0); // Null segment
SetGdtGate(1, 0, 0xFFFFFFFF, 0x9A, 0xA0); // Kernel code (64-bit)
SetGdtGate(2, 0, 0xFFFFFFFF, 0x92, 0xA0); // Kernel data
SetGdtGate(3, 0, 0xFFFFFFFF, 0xFA, 0xA0); // User code (Ring 3, 64-bit)
SetGdtGate(4, 0, 0xFFFFFFFF, 0xF2, 0xA0); // User data (Ring 3)


SetGdtGate(0, 0, 0, 0, 0); // 0x00: Null segment
SetGdtGate(1, 0, 0xFFFFFFFF, GDT_ACCESS_CODE_PL0, GDT_GRAN_CODE); // 0x08: Kernel Code
SetGdtGate(2, 0, 0xFFFFFFFF, GDT_ACCESS_DATA_PL0, GDT_GRAN_DATA); // 0x10: Kernel Data
SetGdtGate(3, 0, 0xFFFFFFFF, GDT_ACCESS_CODE_PL3, GDT_GRAN_CODE); // 0x18: User Code
SetGdtGate(4, 0, 0xFFFFFFFF, GDT_ACCESS_DATA_PL3, GDT_GRAN_DATA); // 0x20: User Data

// Setup TSS. It starts at index 5 and occupies entries 5 and 6.
// The selector will be 0x28 (5 * 8)
uint64_t tss_base = (uint64_t)&tss;
uint64_t tss_limit = sizeof(struct TssEntry) - 1;
SetTssGate(5, tss_base, tss_limit);

// Initialize TSS fields (make sure tss is zero-initialized)
// tss.rsp0 will be set later when a process is created
tss.iomap_base = sizeof(struct TssEntry); // Set IOMAP base beyond the TSS limit to disable it.

GdtFlush((uint64_t)&gdt_ptr);
return 0;
TssFlush(); // Load the Task Register with selector 0x28
}

void SetTssRsp0(uint64_t rsp0) {
tss.rsp0 = rsp0;
}
35 changes: 34 additions & 1 deletion arch/x86_64/gdt/Gdt.h
Original file line number Diff line number Diff line change
Expand Up @@ -3,11 +3,24 @@

#include "stdint.h"

#define GDT_ACCESS_CODE_PL0 0x9A // Present, Ring 0, Executable, Read/Write
#define GDT_ACCESS_DATA_PL0 0x92 // Present, Ring 0, Read/Write
#define GDT_ACCESS_CODE_PL3 0xFA // Present, Ring 3, Executable, Read/Write
#define GDT_ACCESS_DATA_PL3 0xF2 // Present, Ring 3, Read/Write
#define GDT_ACCESS_TSS 0x89 // Present, Ring 0, TSS

#define GDT_FLAG_64BIT 0x20 // 64-bit segment
#define GDT_FLAG_4K_GRAN 0x80 // 4KB granularity

#define GDT_GRAN_CODE (GDT_FLAG_64BIT | GDT_FLAG_4K_GRAN)
#define GDT_GRAN_DATA (GDT_FLAG_4K_GRAN)

// GDT segment selectors
#define KERNEL_CODE_SELECTOR 0x08
#define KERNEL_DATA_SELECTOR 0x10
#define USER_CODE_SELECTOR 0x18
#define USER_DATA_SELECTOR 0x20
#define TSS_SELECTOR 0x28 // New TSS selector

// GDT entry structure
struct GdtEntry {
Expand All @@ -25,6 +38,26 @@ struct GdtPtr {
uint64_t base;
} __attribute__((packed));

int GdtInit(void);
// TSS structure (simplified for 64-bit)
struct TssEntry {
uint32_t reserved0;
uint64_t rsp0;
uint64_t rsp1;
uint64_t rsp2;
uint64_t reserved1;
uint64_t ist1;
uint64_t ist2;
uint64_t ist3;
uint64_t ist4;
uint64_t ist5;
uint64_t ist6;
uint64_t ist7;
uint64_t reserved2;
uint16_t reserved3;
uint16_t iomap_base;
} __attribute__((packed));

void GdtInit(void);
void SetTssRsp0(uint64_t rsp0);

#endif
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
bits 64

global GdtFlush
global TssFlush

GdtFlush:
lgdt [rdi] ; Load new GDT
Expand All @@ -20,4 +21,9 @@ GdtFlush:
retfq

.flush:
ret

TssFlush:
mov ax, 0x28 ; TSS selector (index 5 * 8 = 40 = 0x28)
ltr ax ; Load Task Register
ret
Loading