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
163 changes: 70 additions & 93 deletions kernel/gdt.c
Original file line number Diff line number Diff line change
@@ -1,26 +1,21 @@
// kernel/gdt.c
#include <stdint.h>
#include <stddef.h> /* untuk size_t */
#include "gdt.h"

/* Basic GDT layout:
* 0: null
* 1: kernel code (0x08)
* 2: kernel data (0x10)
* 3: user code (0x18)
* 4: user data (0x20)
* 5-6: TSS descriptor (selector 0x28)
*/
/* forward serial (already initialized by kernel_main) */
extern void serial_write(const char *s);

extern void *stack_end; /* provided by kernel.c */

struct __attribute__((packed)) gdtr {
uint16_t limit;
uint64_t base;
};

static uint64_t gdt_table[7]; /* 7 * 8 = 56 bytes, plus TSS uses two descriptors */

extern void *stack_end;
static uint64_t gdt_table[7]; /* null, code, data, usercode, userdata, tss low, tss high */

/* 64-bit TSS (structure fields we need) */
/* TSS struct (minimal fields we use) */
struct __attribute__((packed)) tss_struct {
uint32_t reserved0;
uint64_t rsp0;
Expand All @@ -37,125 +32,107 @@ struct __attribute__((packed)) tss_struct {
uint64_t reserved2;
uint16_t reserved3;
uint16_t iomap_base;
};

/* TSS instance (aligned) */
static struct tss_struct tss __attribute__((aligned(16)));
} __attribute__((aligned(16)));

/* IST stack for double-fault etc. Place in BSS (kernel link will provide) */
#define IST_STACK_SIZE 8192
static uint8_t ist1_stack[IST_STACK_SIZE] __attribute__((aligned(16)));
static struct tss_struct tss;
#define IST1_STACK_SIZE 8192
static uint8_t ist1_stack[IST1_STACK_SIZE] __attribute__((aligned(16)));

/* helper: build 64-bit code/data descriptor
* access and flags as bytes:
* - access: e.g. 0x9A for kernel code, 0x92 for kernel data
* - flags: high nibble: granularity & L bit; use 0x20 for L bit
*/
static inline uint64_t build_gdt_entry(uint32_t access, uint32_t flags)
/* Build simple 64-bit code/data descriptor (base=0, limit=0) */
static inline uint64_t make_descriptor(uint32_t access, uint32_t flags)
{
/* 64-bit code/data descriptors for flat model commonly use base=0, limit=0xFFFFF with L=1 or limit=0 */
uint64_t entry = 0;
entry = ((uint64_t)(0 & 0xFFFF)) | (((uint64_t)0 & 0xFFFF) << 16);
/* base_mid and access: we place access at bits 40..47 */
entry |= ((uint64_t)(access & 0xFF) << 40);
/* flags (including L bit) and limit high nibble at bits 52..55 */
entry |= ((uint64_t)(flags & 0xFF) << 52);
/* base_high (bits 56..63) zero */
return entry;
uint64_t desc = 0;
desc |= ((uint64_t)access) << 40;
desc |= ((uint64_t)flags) << 52;
return desc;
}

