mirror of
https://github.com/Leonmmcoset/cleonos.git
synced 2026-04-21 18:44:01 +00:00
代码分类
This commit is contained in:
349
clks/kernel/core/interrupts.c
Normal file
349
clks/kernel/core/interrupts.c
Normal 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
465
clks/kernel/core/kmain.c
Normal 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
226
clks/kernel/core/log.c
Normal 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
681
clks/kernel/core/panic.c
Normal 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();
|
||||
}
|
||||
179
clks/kernel/core/scheduler.c
Normal file
179
clks/kernel/core/scheduler.c
Normal 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
140
clks/kernel/core/service.c
Normal 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;
|
||||
}
|
||||
Reference in New Issue
Block a user