代码分类

This commit is contained in:
2026-04-19 16:42:27 +08:00
parent 739be1d7f7
commit c21c5b327e
37 changed files with 0 additions and 103 deletions

View File

@@ -0,0 +1,349 @@
#include <clks/compiler.h>
#include <clks/cpu.h>
#include <clks/exec.h>
#include <clks/interrupts.h>
#include <clks/log.h>
#include <clks/keyboard.h>
#include <clks/mouse.h>
#include <clks/panic.h>
#include <clks/scheduler.h>
#include <clks/syscall.h>
#include <clks/types.h>
#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
#define CLKS_PIC2_CMD 0xA0U
#define CLKS_PIC2_DATA 0xA1U
#define CLKS_PIC_EOI 0x20U
#define CLKS_IRQ_BASE 32U
#define CLKS_IRQ_TIMER 32U
#define CLKS_IRQ_KEYBOARD 33U
#define CLKS_IRQ_MOUSE 44U
#define CLKS_IRQ_LAST 47U
#define CLKS_SYSCALL_VECTOR 128U
#define CLKS_PS2_DATA_PORT 0x60U
#define CLKS_PS2_STATUS_PORT 0x64U
struct clks_idt_entry {
u16 offset_low;
u16 selector;
u8 ist;
u8 type_attr;
u16 offset_mid;
u32 offset_high;
u32 zero;
} CLKS_PACKED;
struct clks_idtr {
u16 limit;
u64 base;
} CLKS_PACKED;
struct clks_interrupt_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;
};
extern void clks_isr_stub_default(void);
extern void clks_isr_stub_0(void);
extern void clks_isr_stub_1(void);
extern void clks_isr_stub_2(void);
extern void clks_isr_stub_3(void);
extern void clks_isr_stub_4(void);
extern void clks_isr_stub_5(void);
extern void clks_isr_stub_6(void);
extern void clks_isr_stub_7(void);
extern void clks_isr_stub_8(void);
extern void clks_isr_stub_9(void);
extern void clks_isr_stub_10(void);
extern void clks_isr_stub_11(void);
extern void clks_isr_stub_12(void);
extern void clks_isr_stub_13(void);
extern void clks_isr_stub_14(void);
extern void clks_isr_stub_15(void);
extern void clks_isr_stub_16(void);
extern void clks_isr_stub_17(void);
extern void clks_isr_stub_18(void);
extern void clks_isr_stub_19(void);
extern void clks_isr_stub_20(void);
extern void clks_isr_stub_21(void);
extern void clks_isr_stub_22(void);
extern void clks_isr_stub_23(void);
extern void clks_isr_stub_24(void);
extern void clks_isr_stub_25(void);
extern void clks_isr_stub_26(void);
extern void clks_isr_stub_27(void);
extern void clks_isr_stub_28(void);
extern void clks_isr_stub_29(void);
extern void clks_isr_stub_30(void);
extern void clks_isr_stub_31(void);
extern void clks_isr_stub_32(void);
extern void clks_isr_stub_33(void);
extern void clks_isr_stub_34(void);
extern void clks_isr_stub_35(void);
extern void clks_isr_stub_36(void);
extern void clks_isr_stub_37(void);
extern void clks_isr_stub_38(void);
extern void clks_isr_stub_39(void);
extern void clks_isr_stub_40(void);
extern void clks_isr_stub_41(void);
extern void clks_isr_stub_42(void);
extern void clks_isr_stub_43(void);
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;
static u64 clks_timer_ticks = 0;
static const char *clks_exception_names[32] = {"DE DIVIDE ERROR",
"DB DEBUG",
"NMI",
"BP BREAKPOINT",
"OF OVERFLOW",
"BR BOUND RANGE",
"UD INVALID OPCODE",
"NM DEVICE NOT AVAILABLE",
"DF DOUBLE FAULT",
"COPROCESSOR SEGMENT",
"TS INVALID TSS",
"NP SEGMENT NOT PRESENT",
"SS STACK SEGMENT",
"GP GENERAL PROTECTION",
"PF PAGE FAULT",
"RESERVED",
"MF X87 FLOAT",
"AC ALIGNMENT CHECK",
"MC MACHINE CHECK",
"XF SIMD FLOAT",
"VE VIRT EXCEPTION",
"CP CONTROL PROTECTION",
"RESERVED",
"RESERVED",
"RESERVED",
"RESERVED",
"RESERVED",
"RESERVED",
"HV HYPERVISOR",
"VC VMM COMM",
"SX SECURITY",
"RESERVED"};
static inline void clks_outb(u16 port, u8 value) {
__asm__ volatile("outb %0, %1" : : "a"(value), "Nd"(port));
}
static inline u8 clks_inb(u16 port) {
u8 value;
__asm__ volatile("inb %1, %0" : "=a"(value) : "Nd"(port));
return value;
}
static inline void clks_io_wait(void) {
__asm__ volatile("outb %%al, $0x80" : : "a"(0));
}
static void clks_pic_remap_and_mask(void) {
u8 master_mask = clks_inb(CLKS_PIC1_DATA);
u8 slave_mask = clks_inb(CLKS_PIC2_DATA);
clks_outb(CLKS_PIC1_CMD, 0x11);
clks_io_wait();
clks_outb(CLKS_PIC2_CMD, 0x11);
clks_io_wait();
clks_outb(CLKS_PIC1_DATA, CLKS_IRQ_BASE);
clks_io_wait();
clks_outb(CLKS_PIC2_DATA, CLKS_IRQ_BASE + 8U);
clks_io_wait();
clks_outb(CLKS_PIC1_DATA, 4U);
clks_io_wait();
clks_outb(CLKS_PIC2_DATA, 2U);
clks_io_wait();
clks_outb(CLKS_PIC1_DATA, 0x01);
clks_io_wait();
clks_outb(CLKS_PIC2_DATA, 0x01);
clks_io_wait();
(void)master_mask;
(void)slave_mask;
clks_outb(CLKS_PIC1_DATA, 0xF8U);
clks_outb(CLKS_PIC2_DATA, 0xEFU);
}
static void clks_pic_send_eoi(u64 vector) {
if (vector >= 40U) {
clks_outb(CLKS_PIC2_CMD, CLKS_PIC_EOI);
}
clks_outb(CLKS_PIC1_CMD, CLKS_PIC_EOI);
}
static void clks_idt_set_gate(u8 vector, void (*handler)(void), u8 flags) {
u64 addr = (u64)handler;
clks_idt[vector].offset_low = (u16)(addr & 0xFFFFULL);
clks_idt[vector].selector = clks_idt_code_selector;
clks_idt[vector].ist = 0;
clks_idt[vector].type_attr = flags;
clks_idt[vector].offset_mid = (u16)((addr >> 16) & 0xFFFFULL);
clks_idt[vector].offset_high = (u32)((addr >> 32) & 0xFFFFFFFFULL);
clks_idt[vector].zero = 0;
}
static void clks_load_idt(void) {
struct clks_idtr idtr;
idtr.limit = (u16)(sizeof(clks_idt) - 1U);
idtr.base = (u64)&clks_idt[0];
__asm__ volatile("lidt %0" : : "m"(idtr));
}
static clks_bool clks_ps2_has_output(void) {
return (clks_inb(CLKS_PS2_STATUS_PORT) & 0x01U) != 0U ? CLKS_TRUE : CLKS_FALSE;
}
static void clks_enable_interrupts(void) {
__asm__ volatile("sti");
}
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) {
if (clks_exec_handle_exception(vector, frame->error_code, frame->rip, &frame->rip, &frame->rdi, &frame->rsi) ==
CLKS_TRUE) {
return;
}
clks_panic_exception(clks_exception_names[vector], vector, frame->error_code, frame->rip, frame->rbp,
frame->rsp);
}
if (vector == CLKS_IRQ_TIMER) {
clks_timer_ticks++;
clks_scheduler_on_timer_tick(clks_timer_ticks);
} else if (vector == CLKS_IRQ_KEYBOARD) {
if (clks_ps2_has_output() == CLKS_TRUE) {
u8 scancode = clks_inb(CLKS_PS2_DATA_PORT);
clks_keyboard_handle_scancode(scancode);
}
} else if (vector == CLKS_IRQ_MOUSE) {
if (clks_ps2_has_output() == CLKS_TRUE) {
u8 data_byte = clks_inb(CLKS_PS2_DATA_PORT);
clks_mouse_handle_byte(data_byte);
}
}
if (vector >= CLKS_IRQ_BASE && vector <= CLKS_IRQ_LAST) {
(void)clks_exec_try_unwind_signaled_process(frame->rip, &frame->rip, &frame->rdi, &frame->rsi);
clks_pic_send_eoi(vector);
}
}
void clks_interrupts_init(void) {
u32 i;
__asm__ volatile("mov %%cs, %0" : "=r"(clks_idt_code_selector));
for (i = 0; i < CLKS_IDT_ENTRY_COUNT; i++) {
clks_idt_set_gate((u8)i, clks_isr_stub_default, CLKS_INTERRUPT_GATE);
}
clks_idt_set_gate(0, clks_isr_stub_0, CLKS_INTERRUPT_GATE);
clks_idt_set_gate(1, clks_isr_stub_1, CLKS_INTERRUPT_GATE);
clks_idt_set_gate(2, clks_isr_stub_2, CLKS_INTERRUPT_GATE);
clks_idt_set_gate(3, clks_isr_stub_3, CLKS_INTERRUPT_GATE);
clks_idt_set_gate(4, clks_isr_stub_4, CLKS_INTERRUPT_GATE);
clks_idt_set_gate(5, clks_isr_stub_5, CLKS_INTERRUPT_GATE);
clks_idt_set_gate(6, clks_isr_stub_6, CLKS_INTERRUPT_GATE);
clks_idt_set_gate(7, clks_isr_stub_7, CLKS_INTERRUPT_GATE);
clks_idt_set_gate(8, clks_isr_stub_8, CLKS_INTERRUPT_GATE);
clks_idt_set_gate(9, clks_isr_stub_9, CLKS_INTERRUPT_GATE);
clks_idt_set_gate(10, clks_isr_stub_10, CLKS_INTERRUPT_GATE);
clks_idt_set_gate(11, clks_isr_stub_11, CLKS_INTERRUPT_GATE);
clks_idt_set_gate(12, clks_isr_stub_12, CLKS_INTERRUPT_GATE);
clks_idt_set_gate(13, clks_isr_stub_13, CLKS_INTERRUPT_GATE);
clks_idt_set_gate(14, clks_isr_stub_14, CLKS_INTERRUPT_GATE);
clks_idt_set_gate(15, clks_isr_stub_15, CLKS_INTERRUPT_GATE);
clks_idt_set_gate(16, clks_isr_stub_16, CLKS_INTERRUPT_GATE);
clks_idt_set_gate(17, clks_isr_stub_17, CLKS_INTERRUPT_GATE);
clks_idt_set_gate(18, clks_isr_stub_18, CLKS_INTERRUPT_GATE);
clks_idt_set_gate(19, clks_isr_stub_19, CLKS_INTERRUPT_GATE);
clks_idt_set_gate(20, clks_isr_stub_20, CLKS_INTERRUPT_GATE);
clks_idt_set_gate(21, clks_isr_stub_21, CLKS_INTERRUPT_GATE);
clks_idt_set_gate(22, clks_isr_stub_22, CLKS_INTERRUPT_GATE);
clks_idt_set_gate(23, clks_isr_stub_23, CLKS_INTERRUPT_GATE);
clks_idt_set_gate(24, clks_isr_stub_24, CLKS_INTERRUPT_GATE);
clks_idt_set_gate(25, clks_isr_stub_25, CLKS_INTERRUPT_GATE);
clks_idt_set_gate(26, clks_isr_stub_26, CLKS_INTERRUPT_GATE);
clks_idt_set_gate(27, clks_isr_stub_27, CLKS_INTERRUPT_GATE);
clks_idt_set_gate(28, clks_isr_stub_28, CLKS_INTERRUPT_GATE);
clks_idt_set_gate(29, clks_isr_stub_29, CLKS_INTERRUPT_GATE);
clks_idt_set_gate(30, clks_isr_stub_30, CLKS_INTERRUPT_GATE);
clks_idt_set_gate(31, clks_isr_stub_31, CLKS_INTERRUPT_GATE);
clks_idt_set_gate(32, clks_isr_stub_32, CLKS_INTERRUPT_GATE);
clks_idt_set_gate(33, clks_isr_stub_33, CLKS_INTERRUPT_GATE);
clks_idt_set_gate(34, clks_isr_stub_34, CLKS_INTERRUPT_GATE);
clks_idt_set_gate(35, clks_isr_stub_35, CLKS_INTERRUPT_GATE);
clks_idt_set_gate(36, clks_isr_stub_36, CLKS_INTERRUPT_GATE);
clks_idt_set_gate(37, clks_isr_stub_37, CLKS_INTERRUPT_GATE);
clks_idt_set_gate(38, clks_isr_stub_38, CLKS_INTERRUPT_GATE);
clks_idt_set_gate(39, clks_isr_stub_39, CLKS_INTERRUPT_GATE);
clks_idt_set_gate(40, clks_isr_stub_40, CLKS_INTERRUPT_GATE);
clks_idt_set_gate(41, clks_isr_stub_41, CLKS_INTERRUPT_GATE);
clks_idt_set_gate(42, clks_isr_stub_42, CLKS_INTERRUPT_GATE);
clks_idt_set_gate(43, clks_isr_stub_43, CLKS_INTERRUPT_GATE);
clks_idt_set_gate(44, clks_isr_stub_44, CLKS_INTERRUPT_GATE);
clks_idt_set_gate(45, clks_isr_stub_45, CLKS_INTERRUPT_GATE);
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();
}
u64 clks_interrupts_timer_ticks(void) {
return clks_timer_ticks;
}