/* helper: write TSS descriptor (two 64-bit entries) */
static inline void write_tss_descriptor(uint64_t *gdt, void *tss_addr, uint32_t tss_limit)
/* write 128-bit TSS descriptor at gdt_table[index] & gdt_table[index+1] */
static inline void write_tss_descriptor(int index, void *tss_addr, uint32_t tss_limit)
{
uint64_t base = (uint64_t)tss_addr;
uint64_t low = 0;
uint64_t high = 0;

/* low: limit[15:0] | base[15:0]<<16 | base[23:16]<<32 | access<<40 | flags<<52 | base[31:24]<<56 */
low = (tss_limit & 0xFFFF);
low |= ( (base & 0xFFFF) << 16 );
low |= ( ( (base >> 16) & 0xFF ) << 32 );
low |= ( (uint64_t)0x89 << 40 ); /* access: present + type(9 = avail 64-bit TSS) */
low |= ( (uint64_t)0x00 << 48 ); /* flags low nibble = 0 */
low |= ( ( (uint64_t)((tss_limit >> 16) & 0xF) ) << 48 );
low |= ( ( (base >> 24) & 0xFF ) << 56 );

/* high: base[63:32] */
high = (uint64_t)( (base >> 32) & 0xFFFFFFFF );
/* rest zero */

gdt[5] = low;
gdt[6] = high;
/* low 64:
limit[15:0] | base[15:0]<<16 | base[23:16]<<32 | access<<40 |
limit[19:16]<<48 | base[31:24]<<56
*/
low = (uint64_t)(tss_limit & 0xFFFF);
low |= ( (base & 0xFFFFULL) << 16 );
low |= ( ((base >> 16) & 0xFFULL) << 32 );
low |= ( (uint64_t)0x89ULL << 40 ); /* access: present + type 9 (available 64-bit TSS) */

/* jangan lakukan shift >=32 pada 32-bit int; gunakan uint64_t */
low |= ( ((uint64_t)((tss_limit >> 16) & 0xF)) << 48 );
low |= ( ((base >> 24) & 0xFFULL) << 56 );

/* high 64: base[63:32] */
high = (base >> 32) & 0xFFFFFFFFULL;

gdt_table[index] = low;
gdt_table[index+1] = high;
}

void gdt_install(void)
{
/* zero table first */
for (int i = 0; i < 7; ++i) gdt_table[i] = 0;
serial_write("[gdt] start\n");

/* NULL descriptor at index 0 (already zero) */
/* zero out table */
for (size_t i = 0; i < sizeof(gdt_table)/sizeof(gdt_table[0]); ++i) gdt_table[i] = 0ULL;

/* index 1: kernel code descriptor (present, ring0, executable, readable), L bit */
/* access 0x9A, flags: 0x20 (L=1) << 8 in build above, but we pass as flags byte */
gdt_table[1] = build_gdt_entry(0x9A, 0x20);
/* Null descriptor (0) left as 0 */

/* index 2: kernel data descriptor (present, ring0, data, writable) */
gdt_table[2] = build_gdt_entry(0x92, 0x00);
/* Kernel code selector (index 1 -> selector 0x08): access=0x9A, flags L=1 => 0x20 */
gdt_table[1] = make_descriptor(0x9A, 0x20);

/* index 3: user code (DPL=3) */
gdt_table[3] = build_gdt_entry(0xFA, 0x20); /* 0xFA = present + DPL=3 + executable */
/* Kernel data selector (index 2 -> selector 0x10): access=0x92 */
gdt_table[2] = make_descriptor(0x92, 0x00);

/* index 4: user data */
gdt_table[4] = build_gdt_entry(0xF2, 0x00);
/* User code (index 3 -> selector 0x18): DPL=3, L=1 */
gdt_table[3] = make_descriptor(0xFA, 0x20);

/* prepare TSS */
for (int i = 0; i < (int)sizeof(tss)/sizeof(uint32_t); ++i) ((uint32_t*)&tss)[i] = 0;
/* User data (index 4 -> selector 0x20): DPL=3 */
gdt_table[4] = make_descriptor(0xF2, 0x00);

/* set RSP0 to kernel stack provided by bootloader (stack_end symbol) if exists */
// extern char stack_end; /* defined in bootloader.S */
tss.rsp0 = (uint64_t)&stack_end;
/* prepare TSS: zero it safely */
{
uint32_t *p = (uint32_t*)&tss;
size_t words = sizeof(tss) / sizeof(uint32_t);
for (size_t i = 0; i < words; ++i) p[i] = 0;
}

/* IST1: point to our IST stack top (grow-down) */
tss.ist1 = (uint64_t)( (uint8_t*)ist1_stack + IST_STACK_SIZE );
/* set RSP0 and IST1 */
tss.rsp0 = (uint64_t)stack_end;
tss.ist1 = (uint64_t)(ist1_stack + IST1_STACK_SIZE);

/* write TSS descriptor entries at gdt[5..6] */
write_tss_descriptor(gdt_table, &tss, (uint32_t)(sizeof(tss)-1));
/* write TSS descriptor entries at index 5 (occupies entries 5 and 6) */
write_tss_descriptor(5, &tss, (uint32_t)(sizeof(tss) - 1));

/* prepare GDTR */
struct gdtr {
uint16_t limit;
uint64_t base;
} __attribute__((packed)) gdtr;

struct gdtr gdtr;
gdtr.limit = (uint16_t)(sizeof(gdt_table) - 1);
gdtr.base = (uint64_t)&gdt_table;

/* load GDT */
serial_write("[gdt] lgdt\n");
asm volatile ("lgdt %0" : : "m"(gdtr));

/* reload segment registers with new selectors */
/* reload data segments (set DS/ES/FS/GS/SS to 0x10) */
serial_write("[gdt] reload segments\n");
asm volatile (
"mov $0x10, %%ax\n" /* data selector = index 2 (0x10) */
"mov $0x10, %%ax\n"
"mov %%ax, %%ds\n"
"mov %%ax, %%es\n"
"mov %%ax, %%fs\n"
"mov %%ax, %%gs\n"
"mov %%ax, %%ss\n"
: : : "ax"
);

/* far jump to flush CS: use asm to do ljmp to code selector 0x08 */
asm volatile (
"pushq $0x08\n"
"lea 1f(%%rip), %%rax\n"
"pushq %%rax\n"
"lretq\n"
"1:\n"
::: "rax"
::: "ax"
);

/* load TR with TSS selector (index 5 -> selector 0x28) */
serial_write("[gdt] load tss\n");
/* Load TR with TSS selector (index 5 -> selector = 5*8 = 0x28) */
uint16_t tss_sel = 0x28;
asm volatile ("ltr %0" : : "r"(tss_sel));
}

