From 0b69c97662607b4ed26dc958435c5f16868efcbe Mon Sep 17 00:00:00 2001 From: Leonmmcoset Date: Fri, 10 Apr 2026 16:55:48 +0800 Subject: [PATCH] Stage 5 --- Makefile | 3 + clks/arch/x86_64/interrupt_stubs.S | 1 + clks/include/clks/boot.h | 1 + clks/include/clks/elf64.h | 35 +++++ clks/include/clks/elfrunner.h | 9 ++ clks/include/clks/limine.h | 43 ++++++ clks/include/clks/syscall.h | 15 ++ clks/kernel/elf64.c | 222 +++++++++++++++++++++++++++++ clks/kernel/elfrunner.c | 38 +++++ clks/kernel/interrupts.c | 12 ++ clks/kernel/kmain.c | 16 ++- clks/kernel/limine_requests.c | 17 +++ clks/kernel/syscall.c | 102 +++++++++++++ docs/stage5.md | 34 +++++ 14 files changed, 547 insertions(+), 1 deletion(-) create mode 100644 clks/include/clks/elf64.h create mode 100644 clks/include/clks/elfrunner.h create mode 100644 clks/include/clks/syscall.h create mode 100644 clks/kernel/elf64.c create mode 100644 clks/kernel/elfrunner.c create mode 100644 clks/kernel/syscall.c create mode 100644 docs/stage5.md diff --git a/Makefile b/Makefile index 870af5b..fe24ddf 100644 --- a/Makefile +++ b/Makefile @@ -72,6 +72,9 @@ C_SOURCES := \ clks/kernel/heap.c \ clks/kernel/interrupts.c \ clks/kernel/scheduler.c \ + clks/kernel/elf64.c \ + clks/kernel/elfrunner.c \ + clks/kernel/syscall.c \ clks/lib/string.c \ clks/drivers/serial/serial.c \ clks/drivers/video/framebuffer.c \ diff --git a/clks/arch/x86_64/interrupt_stubs.S b/clks/arch/x86_64/interrupt_stubs.S index 02f367b..f23a0f1 100644 --- a/clks/arch/x86_64/interrupt_stubs.S +++ b/clks/arch/x86_64/interrupt_stubs.S @@ -72,6 +72,7 @@ ISR_NOERR 44 ISR_NOERR 45 ISR_NOERR 46 ISR_NOERR 47 +ISR_NOERR 128 clks_isr_common: cld diff --git a/clks/include/clks/boot.h b/clks/include/clks/boot.h index 49b350f..9dd0c67 100644 --- a/clks/include/clks/boot.h +++ b/clks/include/clks/boot.h @@ -7,5 +7,6 @@ clks_bool clks_boot_base_revision_supported(void); const struct limine_framebuffer *clks_boot_get_framebuffer(void); const struct limine_memmap_response *clks_boot_get_memmap(void); +const struct limine_file *clks_boot_get_executable_file(void); #endif \ No newline at end of file diff --git a/clks/include/clks/elf64.h b/clks/include/clks/elf64.h new file mode 100644 index 0000000..e307970 --- /dev/null +++ b/clks/include/clks/elf64.h @@ -0,0 +1,35 @@ +#ifndef CLKS_ELF64_H +#define CLKS_ELF64_H + +#include + +#define CLKS_ELF64_MAX_SEGMENTS 16U + +#define CLKS_ELF64_PT_LOAD 1U + +struct clks_elf64_info { + u64 entry; + u16 phnum; + u16 loadable_segments; + u64 total_load_memsz; +}; + +struct clks_elf64_loaded_segment { + void *base; + u64 vaddr; + u64 memsz; + u64 filesz; + u32 flags; +}; + +struct clks_elf64_loaded_image { + u64 entry; + u16 segment_count; + struct clks_elf64_loaded_segment segments[CLKS_ELF64_MAX_SEGMENTS]; +}; + +clks_bool clks_elf64_validate(const void *image, u64 size); +clks_bool clks_elf64_inspect(const void *image, u64 size, struct clks_elf64_info *out_info); +clks_bool clks_elf64_load(const void *image, u64 size, struct clks_elf64_loaded_image *out_loaded); + +#endif \ No newline at end of file diff --git a/clks/include/clks/elfrunner.h b/clks/include/clks/elfrunner.h new file mode 100644 index 0000000..d73c992 --- /dev/null +++ b/clks/include/clks/elfrunner.h @@ -0,0 +1,9 @@ +#ifndef CLKS_ELFRUNNER_H +#define CLKS_ELFRUNNER_H + +#include + +void clks_elfrunner_init(void); +clks_bool clks_elfrunner_probe_kernel_executable(void); + +#endif \ No newline at end of file diff --git a/clks/include/clks/limine.h b/clks/include/clks/limine.h index 44015c2..e8cddec 100644 --- a/clks/include/clks/limine.h +++ b/clks/include/clks/limine.h @@ -31,6 +31,14 @@ 0xe304acdfc50c3c62ULL \ } +#define LIMINE_EXECUTABLE_FILE_REQUEST \ + { \ + LIMINE_COMMON_MAGIC, \ + LIMINE_REQUEST_MAGIC, \ + 0xad97e90e83f1ed67ULL, \ + 0x31eb5d1c5ff23b69ULL \ + } + #define LIMINE_MEMMAP_USABLE 0ULL #define LIMINE_MEMMAP_RESERVED 1ULL #define LIMINE_MEMMAP_ACPI_RECLAIMABLE 2ULL @@ -41,6 +49,30 @@ #define LIMINE_MEMMAP_FRAMEBUFFER 7ULL #define LIMINE_MEMMAP_RESERVED_MAPPED 8ULL +struct limine_uuid { + u32 a; + u16 b; + u16 c; + u8 d[8]; +}; + +struct limine_file { + u64 revision; + void *address; + u64 size; + char *path; + char *string; + u32 media_type; + u32 unused; + u32 tftp_ip; + u32 tftp_port; + u32 partition_index; + u32 mbr_disk_id; + struct limine_uuid gpt_disk_uuid; + struct limine_uuid gpt_part_uuid; + struct limine_uuid part_uuid; +}; + struct limine_framebuffer { void *address; u64 width; @@ -89,4 +121,15 @@ struct limine_memmap_request { struct limine_memmap_response *response; }; +struct limine_executable_file_response { + u64 revision; + struct limine_file *executable_file; +}; + +struct limine_executable_file_request { + u64 id[4]; + u64 revision; + struct limine_executable_file_response *response; +}; + #endif \ No newline at end of file diff --git a/clks/include/clks/syscall.h b/clks/include/clks/syscall.h new file mode 100644 index 0000000..3ccde1f --- /dev/null +++ b/clks/include/clks/syscall.h @@ -0,0 +1,15 @@ +#ifndef CLKS_SYSCALL_H +#define CLKS_SYSCALL_H + +#include + +#define CLKS_SYSCALL_LOG_WRITE 0ULL +#define CLKS_SYSCALL_TIMER_TICKS 1ULL +#define CLKS_SYSCALL_TASK_COUNT 2ULL +#define CLKS_SYSCALL_CURRENT_TASK_ID 3ULL + +void clks_syscall_init(void); +u64 clks_syscall_dispatch(void *frame_ptr); +u64 clks_syscall_invoke_kernel(u64 id, u64 arg0, u64 arg1, u64 arg2); + +#endif \ No newline at end of file diff --git a/clks/kernel/elf64.c b/clks/kernel/elf64.c new file mode 100644 index 0000000..4b8103f --- /dev/null +++ b/clks/kernel/elf64.c @@ -0,0 +1,222 @@ +#include +#include +#include +#include + +#define CLKS_ELF64_MAGIC_0 0x7FU +#define CLKS_ELF64_MAGIC_1 'E' +#define CLKS_ELF64_MAGIC_2 'L' +#define CLKS_ELF64_MAGIC_3 'F' + +#define CLKS_ELF64_CLASS_64 2U +#define CLKS_ELF64_DATA_LSB 1U +#define CLKS_ELF64_VERSION 1U + +#define CLKS_ELF64_ET_EXEC 2U +#define CLKS_ELF64_ET_DYN 3U + +#define CLKS_ELF64_EM_X86_64 62U + +struct clks_elf64_ehdr { + u8 e_ident[16]; + u16 e_type; + u16 e_machine; + u32 e_version; + u64 e_entry; + u64 e_phoff; + u64 e_shoff; + u32 e_flags; + u16 e_ehsize; + u16 e_phentsize; + u16 e_phnum; + u16 e_shentsize; + u16 e_shnum; + u16 e_shstrndx; +}; + +struct clks_elf64_phdr { + u32 p_type; + u32 p_flags; + u64 p_offset; + u64 p_vaddr; + u64 p_paddr; + u64 p_filesz; + u64 p_memsz; + u64 p_align; +}; + +static clks_bool clks_elf64_header_ok(const struct clks_elf64_ehdr *eh) { + if (eh->e_ident[0] != CLKS_ELF64_MAGIC_0 || + eh->e_ident[1] != CLKS_ELF64_MAGIC_1 || + eh->e_ident[2] != CLKS_ELF64_MAGIC_2 || + eh->e_ident[3] != CLKS_ELF64_MAGIC_3) { + return CLKS_FALSE; + } + + if (eh->e_ident[4] != CLKS_ELF64_CLASS_64 || eh->e_ident[5] != CLKS_ELF64_DATA_LSB) { + return CLKS_FALSE; + } + + if (eh->e_ident[6] != CLKS_ELF64_VERSION || eh->e_version != CLKS_ELF64_VERSION) { + return CLKS_FALSE; + } + + if (eh->e_type != CLKS_ELF64_ET_EXEC && eh->e_type != CLKS_ELF64_ET_DYN) { + return CLKS_FALSE; + } + + if (eh->e_machine != CLKS_ELF64_EM_X86_64) { + return CLKS_FALSE; + } + + if (eh->e_ehsize != sizeof(struct clks_elf64_ehdr)) { + return CLKS_FALSE; + } + + if (eh->e_phentsize != sizeof(struct clks_elf64_phdr)) { + return CLKS_FALSE; + } + + return CLKS_TRUE; +} + +static clks_bool clks_elf64_range_ok(u64 off, u64 len, u64 total) { + if (off > total) { + return CLKS_FALSE; + } + + if (len > (total - off)) { + return CLKS_FALSE; + } + + return CLKS_TRUE; +} + +clks_bool clks_elf64_validate(const void *image, u64 size) { + const struct clks_elf64_ehdr *eh; + u64 ph_table_size; + u16 i; + + if (image == CLKS_NULL) { + return CLKS_FALSE; + } + + if (size < sizeof(struct clks_elf64_ehdr)) { + return CLKS_FALSE; + } + + eh = (const struct clks_elf64_ehdr *)image; + + if (clks_elf64_header_ok(eh) == CLKS_FALSE) { + return CLKS_FALSE; + } + + ph_table_size = (u64)eh->e_phnum * (u64)eh->e_phentsize; + + if (clks_elf64_range_ok(eh->e_phoff, ph_table_size, size) == CLKS_FALSE) { + return CLKS_FALSE; + } + + for (i = 0; i < eh->e_phnum; i++) { + const struct clks_elf64_phdr *ph = + (const struct clks_elf64_phdr *)((const u8 *)image + eh->e_phoff + ((u64)i * eh->e_phentsize)); + + if (ph->p_type != CLKS_ELF64_PT_LOAD) { + continue; + } + + if (ph->p_filesz > ph->p_memsz) { + return CLKS_FALSE; + } + + if (clks_elf64_range_ok(ph->p_offset, ph->p_filesz, size) == CLKS_FALSE) { + return CLKS_FALSE; + } + } + + return CLKS_TRUE; +} + +clks_bool clks_elf64_inspect(const void *image, u64 size, struct clks_elf64_info *out_info) { + const struct clks_elf64_ehdr *eh; + u16 i; + + if (out_info == CLKS_NULL) { + return CLKS_FALSE; + } + + clks_memset(out_info, 0, sizeof(*out_info)); + + if (clks_elf64_validate(image, size) == CLKS_FALSE) { + return CLKS_FALSE; + } + + eh = (const struct clks_elf64_ehdr *)image; + + out_info->entry = eh->e_entry; + out_info->phnum = eh->e_phnum; + + for (i = 0; i < eh->e_phnum; i++) { + const struct clks_elf64_phdr *ph = + (const struct clks_elf64_phdr *)((const u8 *)image + eh->e_phoff + ((u64)i * eh->e_phentsize)); + + if (ph->p_type != CLKS_ELF64_PT_LOAD) { + continue; + } + + out_info->loadable_segments++; + out_info->total_load_memsz += ph->p_memsz; + } + + return CLKS_TRUE; +} + +clks_bool clks_elf64_load(const void *image, u64 size, struct clks_elf64_loaded_image *out_loaded) { + const struct clks_elf64_ehdr *eh; + u16 i; + + if (out_loaded == CLKS_NULL) { + return CLKS_FALSE; + } + + clks_memset(out_loaded, 0, sizeof(*out_loaded)); + + if (clks_elf64_validate(image, size) == CLKS_FALSE) { + return CLKS_FALSE; + } + + eh = (const struct clks_elf64_ehdr *)image; + out_loaded->entry = eh->e_entry; + + for (i = 0; i < eh->e_phnum; i++) { + const struct clks_elf64_phdr *ph = + (const struct clks_elf64_phdr *)((const u8 *)image + eh->e_phoff + ((u64)i * eh->e_phentsize)); + void *dst; + + if (ph->p_type != CLKS_ELF64_PT_LOAD || ph->p_memsz == 0ULL) { + continue; + } + + if (out_loaded->segment_count >= CLKS_ELF64_MAX_SEGMENTS) { + return CLKS_FALSE; + } + + dst = clks_kmalloc((usize)ph->p_memsz); + + if (dst == CLKS_NULL) { + return CLKS_FALSE; + } + + clks_memset(dst, 0, (usize)ph->p_memsz); + clks_memcpy(dst, (const void *)((const u8 *)image + ph->p_offset), (usize)ph->p_filesz); + + out_loaded->segments[out_loaded->segment_count].base = dst; + out_loaded->segments[out_loaded->segment_count].vaddr = ph->p_vaddr; + out_loaded->segments[out_loaded->segment_count].memsz = ph->p_memsz; + out_loaded->segments[out_loaded->segment_count].filesz = ph->p_filesz; + out_loaded->segments[out_loaded->segment_count].flags = ph->p_flags; + out_loaded->segment_count++; + } + + return CLKS_TRUE; +} \ No newline at end of file diff --git a/clks/kernel/elfrunner.c b/clks/kernel/elfrunner.c new file mode 100644 index 0000000..f0f941c --- /dev/null +++ b/clks/kernel/elfrunner.c @@ -0,0 +1,38 @@ +#include +#include +#include +#include +#include + +static clks_bool clks_elfrunner_ready = CLKS_FALSE; + +void clks_elfrunner_init(void) { + clks_elfrunner_ready = CLKS_TRUE; + clks_log(CLKS_LOG_INFO, "ELF", "ELFRUNNER FRAMEWORK ONLINE"); +} + +clks_bool clks_elfrunner_probe_kernel_executable(void) { + const struct limine_file *exe = clks_boot_get_executable_file(); + struct clks_elf64_info info; + + if (clks_elfrunner_ready == CLKS_FALSE) { + return CLKS_FALSE; + } + + if (exe == CLKS_NULL || exe->address == CLKS_NULL || exe->size == 0ULL) { + clks_log(CLKS_LOG_ERROR, "ELF", "NO EXECUTABLE FILE FROM LIMINE"); + return CLKS_FALSE; + } + + if (clks_elf64_inspect(exe->address, exe->size, &info) == CLKS_FALSE) { + clks_log(CLKS_LOG_ERROR, "ELF", "KERNEL ELF INSPECT FAILED"); + return CLKS_FALSE; + } + + clks_log_hex(CLKS_LOG_INFO, "ELF", "ENTRY", info.entry); + clks_log_hex(CLKS_LOG_INFO, "ELF", "PHNUM", info.phnum); + clks_log_hex(CLKS_LOG_INFO, "ELF", "LOAD_SEGMENTS", info.loadable_segments); + clks_log_hex(CLKS_LOG_INFO, "ELF", "TOTAL_MEMSZ", info.total_load_memsz); + + return CLKS_TRUE; +} \ No newline at end of file diff --git a/clks/kernel/interrupts.c b/clks/kernel/interrupts.c index a7a56e2..de9b758 100644 --- a/clks/kernel/interrupts.c +++ b/clks/kernel/interrupts.c @@ -3,10 +3,12 @@ #include #include #include +#include #include #define CLKS_IDT_ENTRY_COUNT 256U #define CLKS_INTERRUPT_GATE 0x8EU +#define CLKS_USER_INT_GATE 0xEEU #define CLKS_PIC1_CMD 0x20U #define CLKS_PIC1_DATA 0x21U @@ -17,6 +19,7 @@ #define CLKS_IRQ_BASE 32U #define CLKS_IRQ_TIMER 32U #define CLKS_IRQ_LAST 47U +#define CLKS_SYSCALL_VECTOR 128U struct clks_idt_entry { u16 offset_low; @@ -107,6 +110,7 @@ extern void clks_isr_stub_44(void); extern void clks_isr_stub_45(void); extern void clks_isr_stub_46(void); extern void clks_isr_stub_47(void); +extern void clks_isr_stub_128(void); static struct clks_idt_entry clks_idt[CLKS_IDT_ENTRY_COUNT]; static u16 clks_idt_code_selector = 0x08U; @@ -228,6 +232,11 @@ static void clks_enable_interrupts(void) { void clks_interrupt_dispatch(struct clks_interrupt_frame *frame) { u64 vector = frame->vector; + if (vector == CLKS_SYSCALL_VECTOR) { + frame->rax = clks_syscall_dispatch((void *)frame); + return; + } + if (vector < 32U) { clks_log(CLKS_LOG_ERROR, "EXC", clks_exception_names[vector]); clks_log_hex(CLKS_LOG_ERROR, "EXC", "VECTOR", vector); @@ -238,6 +247,7 @@ void clks_interrupt_dispatch(struct clks_interrupt_frame *frame) { if (vector == CLKS_IRQ_TIMER) { clks_timer_ticks++; + clks_scheduler_on_timer_tick(clks_timer_ticks); } if (vector >= CLKS_IRQ_BASE && vector <= CLKS_IRQ_LAST) { @@ -304,6 +314,8 @@ void clks_interrupts_init(void) { clks_idt_set_gate(46, clks_isr_stub_46, CLKS_INTERRUPT_GATE); clks_idt_set_gate(47, clks_isr_stub_47, CLKS_INTERRUPT_GATE); + clks_idt_set_gate(CLKS_SYSCALL_VECTOR, clks_isr_stub_128, CLKS_USER_INT_GATE); + clks_pic_remap_and_mask(); clks_load_idt(); clks_enable_interrupts(); diff --git a/clks/kernel/kmain.c b/clks/kernel/kmain.c index 1d5b352..6dd85d1 100644 --- a/clks/kernel/kmain.c +++ b/clks/kernel/kmain.c @@ -1,5 +1,6 @@ #include #include +#include #include #include #include @@ -8,6 +9,7 @@ #include #include #include +#include #include #include @@ -18,6 +20,7 @@ void clks_kernel_main(void) { struct clks_heap_stats heap_stats; struct clks_scheduler_stats sched_stats; void *heap_probe = CLKS_NULL; + u64 syscall_ticks; clks_serial_init(); @@ -33,7 +36,7 @@ void clks_kernel_main(void) { clks_tty_init(); } - clks_log(CLKS_LOG_INFO, "BOOT", "CLEONOS STAGE4 START"); + clks_log(CLKS_LOG_INFO, "BOOT", "CLEONOS STAGE5 START"); if (boot_fb == CLKS_NULL) { clks_log(CLKS_LOG_WARN, "VIDEO", "NO FRAMEBUFFER FROM LIMINE"); @@ -93,9 +96,20 @@ void clks_kernel_main(void) { sched_stats = clks_scheduler_get_stats(); clks_log_hex(CLKS_LOG_INFO, "SCHED", "TASK_COUNT", sched_stats.task_count); + clks_elfrunner_init(); + + if (clks_elfrunner_probe_kernel_executable() == CLKS_FALSE) { + clks_log(CLKS_LOG_ERROR, "ELF", "KERNEL ELF PROBE FAILED"); + } + + clks_syscall_init(); + clks_interrupts_init(); clks_log(CLKS_LOG_INFO, "INT", "IDT + PIC INITIALIZED"); + syscall_ticks = clks_syscall_invoke_kernel(CLKS_SYSCALL_TIMER_TICKS, 0ULL, 0ULL, 0ULL); + clks_log_hex(CLKS_LOG_INFO, "SYSCALL", "TICKS", syscall_ticks); + clks_log(CLKS_LOG_INFO, "TTY", "VIRTUAL TTY0 READY"); clks_log(CLKS_LOG_DEBUG, "KERNEL", "IDLE LOOP ENTER"); diff --git a/clks/kernel/limine_requests.c b/clks/kernel/limine_requests.c index 102620f..361b471 100644 --- a/clks/kernel/limine_requests.c +++ b/clks/kernel/limine_requests.c @@ -21,6 +21,13 @@ CLKS_USED static volatile struct limine_memmap_request limine_memmap_request .response = CLKS_NULL, }; +CLKS_USED static volatile struct limine_executable_file_request limine_executable_file_request + __attribute__((section(".limine_requests"))) = { + .id = LIMINE_EXECUTABLE_FILE_REQUEST, + .revision = 0, + .response = CLKS_NULL, + }; + CLKS_USED static volatile u64 limine_requests_end[] __attribute__((section(".limine_requests_end"))) = LIMINE_REQUESTS_END_MARKER; @@ -50,4 +57,14 @@ const struct limine_memmap_response *clks_boot_get_memmap(void) { } return request->response; +} + +const struct limine_file *clks_boot_get_executable_file(void) { + volatile struct limine_executable_file_request *request = &limine_executable_file_request; + + if (request->response == CLKS_NULL) { + return CLKS_NULL; + } + + return request->response->executable_file; } \ No newline at end of file diff --git a/clks/kernel/syscall.c b/clks/kernel/syscall.c new file mode 100644 index 0000000..1e4d069 --- /dev/null +++ b/clks/kernel/syscall.c @@ -0,0 +1,102 @@ +#include +#include +#include +#include +#include + +struct clks_syscall_frame { + u64 rax; + u64 rbx; + u64 rcx; + u64 rdx; + u64 rsi; + u64 rdi; + u64 rbp; + u64 r8; + u64 r9; + u64 r10; + u64 r11; + u64 r12; + u64 r13; + u64 r14; + u64 r15; + u64 vector; + u64 error_code; + u64 rip; + u64 cs; + u64 rflags; + u64 rsp; + u64 ss; +}; + +static clks_bool clks_syscall_ready = CLKS_FALSE; + +static u64 clks_syscall_log_write(u64 arg0, u64 arg1) { + const char *src = (const char *)arg0; + u64 len = arg1; + char buf[192]; + u64 i; + + if (src == CLKS_NULL || len == 0ULL) { + return 0ULL; + } + + if (len > (sizeof(buf) - 1U)) { + len = sizeof(buf) - 1U; + } + + for (i = 0; i < len; i++) { + buf[i] = src[i]; + } + + buf[len] = '\0'; + clks_log(CLKS_LOG_INFO, "SYSCALL", buf); + + return len; +} + +void clks_syscall_init(void) { + clks_syscall_ready = CLKS_TRUE; + clks_log(CLKS_LOG_INFO, "SYSCALL", "INT80 FRAMEWORK ONLINE"); +} + +u64 clks_syscall_dispatch(void *frame_ptr) { + struct clks_syscall_frame *frame = (struct clks_syscall_frame *)frame_ptr; + u64 id; + + if (clks_syscall_ready == CLKS_FALSE || frame == CLKS_NULL) { + return (u64)-1; + } + + id = frame->rax; + + switch (id) { + case CLKS_SYSCALL_LOG_WRITE: + return clks_syscall_log_write(frame->rbx, frame->rcx); + case CLKS_SYSCALL_TIMER_TICKS: + return clks_interrupts_timer_ticks(); + case CLKS_SYSCALL_TASK_COUNT: { + struct clks_scheduler_stats stats = clks_scheduler_get_stats(); + return stats.task_count; + } + case CLKS_SYSCALL_CURRENT_TASK_ID: { + struct clks_scheduler_stats stats = clks_scheduler_get_stats(); + return stats.current_task_id; + } + default: + return (u64)-1; + } +} + +u64 clks_syscall_invoke_kernel(u64 id, u64 arg0, u64 arg1, u64 arg2) { + u64 ret; + + __asm__ volatile( + "int $0x80" + : "=a"(ret) + : "a"(id), "b"(arg0), "c"(arg1), "d"(arg2) + : "memory" + ); + + return ret; +} \ No newline at end of file diff --git a/docs/stage5.md b/docs/stage5.md new file mode 100644 index 0000000..d345707 --- /dev/null +++ b/docs/stage5.md @@ -0,0 +1,34 @@ +# CLeonOS Stage5 + +## Stage Goal +- Add ELF64 parsing and loading framework for CLKS. +- Add executable-file probe path via Limine executable request. +- Add syscall framework with `int 0x80` dispatcher. +- Keep scheduler + interrupt flow integrated with syscall path. + +## Acceptance Criteria +- Kernel logs `CLEONOS STAGE5 START`. +- ELF runner initializes and probes kernel ELF metadata (entry/phnum/segments). +- Syscall framework initializes and `int 0x80` returns timer ticks. +- IRQ timer and scheduler still run without panic/reboot. + +## Build Targets +- `make setup` +- `make iso` +- `make run` +- `make debug` + +## QEMU Command +- `qemu-system-x86_64 -M q35 -m 1024M -cdrom build/CLeonOS-x86_64.iso -serial stdio` + +## Common Bugs and Debugging +- `KERNEL ELF PROBE FAILED`: + - Verify Limine executable file request is present in `.limine_requests` section. +- Syscall always returns `-1`: + - Check `clks_syscall_init()` call order and vector `0x80` IDT gate. +- `int 0x80` causes exception: + - Ensure vector 128 stub exists and IDT gate uses DPL3-capable flags (`0xEE`). +- Linker undefined symbols for ELF/syscall: + - Confirm `elf64.c`, `elfrunner.c`, `syscall.c` are listed in `C_SOURCES`. +- Interrupt instability after syscall integration: + - Confirm timer IRQ EOI path is untouched and syscall vector path returns early. \ No newline at end of file