465
clks/kernel/core/kmain.c Normal file
View File

@@ -0,0 +1,465 @@
// Kernel main function
#include <clks/boot.h>
#include <clks/audio.h>
#include <clks/cpu.h>
#include <clks/desktop.h>
#include <clks/driver.h>
#include <clks/elfrunner.h>
#include <clks/exec.h>
#include <clks/framebuffer.h>
#include <clks/fs.h>
#include <clks/heap.h>
#include <clks/interrupts.h>
#include <clks/keyboard.h>
#include <clks/kelf.h>
#include <clks/kernel.h>
#include <clks/log.h>
#include <clks/mouse.h>
#include <clks/pmm.h>
#include <clks/scheduler.h>
#include <clks/serial.h>
#include <clks/service.h>
#include <clks/shell.h>
#include <clks/syscall.h>
#include <clks/tty.h>
#include <clks/types.h>
#include <clks/userland.h>
#ifndef CLKS_CFG_AUDIO
#define CLKS_CFG_AUDIO 1
#endif
#ifndef CLKS_CFG_MOUSE
#define CLKS_CFG_MOUSE 1
#endif
#ifndef CLKS_CFG_DESKTOP
#define CLKS_CFG_DESKTOP 1
#endif
#ifndef CLKS_CFG_DRIVER_MANAGER
#define CLKS_CFG_DRIVER_MANAGER 1
#endif
#ifndef CLKS_CFG_KELF
#define CLKS_CFG_KELF 1
#endif
#ifndef CLKS_CFG_HEAP_SELFTEST
#define CLKS_CFG_HEAP_SELFTEST 1
#endif
#ifndef CLKS_CFG_EXTERNAL_PSF
#define CLKS_CFG_EXTERNAL_PSF 1
#endif
#ifndef CLKS_CFG_KEYBOARD
#define CLKS_CFG_KEYBOARD 1
#endif
#ifndef CLKS_CFG_ELFRUNNER_PROBE
#define CLKS_CFG_ELFRUNNER_PROBE 1
#endif
#ifndef CLKS_CFG_KLOGD_TASK
#define CLKS_CFG_KLOGD_TASK 1
#endif
#ifndef CLKS_CFG_KWORKER_TASK
#define CLKS_CFG_KWORKER_TASK 1
#endif
#ifndef CLKS_CFG_USRD_TASK
#define CLKS_CFG_USRD_TASK 1
#endif
#ifndef CLKS_CFG_BOOT_VIDEO_LOG
#define CLKS_CFG_BOOT_VIDEO_LOG 1
#endif
#ifndef CLKS_CFG_PMM_STATS_LOG
#define CLKS_CFG_PMM_STATS_LOG 1
#endif
#ifndef CLKS_CFG_HEAP_STATS_LOG
#define CLKS_CFG_HEAP_STATS_LOG 1
#endif
#ifndef CLKS_CFG_FS_ROOT_LOG
#define CLKS_CFG_FS_ROOT_LOG 1
#endif
#ifndef CLKS_CFG_SYSTEM_DIR_CHECK
#define CLKS_CFG_SYSTEM_DIR_CHECK 1
#endif
#ifndef CLKS_CFG_ELFRUNNER_INIT
#define CLKS_CFG_ELFRUNNER_INIT 1
#endif
#ifndef CLKS_CFG_SYSCALL_TICK_QUERY
#define CLKS_CFG_SYSCALL_TICK_QUERY 1
#endif
#ifndef CLKS_CFG_TTY_READY_LOG
#define CLKS_CFG_TTY_READY_LOG 1
#endif
#ifndef CLKS_CFG_IDLE_DEBUG_LOG
#define CLKS_CFG_IDLE_DEBUG_LOG 1
#endif
#ifndef CLKS_CFG_SCHED_TASK_COUNT_LOG
#define CLKS_CFG_SCHED_TASK_COUNT_LOG 1
#endif
#ifndef CLKS_CFG_INTERRUPT_READY_LOG
#define CLKS_CFG_INTERRUPT_READY_LOG 1
#endif
#ifndef CLKS_CFG_SHELL_MODE_LOG
#define CLKS_CFG_SHELL_MODE_LOG 1
#endif
#if CLKS_CFG_KLOGD_TASK
static void clks_task_klogd(u64 tick) {
static u64 last_emit = 0ULL;
clks_service_heartbeat(CLKS_SERVICE_LOG, tick);
if (tick - last_emit >= 1000ULL) {
clks_log_hex(CLKS_LOG_DEBUG, "TASK", "KLOGD_TICK", tick);
last_emit = tick;
}
}
#endif
#if CLKS_CFG_KWORKER_TASK
static void clks_task_kworker(u64 tick) {
static u32 phase = 0U;
clks_service_heartbeat(CLKS_SERVICE_SCHED, tick);
switch (phase) {
case 0U:
clks_service_heartbeat(CLKS_SERVICE_MEM, tick);
break;
case 1U:
clks_service_heartbeat(CLKS_SERVICE_FS, tick);
break;
case 2U:
clks_service_heartbeat(CLKS_SERVICE_DRIVER, tick);
break;
default:
clks_service_heartbeat(CLKS_SERVICE_LOG, tick);
break;
}
phase = (phase + 1U) & 3U;
}
#endif
#if CLKS_CFG_KELF
static void clks_task_kelfd(u64 tick) {
clks_service_heartbeat(CLKS_SERVICE_KELF, tick);
clks_kelf_tick(tick);
}
#endif
#if CLKS_CFG_USRD_TASK
static void clks_task_usrd(u64 tick) {
clks_service_heartbeat(CLKS_SERVICE_USER, tick);
clks_exec_tick(tick);
clks_userland_tick(tick);
#if CLKS_CFG_DESKTOP
clks_desktop_tick(tick);
#endif
clks_tty_tick(tick);
clks_shell_tick(tick);
}
#endif
void clks_kernel_main(void) {
const struct limine_framebuffer *boot_fb;
const struct limine_memmap_response *boot_memmap;
struct clks_pmm_stats pmm_stats;
struct clks_heap_stats heap_stats;
struct clks_fs_node_info fs_system_dir = {0};
u64 syscall_ticks;
u64 fs_root_children;
clks_serial_init();
if (clks_boot_base_revision_supported() == CLKS_FALSE) {
clks_serial_write("[ERROR][BOOT] LIMINE BASE REVISION NOT SUPPORTED\n");
clks_cpu_halt_forever();
}
boot_fb = clks_boot_get_framebuffer();
if (boot_fb != CLKS_NULL) {
clks_fb_init(boot_fb);
clks_tty_init();
}
clks_log(CLKS_LOG_INFO, "BOOT", "CLEONOS START");
if (boot_fb == CLKS_NULL) {
clks_log(CLKS_LOG_WARN, "VIDEO", "NO FRAMEBUFFER FROM LIMINE");
} else {
#if CLKS_CFG_BOOT_VIDEO_LOG
clks_log_hex(CLKS_LOG_INFO, "VIDEO", "WIDTH", boot_fb->width);
clks_log_hex(CLKS_LOG_INFO, "VIDEO", "HEIGHT", boot_fb->height);
clks_log_hex(CLKS_LOG_INFO, "VIDEO", "PITCH", boot_fb->pitch);
clks_log_hex(CLKS_LOG_INFO, "VIDEO", "BPP", boot_fb->bpp);
#else
clks_log(CLKS_LOG_WARN, "CFG", "BOOT VIDEO LOGS DISABLED BY MENUCONFIG");
#endif
}
#if defined(CLKS_ARCH_X86_64)
clks_log(CLKS_LOG_INFO, "ARCH", "X86_64 ONLINE");
#elif defined(CLKS_ARCH_AARCH64)
clks_log(CLKS_LOG_INFO, "ARCH", "AARCH64 ONLINE");
#endif
boot_memmap = clks_boot_get_memmap();
if (boot_memmap == CLKS_NULL) {
clks_log(CLKS_LOG_ERROR, "MEM", "NO LIMINE MEMMAP RESPONSE");
clks_cpu_halt_forever();
}
clks_pmm_init(boot_memmap);
pmm_stats = clks_pmm_get_stats();
#if CLKS_CFG_PMM_STATS_LOG
clks_log_hex(CLKS_LOG_INFO, "PMM", "MANAGED_PAGES", pmm_stats.managed_pages);
clks_log_hex(CLKS_LOG_INFO, "PMM", "FREE_PAGES", pmm_stats.free_pages);
clks_log_hex(CLKS_LOG_INFO, "PMM", "USED_PAGES", pmm_stats.used_pages);
clks_log_hex(CLKS_LOG_INFO, "PMM", "DROPPED_PAGES", pmm_stats.dropped_pages);
#else
(void)pmm_stats;
clks_log(CLKS_LOG_WARN, "CFG", "PMM STATS LOGS DISABLED BY MENUCONFIG");
#endif
clks_heap_init();
heap_stats = clks_heap_get_stats();
#if CLKS_CFG_HEAP_STATS_LOG
clks_log_hex(CLKS_LOG_INFO, "HEAP", "TOTAL_BYTES", heap_stats.total_bytes);
clks_log_hex(CLKS_LOG_INFO, "HEAP", "FREE_BYTES", heap_stats.free_bytes);
#else
(void)heap_stats;
clks_log(CLKS_LOG_WARN, "CFG", "HEAP STATS LOGS DISABLED BY MENUCONFIG");
#endif
#if CLKS_CFG_HEAP_SELFTEST
void *heap_probe = clks_kmalloc(128);
if (heap_probe == CLKS_NULL) {
clks_log(CLKS_LOG_ERROR, "HEAP", "KMALLOC SELFTEST FAILED");
} else {
clks_log(CLKS_LOG_INFO, "HEAP", "KMALLOC SELFTEST OK");
clks_kfree(heap_probe);
}
#else
clks_log(CLKS_LOG_WARN, "CFG", "HEAP SELFTEST DISABLED BY MENUCONFIG");
#endif
clks_fs_init();
if (clks_fs_is_ready() == CLKS_FALSE) {
clks_log(CLKS_LOG_ERROR, "FS", "RAMDISK FS INIT FAILED");
clks_cpu_halt_forever();
}
fs_root_children = clks_fs_count_children("/");
#if CLKS_CFG_FS_ROOT_LOG
clks_log_hex(CLKS_LOG_INFO, "FS", "ROOT_CHILDREN", fs_root_children);
#else
(void)fs_root_children;
#endif
#if CLKS_CFG_SYSTEM_DIR_CHECK
if (clks_fs_stat("/system", &fs_system_dir) == CLKS_FALSE || fs_system_dir.type != CLKS_FS_NODE_DIR) {
clks_log(CLKS_LOG_ERROR, "FS", "/SYSTEM DIRECTORY CHECK FAILED");
clks_cpu_halt_forever();
}
#else
(void)fs_system_dir;
clks_log(CLKS_LOG_WARN, "CFG", "/SYSTEM DIRECTORY CHECK DISABLED BY MENUCONFIG");
#endif
if (boot_fb != CLKS_NULL) {
#if CLKS_CFG_EXTERNAL_PSF
const void *tty_psf_blob;
u64 tty_psf_size = 0ULL;
tty_psf_blob = clks_fs_read_all("/system/tty.psf", &tty_psf_size);
if (tty_psf_blob != CLKS_NULL && clks_fb_load_psf_font(tty_psf_blob, tty_psf_size) == CLKS_TRUE) {
clks_tty_init();
clks_log(CLKS_LOG_INFO, "TTY", "EXTERNAL PSF LOADED /SYSTEM/TTY.PSF");
clks_log_hex(CLKS_LOG_INFO, "TTY", "PSF_SIZE", tty_psf_size);
} else {
clks_log(CLKS_LOG_WARN, "TTY", "EXTERNAL PSF LOAD FAILED, USING BUILTIN");
}
#else
clks_log(CLKS_LOG_WARN, "CFG", "EXTERNAL PSF LOADING DISABLED BY MENUCONFIG");
#endif
}
clks_exec_init();
#if CLKS_CFG_AUDIO
clks_audio_init();
#else
clks_log(CLKS_LOG_WARN, "CFG", "AUDIO DISABLED BY MENUCONFIG");
#endif
#if CLKS_CFG_KEYBOARD
clks_keyboard_init();
#else
clks_log(CLKS_LOG_WARN, "CFG", "KEYBOARD DISABLED BY MENUCONFIG");
#endif
#if CLKS_CFG_MOUSE
clks_mouse_init();
#else
clks_log(CLKS_LOG_WARN, "CFG", "MOUSE DISABLED BY MENUCONFIG");
#endif
#if CLKS_CFG_DESKTOP
clks_desktop_init();
#else
clks_log(CLKS_LOG_WARN, "CFG", "DESKTOP DISABLED BY MENUCONFIG");
#endif
if (clks_userland_init() == CLKS_FALSE) {
clks_log(CLKS_LOG_ERROR, "USER", "USERLAND INIT FAILED");
clks_cpu_halt_forever();
}
#if CLKS_CFG_DRIVER_MANAGER
clks_driver_init();
#else
clks_log(CLKS_LOG_WARN, "CFG", "DRIVER MANAGER DISABLED BY MENUCONFIG");
#endif
#if CLKS_CFG_KELF
clks_kelf_init();
#else
clks_log(CLKS_LOG_WARN, "CFG", "KELF DISABLED BY MENUCONFIG");
#endif
clks_scheduler_init();
#if CLKS_CFG_KLOGD_TASK
if (clks_scheduler_add_kernel_task_ex("klogd", 4U, clks_task_klogd) == CLKS_FALSE) {
clks_log(CLKS_LOG_WARN, "SCHED", "FAILED TO ADD KLOGD TASK");
}
#else
clks_log(CLKS_LOG_WARN, "SCHED", "KLOGD TASK DISABLED BY MENUCONFIG");
#endif
#if CLKS_CFG_KWORKER_TASK
if (clks_scheduler_add_kernel_task_ex("kworker", 3U, clks_task_kworker) == CLKS_FALSE) {
clks_log(CLKS_LOG_WARN, "SCHED", "FAILED TO ADD KWORKER TASK");
}
#else
clks_log(CLKS_LOG_WARN, "SCHED", "KWORKER TASK DISABLED BY MENUCONFIG");
#endif
#if CLKS_CFG_KELF
if (clks_scheduler_add_kernel_task_ex("kelfd", 5U, clks_task_kelfd) == CLKS_FALSE) {
clks_log(CLKS_LOG_WARN, "SCHED", "FAILED TO ADD KELFD TASK");
}
#else
clks_log(CLKS_LOG_WARN, "SCHED", "KELFD TASK DISABLED BY MENUCONFIG");
#endif
#if CLKS_CFG_USRD_TASK
if (clks_scheduler_add_kernel_task_ex("usrd", 4U, clks_task_usrd) == CLKS_FALSE) {
clks_log(CLKS_LOG_WARN, "SCHED", "FAILED TO ADD USRD TASK");
}
#else
clks_log(CLKS_LOG_WARN, "SCHED", "USRD TASK DISABLED BY MENUCONFIG");
#endif
#if CLKS_CFG_SCHED_TASK_COUNT_LOG
{
struct clks_scheduler_stats sched_stats = clks_scheduler_get_stats();
clks_log_hex(CLKS_LOG_INFO, "SCHED", "TASK_COUNT", sched_stats.task_count);
}
#else
clks_log(CLKS_LOG_WARN, "CFG", "SCHED TASK COUNT LOG DISABLED BY MENUCONFIG");
#endif
clks_service_init();
#if CLKS_CFG_ELFRUNNER_INIT
clks_elfrunner_init();
#else
clks_log(CLKS_LOG_WARN, "CFG", "ELFRUNNER INIT DISABLED BY MENUCONFIG");
#endif
#if CLKS_CFG_ELFRUNNER_INIT
#if CLKS_CFG_ELFRUNNER_PROBE
if (clks_elfrunner_probe_kernel_executable() == CLKS_FALSE) {
clks_log(CLKS_LOG_ERROR, "ELF", "KERNEL ELF PROBE FAILED");
}
#else
clks_log(CLKS_LOG_WARN, "CFG", "ELFRUNNER PROBE DISABLED BY MENUCONFIG");
#endif
#else
clks_log(CLKS_LOG_WARN, "CFG", "ELFRUNNER PROBE SKIPPED (INIT DISABLED)");
#endif
clks_syscall_init();
clks_interrupts_init();
#if CLKS_CFG_INTERRUPT_READY_LOG
clks_log(CLKS_LOG_INFO, "INT", "IDT + PIC INITIALIZED");
#endif
#if CLKS_CFG_SYSCALL_TICK_QUERY
syscall_ticks = clks_syscall_invoke_kernel(CLKS_SYSCALL_TIMER_TICKS, 0ULL, 0ULL, 0ULL);
clks_log_hex(CLKS_LOG_INFO, "SYSCALL", "TICKS", syscall_ticks);
#else
(void)syscall_ticks;
clks_log(CLKS_LOG_WARN, "CFG", "SYSCALL TICK QUERY DISABLED BY MENUCONFIG");
#endif
clks_shell_init();
#if CLKS_CFG_USRD_TASK
#if CLKS_CFG_SHELL_MODE_LOG
if (clks_userland_shell_auto_exec_enabled() == CLKS_TRUE) {
clks_log(CLKS_LOG_INFO, "SHELL", "DEFAULT ENTER USER SHELL MODE");
} else {
clks_log(CLKS_LOG_INFO, "SHELL", "KERNEL SHELL ACTIVE");
}
#endif
#else
#if CLKS_CFG_SHELL_MODE_LOG
clks_log(CLKS_LOG_WARN, "SHELL", "USRD TASK DISABLED; INTERACTIVE SHELL TICK OFF");
#endif
#endif
#if CLKS_CFG_TTY_READY_LOG
clks_log_hex(CLKS_LOG_INFO, "TTY", "COUNT", (u64)clks_tty_count());
clks_log_hex(CLKS_LOG_INFO, "TTY", "ACTIVE", (u64)clks_tty_active());
clks_log(CLKS_LOG_INFO, "TTY", "VIRTUAL TTY0 READY");
clks_log(CLKS_LOG_INFO, "TTY", "CURSOR ENABLED");
#endif
#if CLKS_CFG_IDLE_DEBUG_LOG
clks_log(CLKS_LOG_DEBUG, "KERNEL", "IDLE LOOP ENTER");
#endif
for (;;) {
u64 tick_now = clks_interrupts_timer_ticks();
clks_scheduler_dispatch_current(tick_now);
#if defined(CLKS_ARCH_X86_64)
__asm__ volatile("hlt");
#elif defined(CLKS_ARCH_AARCH64)
__asm__ volatile("wfe");
#endif
}
}

