From 131abf1726c337e09d3066d4ac5627ed3200098a Mon Sep 17 00:00:00 2001 From: Uoc Date: Sat, 6 Dec 2025 04:08:51 +0000 Subject: [PATCH 1/4] Update: gdt.c changes and add additional features --- kernel/gdt.c | 163 ++++++++++++++++++++++----------------------------- 1 file changed, 70 insertions(+), 93 deletions(-) diff --git a/kernel/gdt.c b/kernel/gdt.c index 5dda0e7..497c39e 100644 --- a/kernel/gdt.c +++ b/kernel/gdt.c @@ -1,26 +1,21 @@ // kernel/gdt.c #include +#include /* 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; @@ -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"); +} From 1449e702c9e0ac9f13c64aca2f1131ab715fd5bc Mon Sep 17 00:00:00 2001 From: Uoc Date: Sun, 7 Dec 2025 00:05:08 +0000 Subject: [PATCH 2/4] Update: idt.h IDT crash before executing new instructions --- kernel/idt.h | 12 +++++------- 1 file changed, 5 insertions(+), 7 deletions(-) diff --git a/kernel/idt.h b/kernel/idt.h index 0d3aca2..b8c6802 100644 --- a/kernel/idt.h +++ b/kernel/idt.h @@ -1,8 +1,4 @@ -/* kernel/idt.h */ - -// @UocDev — Type Notation -// @NurAzizah — Helper - +// kernel/idt.h #ifndef IDT_H #define IDT_H @@ -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 From 6d72259c9e1fb38831a4af903a83e210b0cbfc23 Mon Sep 17 00:00:00 2001 From: Uoc Date: Sun, 7 Dec 2025 00:05:50 +0000 Subject: [PATCH 3/4] Update: idt.c this change affected by header file and kernel.c --- kernel/idt.c | 134 ++++++++++++++++++++++++++++++--------------------- 1 file changed, 80 insertions(+), 54 deletions(-) diff --git a/kernel/idt.c b/kernel/idt.c index 5c291f9..a997d0f 100644 --- a/kernel/idt.c +++ b/kernel/idt.c @@ -1,10 +1,12 @@ -/* kernel/idt.c */ - -// @UocDev — Type Notation -// @NurAzizah — Helper - +// kernel/idt.c +#include #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(); @@ -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)); } From 80fb9d8f3fb0b09b327e75c2d358ac4496c50ffe Mon Sep 17 00:00:00 2001 From: Uoc Date: Sun, 7 Dec 2025 00:07:27 +0000 Subject: [PATCH 4/4] Update: kernel.c change function name from 'idt_init()' into 'idt_install()' --- kernel/kernel.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/kernel/kernel.c b/kernel/kernel.c index 63735cf..d872e77 100644 --- a/kernel/kernel.c +++ b/kernel/kernel.c @@ -162,7 +162,7 @@ void kernel_main(void) { vga_puts("GDT+TSS installed.\n"); vga_puts("Initializing IDT...\n"); - idt_init(); + idt_install(); serial_write("IDT installed.\n"); vga_puts("IDT installed.\n");