serial_write("[gdt] done\n");
}
134 changes: 80 additions & 54 deletions kernel/idt.c
Original file line number Diff line number Diff line change
@@ -1,10 +1,12 @@
/* kernel/idt.c */

// @UocDev — Type Notation
// @NurAzizah — Helper

// kernel/idt.c
#include <stdint.h>
#include "idt.h"
#include "gdt.h" /* not required but ok to include */

extern void serial_write(const char *s);
extern void serial_write_hex(uint64_t v);

/* Extern isr stubs */
extern void isr0();
extern void isr1();
extern void isr2();
Expand Down Expand Up @@ -38,62 +40,86 @@ extern void isr29();
extern void isr30();
extern void isr31();

static struct idt_entry idt[256];
static struct idt_ptr idtr;
#define IDT_ENTRIES 256

static inline void lidt(void* base, uint16_t size)
static struct idt_entry idt[IDT_ENTRIES];
static struct idt_ptr idtp;

/* helper to install single gate with IST */
void idt_set_gate_ist(int n, void (*handler)(), uint8_t ist)
{
struct idt_ptr idtr;
idtr.base = (uint64_t) base;
idtr.limit = size - 1;
asm volatile ("lidt %0" : : "m"(idtr));
uint64_t addr = (uint64_t)handler;
idt[n].offset_low = (uint16_t)(addr & 0xFFFF);
idt[n].selector = 0x08; // kernel code selector
idt[n].ist = ist & 0x7;
idt[n].type_attr = 0x8E; // present, DPL=0, interrupt gate (0xE)
idt[n].offset_mid = (uint16_t)((addr >> 16) & 0xFFFF);
idt[n].offset_high = (uint32_t)((addr >> 32) & 0xFFFFFFFF);
idt[n].zero = 0;
}

void idt_set_gate(int n, uint64_t handler)
/* convenience wrapper (ist=0) */
void idt_set_gate(int n, void (*handler)()) {
idt_set_gate_ist(n, handler, 0);
}

/* load IDT */
static inline void lidt_load(void *base, uint16_t size)
{
idt[n].offset_low = handler & 0xFFFF;
idt[n].selector = 0x08;
idt[n].ist = 0;
idt[n].type_attr = 0x8E;
idt[n].offset_mid = (handler >> 16) & 0xFFFF;
idt[n].offset_high = (handler >> 32) & 0xFFFFFFFF;
idt[n].zero = 0;
idtp.base = (uint64_t)base;
idtp.limit = size - 1;
__asm__ volatile ("lidt %0" : : "m"(idtp));
}