226
clks/kernel/core/log.c Normal file
View File

@@ -0,0 +1,226 @@
#include <clks/log.h>
#include <clks/serial.h>
#include <clks/tty.h>
#include <clks/types.h>
#define CLKS_LOG_LINE_MAX 256
#define CLKS_LOG_JOURNAL_CAP 256
#define CLKS_LOG_ANSI_RESET "\x1B[0m"
static char clks_log_journal[CLKS_LOG_JOURNAL_CAP][CLKS_LOG_LINE_MAX];
static u32 clks_log_journal_head = 0U;
static u32 clks_log_journal_count_live = 0U;
static const char *clks_log_level_name(enum clks_log_level level) {
switch (level) {
case CLKS_LOG_DEBUG:
return "DEBUG";
case CLKS_LOG_INFO:
return "INFO";
case CLKS_LOG_WARN:
return "WARN";
case CLKS_LOG_ERROR:
return "ERROR";
default:
return "UNK";
}
}
static void clks_log_append_char(char *buffer, usize *cursor, char ch) {
if (*cursor >= (CLKS_LOG_LINE_MAX - 1)) {
return;
}
buffer[*cursor] = ch;
(*cursor)++;
}
static void clks_log_append_text(char *buffer, usize *cursor, const char *text) {
usize i = 0;
if (text == CLKS_NULL) {
return;
}
while (text[i] != '\0') {
clks_log_append_char(buffer, cursor, text[i]);
i++;
}
}
static void clks_log_append_hex_u64(char *buffer, usize *cursor, u64 value) {
int nibble;
clks_log_append_text(buffer, cursor, "0X");
for (nibble = 15; nibble >= 0; nibble--) {
u8 current = (u8)((value >> (nibble * 4)) & 0x0FULL);
char out = (current < 10) ? (char)('0' + current) : (char)('A' + (current - 10));
clks_log_append_char(buffer, cursor, out);
}
}
static void clks_log_journal_copy_line(char *dst, usize dst_size, const char *src) {
usize i = 0U;
if (dst == CLKS_NULL || src == CLKS_NULL || dst_size == 0U) {
return;
}
while (i + 1U < dst_size && src[i] != '\0') {
dst[i] = src[i];
i++;
}
dst[i] = '\0';
}
static void clks_log_journal_push(const char *line) {
if (line == CLKS_NULL) {
return;
}
clks_log_journal_copy_line(clks_log_journal[clks_log_journal_head], CLKS_LOG_LINE_MAX, line);
clks_log_journal_head = (clks_log_journal_head + 1U) % CLKS_LOG_JOURNAL_CAP;
if (clks_log_journal_count_live < CLKS_LOG_JOURNAL_CAP) {
clks_log_journal_count_live++;
}
}
static const char *clks_log_level_ansi(enum clks_log_level level) {
switch (level) {
case CLKS_LOG_DEBUG:
return "\x1B[38;5;110m";
case CLKS_LOG_INFO:
return "\x1B[38;5;120m";
case CLKS_LOG_WARN:
return "\x1B[1;38;5;220m";
case CLKS_LOG_ERROR:
return "\x1B[1;38;5;203m";
default:
return "\x1B[38;5;250m";
}
}
static const char *clks_log_tag_ansi(const char *tag) {
static const char *palette[] = {
"\x1B[38;5;81m", "\x1B[38;5;117m", "\x1B[38;5;159m", "\x1B[38;5;45m",
"\x1B[38;5;75m", "\x1B[38;5;141m", "\x1B[38;5;214m", "\x1B[38;5;168m",
};
u32 hash = 5381U;
usize i = 0U;
usize palette_count = sizeof(palette) / sizeof(palette[0]);
if (tag == CLKS_NULL || tag[0] == '\0') {
return palette[0];
}
while (tag[i] != '\0') {
hash = ((hash << 5U) + hash) ^ (u32)(u8)tag[i];
i++;
}
return palette[hash % (u32)palette_count];
}
static void clks_log_emit_tty_colored(enum clks_log_level level, const char *tag, const char *message) {
const char *safe_tag = (tag == CLKS_NULL) ? "LOG" : tag;
const char *safe_message = (message == CLKS_NULL) ? "" : message;
clks_tty_write(clks_log_level_ansi(level));
clks_tty_write("[");
clks_tty_write(clks_log_level_name(level));
clks_tty_write("]");
clks_tty_write(clks_log_tag_ansi(safe_tag));
clks_tty_write("[");
clks_tty_write(safe_tag);
clks_tty_write("]");
clks_tty_write(CLKS_LOG_ANSI_RESET);
clks_tty_write(" ");
clks_tty_write(safe_message);
clks_tty_write("\n");
}
static void clks_log_build_line(enum clks_log_level level, const char *tag, const char *message, char *line) {
const char *safe_tag = (tag == CLKS_NULL) ? "LOG" : tag;
const char *safe_message = (message == CLKS_NULL) ? "" : message;
usize cursor = 0U;
if (line == CLKS_NULL) {
return;
}
clks_log_append_char(line, &cursor, '[');
clks_log_append_text(line, &cursor, clks_log_level_name(level));
clks_log_append_char(line, &cursor, ']');
clks_log_append_char(line, &cursor, '[');
clks_log_append_text(line, &cursor, safe_tag);
clks_log_append_char(line, &cursor, ']');
clks_log_append_char(line, &cursor, ' ');
clks_log_append_text(line, &cursor, safe_message);
line[cursor] = '\0';
}
static void clks_log_emit_line(enum clks_log_level level, const char *tag, const char *message, const char *line) {
if (line == CLKS_NULL) {
return;
}
clks_log_journal_push(line);
clks_serial_write(line);
clks_serial_write("\n");
clks_log_emit_tty_colored(level, tag, message);
}
void clks_log(enum clks_log_level level, const char *tag, const char *message) {
char line[CLKS_LOG_LINE_MAX];
clks_log_build_line(level, tag, message, line);
clks_log_emit_line(level, tag, message, line);
}
void clks_log_hex(enum clks_log_level level, const char *tag, const char *label, u64 value) {
char message[CLKS_LOG_LINE_MAX];
char line[CLKS_LOG_LINE_MAX];
usize cursor = 0U;
clks_log_append_text(message, &cursor, (label == CLKS_NULL) ? "VALUE" : label);
clks_log_append_char(message, &cursor, ':');
clks_log_append_char(message, &cursor, ' ');
clks_log_append_hex_u64(message, &cursor, value);
message[cursor] = '\0';
clks_log_build_line(level, tag, message, line);
clks_log_emit_line(level, tag, message, line);
}
u64 clks_log_journal_count(void) {
return (u64)clks_log_journal_count_live;
}
clks_bool clks_log_journal_read(u64 index_from_oldest, char *out_line, usize out_line_size) {
u32 oldest;
u32 slot;
if (out_line == CLKS_NULL || out_line_size == 0U) {
return CLKS_FALSE;
}
out_line[0] = '\0';
if (index_from_oldest >= (u64)clks_log_journal_count_live) {
return CLKS_FALSE;
}
oldest = (clks_log_journal_head + CLKS_LOG_JOURNAL_CAP - clks_log_journal_count_live) % CLKS_LOG_JOURNAL_CAP;
slot = (oldest + (u32)index_from_oldest) % CLKS_LOG_JOURNAL_CAP;
clks_log_journal_copy_line(out_line, out_line_size, clks_log_journal[slot]);
return CLKS_TRUE;
}

