mirror of
https://github.com/Leonmmcoset/cleonos.git
synced 2026-04-24 11:14:01 +00:00
接着上个
This commit is contained in:
349
clks.local.bak/kernel/core/interrupts.c
Normal file
349
clks.local.bak/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;
|
||||
}
|
||||
472
clks.local.bak/kernel/core/kmain.c
Normal file
472
clks.local.bak/kernel/core/kmain.c
Normal file
@@ -0,0 +1,472 @@
|
||||
// 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>
|
||||
|
||||
/* Boot orchestration file: one wrong init order and the whole damn thing faceplants. */
|
||||
|
||||
#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;
|
||||
|
||||
/* Serial first, because when graphics dies we still need a heartbeat. */
|
||||
clks_serial_init();
|
||||
|
||||
/* If boot protocol handshake fails, continuing would be pure fantasy. */
|
||||
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();
|
||||
|
||||
/* TTY comes up only when framebuffer exists; no pixels, no pretty lies. */
|
||||
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
|
||||
|
||||
/* Scheduler init is the "okay, now this mess is actually alive" moment. */
|
||||
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
|
||||
|
||||
/* Infinite idle loop: glamorous name for "wait forever and hope interrupts behave". */
|
||||
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.local.bak/kernel/core/log.c
Normal file
226
clks.local.bak/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;
|
||||
}
|
||||
864
clks.local.bak/kernel/core/panic.c
Normal file
864
clks.local.bak/kernel/core/panic.c
Normal file
@@ -0,0 +1,864 @@
|
||||
#include <clks/cpu.h>
|
||||
#include <clks/framebuffer.h>
|
||||
#include <clks/fs.h>
|
||||
#include <clks/panic.h>
|
||||
#include <clks/panic_qr.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
|
||||
#define CLKS_PANIC_QR_HINT "\nPress SPACE to toggle panic log QR.\n"
|
||||
#define CLKS_PANIC_REASON_MAX 192U
|
||||
#define CLKS_PANIC_NAME_MAX 64U
|
||||
|
||||
#define CLKS_PANIC_PS2_DATA_PORT 0x60U
|
||||
#define CLKS_PANIC_PS2_STATUS_PORT 0x64U
|
||||
#define CLKS_PANIC_PS2_STATUS_OBF 0x01U
|
||||
#define CLKS_PANIC_SC_SPACE_MAKE 0x39U
|
||||
#define CLKS_PANIC_SC_SPACE_BREAK 0xB9U
|
||||
#define CLKS_PANIC_SC_EXT_PREFIX 0xE0U
|
||||
|
||||
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;
|
||||
|
||||
enum clks_panic_screen_kind {
|
||||
CLKS_PANIC_SCREEN_NONE = 0,
|
||||
CLKS_PANIC_SCREEN_REASON = 1,
|
||||
CLKS_PANIC_SCREEN_EXCEPTION = 2
|
||||
};
|
||||
|
||||
struct clks_panic_screen_snapshot {
|
||||
enum clks_panic_screen_kind kind;
|
||||
char reason[CLKS_PANIC_REASON_MAX];
|
||||
char name[CLKS_PANIC_NAME_MAX];
|
||||
u64 vector;
|
||||
u64 error_code;
|
||||
u64 rip;
|
||||
u64 rbp;
|
||||
u64 rsp;
|
||||
clks_bool has_reason;
|
||||
clks_bool has_name;
|
||||
};
|
||||
|
||||
static struct clks_panic_screen_snapshot clks_panic_screen = {
|
||||
CLKS_PANIC_SCREEN_NONE, {0}, {0}, 0ULL, 0ULL, 0ULL, 0ULL, 0ULL, CLKS_FALSE, CLKS_FALSE};
|
||||
|
||||
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
|
||||
}
|
||||
|
||||
#if defined(CLKS_ARCH_X86_64)
|
||||
static inline u8 clks_panic_inb(u16 port) {
|
||||
u8 value;
|
||||
|
||||
__asm__ volatile("inb %1, %0" : "=a"(value) : "Nd"(port));
|
||||
return value;
|
||||
}
|
||||
|
||||
static clks_bool clks_panic_ps2_has_output(void) {
|
||||
return ((clks_panic_inb(CLKS_PANIC_PS2_STATUS_PORT) & CLKS_PANIC_PS2_STATUS_OBF) != 0U) ? CLKS_TRUE : CLKS_FALSE;
|
||||
}
|
||||
#endif
|
||||
|
||||
static clks_bool clks_panic_poll_space_press(clks_bool *space_down) {
|
||||
#if defined(CLKS_ARCH_X86_64)
|
||||
clks_bool pressed = CLKS_FALSE;
|
||||
|
||||
if (space_down == CLKS_NULL) {
|
||||
return CLKS_FALSE;
|
||||
}
|
||||
|
||||
while (clks_panic_ps2_has_output() == CLKS_TRUE) {
|
||||
u8 scancode = clks_panic_inb(CLKS_PANIC_PS2_DATA_PORT);
|
||||
|
||||
if (scancode == CLKS_PANIC_SC_EXT_PREFIX) {
|
||||
continue;
|
||||
}
|
||||
|
||||
if (scancode == CLKS_PANIC_SC_SPACE_BREAK) {
|
||||
*space_down = CLKS_FALSE;
|
||||
continue;
|
||||
}
|
||||
|
||||
if (scancode == CLKS_PANIC_SC_SPACE_MAKE) {
|
||||
if (*space_down == CLKS_FALSE) {
|
||||
*space_down = CLKS_TRUE;
|
||||
pressed = CLKS_TRUE;
|
||||
}
|
||||
continue;
|
||||
}
|
||||
}
|
||||
|
||||
return pressed;
|
||||
#else
|
||||
(void)space_down;
|
||||
return CLKS_FALSE;
|
||||
#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, clks_bool serial_enabled) {
|
||||
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);
|
||||
|
||||
if (serial_enabled == CLKS_TRUE) {
|
||||
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,
|
||||
clks_bool serial_enabled) {
|
||||
u64 current_rbp;
|
||||
u64 stack_low;
|
||||
u64 stack_high;
|
||||
u32 frame = 0U;
|
||||
|
||||
if (rip == 0ULL) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (serial_enabled == CLKS_TRUE) {
|
||||
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, serial_enabled);
|
||||
frame++;
|
||||
|
||||
if (rbp == 0ULL || rsp == 0ULL || frame >= CLKS_PANIC_BACKTRACE_MAX) {
|
||||
if (serial_enabled == CLKS_TRUE) {
|
||||
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) {
|
||||
if (serial_enabled == CLKS_TRUE) {
|
||||
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, serial_enabled);
|
||||
frame++;
|
||||
|
||||
if (next_rbp <= current_rbp) {
|
||||
break;
|
||||
}
|
||||
|
||||
current_rbp = next_rbp;
|
||||
}
|
||||
|
||||
if (serial_enabled == CLKS_TRUE) {
|
||||
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 void clks_panic_copy_text(char *dst, usize dst_size, const char *src) {
|
||||
usize i = 0U;
|
||||
|
||||
if (dst == CLKS_NULL || dst_size == 0U) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (src == CLKS_NULL) {
|
||||
dst[0] = '\0';
|
||||
return;
|
||||
}
|
||||
|
||||
while (i + 1U < dst_size && src[i] != '\0') {
|
||||
dst[i] = src[i];
|
||||
i++;
|
||||
}
|
||||
|
||||
dst[i] = '\0';
|
||||
}
|
||||
|
||||
static void clks_panic_snapshot_reason(const char *reason, u64 rip, u64 rbp, u64 rsp) {
|
||||
clks_panic_screen.kind = CLKS_PANIC_SCREEN_REASON;
|
||||
clks_panic_screen.vector = 0ULL;
|
||||
clks_panic_screen.error_code = 0ULL;
|
||||
clks_panic_screen.rip = rip;
|
||||
clks_panic_screen.rbp = rbp;
|
||||
clks_panic_screen.rsp = rsp;
|
||||
clks_panic_screen.has_name = CLKS_FALSE;
|
||||
clks_panic_screen.name[0] = '\0';
|
||||
|
||||
if (reason != CLKS_NULL && reason[0] != '\0') {
|
||||
clks_panic_copy_text(clks_panic_screen.reason, sizeof(clks_panic_screen.reason), reason);
|
||||
clks_panic_screen.has_reason = CLKS_TRUE;
|
||||
} else {
|
||||
clks_panic_screen.reason[0] = '\0';
|
||||
clks_panic_screen.has_reason = CLKS_FALSE;
|
||||
}
|
||||
}
|
||||
|
||||
static void clks_panic_snapshot_exception(const char *name, u64 vector, u64 error_code, u64 rip, u64 rbp, u64 rsp) {
|
||||
clks_panic_screen.kind = CLKS_PANIC_SCREEN_EXCEPTION;
|
||||
clks_panic_screen.vector = vector;
|
||||
clks_panic_screen.error_code = error_code;
|
||||
clks_panic_screen.rip = rip;
|
||||
clks_panic_screen.rbp = rbp;
|
||||
clks_panic_screen.rsp = rsp;
|
||||
clks_panic_screen.has_reason = CLKS_FALSE;
|
||||
clks_panic_screen.reason[0] = '\0';
|
||||
|
||||
if (name != CLKS_NULL && name[0] != '\0') {
|
||||
clks_panic_copy_text(clks_panic_screen.name, sizeof(clks_panic_screen.name), name);
|
||||
clks_panic_screen.has_name = CLKS_TRUE;
|
||||
} else {
|
||||
clks_panic_screen.name[0] = '\0';
|
||||
clks_panic_screen.has_name = CLKS_FALSE;
|
||||
}
|
||||
}
|
||||
|
||||
static void clks_panic_render_snapshot_console(clks_bool serial_backtrace) {
|
||||
struct clks_panic_console console;
|
||||
char hex_buf[19];
|
||||
|
||||
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 (clks_panic_screen.kind == CLKS_PANIC_SCREEN_EXCEPTION) {
|
||||
clks_panic_console_write(&console, "TYPE: CPU EXCEPTION\n");
|
||||
|
||||
if (clks_panic_screen.has_name == CLKS_TRUE) {
|
||||
clks_panic_console_write(&console, "NAME: ");
|
||||
clks_panic_console_write(&console, clks_panic_screen.name);
|
||||
clks_panic_console_write(&console, "\n");
|
||||
}
|
||||
|
||||
clks_panic_u64_to_hex(clks_panic_screen.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(clks_panic_screen.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(clks_panic_screen.rip, hex_buf);
|
||||
clks_panic_console_write(&console, "RIP: ");
|
||||
clks_panic_console_write(&console, hex_buf);
|
||||
clks_panic_console_write(&console, "\n");
|
||||
} else if (clks_panic_screen.has_reason == CLKS_TRUE) {
|
||||
clks_panic_console_write(&console, "REASON: ");
|
||||
clks_panic_console_write(&console, clks_panic_screen.reason);
|
||||
clks_panic_console_write(&console, "\n");
|
||||
}
|
||||
|
||||
clks_panic_emit_backtrace(&console, clks_panic_screen.rip, clks_panic_screen.rbp, clks_panic_screen.rsp,
|
||||
serial_backtrace);
|
||||
clks_panic_console_write(&console, "\nSystem halted. Please reboot the computer.\n");
|
||||
clks_panic_console_write(&console, CLKS_PANIC_QR_HINT);
|
||||
} else {
|
||||
clks_panic_emit_backtrace(CLKS_NULL, clks_panic_screen.rip, clks_panic_screen.rbp, clks_panic_screen.rsp,
|
||||
serial_backtrace);
|
||||
}
|
||||
}
|
||||
|
||||
static CLKS_NORETURN void clks_panic_halt_loop(void) {
|
||||
clks_bool space_down = CLKS_FALSE;
|
||||
clks_bool qr_shown = CLKS_FALSE;
|
||||
|
||||
for (;;) {
|
||||
if (clks_panic_poll_space_press(&space_down) == CLKS_TRUE) {
|
||||
if (qr_shown == CLKS_FALSE) {
|
||||
if (clks_panic_qr_show() == CLKS_TRUE) {
|
||||
qr_shown = CLKS_TRUE;
|
||||
clks_panic_serial_write_line("[PANIC][QR] DISPLAYED");
|
||||
} else {
|
||||
clks_panic_serial_write_line("[PANIC][QR] PREPARE/SHOW FAILED");
|
||||
}
|
||||
} else {
|
||||
clks_panic_render_snapshot_console(CLKS_FALSE);
|
||||
qr_shown = CLKS_FALSE;
|
||||
clks_panic_serial_write_line("[PANIC][QR] RETURNED TO PANIC PAGE");
|
||||
}
|
||||
}
|
||||
|
||||
clks_cpu_pause();
|
||||
}
|
||||
}
|
||||
|
||||
CLKS_NORETURN void clks_panic(const char *reason) {
|
||||
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);
|
||||
}
|
||||
|
||||
clks_panic_snapshot_reason(reason, rip, rbp, rsp);
|
||||
clks_panic_render_snapshot_console(CLKS_TRUE);
|
||||
|
||||
if (clks_panic_qr_prepare() == CLKS_TRUE) {
|
||||
clks_panic_serial_write_line("[PANIC][QR] READY (PRESS SPACE TO TOGGLE)");
|
||||
} else {
|
||||
clks_panic_serial_write_line("[PANIC][QR] NOT AVAILABLE");
|
||||
}
|
||||
|
||||
clks_panic_halt_loop();
|
||||
}
|
||||
|
||||
CLKS_NORETURN void clks_panic_exception(const char *name, u64 vector, u64 error_code, u64 rip, u64 rbp, u64 rsp) {
|
||||
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);
|
||||
|
||||
clks_panic_snapshot_exception(name, vector, error_code, rip, rbp, rsp);
|
||||
clks_panic_render_snapshot_console(CLKS_TRUE);
|
||||
|
||||
if (clks_panic_qr_prepare() == CLKS_TRUE) {
|
||||
clks_panic_serial_write_line("[PANIC][QR] READY (PRESS SPACE TO TOGGLE)");
|
||||
} else {
|
||||
clks_panic_serial_write_line("[PANIC][QR] NOT AVAILABLE");
|
||||
}
|
||||
|
||||
clks_panic_halt_loop();
|
||||
}
|
||||
395
clks.local.bak/kernel/core/panic_qr.cpp
Normal file
395
clks.local.bak/kernel/core/panic_qr.cpp
Normal file
@@ -0,0 +1,395 @@
|
||||
extern "C" {
|
||||
#include <clks/framebuffer.h>
|
||||
#include <clks/log.h>
|
||||
#include <clks/panic_qr.h>
|
||||
#include <clks/serial.h>
|
||||
#include <clks/string.h>
|
||||
#include <clks/types.h>
|
||||
}
|
||||
|
||||
#ifndef NDEBUG
|
||||
#define NDEBUG 1
|
||||
#endif
|
||||
|
||||
#define MINIZ_NO_STDIO 1
|
||||
#define MINIZ_NO_INFLATE_APIS 1
|
||||
#define MINIZ_NO_TIME 1
|
||||
#define MINIZ_NO_MALLOC 1
|
||||
#define MINIZ_NO_ZLIB_COMPATIBLE_NAMES 1
|
||||
#include "../../third_party/miniz/miniz.h"
|
||||
|
||||
extern "C" {
|
||||
#include "../../third_party/qrcodegen/qrcodegen.h"
|
||||
}
|
||||
|
||||
#define CLKS_PANIC_QR_BORDER 4U
|
||||
#define CLKS_PANIC_QR_MAX_LINES 256U
|
||||
#define CLKS_PANIC_QR_LINE_MAX 256U
|
||||
#define CLKS_PANIC_QR_TEXT_MAX ((CLKS_PANIC_QR_MAX_LINES * CLKS_PANIC_QR_LINE_MAX) + CLKS_PANIC_QR_MAX_LINES)
|
||||
#define CLKS_PANIC_QR_COMP_MAX (CLKS_PANIC_QR_TEXT_MAX + 2048U)
|
||||
#define CLKS_PANIC_QR_MAX_COMP_BYTES 2953U
|
||||
#define CLKS_PANIC_QR_DIGITS_MAX (((CLKS_PANIC_QR_MAX_COMP_BYTES / 7U) * 17U) + 17U)
|
||||
#define CLKS_PANIC_QR_URL_PREFIX "https://panic.archlinux.org/panic_report#?a=cleonos-x86_64&v=cleonos&z="
|
||||
#define CLKS_PANIC_QR_URL_PREFIX_LEN ((u64)(sizeof(CLKS_PANIC_QR_URL_PREFIX) - 1U))
|
||||
|
||||
#define CLKS_PANIC_QR_COLOR_DARK 0x00000000U
|
||||
#define CLKS_PANIC_QR_COLOR_LIGHT 0x00FFFFFFU
|
||||
|
||||
static char clks_panic_qr_lines[CLKS_PANIC_QR_MAX_LINES][CLKS_PANIC_QR_LINE_MAX];
|
||||
static u16 clks_panic_qr_line_len[CLKS_PANIC_QR_MAX_LINES];
|
||||
|
||||
static char clks_panic_qr_text[CLKS_PANIC_QR_TEXT_MAX];
|
||||
static u8 clks_panic_qr_comp[CLKS_PANIC_QR_COMP_MAX];
|
||||
static char clks_panic_qr_digits[CLKS_PANIC_QR_DIGITS_MAX];
|
||||
|
||||
static u8 clks_panic_qr_payload[qrcodegen_BUFFER_LEN_MAX];
|
||||
static u8 clks_panic_qr_code[qrcodegen_BUFFER_LEN_MAX];
|
||||
static u8 clks_panic_qr_url_seg_buf[qrcodegen_BUFFER_LEN_MAX];
|
||||
static u8 clks_panic_qr_num_seg_buf[qrcodegen_BUFFER_LEN_MAX];
|
||||
|
||||
static clks_bool clks_panic_qr_ready = CLKS_FALSE;
|
||||
static clks_bool clks_panic_qr_attempted = CLKS_FALSE;
|
||||
static u64 clks_panic_qr_total_lines_cache = 0ULL;
|
||||
static u64 clks_panic_qr_dropped_lines_cache = 0ULL;
|
||||
static u64 clks_panic_qr_comp_size_cache = 0ULL;
|
||||
static u64 clks_panic_qr_digits_size_cache = 0ULL;
|
||||
|
||||
static u64 clks_panic_qr_collect_lines(void) {
|
||||
u64 journal_count = clks_log_journal_count();
|
||||
u64 i;
|
||||
u64 line_count = 0ULL;
|
||||
|
||||
if (journal_count > CLKS_PANIC_QR_MAX_LINES) {
|
||||
journal_count = CLKS_PANIC_QR_MAX_LINES;
|
||||
}
|
||||
|
||||
for (i = 0ULL; i < journal_count; i++) {
|
||||
if (clks_log_journal_read(i, clks_panic_qr_lines[line_count], CLKS_PANIC_QR_LINE_MAX) == CLKS_TRUE) {
|
||||
clks_panic_qr_line_len[line_count] = (u16)clks_strlen(clks_panic_qr_lines[line_count]);
|
||||
line_count++;
|
||||
}
|
||||
}
|
||||
|
||||
return line_count;
|
||||
}
|
||||
|
||||
static u64 clks_panic_qr_build_text(u64 line_start, u64 line_count) {
|
||||
u64 i;
|
||||
u64 out_len = 0ULL;
|
||||
|
||||
if (line_start >= line_count) {
|
||||
return 0ULL;
|
||||
}
|
||||
|
||||
for (i = line_start; i < line_count; i++) {
|
||||
u64 len = (u64)clks_panic_qr_line_len[i];
|
||||
|
||||
if (out_len + len + 1ULL > CLKS_PANIC_QR_TEXT_MAX) {
|
||||
break;
|
||||
}
|
||||
|
||||
if (len > 0ULL) {
|
||||
clks_memcpy(&clks_panic_qr_text[out_len], clks_panic_qr_lines[i], (usize)len);
|
||||
out_len += len;
|
||||
}
|
||||
|
||||
clks_panic_qr_text[out_len++] = '\n';
|
||||
}
|
||||
|
||||
return out_len;
|
||||
}
|
||||
|
||||
static clks_bool clks_panic_qr_compress(const char *src, u64 src_len, u8 *dst, u64 dst_cap, u64 *out_len) {
|
||||
tdefl_compressor comp;
|
||||
tdefl_status init_status;
|
||||
tdefl_status comp_status;
|
||||
size_t in_size;
|
||||
size_t out_size;
|
||||
mz_uint flags;
|
||||
|
||||
if (src == CLKS_NULL || dst == CLKS_NULL || out_len == CLKS_NULL || src_len == 0ULL || dst_cap == 0ULL) {
|
||||
return CLKS_FALSE;
|
||||
}
|
||||
|
||||
flags = tdefl_create_comp_flags_from_zip_params(6, 12, MZ_DEFAULT_STRATEGY);
|
||||
init_status = tdefl_init(&comp, (tdefl_put_buf_func_ptr)0, (void *)0, (int)flags);
|
||||
if (init_status < 0) {
|
||||
return CLKS_FALSE;
|
||||
}
|
||||
|
||||
in_size = (size_t)src_len;
|
||||
out_size = (size_t)dst_cap;
|
||||
comp_status = tdefl_compress(&comp, src, &in_size, dst, &out_size, TDEFL_FINISH);
|
||||
|
||||
if (comp_status != TDEFL_STATUS_DONE || in_size != (size_t)src_len) {
|
||||
return CLKS_FALSE;
|
||||
}
|
||||
|
||||
*out_len = (u64)out_size;
|
||||
return CLKS_TRUE;
|
||||
}
|
||||
|
||||
static void clks_panic_qr_u64_to_dec_padded(u64 value, u32 digits, char *out) {
|
||||
u32 i;
|
||||
|
||||
if (out == CLKS_NULL || digits == 0U) {
|
||||
return;
|
||||
}
|
||||
|
||||
for (i = 0U; i < digits; i++) {
|
||||
out[digits - 1U - i] = (char)('0' + (value % 10ULL));
|
||||
value /= 10ULL;
|
||||
}
|
||||
}
|
||||
|
||||
static u64 clks_panic_qr_binary_to_decimal(const u8 *src, u64 src_len, char *dst, u64 dst_cap) {
|
||||
static const u8 tail_digits[7] = {0U, 3U, 5U, 8U, 10U, 13U, 15U};
|
||||
u64 in_pos = 0ULL;
|
||||
u64 out_pos = 0ULL;
|
||||
|
||||
if (src == CLKS_NULL || dst == CLKS_NULL || dst_cap == 0ULL) {
|
||||
return 0ULL;
|
||||
}
|
||||
|
||||
while (in_pos + 7ULL <= src_len) {
|
||||
u64 value = 0ULL;
|
||||
u32 i;
|
||||
|
||||
if (out_pos + 17ULL + 1ULL > dst_cap) {
|
||||
return 0ULL;
|
||||
}
|
||||
|
||||
for (i = 0U; i < 7U; i++) {
|
||||
value |= ((u64)src[in_pos + (u64)i]) << (i * 8U);
|
||||
}
|
||||
|
||||
clks_panic_qr_u64_to_dec_padded(value, 17U, &dst[out_pos]);
|
||||
out_pos += 17ULL;
|
||||
in_pos += 7ULL;
|
||||
}
|
||||
|
||||
if (in_pos < src_len) {
|
||||
u64 value = 0ULL;
|
||||
u64 rem = src_len - in_pos;
|
||||
u32 digits = tail_digits[rem];
|
||||
u32 i;
|
||||
|
||||
if (digits == 0U || out_pos + (u64)digits + 1ULL > dst_cap) {
|
||||
return 0ULL;
|
||||
}
|
||||
|
||||
for (i = 0U; i < (u32)rem; i++) {
|
||||
value |= ((u64)src[in_pos + (u64)i]) << (i * 8U);
|
||||
}
|
||||
|
||||
clks_panic_qr_u64_to_dec_padded(value, digits, &dst[out_pos]);
|
||||
out_pos += (u64)digits;
|
||||
}
|
||||
|
||||
dst[out_pos] = '\0';
|
||||
return out_pos;
|
||||
}
|
||||
|
||||
static clks_bool clks_panic_qr_encode_payload(const u8 *payload, u64 payload_size, u64 *digit_len_out) {
|
||||
struct qrcodegen_Segment segs[2];
|
||||
u64 digit_len;
|
||||
size_t url_seg_buf_len;
|
||||
size_t num_seg_buf_len;
|
||||
|
||||
if (payload == CLKS_NULL || payload_size == 0ULL || payload_size > CLKS_PANIC_QR_MAX_COMP_BYTES) {
|
||||
return CLKS_FALSE;
|
||||
}
|
||||
|
||||
digit_len = clks_panic_qr_binary_to_decimal(payload, payload_size, clks_panic_qr_digits, CLKS_PANIC_QR_DIGITS_MAX);
|
||||
if (digit_len == 0ULL) {
|
||||
return CLKS_FALSE;
|
||||
}
|
||||
|
||||
url_seg_buf_len = qrcodegen_calcSegmentBufferSize(qrcodegen_Mode_BYTE, (size_t)CLKS_PANIC_QR_URL_PREFIX_LEN);
|
||||
num_seg_buf_len = qrcodegen_calcSegmentBufferSize(qrcodegen_Mode_NUMERIC, (size_t)digit_len);
|
||||
if (url_seg_buf_len == (size_t)-1 || num_seg_buf_len == (size_t)-1 || url_seg_buf_len > qrcodegen_BUFFER_LEN_MAX ||
|
||||
num_seg_buf_len > qrcodegen_BUFFER_LEN_MAX) {
|
||||
return CLKS_FALSE;
|
||||
}
|
||||
|
||||
segs[0] = qrcodegen_makeBytes((const u8 *)CLKS_PANIC_QR_URL_PREFIX, (size_t)CLKS_PANIC_QR_URL_PREFIX_LEN,
|
||||
clks_panic_qr_url_seg_buf);
|
||||
segs[1] = qrcodegen_makeNumeric(clks_panic_qr_digits, clks_panic_qr_num_seg_buf);
|
||||
|
||||
if (qrcodegen_encodeSegmentsAdvanced(segs, 2U, qrcodegen_Ecc_LOW, qrcodegen_VERSION_MIN, qrcodegen_VERSION_MAX,
|
||||
qrcodegen_Mask_AUTO, true, clks_panic_qr_payload,
|
||||
clks_panic_qr_code) == false) {
|
||||
return CLKS_FALSE;
|
||||
}
|
||||
|
||||
if (digit_len_out != CLKS_NULL) {
|
||||
*digit_len_out = digit_len;
|
||||
}
|
||||
|
||||
return CLKS_TRUE;
|
||||
}
|
||||
|
||||
extern "C" clks_bool clks_panic_qr_prepare(void) {
|
||||
u64 line_count;
|
||||
u64 start;
|
||||
|
||||
if (clks_panic_qr_attempted == CLKS_TRUE) {
|
||||
return clks_panic_qr_ready;
|
||||
}
|
||||
|
||||
clks_panic_qr_attempted = CLKS_TRUE;
|
||||
clks_panic_qr_ready = CLKS_FALSE;
|
||||
clks_panic_qr_total_lines_cache = 0ULL;
|
||||
clks_panic_qr_dropped_lines_cache = 0ULL;
|
||||
clks_panic_qr_comp_size_cache = 0ULL;
|
||||
clks_panic_qr_digits_size_cache = 0ULL;
|
||||
|
||||
line_count = clks_panic_qr_collect_lines();
|
||||
clks_panic_qr_total_lines_cache = line_count;
|
||||
|
||||
if (line_count == 0ULL) {
|
||||
return CLKS_FALSE;
|
||||
}
|
||||
|
||||
for (start = 0ULL; start < line_count; start++) {
|
||||
u64 text_len = clks_panic_qr_build_text(start, line_count);
|
||||
u64 comp_len = 0ULL;
|
||||
u64 digit_len = 0ULL;
|
||||
|
||||
if (text_len == 0ULL) {
|
||||
continue;
|
||||
}
|
||||
|
||||
if (clks_panic_qr_compress(clks_panic_qr_text, text_len, clks_panic_qr_comp, CLKS_PANIC_QR_COMP_MAX,
|
||||
&comp_len) == CLKS_FALSE) {
|
||||
continue;
|
||||
}
|
||||
|
||||
if (comp_len > CLKS_PANIC_QR_MAX_COMP_BYTES) {
|
||||
continue;
|
||||
}
|
||||
|
||||
if (clks_panic_qr_encode_payload(clks_panic_qr_comp, comp_len, &digit_len) == CLKS_FALSE) {
|
||||
continue;
|
||||
}
|
||||
|
||||
clks_panic_qr_dropped_lines_cache = start;
|
||||
clks_panic_qr_comp_size_cache = comp_len;
|
||||
clks_panic_qr_digits_size_cache = digit_len;
|
||||
clks_panic_qr_ready = CLKS_TRUE;
|
||||
return CLKS_TRUE;
|
||||
}
|
||||
|
||||
return CLKS_FALSE;
|
||||
}
|
||||
|
||||
extern "C" clks_bool clks_panic_qr_show(void) {
|
||||
struct clks_framebuffer_info fb_info;
|
||||
int qr_size;
|
||||
u32 modules;
|
||||
u32 scale;
|
||||
u32 draw_w;
|
||||
u32 draw_h;
|
||||
u32 base_x;
|
||||
u32 base_y;
|
||||
u32 y;
|
||||
u32 x;
|
||||
|
||||
if (clks_panic_qr_ready == CLKS_FALSE) {
|
||||
if (clks_panic_qr_prepare() == CLKS_FALSE) {
|
||||
return CLKS_FALSE;
|
||||
}
|
||||
}
|
||||
|
||||
if (clks_fb_ready() == CLKS_FALSE) {
|
||||
return CLKS_FALSE;
|
||||
}
|
||||
|
||||
qr_size = qrcodegen_getSize(clks_panic_qr_code);
|
||||
if (qr_size <= 0) {
|
||||
return CLKS_FALSE;
|
||||
}
|
||||
|
||||
fb_info = clks_fb_info();
|
||||
modules = (u32)qr_size + (CLKS_PANIC_QR_BORDER * 2U);
|
||||
if (modules == 0U) {
|
||||
return CLKS_FALSE;
|
||||
}
|
||||
|
||||
scale = fb_info.width / modules;
|
||||
if ((fb_info.height / modules) < scale) {
|
||||
scale = fb_info.height / modules;
|
||||
}
|
||||
|
||||
if (scale == 0U) {
|
||||
return CLKS_FALSE;
|
||||
}
|
||||
|
||||
draw_w = modules * scale;
|
||||
draw_h = modules * scale;
|
||||
base_x = (fb_info.width > draw_w) ? ((fb_info.width - draw_w) / 2U) : 0U;
|
||||
base_y = (fb_info.height > draw_h) ? ((fb_info.height - draw_h) / 2U) : 0U;
|
||||
|
||||
clks_fb_clear(CLKS_PANIC_QR_COLOR_LIGHT);
|
||||
|
||||
for (y = 0U; y < modules; y++) {
|
||||
for (x = 0U; x < modules; x++) {
|
||||
int qx = (int)x - (int)CLKS_PANIC_QR_BORDER;
|
||||
int qy = (int)y - (int)CLKS_PANIC_QR_BORDER;
|
||||
clks_bool dark = CLKS_FALSE;
|
||||
|
||||
if (qx >= 0 && qy >= 0 && qx < qr_size && qy < qr_size) {
|
||||
dark = qrcodegen_getModule(clks_panic_qr_code, qx, qy) ? CLKS_TRUE : CLKS_FALSE;
|
||||
}
|
||||
|
||||
if (dark == CLKS_TRUE) {
|
||||
clks_fb_fill_rect(base_x + (x * scale), base_y + (y * scale), scale, scale, CLKS_PANIC_QR_COLOR_DARK);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
clks_serial_write("[PANIC][QR] LINES:");
|
||||
{
|
||||
char hex_buf[19];
|
||||
clks_serial_write(" TOTAL=");
|
||||
clks_memset(hex_buf, 0, sizeof(hex_buf));
|
||||
hex_buf[0] = '0';
|
||||
hex_buf[1] = 'X';
|
||||
for (int i = 0; i < 16; i++) {
|
||||
u8 n = (u8)((clks_panic_qr_total_lines_cache >> ((15 - i) * 4)) & 0x0FULL);
|
||||
hex_buf[2 + i] = (n < 10U) ? (char)('0' + n) : (char)('A' + (n - 10U));
|
||||
}
|
||||
clks_serial_write(hex_buf);
|
||||
|
||||
clks_serial_write(" DROPPED=");
|
||||
for (int i = 0; i < 16; i++) {
|
||||
u8 n = (u8)((clks_panic_qr_dropped_lines_cache >> ((15 - i) * 4)) & 0x0FULL);
|
||||
hex_buf[2 + i] = (n < 10U) ? (char)('0' + n) : (char)('A' + (n - 10U));
|
||||
}
|
||||
clks_serial_write(hex_buf);
|
||||
|
||||
clks_serial_write(" COMP_BYTES=");
|
||||
for (int i = 0; i < 16; i++) {
|
||||
u8 n = (u8)((clks_panic_qr_comp_size_cache >> ((15 - i) * 4)) & 0x0FULL);
|
||||
hex_buf[2 + i] = (n < 10U) ? (char)('0' + n) : (char)('A' + (n - 10U));
|
||||
}
|
||||
clks_serial_write(hex_buf);
|
||||
clks_serial_write(" DIGITS=");
|
||||
for (int i = 0; i < 16; i++) {
|
||||
u8 n = (u8)((clks_panic_qr_digits_size_cache >> ((15 - i) * 4)) & 0x0FULL);
|
||||
hex_buf[2 + i] = (n < 10U) ? (char)('0' + n) : (char)('A' + (n - 10U));
|
||||
}
|
||||
clks_serial_write(hex_buf);
|
||||
clks_serial_write("\n");
|
||||
}
|
||||
|
||||
return CLKS_TRUE;
|
||||
}
|
||||
|
||||
extern "C" u64 clks_panic_qr_total_lines(void) {
|
||||
return clks_panic_qr_total_lines_cache;
|
||||
}
|
||||
|
||||
extern "C" u64 clks_panic_qr_dropped_lines(void) {
|
||||
return clks_panic_qr_dropped_lines_cache;
|
||||
}
|
||||
179
clks.local.bak/kernel/core/scheduler.c
Normal file
179
clks.local.bak/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.local.bak/kernel/core/service.c
Normal file
140
clks.local.bak/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