void idt_init()
void idt_install(void)
{
idt_set_gate(0, (uint64_t)isr0);
idt_set_gate(1, (uint64_t)isr1);
idt_set_gate(2, (uint64_t)isr2);
idt_set_gate(3, (uint64_t)isr3);
idt_set_gate(4, (uint64_t)isr4);
idt_set_gate(5, (uint64_t)isr5);
idt_set_gate(6, (uint64_t)isr6);
idt_set_gate(7, (uint64_t)isr7);
idt_set_gate(8, (uint64_t)isr8);
idt_set_gate(9, (uint64_t)isr9);
idt_set_gate(10, (uint64_t)isr10);
idt_set_gate(11, (uint64_t)isr11);
idt_set_gate(12, (uint64_t)isr12);
idt_set_gate(13, (uint64_t)isr13);
idt_set_gate(14, (uint64_t)isr14);
idt_set_gate(15, (uint64_t)isr15);
idt_set_gate(16, (uint64_t)isr16);
idt_set_gate(17, (uint64_t)isr17);
idt_set_gate(18, (uint64_t)isr18);
idt_set_gate(19, (uint64_t)isr19);
idt_set_gate(20, (uint64_t)isr20);
idt_set_gate(21, (uint64_t)isr21);
idt_set_gate(22, (uint64_t)isr22);
idt_set_gate(23, (uint64_t)isr23);
idt_set_gate(24, (uint64_t)isr24);
idt_set_gate(25, (uint64_t)isr25);
idt_set_gate(26, (uint64_t)isr26);
idt_set_gate(27, (uint64_t)isr27);
idt_set_gate(28, (uint64_t)isr28);
idt_set_gate(29, (uint64_t)isr29);
idt_set_gate(30, (uint64_t)isr30);
idt_set_gate(31, (uint64_t)isr31);
/* clear */
for (int i = 0; i < IDT_ENTRIES; ++i) {
idt[i].offset_low = 0;
idt[i].selector = 0;
idt[i].ist = 0;
idt[i].type_attr = 0;
idt[i].offset_mid = 0;
idt[i].offset_high = 0;
idt[i].zero = 0;
}

/* Set gates for exceptions 0..31.
For double-fault (vector 8) set IST=1 to use TSS.ist1 stack.
*/
idt_set_gate(0, isr0);
idt_set_gate(1, isr1);
idt_set_gate(2, isr2);
idt_set_gate(3, isr3);
idt_set_gate(4, isr4);
idt_set_gate(5, isr5);
idt_set_gate(6, isr6);
idt_set_gate(7, isr7);
idt_set_gate_ist(8, isr8, 1); /* DOUBLE FAULT -> use IST1 */
idt_set_gate(9, isr9);
idt_set_gate(10, isr10);
idt_set_gate(11, isr11);
idt_set_gate(12, isr12);
idt_set_gate(13, isr13);
idt_set_gate(14, isr14);
idt_set_gate(15, isr15);
idt_set_gate(16, isr16);
idt_set_gate(17, isr17);
idt_set_gate(18, isr18);
idt_set_gate(19, isr19);
idt_set_gate(20, isr20);
idt_set_gate(21, isr21);
idt_set_gate(22, isr22);
idt_set_gate(23, isr23);
idt_set_gate(24, isr24);
idt_set_gate(25, isr25);
idt_set_gate(26, isr26);
idt_set_gate(27, isr27);
idt_set_gate(28, isr28);
idt_set_gate(29, isr29);
idt_set_gate(30, isr30);
idt_set_gate(31, isr31);

lidt(idt, sizeof(idt));
/* load */
lidt_load(idt, sizeof(idt));
}
12 changes: 5 additions & 7 deletions kernel/idt.h
Original file line number Diff line number Diff line change
@@ -1,8 +1,4 @@
/* kernel/idt.h */

// @UocDev — Type Notation
// @NurAzizah — Helper

// kernel/idt.h
#ifndef IDT_H
#define IDT_H

Expand All @@ -23,7 +19,9 @@ struct idt_ptr {
uint64_t base;
} __attribute__((packed));

void idt_init();
void idt_set_gate(int n, uint64_t handler);
void idt_install(void);

/* New: set gate with explicit IST value (0..7) */
void idt_set_gate_ist(int n, void (*handler)(), uint8_t ist);

#endif
Loading