681
clks/kernel/core/panic.c Normal file
View File

@@ -0,0 +1,681 @@
#include <clks/cpu.h>
#include <clks/framebuffer.h>
#include <clks/fs.h>
#include <clks/panic.h>
#include <clks/serial.h>
#include <clks/string.h>
#include <clks/types.h>
#define CLKS_PANIC_BG 0x00200000U
#define CLKS_PANIC_FG 0x00FFE0E0U
#define CLKS_PANIC_BACKTRACE_MAX 20U
#define CLKS_PANIC_STACK_WINDOW_BYTES (128ULL * 1024ULL)
#define CLKS_PANIC_SYMBOL_FILE "/system/kernel.sym"
#define CLKS_PANIC_KERNEL_ADDR_BASE 0xFFFF800000000000ULL
struct clks_panic_console {
u32 cols;
u32 rows;
u32 row;
u32 col;
u32 cell_w;
u32 cell_h;
};
static clks_bool clks_panic_active = CLKS_FALSE;
static clks_bool clks_panic_symbols_checked = CLKS_FALSE;
static const char *clks_panic_symbols_data = CLKS_NULL;
static u64 clks_panic_symbols_size = 0ULL;
static inline void clks_panic_disable_interrupts(void) {
#if defined(CLKS_ARCH_X86_64)
__asm__ volatile("cli");
#elif defined(CLKS_ARCH_AARCH64)
__asm__ volatile("msr daifset, #0xf");
#endif
}
static void clks_panic_u64_to_hex(u64 value, char out[19]) {
int nibble;
out[0] = '0';
out[1] = 'X';
for (nibble = 0; nibble < 16; nibble++) {
u8 current = (u8)((value >> ((15 - nibble) * 4)) & 0x0FULL);
out[2 + nibble] = (current < 10U) ? (char)('0' + current) : (char)('A' + (current - 10U));
}
out[18] = '\0';
}
static void clks_panic_u32_to_dec(u32 value, char *out, usize out_size) {
char tmp[11];
usize len = 0U;
usize i;
if (out == CLKS_NULL || out_size == 0U) {
return;
}
if (value == 0U) {
if (out_size >= 2U) {
out[0] = '0';
out[1] = '\0';
} else {
out[0] = '\0';
}
return;
}
while (value != 0U && len < sizeof(tmp)) {
tmp[len++] = (char)('0' + (value % 10U));
value /= 10U;
}
if (len + 1U > out_size) {
len = out_size - 1U;
}
for (i = 0U; i < len; i++) {
out[i] = tmp[len - 1U - i];
}
out[len] = '\0';
}
static clks_bool clks_panic_console_init(struct clks_panic_console *console) {
struct clks_framebuffer_info info;
if (console == CLKS_NULL || clks_fb_ready() == CLKS_FALSE) {
return CLKS_FALSE;
}
info = clks_fb_info();
console->cell_w = clks_fb_cell_width();
console->cell_h = clks_fb_cell_height();
if (console->cell_w == 0U) {
console->cell_w = 8U;
}
if (console->cell_h == 0U) {
console->cell_h = 8U;
}
console->cols = info.width / console->cell_w;
console->rows = info.height / console->cell_h;
console->row = 0U;
console->col = 0U;
if (console->cols == 0U || console->rows == 0U) {
return CLKS_FALSE;
}
return CLKS_TRUE;
}
static void clks_panic_console_newline(struct clks_panic_console *console) {
if (console == CLKS_NULL) {
return;
}
console->col = 0U;
if (console->row + 1U < console->rows) {
console->row++;
}
}
static void clks_panic_console_put_char(struct clks_panic_console *console, char ch) {
u32 x;
u32 y;
if (console == CLKS_NULL) {
return;
}
if (ch == '\n') {
clks_panic_console_newline(console);
return;
}
if (ch == '\r') {
console->col = 0U;
return;
}
if (console->row >= console->rows || console->col >= console->cols) {
return;
}
x = console->col * console->cell_w;
y = console->row * console->cell_h;
clks_fb_draw_char(x, y, ch, CLKS_PANIC_FG, CLKS_PANIC_BG);
console->col++;
if (console->col >= console->cols) {
clks_panic_console_newline(console);
}
}
static void clks_panic_console_write_n(struct clks_panic_console *console, const char *text, usize len) {
usize i = 0U;
if (console == CLKS_NULL || text == CLKS_NULL) {
return;
}
while (i < len) {
clks_panic_console_put_char(console, text[i]);
i++;
}
}
static void clks_panic_console_write(struct clks_panic_console *console, const char *text) {
if (console == CLKS_NULL || text == CLKS_NULL) {
return;
}
clks_panic_console_write_n(console, text, clks_strlen(text));
}
static void clks_panic_serial_write_n(const char *text, usize len) {
usize i = 0U;
if (text == CLKS_NULL) {
return;
}
while (i < len) {
clks_serial_write_char(text[i]);
i++;
}
}
static void clks_panic_serial_write_line(const char *line) {
if (line == CLKS_NULL) {
return;
}
clks_serial_write(line);
clks_serial_write("\n");
}
static clks_bool clks_panic_is_hex(char ch) {
if ((ch >= '0' && ch <= '9') || (ch >= 'a' && ch <= 'f') || (ch >= 'A' && ch <= 'F')) {
return CLKS_TRUE;
}
return CLKS_FALSE;
}
static u8 clks_panic_hex_value(char ch) {
if (ch >= '0' && ch <= '9') {
return (u8)(ch - '0');
}
if (ch >= 'a' && ch <= 'f') {
return (u8)(10 + (ch - 'a'));
}
return (u8)(10 + (ch - 'A'));
}
static clks_bool clks_panic_parse_symbol_line(const char *line, usize len, u64 *out_addr, const char **out_name,
usize *out_name_len, const char **out_source, usize *out_source_len) {
usize i = 0U;
u64 addr = 0ULL;
u32 digits = 0U;
usize name_start;
usize name_end;
usize source_start;
usize source_end;
if (line == CLKS_NULL || out_addr == CLKS_NULL || out_name == CLKS_NULL || out_name_len == CLKS_NULL ||
out_source == CLKS_NULL || out_source_len == CLKS_NULL) {
return CLKS_FALSE;
}
if (len == 0U) {
return CLKS_FALSE;
}
if (len >= 2U && line[0] == '0' && (line[1] == 'X' || line[1] == 'x')) {
i = 2U;
}
while (i < len && clks_panic_is_hex(line[i]) == CLKS_TRUE) {
addr = (addr << 4) | (u64)clks_panic_hex_value(line[i]);
digits++;
i++;
}
if (digits == 0U) {
return CLKS_FALSE;
}
while (i < len && (line[i] == ' ' || line[i] == '\t')) {
i++;
}
if (i >= len) {
return CLKS_FALSE;
}
name_start = i;
while (i < len && line[i] != ' ' && line[i] != '\t' && line[i] != '\r') {
i++;
}
name_end = i;
if (name_end <= name_start) {
return CLKS_FALSE;
}
while (i < len && (line[i] == ' ' || line[i] == '\t')) {
i++;
}
source_start = i;
source_end = len;
while (source_end > source_start &&
(line[source_end - 1U] == ' ' || line[source_end - 1U] == '\t' || line[source_end - 1U] == '\r')) {
source_end--;
}
*out_addr = addr;
*out_name = &line[name_start];
*out_name_len = name_end - name_start;
*out_source = (source_end > source_start) ? &line[source_start] : CLKS_NULL;
*out_source_len = (source_end > source_start) ? (source_end - source_start) : 0U;
return CLKS_TRUE;
}
static clks_bool clks_panic_symbols_ready(void) {
u64 size = 0ULL;
const void *data;
if (clks_panic_symbols_checked == CLKS_TRUE) {
return (clks_panic_symbols_data != CLKS_NULL && clks_panic_symbols_size > 0ULL) ? CLKS_TRUE : CLKS_FALSE;
}
clks_panic_symbols_checked = CLKS_TRUE;
if (clks_fs_is_ready() == CLKS_FALSE) {
return CLKS_FALSE;
}
data = clks_fs_read_all(CLKS_PANIC_SYMBOL_FILE, &size);
if (data == CLKS_NULL || size == 0ULL) {
return CLKS_FALSE;
}
clks_panic_symbols_data = (const char *)data;
clks_panic_symbols_size = size;
return CLKS_TRUE;
}
static clks_bool clks_panic_lookup_symbol(u64 addr, const char **out_name, usize *out_name_len, u64 *out_base,
const char **out_source, usize *out_source_len) {
const char *data;
const char *end;
const char *line;
const char *best_name = CLKS_NULL;
const char *best_source = CLKS_NULL;
usize best_len = 0U;
usize best_source_len = 0U;
u64 best_addr = 0ULL;
clks_bool found = CLKS_FALSE;
if (out_name == CLKS_NULL || out_name_len == CLKS_NULL || out_base == CLKS_NULL || out_source == CLKS_NULL ||
out_source_len == CLKS_NULL) {
return CLKS_FALSE;
}
*out_name = CLKS_NULL;
*out_name_len = 0U;
*out_base = 0ULL;
*out_source = CLKS_NULL;
*out_source_len = 0U;
if (clks_panic_symbols_ready() == CLKS_FALSE) {
return CLKS_FALSE;
}
data = clks_panic_symbols_data;
end = clks_panic_symbols_data + clks_panic_symbols_size;
while (data < end) {
u64 line_addr;
const char *line_name;
usize line_name_len;
const char *line_source;
usize line_source_len;
usize line_len = 0U;
line = data;
while (data < end && *data != '\n') {
data++;
line_len++;
}
if (data < end && *data == '\n') {
data++;
}
if (clks_panic_parse_symbol_line(line, line_len, &line_addr, &line_name, &line_name_len, &line_source,
&line_source_len) == CLKS_FALSE) {
continue;
}
if (line_addr <= addr && (found == CLKS_FALSE || line_addr >= best_addr)) {
best_addr = line_addr;
best_name = line_name;
best_len = line_name_len;
best_source = line_source;
best_source_len = line_source_len;
found = CLKS_TRUE;
}
}
if (found == CLKS_FALSE) {
return CLKS_FALSE;
}
*out_name = best_name;
*out_name_len = best_len;
*out_base = best_addr;
*out_source = best_source;
*out_source_len = best_source_len;
return CLKS_TRUE;
}
static void clks_panic_emit_bt_entry(struct clks_panic_console *console, u32 index, u64 rip) {
char index_dec[12];
char rip_hex[19];
const char *sym_name = CLKS_NULL;
const char *sym_source = CLKS_NULL;
usize sym_name_len = 0U;
usize sym_source_len = 0U;
u64 sym_base = 0ULL;
clks_bool has_symbol;
clks_panic_u32_to_dec(index, index_dec, sizeof(index_dec));
clks_panic_u64_to_hex(rip, rip_hex);
has_symbol = clks_panic_lookup_symbol(rip, &sym_name, &sym_name_len, &sym_base, &sym_source, &sym_source_len);
clks_serial_write("[PANIC][BT] #");
clks_serial_write(index_dec);
clks_serial_write(" ");
clks_serial_write(rip_hex);
if (has_symbol == CLKS_TRUE) {
char off_hex[19];
u64 off = rip - sym_base;
clks_panic_u64_to_hex(off, off_hex);
clks_serial_write(" ");
clks_panic_serial_write_n(sym_name, sym_name_len);
clks_serial_write("+");
clks_serial_write(off_hex);
if (sym_source != CLKS_NULL && sym_source_len > 0U) {
clks_serial_write(" @ ");
clks_panic_serial_write_n(sym_source, sym_source_len);
}
}
clks_serial_write("\n");
if (console == CLKS_NULL) {
return;
}
clks_panic_console_write(console, "BT#");
clks_panic_console_write(console, index_dec);
clks_panic_console_write(console, " ");
clks_panic_console_write(console, rip_hex);
if (has_symbol == CLKS_TRUE) {
char off_hex[19];
u64 off = rip - sym_base;
clks_panic_u64_to_hex(off, off_hex);
clks_panic_console_write(console, " ");
clks_panic_console_write_n(console, sym_name, sym_name_len);
clks_panic_console_write(console, "+");
clks_panic_console_write(console, off_hex);
if (sym_source != CLKS_NULL && sym_source_len > 0U) {
clks_panic_console_write(console, " @ ");
clks_panic_console_write_n(console, sym_source, sym_source_len);
}
}
clks_panic_console_write(console, "\n");
}
static clks_bool clks_panic_stack_ptr_valid(u64 ptr, u64 stack_low, u64 stack_high) {
if ((ptr & 0x7ULL) != 0ULL) {
return CLKS_FALSE;
}
if (ptr < stack_low || ptr + 16ULL > stack_high) {
return CLKS_FALSE;
}
if (ptr < CLKS_PANIC_KERNEL_ADDR_BASE) {
return CLKS_FALSE;
}
return CLKS_TRUE;
}
static void clks_panic_emit_backtrace(struct clks_panic_console *console, u64 rip, u64 rbp, u64 rsp) {
u64 current_rbp;
u64 stack_low;
u64 stack_high;
u32 frame = 0U;
if (rip == 0ULL) {
return;
}
clks_panic_serial_write_line("[PANIC][BT] BEGIN");
if (console != CLKS_NULL) {
clks_panic_console_write(console, "\nBACKTRACE:\n");
}
clks_panic_emit_bt_entry(console, frame, rip);
frame++;
if (rbp == 0ULL || rsp == 0ULL || frame >= CLKS_PANIC_BACKTRACE_MAX) {
clks_panic_serial_write_line("[PANIC][BT] END");
return;
}
stack_low = rsp;
stack_high = rsp + CLKS_PANIC_STACK_WINDOW_BYTES;
if (stack_high <= stack_low) {
clks_panic_serial_write_line("[PANIC][BT] END");
return;
}
current_rbp = rbp;
while (frame < CLKS_PANIC_BACKTRACE_MAX) {
const u64 *frame_ptr;
u64 next_rbp;
u64 ret_rip;
if (clks_panic_stack_ptr_valid(current_rbp, stack_low, stack_high) == CLKS_FALSE) {
break;
}
frame_ptr = (const u64 *)(usize)current_rbp;
next_rbp = frame_ptr[0];
ret_rip = frame_ptr[1];
if (ret_rip == 0ULL) {
break;
}
clks_panic_emit_bt_entry(console, frame, ret_rip);
frame++;
if (next_rbp <= current_rbp) {
break;
}
current_rbp = next_rbp;
}
clks_panic_serial_write_line("[PANIC][BT] END");
}
static void clks_panic_capture_context(u64 *out_rip, u64 *out_rbp, u64 *out_rsp) {
if (out_rip != CLKS_NULL) {
*out_rip = 0ULL;
}
if (out_rbp != CLKS_NULL) {
*out_rbp = 0ULL;
}
if (out_rsp != CLKS_NULL) {
*out_rsp = 0ULL;
}
#if defined(CLKS_ARCH_X86_64)
if (out_rbp != CLKS_NULL) {
__asm__ volatile("mov %%rbp, %0" : "=r"(*out_rbp));
}
if (out_rsp != CLKS_NULL) {
__asm__ volatile("mov %%rsp, %0" : "=r"(*out_rsp));
}
if (out_rip != CLKS_NULL) {
*out_rip = (u64)(usize)__builtin_return_address(0);
}
#endif
}
static CLKS_NORETURN void clks_panic_halt_loop(void) {
clks_cpu_halt_forever();
}
CLKS_NORETURN void clks_panic(const char *reason) {
struct clks_panic_console console;
u64 rip = 0ULL;
u64 rbp = 0ULL;
u64 rsp = 0ULL;
clks_panic_disable_interrupts();
if (clks_panic_active == CLKS_TRUE) {
clks_panic_halt_loop();
}
clks_panic_active = CLKS_TRUE;
clks_panic_capture_context(&rip, &rbp, &rsp);
clks_panic_serial_write_line("[PANIC] CLeonOS KERNEL PANIC");
if (reason != CLKS_NULL) {
clks_panic_serial_write_line(reason);
}
if (clks_panic_console_init(&console) == CLKS_TRUE) {
clks_fb_clear(CLKS_PANIC_BG);
clks_panic_console_write(&console, "CLeonOS KERNEL PANIC\n");
clks_panic_console_write(&console, "====================\n\n");
if (reason != CLKS_NULL) {
clks_panic_console_write(&console, "REASON: ");
clks_panic_console_write(&console, reason);
clks_panic_console_write(&console, "\n");
}
clks_panic_emit_backtrace(&console, rip, rbp, rsp);
clks_panic_console_write(&console, "\nSystem halted. Please reboot the computer.\n");
} else {
clks_panic_emit_backtrace(CLKS_NULL, rip, rbp, rsp);
}
clks_panic_halt_loop();
}
CLKS_NORETURN void clks_panic_exception(const char *name, u64 vector, u64 error_code, u64 rip, u64 rbp, u64 rsp) {
struct clks_panic_console console;
char hex_buf[19];
clks_panic_disable_interrupts();
if (clks_panic_active == CLKS_TRUE) {
clks_panic_halt_loop();
}
clks_panic_active = CLKS_TRUE;
clks_panic_serial_write_line("[PANIC] CPU EXCEPTION");
if (name != CLKS_NULL) {
clks_panic_serial_write_line(name);
}
clks_panic_u64_to_hex(vector, hex_buf);
clks_panic_serial_write_line(hex_buf);
clks_panic_u64_to_hex(error_code, hex_buf);
clks_panic_serial_write_line(hex_buf);
clks_panic_u64_to_hex(rip, hex_buf);
clks_panic_serial_write_line(hex_buf);
if (clks_panic_console_init(&console) == CLKS_TRUE) {
clks_fb_clear(CLKS_PANIC_BG);
clks_panic_console_write(&console, "CLeonOS KERNEL PANIC\n");
clks_panic_console_write(&console, "====================\n\n");
clks_panic_console_write(&console, "TYPE: CPU EXCEPTION\n");
if (name != CLKS_NULL) {
clks_panic_console_write(&console, "NAME: ");
clks_panic_console_write(&console, name);
clks_panic_console_write(&console, "\n");
}
clks_panic_u64_to_hex(vector, hex_buf);
clks_panic_console_write(&console, "VECTOR: ");
clks_panic_console_write(&console, hex_buf);
clks_panic_console_write(&console, "\n");
clks_panic_u64_to_hex(error_code, hex_buf);
clks_panic_console_write(&console, "ERROR: ");
clks_panic_console_write(&console, hex_buf);
clks_panic_console_write(&console, "\n");
clks_panic_u64_to_hex(rip, hex_buf);
clks_panic_console_write(&console, "RIP: ");
clks_panic_console_write(&console, hex_buf);
clks_panic_console_write(&console, "\n");
clks_panic_emit_backtrace(&console, rip, rbp, rsp);
clks_panic_console_write(&console, "\nSystem halted. Please reboot the computer.\n");
} else {
clks_panic_emit_backtrace(CLKS_NULL, rip, rbp, rsp);
}
clks_panic_halt_loop();
}

View File

@@ -0,0 +1,179 @@
#include <clks/log.h>
#include <clks/scheduler.h>
#include <clks/string.h>
#include <clks/types.h>
#define CLKS_SCHED_MAX_TASKS 16U
#define CLKS_SCHED_MIN_SLICE 1U
static struct clks_task_descriptor clks_tasks[CLKS_SCHED_MAX_TASKS];
static u32 clks_task_count = 0;
static u32 clks_current_task = 0;
static u64 clks_total_timer_ticks = 0;
static u64 clks_context_switch_count = 0;
static clks_bool clks_dispatch_active = CLKS_FALSE;
static void clks_sched_copy_name(char *dst, const char *src) {
u32 i = 0;
while (i < (CLKS_TASK_NAME_MAX - 1U) && src[i] != '\0') {
dst[i] = src[i];
i++;
}
dst[i] = '\0';
}
static u32 clks_sched_next_ready_task(u32 from) {
u32 i;
for (i = 1U; i <= clks_task_count; i++) {
u32 idx = (from + i) % clks_task_count;
if (clks_tasks[idx].state == CLKS_TASK_READY || clks_tasks[idx].state == CLKS_TASK_RUNNING) {
return idx;
}
}
return from;
}
void clks_scheduler_init(void) {
clks_memset(clks_tasks, 0, sizeof(clks_tasks));
clks_task_count = 0;
clks_current_task = 0;
clks_total_timer_ticks = 0;
clks_context_switch_count = 0;
clks_dispatch_active = CLKS_FALSE;
clks_scheduler_add_kernel_task_ex("idle", 1U, CLKS_NULL);
clks_tasks[0].state = CLKS_TASK_RUNNING;
clks_tasks[0].remaining_ticks = clks_tasks[0].time_slice_ticks;
clks_log(CLKS_LOG_INFO, "SCHED", "ROUND-ROBIN ONLINE");
}
clks_bool clks_scheduler_add_kernel_task_ex(const char *name, u32 time_slice_ticks, clks_task_entry_fn entry) {
struct clks_task_descriptor *task;
if (name == CLKS_NULL) {
return CLKS_FALSE;
}
if (clks_task_count >= CLKS_SCHED_MAX_TASKS) {
return CLKS_FALSE;
}
if (time_slice_ticks < CLKS_SCHED_MIN_SLICE) {
time_slice_ticks = CLKS_SCHED_MIN_SLICE;
}
task = &clks_tasks[clks_task_count];
task->id = clks_task_count;
clks_sched_copy_name(task->name, name);
task->state = CLKS_TASK_READY;
task->time_slice_ticks = time_slice_ticks;
task->remaining_ticks = time_slice_ticks;
task->total_ticks = 0ULL;
task->switch_count = 0ULL;
task->run_count = 0ULL;
task->last_run_tick = 0ULL;
task->entry = entry;
clks_task_count++;
return CLKS_TRUE;
}
clks_bool clks_scheduler_add_kernel_task(const char *name, u32 time_slice_ticks) {
return clks_scheduler_add_kernel_task_ex(name, time_slice_ticks, CLKS_NULL);
}
void clks_scheduler_dispatch_current(u64 tick) {
struct clks_task_descriptor *current;
if (clks_task_count == 0U) {
return;
}
if (clks_dispatch_active == CLKS_TRUE) {
return;
}
current = &clks_tasks[clks_current_task];
if (current->state != CLKS_TASK_RUNNING && current->state != CLKS_TASK_READY) {
return;
}
current->state = CLKS_TASK_RUNNING;
current->run_count++;
current->last_run_tick = tick;
if (current->entry != CLKS_NULL) {
clks_dispatch_active = CLKS_TRUE;
current->entry(tick);
clks_dispatch_active = CLKS_FALSE;
}
}
void clks_scheduler_on_timer_tick(u64 tick) {
struct clks_task_descriptor *current;
if (clks_task_count == 0U) {
return;
}
clks_total_timer_ticks = tick;
if (clks_dispatch_active == CLKS_TRUE) {
return;
}
current = &clks_tasks[clks_current_task];
if (current->state == CLKS_TASK_RUNNING || current->state == CLKS_TASK_READY) {
current->total_ticks++;
if (current->remaining_ticks > 0U) {
current->remaining_ticks--;
}
}
if (current->remaining_ticks == 0U) {
u32 next = clks_sched_next_ready_task(clks_current_task);
current->remaining_ticks = current->time_slice_ticks;
if (next != clks_current_task) {
if (current->state == CLKS_TASK_RUNNING) {
current->state = CLKS_TASK_READY;
}
clks_current_task = next;
clks_tasks[clks_current_task].state = CLKS_TASK_RUNNING;
clks_tasks[clks_current_task].switch_count++;
clks_tasks[clks_current_task].remaining_ticks = clks_tasks[clks_current_task].time_slice_ticks;
clks_context_switch_count++;
}
}
}
struct clks_scheduler_stats clks_scheduler_get_stats(void) {
struct clks_scheduler_stats stats;
stats.task_count = clks_task_count;
stats.current_task_id = clks_current_task;
stats.total_timer_ticks = clks_total_timer_ticks;
stats.context_switch_count = clks_context_switch_count;
return stats;
}
const struct clks_task_descriptor *clks_scheduler_get_task(u32 task_id) {
if (task_id >= clks_task_count) {
return CLKS_NULL;
}
return &clks_tasks[task_id];
}

140
clks/kernel/core/service.c Normal file
View File

@@ -0,0 +1,140 @@
#include <clks/driver.h>
#include <clks/fs.h>
#include <clks/heap.h>
#include <clks/kelf.h>
#include <clks/log.h>
#include <clks/scheduler.h>
#include <clks/service.h>
#include <clks/string.h>
#include <clks/types.h>
#include <clks/userland.h>
#define CLKS_SERVICE_MAX 8U
static struct clks_service_info clks_services[CLKS_SERVICE_MAX];
static u64 clks_service_used = 0ULL;
static void clks_service_copy_name(char *dst, usize dst_size, const char *src) {
usize i = 0U;
if (dst == CLKS_NULL || dst_size == 0U) {
return;
}
while (i + 1U < dst_size && src[i] != '\0') {
dst[i] = src[i];
i++;
}
dst[i] = '\0';
}
static i32 clks_service_find_index(u32 service_id) {
u64 i;
for (i = 0ULL; i < clks_service_used; i++) {
if (clks_services[i].id == service_id) {
return (i32)i;
}
}
return -1;
}
static clks_bool clks_service_register(u32 id, const char *name, enum clks_service_state state) {
struct clks_service_info *slot;
if (clks_service_used >= CLKS_SERVICE_MAX) {
return CLKS_FALSE;
}
slot = &clks_services[clks_service_used];
clks_memset(slot, 0, sizeof(*slot));
slot->id = id;
clks_service_copy_name(slot->name, sizeof(slot->name), name);
slot->state = state;
slot->heartbeat_count = 0ULL;
slot->last_heartbeat_tick = 0ULL;
clks_service_used++;
return CLKS_TRUE;
}
void clks_service_init(void) {
struct clks_heap_stats heap_stats;
clks_memset(clks_services, 0, sizeof(clks_services));
clks_service_used = 0ULL;
heap_stats = clks_heap_get_stats();
clks_service_register(CLKS_SERVICE_LOG, "log", CLKS_SERVICE_STATE_READY);
clks_service_register(CLKS_SERVICE_MEM, "memory",
(heap_stats.total_bytes > 0U) ? CLKS_SERVICE_STATE_READY : CLKS_SERVICE_STATE_DEGRADED);
clks_service_register(CLKS_SERVICE_FS, "filesystem",
(clks_fs_is_ready() == CLKS_TRUE) ? CLKS_SERVICE_STATE_READY : CLKS_SERVICE_STATE_DEGRADED);
clks_service_register(CLKS_SERVICE_DRIVER, "driver",
(clks_driver_count() > 0ULL) ? CLKS_SERVICE_STATE_READY : CLKS_SERVICE_STATE_DEGRADED);
clks_service_register(CLKS_SERVICE_SCHED, "scheduler", CLKS_SERVICE_STATE_READY);
clks_service_register(CLKS_SERVICE_KELF, "kelf",
(clks_kelf_count() > 0ULL) ? CLKS_SERVICE_STATE_READY : CLKS_SERVICE_STATE_DEGRADED);
clks_service_register(CLKS_SERVICE_USER, "userland",
(clks_userland_shell_ready() == CLKS_TRUE) ? CLKS_SERVICE_STATE_READY
: CLKS_SERVICE_STATE_DEGRADED);
clks_log(CLKS_LOG_INFO, "SRV", "KERNEL SERVICES ONLINE");
clks_log_hex(CLKS_LOG_INFO, "SRV", "COUNT", clks_service_count());
clks_log_hex(CLKS_LOG_INFO, "SRV", "READY", clks_service_ready_count());
}
clks_bool clks_service_heartbeat(u32 service_id, u64 tick) {
i32 idx = clks_service_find_index(service_id);
if (idx < 0) {
return CLKS_FALSE;
}
clks_services[(u32)idx].heartbeat_count++;
clks_services[(u32)idx].last_heartbeat_tick = tick;
if (clks_services[(u32)idx].state == CLKS_SERVICE_STATE_OFFLINE) {
clks_services[(u32)idx].state = CLKS_SERVICE_STATE_READY;
}
return CLKS_TRUE;
}
u64 clks_service_count(void) {
return clks_service_used;
}
u64 clks_service_ready_count(void) {
u64 i;
u64 ready = 0ULL;
for (i = 0ULL; i < clks_service_used; i++) {
if (clks_services[i].state == CLKS_SERVICE_STATE_READY) {
ready++;
}
}
return ready;
}
clks_bool clks_service_get(u32 service_id, struct clks_service_info *out_info) {
i32 idx;
if (out_info == CLKS_NULL) {
return CLKS_FALSE;
}
idx = clks_service_find_index(service_id);
if (idx < 0) {
return CLKS_FALSE;
}
*out_info = clks_services[(u32)idx];
return CLKS_TRUE;
}