mirror of
https://github.com/Leonmmcoset/cleonos.git
synced 2026-04-24 11:14:01 +00:00
接着上个
This commit is contained in:
101
clks.local.bak/kernel/boot/limine/limine_requests.c
Normal file
101
clks.local.bak/kernel/boot/limine/limine_requests.c
Normal file
@@ -0,0 +1,101 @@
|
||||
#include <clks/boot.h>
|
||||
#include <clks/compiler.h>
|
||||
|
||||
CLKS_USED static volatile u64 limine_requests_start[] __attribute__((section(".limine_requests_start"))) =
|
||||
LIMINE_REQUESTS_START_MARKER;
|
||||
|
||||
CLKS_USED static volatile u64 limine_base_revision[] __attribute__((section(".limine_requests"))) =
|
||||
LIMINE_BASE_REVISION(3);
|
||||
|
||||
CLKS_USED static volatile struct limine_framebuffer_request limine_framebuffer_request
|
||||
__attribute__((section(".limine_requests"))) = {
|
||||
.id = LIMINE_FRAMEBUFFER_REQUEST,
|
||||
.revision = 0,
|
||||
.response = CLKS_NULL,
|
||||
};
|
||||
|
||||
CLKS_USED static volatile struct limine_memmap_request limine_memmap_request
|
||||
__attribute__((section(".limine_requests"))) = {
|
||||
.id = LIMINE_MEMMAP_REQUEST,
|
||||
.revision = 0,
|
||||
.response = CLKS_NULL,
|
||||
};
|
||||
|
||||
CLKS_USED static volatile struct limine_executable_file_request limine_executable_file_request
|
||||
__attribute__((section(".limine_requests"))) = {
|
||||
.id = LIMINE_EXECUTABLE_FILE_REQUEST,
|
||||
.revision = 0,
|
||||
.response = CLKS_NULL,
|
||||
};
|
||||
|
||||
CLKS_USED static volatile struct limine_module_request limine_module_request
|
||||
__attribute__((section(".limine_requests"))) = {
|
||||
.id = LIMINE_MODULE_REQUEST,
|
||||
.revision = 0,
|
||||
.response = CLKS_NULL,
|
||||
};
|
||||
|
||||
CLKS_USED static volatile u64 limine_requests_end[] __attribute__((section(".limine_requests_end"))) =
|
||||
LIMINE_REQUESTS_END_MARKER;
|
||||
|
||||
clks_bool clks_boot_base_revision_supported(void) {
|
||||
return (limine_base_revision[2] == 0) ? CLKS_TRUE : CLKS_FALSE;
|
||||
}
|
||||
|
||||
const struct limine_framebuffer *clks_boot_get_framebuffer(void) {
|
||||
volatile struct limine_framebuffer_request *request = &limine_framebuffer_request;
|
||||
|
||||
if (request->response == CLKS_NULL) {
|
||||
return CLKS_NULL;
|
||||
}
|
||||
|
||||
if (request->response->framebuffer_count < 1) {
|
||||
return CLKS_NULL;
|
||||
}
|
||||
|
||||
return request->response->framebuffers[0];
|
||||
}
|
||||
|
||||
const struct limine_memmap_response *clks_boot_get_memmap(void) {
|
||||
volatile struct limine_memmap_request *request = &limine_memmap_request;
|
||||
|
||||
if (request->response == CLKS_NULL) {
|
||||
return CLKS_NULL;
|
||||
}
|
||||
|
||||
return request->response;
|
||||
}
|
||||
|
||||
const struct limine_file *clks_boot_get_executable_file(void) {
|
||||
volatile struct limine_executable_file_request *request = &limine_executable_file_request;
|
||||
|
||||
if (request->response == CLKS_NULL) {
|
||||
return CLKS_NULL;
|
||||
}
|
||||
|
||||
return request->response->executable_file;
|
||||
}
|
||||
|
||||
u64 clks_boot_get_module_count(void) {
|
||||
volatile struct limine_module_request *request = &limine_module_request;
|
||||
|
||||
if (request->response == CLKS_NULL) {
|
||||
return 0ULL;
|
||||
}
|
||||
|
||||
return request->response->module_count;
|
||||
}
|
||||
|
||||
const struct limine_file *clks_boot_get_module(u64 index) {
|
||||
volatile struct limine_module_request *request = &limine_module_request;
|
||||
|
||||
if (request->response == CLKS_NULL) {
|
||||
return CLKS_NULL;
|
||||
}
|
||||
|
||||
if (index >= request->response->module_count) {
|
||||
return CLKS_NULL;
|
||||
}
|
||||
|
||||
return request->response->modules[index];
|
||||
}
|
||||
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;
|
||||
}
|
||||
126
clks.local.bak/kernel/hal/audio/pcspeaker.c
Normal file
126
clks.local.bak/kernel/hal/audio/pcspeaker.c
Normal file
@@ -0,0 +1,126 @@
|
||||
#include <clks/audio.h>
|
||||
#include <clks/exec.h>
|
||||
#include <clks/log.h>
|
||||
#include <clks/types.h>
|
||||
|
||||
#define CLKS_AUDIO_PIT_BASE_HZ 1193182ULL
|
||||
#define CLKS_AUDIO_FREQ_MIN 20ULL
|
||||
#define CLKS_AUDIO_FREQ_MAX 20000ULL
|
||||
#define CLKS_AUDIO_TICKS_MAX 2048ULL
|
||||
|
||||
static clks_bool clks_audio_ready = CLKS_FALSE;
|
||||
static u64 clks_audio_played_count = 0ULL;
|
||||
|
||||
#if defined(CLKS_ARCH_X86_64)
|
||||
static inline void clks_audio_outb(u16 port, u8 value) {
|
||||
__asm__ volatile("outb %0, %1" : : "a"(value), "Nd"(port));
|
||||
}
|
||||
|
||||
static inline u8 clks_audio_inb(u16 port) {
|
||||
u8 value;
|
||||
__asm__ volatile("inb %1, %0" : "=a"(value) : "Nd"(port));
|
||||
return value;
|
||||
}
|
||||
|
||||
static void clks_audio_program_pc_speaker(u64 hz) {
|
||||
u64 divisor64 = CLKS_AUDIO_PIT_BASE_HZ / hz;
|
||||
u16 divisor;
|
||||
u8 control;
|
||||
|
||||
if (divisor64 == 0ULL) {
|
||||
divisor64 = 1ULL;
|
||||
}
|
||||
|
||||
if (divisor64 > 0xFFFFULL) {
|
||||
divisor64 = 0xFFFFULL;
|
||||
}
|
||||
|
||||
divisor = (u16)divisor64;
|
||||
clks_audio_outb(0x43U, 0xB6U);
|
||||
clks_audio_outb(0x42U, (u8)(divisor & 0xFFU));
|
||||
clks_audio_outb(0x42U, (u8)((divisor >> 8) & 0xFFU));
|
||||
|
||||
control = clks_audio_inb(0x61U);
|
||||
clks_audio_outb(0x61U, (u8)(control | 0x03U));
|
||||
}
|
||||
#endif
|
||||
|
||||
static u64 clks_audio_clamp_hz(u64 hz) {
|
||||
if (hz < CLKS_AUDIO_FREQ_MIN) {
|
||||
return CLKS_AUDIO_FREQ_MIN;
|
||||
}
|
||||
|
||||
if (hz > CLKS_AUDIO_FREQ_MAX) {
|
||||
return CLKS_AUDIO_FREQ_MAX;
|
||||
}
|
||||
|
||||
return hz;
|
||||
}
|
||||
|
||||
void clks_audio_init(void) {
|
||||
#if defined(CLKS_ARCH_X86_64)
|
||||
clks_audio_ready = CLKS_TRUE;
|
||||
clks_audio_played_count = 0ULL;
|
||||
clks_audio_stop();
|
||||
|
||||
clks_log(CLKS_LOG_INFO, "AUDIO", "PC SPEAKER ONLINE");
|
||||
clks_log_hex(CLKS_LOG_INFO, "AUDIO", "PIT_BASE_HZ", CLKS_AUDIO_PIT_BASE_HZ);
|
||||
#else
|
||||
clks_audio_ready = CLKS_FALSE;
|
||||
clks_audio_played_count = 0ULL;
|
||||
clks_log(CLKS_LOG_WARN, "AUDIO", "AUDIO OUTPUT NOT AVAILABLE ON THIS ARCH");
|
||||
#endif
|
||||
}
|
||||
|
||||
clks_bool clks_audio_available(void) {
|
||||
return clks_audio_ready;
|
||||
}
|
||||
|
||||
clks_bool clks_audio_play_tone(u64 hz, u64 ticks) {
|
||||
if (clks_audio_ready == CLKS_FALSE) {
|
||||
return CLKS_FALSE;
|
||||
}
|
||||
|
||||
if (ticks == 0ULL) {
|
||||
return CLKS_TRUE;
|
||||
}
|
||||
|
||||
if (ticks > CLKS_AUDIO_TICKS_MAX) {
|
||||
ticks = CLKS_AUDIO_TICKS_MAX;
|
||||
}
|
||||
|
||||
if (hz == 0ULL) {
|
||||
clks_audio_stop();
|
||||
(void)clks_exec_sleep_ticks(ticks);
|
||||
return CLKS_TRUE;
|
||||
}
|
||||
|
||||
hz = clks_audio_clamp_hz(hz);
|
||||
|
||||
#if defined(CLKS_ARCH_X86_64)
|
||||
clks_audio_program_pc_speaker(hz);
|
||||
(void)clks_exec_sleep_ticks(ticks);
|
||||
clks_audio_stop();
|
||||
clks_audio_played_count++;
|
||||
return CLKS_TRUE;
|
||||
#else
|
||||
return CLKS_FALSE;
|
||||
#endif
|
||||
}
|
||||
|
||||
void clks_audio_stop(void) {
|
||||
#if defined(CLKS_ARCH_X86_64)
|
||||
u8 control;
|
||||
|
||||
if (clks_audio_ready == CLKS_FALSE) {
|
||||
return;
|
||||
}
|
||||
|
||||
control = clks_audio_inb(0x61U);
|
||||
clks_audio_outb(0x61U, (u8)(control & 0xFCU));
|
||||
#endif
|
||||
}
|
||||
|
||||
u64 clks_audio_play_count(void) {
|
||||
return clks_audio_played_count;
|
||||
}
|
||||
67
clks.local.bak/kernel/hal/serial/serial.c
Normal file
67
clks.local.bak/kernel/hal/serial/serial.c
Normal file
@@ -0,0 +1,67 @@
|
||||
#include <clks/compiler.h>
|
||||
#include <clks/serial.h>
|
||||
#include <clks/types.h>
|
||||
|
||||
#if defined(CLKS_ARCH_X86_64)
|
||||
|
||||
#define CLKS_COM1_PORT 0x3F8
|
||||
|
||||
static inline void clks_x86_outb(u16 port, u8 value) {
|
||||
__asm__ volatile("outb %0, %1" : : "a"(value), "Nd"(port));
|
||||
}
|
||||
|
||||
static inline u8 clks_x86_inb(u16 port) {
|
||||
u8 value;
|
||||
__asm__ volatile("inb %1, %0" : "=a"(value) : "Nd"(port));
|
||||
return value;
|
||||
}
|
||||
|
||||
void clks_serial_init(void) {
|
||||
clks_x86_outb(CLKS_COM1_PORT + 1, 0x00);
|
||||
clks_x86_outb(CLKS_COM1_PORT + 3, 0x80);
|
||||
clks_x86_outb(CLKS_COM1_PORT + 0, 0x03);
|
||||
clks_x86_outb(CLKS_COM1_PORT + 1, 0x00);
|
||||
clks_x86_outb(CLKS_COM1_PORT + 3, 0x03);
|
||||
clks_x86_outb(CLKS_COM1_PORT + 2, 0xC7);
|
||||
clks_x86_outb(CLKS_COM1_PORT + 4, 0x0B);
|
||||
}
|
||||
|
||||
void clks_serial_write_char(char ch) {
|
||||
while ((clks_x86_inb(CLKS_COM1_PORT + 5) & 0x20) == 0) {
|
||||
}
|
||||
|
||||
clks_x86_outb(CLKS_COM1_PORT, (u8)ch);
|
||||
}
|
||||
|
||||
#elif defined(CLKS_ARCH_AARCH64)
|
||||
|
||||
#define CLKS_PL011_BASE 0x09000000ULL
|
||||
#define CLKS_PL011_DR (*(volatile u32 *)(CLKS_PL011_BASE + 0x00))
|
||||
#define CLKS_PL011_FR (*(volatile u32 *)(CLKS_PL011_BASE + 0x18))
|
||||
#define CLKS_PL011_TXFF (1U << 5)
|
||||
|
||||
void clks_serial_init(void) {}
|
||||
|
||||
void clks_serial_write_char(char ch) {
|
||||
while ((CLKS_PL011_FR & CLKS_PL011_TXFF) != 0) {
|
||||
}
|
||||
|
||||
CLKS_PL011_DR = (u32)(u8)ch;
|
||||
}
|
||||
|
||||
#else
|
||||
#error "Unsupported architecture"
|
||||
#endif
|
||||
|
||||
void clks_serial_write(const char *text) {
|
||||
usize i = 0;
|
||||
|
||||
while (text[i] != '\0') {
|
||||
if (text[i] == '\n') {
|
||||
clks_serial_write_char('\r');
|
||||
}
|
||||
|
||||
clks_serial_write_char(text[i]);
|
||||
i++;
|
||||
}
|
||||
}
|
||||
53
clks.local.bak/kernel/hal/video/font8x8.c
Normal file
53
clks.local.bak/kernel/hal/video/font8x8.c
Normal file
@@ -0,0 +1,53 @@
|
||||
#include "font8x8.h"
|
||||
|
||||
#include <clks/types.h>
|
||||
|
||||
struct clks_glyph8x8 {
|
||||
char ch;
|
||||
u8 rows[8];
|
||||
};
|
||||
|
||||
static const struct clks_glyph8x8 clks_font_table[] = {
|
||||
{' ', {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}}, {'[', {0x1E, 0x10, 0x10, 0x10, 0x10, 0x10, 0x1E, 0x00}},
|
||||
{']', {0x78, 0x08, 0x08, 0x08, 0x08, 0x08, 0x78, 0x00}}, {':', {0x00, 0x18, 0x18, 0x00, 0x18, 0x18, 0x00, 0x00}},
|
||||
{'.', {0x00, 0x00, 0x00, 0x00, 0x00, 0x18, 0x18, 0x00}}, {'-', {0x00, 0x00, 0x00, 0x7E, 0x00, 0x00, 0x00, 0x00}},
|
||||
{'/', {0x02, 0x04, 0x08, 0x10, 0x20, 0x40, 0x00, 0x00}}, {'_', {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x7E, 0x00}},
|
||||
{'?', {0x3C, 0x42, 0x02, 0x0C, 0x10, 0x00, 0x10, 0x00}}, {'0', {0x3C, 0x42, 0x46, 0x4A, 0x52, 0x62, 0x3C, 0x00}},
|
||||
{'1', {0x18, 0x28, 0x08, 0x08, 0x08, 0x08, 0x3E, 0x00}}, {'2', {0x3C, 0x42, 0x02, 0x0C, 0x30, 0x40, 0x7E, 0x00}},
|
||||
{'3', {0x3C, 0x42, 0x02, 0x1C, 0x02, 0x42, 0x3C, 0x00}}, {'4', {0x0C, 0x14, 0x24, 0x44, 0x7E, 0x04, 0x04, 0x00}},
|
||||
{'5', {0x7E, 0x40, 0x7C, 0x02, 0x02, 0x42, 0x3C, 0x00}}, {'6', {0x1C, 0x20, 0x40, 0x7C, 0x42, 0x42, 0x3C, 0x00}},
|
||||
{'7', {0x7E, 0x02, 0x04, 0x08, 0x10, 0x20, 0x20, 0x00}}, {'8', {0x3C, 0x42, 0x42, 0x3C, 0x42, 0x42, 0x3C, 0x00}},
|
||||
{'9', {0x3C, 0x42, 0x42, 0x3E, 0x02, 0x04, 0x38, 0x00}}, {'A', {0x18, 0x24, 0x42, 0x7E, 0x42, 0x42, 0x42, 0x00}},
|
||||
{'B', {0x7C, 0x42, 0x42, 0x7C, 0x42, 0x42, 0x7C, 0x00}}, {'C', {0x3C, 0x42, 0x40, 0x40, 0x40, 0x42, 0x3C, 0x00}},
|
||||
{'D', {0x78, 0x44, 0x42, 0x42, 0x42, 0x44, 0x78, 0x00}}, {'E', {0x7E, 0x40, 0x40, 0x7C, 0x40, 0x40, 0x7E, 0x00}},
|
||||
{'F', {0x7E, 0x40, 0x40, 0x7C, 0x40, 0x40, 0x40, 0x00}}, {'G', {0x3C, 0x42, 0x40, 0x4E, 0x42, 0x42, 0x3C, 0x00}},
|
||||
{'H', {0x42, 0x42, 0x42, 0x7E, 0x42, 0x42, 0x42, 0x00}}, {'I', {0x3E, 0x08, 0x08, 0x08, 0x08, 0x08, 0x3E, 0x00}},
|
||||
{'J', {0x1E, 0x04, 0x04, 0x04, 0x44, 0x44, 0x38, 0x00}}, {'K', {0x42, 0x44, 0x48, 0x70, 0x48, 0x44, 0x42, 0x00}},
|
||||
{'L', {0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x7E, 0x00}}, {'M', {0x42, 0x66, 0x5A, 0x5A, 0x42, 0x42, 0x42, 0x00}},
|
||||
{'N', {0x42, 0x62, 0x52, 0x4A, 0x46, 0x42, 0x42, 0x00}}, {'O', {0x3C, 0x42, 0x42, 0x42, 0x42, 0x42, 0x3C, 0x00}},
|
||||
{'P', {0x7C, 0x42, 0x42, 0x7C, 0x40, 0x40, 0x40, 0x00}}, {'Q', {0x3C, 0x42, 0x42, 0x42, 0x4A, 0x44, 0x3A, 0x00}},
|
||||
{'R', {0x7C, 0x42, 0x42, 0x7C, 0x48, 0x44, 0x42, 0x00}}, {'S', {0x3C, 0x42, 0x40, 0x3C, 0x02, 0x42, 0x3C, 0x00}},
|
||||
{'T', {0x7F, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x00}}, {'U', {0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x3C, 0x00}},
|
||||
{'V', {0x42, 0x42, 0x42, 0x42, 0x42, 0x24, 0x18, 0x00}}, {'W', {0x42, 0x42, 0x42, 0x5A, 0x5A, 0x66, 0x42, 0x00}},
|
||||
{'X', {0x42, 0x42, 0x24, 0x18, 0x24, 0x42, 0x42, 0x00}}, {'Y', {0x42, 0x42, 0x24, 0x18, 0x08, 0x08, 0x08, 0x00}},
|
||||
{'Z', {0x7E, 0x02, 0x04, 0x18, 0x20, 0x40, 0x7E, 0x00}},
|
||||
};
|
||||
|
||||
static const u8 clks_unknown[8] = {0x3C, 0x42, 0x02, 0x0C, 0x10, 0x00, 0x10, 0x00};
|
||||
|
||||
const u8 *clks_font8x8_get(char ch) {
|
||||
usize i;
|
||||
char upper = ch;
|
||||
|
||||
if (upper >= 'a' && upper <= 'z') {
|
||||
upper = (char)(upper - ('a' - 'A'));
|
||||
}
|
||||
|
||||
for (i = 0; i < (sizeof(clks_font_table) / sizeof(clks_font_table[0])); i++) {
|
||||
if (clks_font_table[i].ch == upper) {
|
||||
return clks_font_table[i].rows;
|
||||
}
|
||||
}
|
||||
|
||||
return clks_unknown;
|
||||
}
|
||||
8
clks.local.bak/kernel/hal/video/font8x8.h
Normal file
8
clks.local.bak/kernel/hal/video/font8x8.h
Normal file
@@ -0,0 +1,8 @@
|
||||
#ifndef CLKS_FONT8X8_H
|
||||
#define CLKS_FONT8X8_H
|
||||
|
||||
#include <clks/types.h>
|
||||
|
||||
const u8 *clks_font8x8_get(char ch);
|
||||
|
||||
#endif
|
||||
315
clks.local.bak/kernel/hal/video/framebuffer.c
Normal file
315
clks.local.bak/kernel/hal/video/framebuffer.c
Normal file
@@ -0,0 +1,315 @@
|
||||
#include <clks/framebuffer.h>
|
||||
#include <clks/string.h>
|
||||
#include <clks/types.h>
|
||||
|
||||
#include "psf_font.h"
|
||||
|
||||
struct clks_fb_state {
|
||||
volatile u8 *address;
|
||||
struct clks_framebuffer_info info;
|
||||
const struct clks_psf_font *font;
|
||||
struct clks_psf_font external_font;
|
||||
clks_bool external_font_active;
|
||||
u32 glyph_width;
|
||||
u32 glyph_height;
|
||||
clks_bool ready;
|
||||
};
|
||||
|
||||
static struct clks_fb_state clks_fb = {
|
||||
.address = CLKS_NULL,
|
||||
.info = {0, 0, 0, 0},
|
||||
.font = CLKS_NULL,
|
||||
.external_font = {0, 0, 0, 0, 0, CLKS_NULL},
|
||||
.external_font_active = CLKS_FALSE,
|
||||
.glyph_width = 8U,
|
||||
.glyph_height = 8U,
|
||||
.ready = CLKS_FALSE,
|
||||
};
|
||||
|
||||
static void clks_fb_apply_font(const struct clks_psf_font *font) {
|
||||
clks_fb.font = font;
|
||||
clks_fb.glyph_width = 8U;
|
||||
clks_fb.glyph_height = 8U;
|
||||
|
||||
if (font != CLKS_NULL) {
|
||||
if (font->width != 0U) {
|
||||
clks_fb.glyph_width = font->width;
|
||||
}
|
||||
|
||||
if (font->height != 0U) {
|
||||
clks_fb.glyph_height = font->height;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static void clks_fb_put_pixel(u32 x, u32 y, u32 rgb) {
|
||||
volatile u8 *row;
|
||||
volatile u32 *pixel;
|
||||
|
||||
if (clks_fb.ready == CLKS_FALSE) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (x >= clks_fb.info.width || y >= clks_fb.info.height) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (clks_fb.info.bpp != 32) {
|
||||
return;
|
||||
}
|
||||
|
||||
row = clks_fb.address + ((usize)y * (usize)clks_fb.info.pitch);
|
||||
pixel = (volatile u32 *)(row + ((usize)x * 4U));
|
||||
*pixel = rgb;
|
||||
}
|
||||
|
||||
void clks_fb_init(const struct limine_framebuffer *fb) {
|
||||
if (fb == CLKS_NULL) {
|
||||
clks_fb.ready = CLKS_FALSE;
|
||||
return;
|
||||
}
|
||||
|
||||
clks_fb.address = (volatile u8 *)fb->address;
|
||||
clks_fb.info.width = (u32)fb->width;
|
||||
clks_fb.info.height = (u32)fb->height;
|
||||
clks_fb.info.pitch = (u32)fb->pitch;
|
||||
clks_fb.info.bpp = fb->bpp;
|
||||
|
||||
clks_fb.external_font_active = CLKS_FALSE;
|
||||
clks_fb_apply_font(clks_psf_default_font());
|
||||
|
||||
clks_fb.ready = CLKS_TRUE;
|
||||
}
|
||||
|
||||
clks_bool clks_fb_ready(void) {
|
||||
return clks_fb.ready;
|
||||
}
|
||||
|
||||
struct clks_framebuffer_info clks_fb_info(void) {
|
||||
return clks_fb.info;
|
||||
}
|
||||
|
||||
void clks_fb_draw_pixel(u32 x, u32 y, u32 rgb) {
|
||||
clks_fb_put_pixel(x, y, rgb);
|
||||
}
|
||||
|
||||
clks_bool clks_fb_read_pixel(u32 x, u32 y, u32 *out_rgb) {
|
||||
volatile u8 *row;
|
||||
volatile u32 *pixel;
|
||||
|
||||
if (out_rgb == CLKS_NULL) {
|
||||
return CLKS_FALSE;
|
||||
}
|
||||
|
||||
if (clks_fb.ready == CLKS_FALSE) {
|
||||
return CLKS_FALSE;
|
||||
}
|
||||
|
||||
if (x >= clks_fb.info.width || y >= clks_fb.info.height) {
|
||||
return CLKS_FALSE;
|
||||
}
|
||||
|
||||
if (clks_fb.info.bpp != 32) {
|
||||
return CLKS_FALSE;
|
||||
}
|
||||
|
||||
row = clks_fb.address + ((usize)y * (usize)clks_fb.info.pitch);
|
||||
pixel = (volatile u32 *)(row + ((usize)x * 4U));
|
||||
*out_rgb = *pixel;
|
||||
return CLKS_TRUE;
|
||||
}
|
||||
|
||||
void clks_fb_fill_rect(u32 x, u32 y, u32 width, u32 height, u32 rgb) {
|
||||
u32 px;
|
||||
u32 py;
|
||||
u32 end_x;
|
||||
u32 end_y;
|
||||
u64 end_x64;
|
||||
u64 end_y64;
|
||||
|
||||
if (clks_fb.ready == CLKS_FALSE) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (width == 0U || height == 0U) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (x >= clks_fb.info.width || y >= clks_fb.info.height) {
|
||||
return;
|
||||
}
|
||||
|
||||
end_x64 = (u64)x + (u64)width;
|
||||
end_y64 = (u64)y + (u64)height;
|
||||
|
||||
end_x = (end_x64 > (u64)clks_fb.info.width) ? clks_fb.info.width : (u32)end_x64;
|
||||
end_y = (end_y64 > (u64)clks_fb.info.height) ? clks_fb.info.height : (u32)end_y64;
|
||||
|
||||
for (py = y; py < end_y; py++) {
|
||||
for (px = x; px < end_x; px++) {
|
||||
clks_fb_put_pixel(px, py, rgb);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void clks_fb_clear(u32 rgb) {
|
||||
clks_fb_fill_rect(0U, 0U, clks_fb.info.width, clks_fb.info.height, rgb);
|
||||
}
|
||||
|
||||
void clks_fb_scroll_up(u32 pixel_rows, u32 fill_rgb) {
|
||||
usize row_bytes;
|
||||
usize move_bytes;
|
||||
u32 y;
|
||||
|
||||
if (clks_fb.ready == CLKS_FALSE) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (clks_fb.info.bpp != 32) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (pixel_rows == 0U) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (pixel_rows >= clks_fb.info.height) {
|
||||
clks_fb_clear(fill_rgb);
|
||||
return;
|
||||
}
|
||||
|
||||
row_bytes = (usize)clks_fb.info.pitch;
|
||||
move_bytes = (usize)(clks_fb.info.height - pixel_rows) * row_bytes;
|
||||
|
||||
clks_memmove((void *)clks_fb.address, (const void *)(clks_fb.address + ((usize)pixel_rows * row_bytes)),
|
||||
move_bytes);
|
||||
|
||||
for (y = clks_fb.info.height - pixel_rows; y < clks_fb.info.height; y++) {
|
||||
volatile u32 *row_ptr = (volatile u32 *)(clks_fb.address + ((usize)y * row_bytes));
|
||||
u32 x;
|
||||
|
||||
for (x = 0U; x < clks_fb.info.width; x++) {
|
||||
row_ptr[x] = fill_rgb;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void clks_fb_draw_char_styled(u32 x, u32 y, char ch, u32 fg_rgb, u32 bg_rgb, u32 style_flags) {
|
||||
const u8 *glyph;
|
||||
u32 row;
|
||||
u32 col;
|
||||
u32 cols;
|
||||
u32 rows;
|
||||
u32 row_stride;
|
||||
u32 draw_cols;
|
||||
u32 draw_rows;
|
||||
clks_bool style_bold;
|
||||
clks_bool style_underline;
|
||||
u32 underline_row;
|
||||
|
||||
if (clks_fb.ready == CLKS_FALSE || clks_fb.font == CLKS_NULL) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (clks_fb.info.bpp != 32) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (x >= clks_fb.info.width || y >= clks_fb.info.height) {
|
||||
return;
|
||||
}
|
||||
|
||||
glyph = clks_psf_glyph(clks_fb.font, (u32)(u8)ch);
|
||||
|
||||
cols = clks_fb.glyph_width;
|
||||
rows = clks_fb.glyph_height;
|
||||
|
||||
if (cols == 0U) {
|
||||
cols = 8U;
|
||||
}
|
||||
|
||||
if (rows == 0U) {
|
||||
rows = 8U;
|
||||
}
|
||||
|
||||
row_stride = clks_fb.font->bytes_per_row;
|
||||
|
||||
if (row_stride == 0U) {
|
||||
row_stride = (cols + 7U) / 8U;
|
||||
}
|
||||
|
||||
if (row_stride == 0U) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (((usize)row_stride * (usize)rows) > (usize)clks_fb.font->bytes_per_glyph) {
|
||||
return;
|
||||
}
|
||||
|
||||
draw_cols = cols;
|
||||
if (x + draw_cols > clks_fb.info.width) {
|
||||
draw_cols = clks_fb.info.width - x;
|
||||
}
|
||||
|
||||
draw_rows = rows;
|
||||
if (y + draw_rows > clks_fb.info.height) {
|
||||
draw_rows = clks_fb.info.height - y;
|
||||
}
|
||||
|
||||
style_bold = ((style_flags & CLKS_FB_STYLE_BOLD) != 0U) ? CLKS_TRUE : CLKS_FALSE;
|
||||
style_underline = ((style_flags & CLKS_FB_STYLE_UNDERLINE) != 0U) ? CLKS_TRUE : CLKS_FALSE;
|
||||
underline_row = (rows > 1U) ? (rows - 2U) : 0U;
|
||||
|
||||
for (row = 0U; row < draw_rows; row++) {
|
||||
const u8 *row_bits = glyph + ((usize)row * (usize)row_stride);
|
||||
volatile u32 *dst_row =
|
||||
(volatile u32 *)(clks_fb.address + ((usize)(y + row) * (usize)clks_fb.info.pitch) + ((usize)x * 4U));
|
||||
|
||||
for (col = 0U; col < draw_cols; col++) {
|
||||
u8 bits = row_bits[col >> 3U];
|
||||
u8 mask = (u8)(0x80U >> (col & 7U));
|
||||
clks_bool pixel_on = ((bits & mask) != 0U) ? CLKS_TRUE : CLKS_FALSE;
|
||||
|
||||
if (style_bold == CLKS_TRUE && pixel_on == CLKS_FALSE && col > 0U) {
|
||||
u32 left_col = col - 1U;
|
||||
u8 left_bits = row_bits[left_col >> 3U];
|
||||
u8 left_mask = (u8)(0x80U >> (left_col & 7U));
|
||||
|
||||
if ((left_bits & left_mask) != 0U) {
|
||||
pixel_on = CLKS_TRUE;
|
||||
}
|
||||
}
|
||||
|
||||
if (style_underline == CLKS_TRUE && row == underline_row) {
|
||||
pixel_on = CLKS_TRUE;
|
||||
}
|
||||
|
||||
dst_row[col] = (pixel_on == CLKS_TRUE) ? fg_rgb : bg_rgb;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void clks_fb_draw_char(u32 x, u32 y, char ch, u32 fg_rgb, u32 bg_rgb) {
|
||||
clks_fb_draw_char_styled(x, y, ch, fg_rgb, bg_rgb, 0U);
|
||||
}
|
||||
|
||||
clks_bool clks_fb_load_psf_font(const void *blob, u64 blob_size) {
|
||||
struct clks_psf_font parsed = {0, 0, 0, 0, 0, CLKS_NULL};
|
||||
|
||||
if (clks_psf_parse_font(blob, blob_size, &parsed) == CLKS_FALSE) {
|
||||
return CLKS_FALSE;
|
||||
}
|
||||
|
||||
clks_fb.external_font = parsed;
|
||||
clks_fb.external_font_active = CLKS_TRUE;
|
||||
clks_fb_apply_font(&clks_fb.external_font);
|
||||
return CLKS_TRUE;
|
||||
}
|
||||
|
||||
u32 clks_fb_cell_width(void) {
|
||||
return clks_fb.glyph_width == 0U ? 8U : clks_fb.glyph_width;
|
||||
}
|
||||
|
||||
u32 clks_fb_cell_height(void) {
|
||||
return clks_fb.glyph_height == 0U ? 8U : clks_fb.glyph_height;
|
||||
}
|
||||
258
clks.local.bak/kernel/hal/video/psf_font.c
Normal file
258
clks.local.bak/kernel/hal/video/psf_font.c
Normal file
@@ -0,0 +1,258 @@
|
||||
#include "psf_font.h"
|
||||
|
||||
#include <clks/string.h>
|
||||
#include <clks/types.h>
|
||||
|
||||
#define CLKS_PSF1_MAGIC0 0x36U
|
||||
#define CLKS_PSF1_MAGIC1 0x04U
|
||||
#define CLKS_PSF1_HEADER_SIZE 4U
|
||||
#define CLKS_PSF1_GLYPH_COUNT 256U
|
||||
#define CLKS_PSF1_GLYPH_BYTES 8U
|
||||
#define CLKS_PSF1_BLOB_SIZE (CLKS_PSF1_HEADER_SIZE + (CLKS_PSF1_GLYPH_COUNT * CLKS_PSF1_GLYPH_BYTES))
|
||||
|
||||
#define CLKS_PSF2_MAGIC 0x864AB572U
|
||||
#define CLKS_PSF2_HEADER_MIN_SIZE 32U
|
||||
|
||||
struct clks_psf1_header {
|
||||
u8 magic[2];
|
||||
u8 mode;
|
||||
u8 charsize;
|
||||
};
|
||||
|
||||
struct clks_psf2_header {
|
||||
u32 magic;
|
||||
u32 version;
|
||||
u32 headersize;
|
||||
u32 flags;
|
||||
u32 length;
|
||||
u32 charsize;
|
||||
u32 height;
|
||||
u32 width;
|
||||
};
|
||||
|
||||
struct clks_psf_seed_glyph {
|
||||
u8 code;
|
||||
u8 rows[CLKS_PSF1_GLYPH_BYTES];
|
||||
};
|
||||
|
||||
static const u8 clks_psf_unknown[CLKS_PSF1_GLYPH_BYTES] = {0x3C, 0x42, 0x02, 0x0C, 0x10, 0x00, 0x10, 0x00};
|
||||
|
||||
static const struct clks_psf_seed_glyph clks_psf_seed_table[] = {
|
||||
{' ', {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}}, {'[', {0x1E, 0x10, 0x10, 0x10, 0x10, 0x10, 0x1E, 0x00}},
|
||||
{']', {0x78, 0x08, 0x08, 0x08, 0x08, 0x08, 0x78, 0x00}}, {':', {0x00, 0x18, 0x18, 0x00, 0x18, 0x18, 0x00, 0x00}},
|
||||
{'.', {0x00, 0x00, 0x00, 0x00, 0x00, 0x18, 0x18, 0x00}}, {'-', {0x00, 0x00, 0x00, 0x7E, 0x00, 0x00, 0x00, 0x00}},
|
||||
{'/', {0x02, 0x04, 0x08, 0x10, 0x20, 0x40, 0x00, 0x00}}, {'_', {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x7E, 0x00}},
|
||||
{'?', {0x3C, 0x42, 0x02, 0x0C, 0x10, 0x00, 0x10, 0x00}}, {'0', {0x3C, 0x42, 0x46, 0x4A, 0x52, 0x62, 0x3C, 0x00}},
|
||||
{'1', {0x18, 0x28, 0x08, 0x08, 0x08, 0x08, 0x3E, 0x00}}, {'2', {0x3C, 0x42, 0x02, 0x0C, 0x30, 0x40, 0x7E, 0x00}},
|
||||
{'3', {0x3C, 0x42, 0x02, 0x1C, 0x02, 0x42, 0x3C, 0x00}}, {'4', {0x0C, 0x14, 0x24, 0x44, 0x7E, 0x04, 0x04, 0x00}},
|
||||
{'5', {0x7E, 0x40, 0x7C, 0x02, 0x02, 0x42, 0x3C, 0x00}}, {'6', {0x1C, 0x20, 0x40, 0x7C, 0x42, 0x42, 0x3C, 0x00}},
|
||||
{'7', {0x7E, 0x02, 0x04, 0x08, 0x10, 0x20, 0x20, 0x00}}, {'8', {0x3C, 0x42, 0x42, 0x3C, 0x42, 0x42, 0x3C, 0x00}},
|
||||
{'9', {0x3C, 0x42, 0x42, 0x3E, 0x02, 0x04, 0x38, 0x00}}, {'A', {0x18, 0x24, 0x42, 0x7E, 0x42, 0x42, 0x42, 0x00}},
|
||||
{'B', {0x7C, 0x42, 0x42, 0x7C, 0x42, 0x42, 0x7C, 0x00}}, {'C', {0x3C, 0x42, 0x40, 0x40, 0x40, 0x42, 0x3C, 0x00}},
|
||||
{'D', {0x78, 0x44, 0x42, 0x42, 0x42, 0x44, 0x78, 0x00}}, {'E', {0x7E, 0x40, 0x40, 0x7C, 0x40, 0x40, 0x7E, 0x00}},
|
||||
{'F', {0x7E, 0x40, 0x40, 0x7C, 0x40, 0x40, 0x40, 0x00}}, {'G', {0x3C, 0x42, 0x40, 0x4E, 0x42, 0x42, 0x3C, 0x00}},
|
||||
{'H', {0x42, 0x42, 0x42, 0x7E, 0x42, 0x42, 0x42, 0x00}}, {'I', {0x3E, 0x08, 0x08, 0x08, 0x08, 0x08, 0x3E, 0x00}},
|
||||
{'J', {0x1E, 0x04, 0x04, 0x04, 0x44, 0x44, 0x38, 0x00}}, {'K', {0x42, 0x44, 0x48, 0x70, 0x48, 0x44, 0x42, 0x00}},
|
||||
{'L', {0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x7E, 0x00}}, {'M', {0x42, 0x66, 0x5A, 0x5A, 0x42, 0x42, 0x42, 0x00}},
|
||||
{'N', {0x42, 0x62, 0x52, 0x4A, 0x46, 0x42, 0x42, 0x00}}, {'O', {0x3C, 0x42, 0x42, 0x42, 0x42, 0x42, 0x3C, 0x00}},
|
||||
{'P', {0x7C, 0x42, 0x42, 0x7C, 0x40, 0x40, 0x40, 0x00}}, {'Q', {0x3C, 0x42, 0x42, 0x42, 0x4A, 0x44, 0x3A, 0x00}},
|
||||
{'R', {0x7C, 0x42, 0x42, 0x7C, 0x48, 0x44, 0x42, 0x00}}, {'S', {0x3C, 0x42, 0x40, 0x3C, 0x02, 0x42, 0x3C, 0x00}},
|
||||
{'T', {0x7F, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x00}}, {'U', {0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x3C, 0x00}},
|
||||
{'V', {0x42, 0x42, 0x42, 0x42, 0x42, 0x24, 0x18, 0x00}}, {'W', {0x42, 0x42, 0x42, 0x5A, 0x5A, 0x66, 0x42, 0x00}},
|
||||
{'X', {0x42, 0x42, 0x24, 0x18, 0x24, 0x42, 0x42, 0x00}}, {'Y', {0x42, 0x42, 0x24, 0x18, 0x08, 0x08, 0x08, 0x00}},
|
||||
{'Z', {0x7E, 0x02, 0x04, 0x18, 0x20, 0x40, 0x7E, 0x00}},
|
||||
};
|
||||
|
||||
static u8 clks_psf_default_blob[CLKS_PSF1_BLOB_SIZE];
|
||||
static struct clks_psf_font clks_psf_default = {8U, 8U, 0U, 0U, 1U, CLKS_NULL};
|
||||
static clks_bool clks_psf_default_ready = CLKS_FALSE;
|
||||
|
||||
static clks_bool clks_psf_parse_psf1(const u8 *blob, usize blob_size, struct clks_psf_font *out_font) {
|
||||
const struct clks_psf1_header *hdr;
|
||||
u32 glyph_count;
|
||||
u32 glyph_bytes;
|
||||
usize payload_size;
|
||||
|
||||
if (blob == CLKS_NULL || out_font == CLKS_NULL) {
|
||||
return CLKS_FALSE;
|
||||
}
|
||||
|
||||
if (blob_size < CLKS_PSF1_HEADER_SIZE) {
|
||||
return CLKS_FALSE;
|
||||
}
|
||||
|
||||
hdr = (const struct clks_psf1_header *)blob;
|
||||
|
||||
if (hdr->magic[0] != CLKS_PSF1_MAGIC0 || hdr->magic[1] != CLKS_PSF1_MAGIC1) {
|
||||
return CLKS_FALSE;
|
||||
}
|
||||
|
||||
glyph_count = (hdr->mode & 0x01U) != 0U ? 512U : 256U;
|
||||
glyph_bytes = (u32)hdr->charsize;
|
||||
|
||||
if (glyph_bytes == 0U) {
|
||||
return CLKS_FALSE;
|
||||
}
|
||||
|
||||
payload_size = (usize)glyph_count * (usize)glyph_bytes;
|
||||
|
||||
if (blob_size < (usize)CLKS_PSF1_HEADER_SIZE + payload_size) {
|
||||
return CLKS_FALSE;
|
||||
}
|
||||
|
||||
out_font->width = 8U;
|
||||
out_font->height = glyph_bytes;
|
||||
out_font->glyph_count = glyph_count;
|
||||
out_font->bytes_per_glyph = glyph_bytes;
|
||||
out_font->bytes_per_row = 1U;
|
||||
out_font->glyphs = blob + CLKS_PSF1_HEADER_SIZE;
|
||||
return CLKS_TRUE;
|
||||
}
|
||||
|
||||
static clks_bool clks_psf_parse_psf2(const u8 *blob, usize blob_size, struct clks_psf_font *out_font) {
|
||||
const struct clks_psf2_header *hdr;
|
||||
u32 bytes_per_row;
|
||||
usize min_bytes_per_glyph;
|
||||
usize payload_size;
|
||||
|
||||
if (blob == CLKS_NULL || out_font == CLKS_NULL) {
|
||||
return CLKS_FALSE;
|
||||
}
|
||||
|
||||
if (blob_size < CLKS_PSF2_HEADER_MIN_SIZE) {
|
||||
return CLKS_FALSE;
|
||||
}
|
||||
|
||||
hdr = (const struct clks_psf2_header *)blob;
|
||||
|
||||
if (hdr->magic != CLKS_PSF2_MAGIC) {
|
||||
return CLKS_FALSE;
|
||||
}
|
||||
|
||||
if (hdr->headersize < CLKS_PSF2_HEADER_MIN_SIZE || hdr->headersize > blob_size) {
|
||||
return CLKS_FALSE;
|
||||
}
|
||||
|
||||
if (hdr->width == 0U || hdr->height == 0U || hdr->length == 0U || hdr->charsize == 0U) {
|
||||
return CLKS_FALSE;
|
||||
}
|
||||
|
||||
bytes_per_row = (hdr->width + 7U) / 8U;
|
||||
|
||||
if (bytes_per_row == 0U) {
|
||||
return CLKS_FALSE;
|
||||
}
|
||||
|
||||
min_bytes_per_glyph = (usize)bytes_per_row * (usize)hdr->height;
|
||||
|
||||
if (min_bytes_per_glyph > hdr->charsize) {
|
||||
return CLKS_FALSE;
|
||||
}
|
||||
|
||||
if ((usize)hdr->length > (((usize)-1) / (usize)hdr->charsize)) {
|
||||
return CLKS_FALSE;
|
||||
}
|
||||
|
||||
payload_size = (usize)hdr->length * (usize)hdr->charsize;
|
||||
|
||||
if (payload_size > (blob_size - (usize)hdr->headersize)) {
|
||||
return CLKS_FALSE;
|
||||
}
|
||||
|
||||
out_font->width = hdr->width;
|
||||
out_font->height = hdr->height;
|
||||
out_font->glyph_count = hdr->length;
|
||||
out_font->bytes_per_glyph = hdr->charsize;
|
||||
out_font->bytes_per_row = bytes_per_row;
|
||||
out_font->glyphs = blob + hdr->headersize;
|
||||
return CLKS_TRUE;
|
||||
}
|
||||
|
||||
static void clks_psf_seed_default_blob(void) {
|
||||
struct clks_psf1_header *hdr;
|
||||
u32 i;
|
||||
|
||||
clks_memset(clks_psf_default_blob, 0, sizeof(clks_psf_default_blob));
|
||||
|
||||
hdr = (struct clks_psf1_header *)clks_psf_default_blob;
|
||||
hdr->magic[0] = CLKS_PSF1_MAGIC0;
|
||||
hdr->magic[1] = CLKS_PSF1_MAGIC1;
|
||||
hdr->mode = 0x00U;
|
||||
hdr->charsize = (u8)CLKS_PSF1_GLYPH_BYTES;
|
||||
|
||||
for (i = 0U; i < CLKS_PSF1_GLYPH_COUNT; i++) {
|
||||
u8 *dst = clks_psf_default_blob + CLKS_PSF1_HEADER_SIZE + ((usize)i * CLKS_PSF1_GLYPH_BYTES);
|
||||
clks_memcpy(dst, clks_psf_unknown, CLKS_PSF1_GLYPH_BYTES);
|
||||
}
|
||||
|
||||
for (i = 0U; i < (u32)(sizeof(clks_psf_seed_table) / sizeof(clks_psf_seed_table[0])); i++) {
|
||||
const struct clks_psf_seed_glyph *seed = &clks_psf_seed_table[i];
|
||||
u8 *dst = clks_psf_default_blob + CLKS_PSF1_HEADER_SIZE + ((usize)seed->code * CLKS_PSF1_GLYPH_BYTES);
|
||||
clks_memcpy(dst, seed->rows, CLKS_PSF1_GLYPH_BYTES);
|
||||
}
|
||||
|
||||
for (i = (u32)'A'; i <= (u32)'Z'; i++) {
|
||||
const u8 *upper = clks_psf_default_blob + CLKS_PSF1_HEADER_SIZE + ((usize)i * CLKS_PSF1_GLYPH_BYTES);
|
||||
u8 *lower = clks_psf_default_blob + CLKS_PSF1_HEADER_SIZE + ((usize)(i + ('a' - 'A')) * CLKS_PSF1_GLYPH_BYTES);
|
||||
clks_memcpy(lower, upper, CLKS_PSF1_GLYPH_BYTES);
|
||||
}
|
||||
}
|
||||
|
||||
const struct clks_psf_font *clks_psf_default_font(void) {
|
||||
if (clks_psf_default_ready == CLKS_FALSE) {
|
||||
clks_psf_seed_default_blob();
|
||||
|
||||
if (clks_psf_parse_psf1(clks_psf_default_blob, sizeof(clks_psf_default_blob), &clks_psf_default) ==
|
||||
CLKS_FALSE) {
|
||||
clks_psf_default.width = 8U;
|
||||
clks_psf_default.height = 8U;
|
||||
clks_psf_default.glyph_count = 1U;
|
||||
clks_psf_default.bytes_per_glyph = CLKS_PSF1_GLYPH_BYTES;
|
||||
clks_psf_default.bytes_per_row = 1U;
|
||||
clks_psf_default.glyphs = clks_psf_unknown;
|
||||
}
|
||||
|
||||
clks_psf_default_ready = CLKS_TRUE;
|
||||
}
|
||||
|
||||
return &clks_psf_default;
|
||||
}
|
||||
|
||||
const u8 *clks_psf_glyph(const struct clks_psf_font *font, u32 codepoint) {
|
||||
u32 index = codepoint;
|
||||
|
||||
if (font == CLKS_NULL || font->glyphs == CLKS_NULL || font->bytes_per_glyph == 0U) {
|
||||
return clks_psf_unknown;
|
||||
}
|
||||
|
||||
if (index >= font->glyph_count) {
|
||||
index = (u32)'?';
|
||||
|
||||
if (index >= font->glyph_count) {
|
||||
index = 0U;
|
||||
}
|
||||
}
|
||||
|
||||
return font->glyphs + ((usize)index * (usize)font->bytes_per_glyph);
|
||||
}
|
||||
|
||||
clks_bool clks_psf_parse_font(const void *blob, u64 blob_size, struct clks_psf_font *out_font) {
|
||||
const u8 *bytes;
|
||||
u32 magic32;
|
||||
|
||||
if (blob == CLKS_NULL || out_font == CLKS_NULL || blob_size == 0ULL) {
|
||||
return CLKS_FALSE;
|
||||
}
|
||||
|
||||
bytes = (const u8 *)blob;
|
||||
|
||||
if (blob_size >= 4ULL) {
|
||||
magic32 = ((u32)bytes[0]) | (((u32)bytes[1]) << 8U) | (((u32)bytes[2]) << 16U) | (((u32)bytes[3]) << 24U);
|
||||
|
||||
if (magic32 == CLKS_PSF2_MAGIC) {
|
||||
return clks_psf_parse_psf2(bytes, (usize)blob_size, out_font);
|
||||
}
|
||||
}
|
||||
|
||||
return clks_psf_parse_psf1(bytes, (usize)blob_size, out_font);
|
||||
}
|
||||
19
clks.local.bak/kernel/hal/video/psf_font.h
Normal file
19
clks.local.bak/kernel/hal/video/psf_font.h
Normal file
@@ -0,0 +1,19 @@
|
||||
#ifndef CLKS_PSF_FONT_H
|
||||
#define CLKS_PSF_FONT_H
|
||||
|
||||
#include <clks/types.h>
|
||||
|
||||
struct clks_psf_font {
|
||||
u32 width;
|
||||
u32 height;
|
||||
u32 glyph_count;
|
||||
u32 bytes_per_glyph;
|
||||
u32 bytes_per_row;
|
||||
const u8 *glyphs;
|
||||
};
|
||||
|
||||
const struct clks_psf_font *clks_psf_default_font(void);
|
||||
const u8 *clks_psf_glyph(const struct clks_psf_font *font, u32 codepoint);
|
||||
clks_bool clks_psf_parse_font(const void *blob, u64 blob_size, struct clks_psf_font *out_font);
|
||||
|
||||
#endif
|
||||
464
clks.local.bak/kernel/input/keyboard.c
Normal file
464
clks.local.bak/kernel/input/keyboard.c
Normal file
@@ -0,0 +1,464 @@
|
||||
#include <clks/exec.h>
|
||||
#include <clks/keyboard.h>
|
||||
#include <clks/log.h>
|
||||
#include <clks/shell.h>
|
||||
#include <clks/tty.h>
|
||||
#include <clks/types.h>
|
||||
|
||||
#define CLKS_SC_ALT 0x38U
|
||||
#define CLKS_SC_LSHIFT 0x2AU
|
||||
#define CLKS_SC_RSHIFT 0x36U
|
||||
#define CLKS_SC_CTRL 0x1DU
|
||||
#define CLKS_SC_F1 0x3BU
|
||||
#define CLKS_SC_F2 0x3CU
|
||||
#define CLKS_SC_F3 0x3DU
|
||||
#define CLKS_SC_F4 0x3EU
|
||||
#define CLKS_SC_C 0x2EU
|
||||
#define CLKS_SC_EXT_PREFIX 0xE0U
|
||||
|
||||
#define CLKS_SC_EXT_HOME 0x47U
|
||||
#define CLKS_SC_EXT_UP 0x48U
|
||||
#define CLKS_SC_EXT_LEFT 0x4BU
|
||||
#define CLKS_SC_EXT_RIGHT 0x4DU
|
||||
#define CLKS_SC_EXT_END 0x4FU
|
||||
#define CLKS_SC_EXT_DOWN 0x50U
|
||||
#define CLKS_SC_EXT_PAGEUP 0x49U
|
||||
#define CLKS_SC_EXT_PAGEDOWN 0x51U
|
||||
#define CLKS_SC_EXT_DELETE 0x53U
|
||||
|
||||
#define CLKS_KBD_INPUT_CAP 256U
|
||||
#define CLKS_KBD_TTY_MAX 8U
|
||||
#define CLKS_KBD_DROP_LOG_EVERY 64ULL
|
||||
|
||||
#ifndef CLKS_CFG_KBD_TTY_SWITCH_HOTKEY
|
||||
#define CLKS_CFG_KBD_TTY_SWITCH_HOTKEY 1
|
||||
#endif
|
||||
|
||||
#ifndef CLKS_CFG_KBD_CTRL_SHORTCUTS
|
||||
#define CLKS_CFG_KBD_CTRL_SHORTCUTS 1
|
||||
#endif
|
||||
|
||||
#ifndef CLKS_CFG_KBD_FORCE_STOP_HOTKEY
|
||||
#define CLKS_CFG_KBD_FORCE_STOP_HOTKEY 1
|
||||
#endif
|
||||
|
||||
static const char clks_kbd_map[128] = {
|
||||
[2] = '1', [3] = '2', [4] = '3', [5] = '4', [6] = '5', [7] = '6', [8] = '7', [9] = '8', [10] = '9',
|
||||
[11] = '0', [12] = '-', [13] = '=', [14] = '\b', [15] = '\t', [16] = 'q', [17] = 'w', [18] = 'e', [19] = 'r',
|
||||
[20] = 't', [21] = 'y', [22] = 'u', [23] = 'i', [24] = 'o', [25] = 'p', [26] = '[', [27] = ']', [28] = '\n',
|
||||
[30] = 'a', [31] = 's', [32] = 'd', [33] = 'f', [34] = 'g', [35] = 'h', [36] = 'j', [37] = 'k', [38] = 'l',
|
||||
[39] = ';', [40] = '\'', [41] = '`', [43] = '\\', [44] = 'z', [45] = 'x', [46] = 'c', [47] = 'v', [48] = 'b',
|
||||
[49] = 'n', [50] = 'm', [51] = ',', [52] = '.', [53] = '/', [57] = ' '};
|
||||
|
||||
static const char clks_kbd_shift_map[128] = {
|
||||
[2] = '!', [3] = '@', [4] = '#', [5] = '$', [6] = '%', [7] = '^', [8] = '&', [9] = '*', [10] = '(',
|
||||
[11] = ')', [12] = '_', [13] = '+', [14] = '\b', [15] = '\t', [16] = 'Q', [17] = 'W', [18] = 'E', [19] = 'R',
|
||||
[20] = 'T', [21] = 'Y', [22] = 'U', [23] = 'I', [24] = 'O', [25] = 'P', [26] = '{', [27] = '}', [28] = '\n',
|
||||
[30] = 'A', [31] = 'S', [32] = 'D', [33] = 'F', [34] = 'G', [35] = 'H', [36] = 'J', [37] = 'K', [38] = 'L',
|
||||
[39] = ':', [40] = '"', [41] = '~', [43] = '|', [44] = 'Z', [45] = 'X', [46] = 'C', [47] = 'V', [48] = 'B',
|
||||
[49] = 'N', [50] = 'M', [51] = '<', [52] = '>', [53] = '?', [57] = ' '};
|
||||
|
||||
static char clks_kbd_input_queue[CLKS_KBD_TTY_MAX][CLKS_KBD_INPUT_CAP];
|
||||
static u16 clks_kbd_input_head[CLKS_KBD_TTY_MAX];
|
||||
static u16 clks_kbd_input_tail[CLKS_KBD_TTY_MAX];
|
||||
static u16 clks_kbd_input_count[CLKS_KBD_TTY_MAX];
|
||||
|
||||
static clks_bool clks_kbd_alt_down = CLKS_FALSE;
|
||||
static clks_bool clks_kbd_lshift_down = CLKS_FALSE;
|
||||
static clks_bool clks_kbd_rshift_down = CLKS_FALSE;
|
||||
static clks_bool clks_kbd_lctrl_down = CLKS_FALSE;
|
||||
static clks_bool clks_kbd_rctrl_down = CLKS_FALSE;
|
||||
static clks_bool clks_kbd_e0_prefix = CLKS_FALSE;
|
||||
static clks_bool clks_kbd_force_stop_latch = CLKS_FALSE;
|
||||
static u64 clks_kbd_hotkey_switches = 0ULL;
|
||||
|
||||
static u64 clks_kbd_push_count = 0ULL;
|
||||
static u64 clks_kbd_pop_count = 0ULL;
|
||||
static u64 clks_kbd_drop_count = 0ULL;
|
||||
|
||||
static u32 clks_keyboard_effective_tty_count(void) {
|
||||
u32 tty_count = clks_tty_count();
|
||||
|
||||
if (tty_count == 0U) {
|
||||
return 1U;
|
||||
}
|
||||
|
||||
if (tty_count > CLKS_KBD_TTY_MAX) {
|
||||
return CLKS_KBD_TTY_MAX;
|
||||
}
|
||||
|
||||
return tty_count;
|
||||
}
|
||||
|
||||
static u32 clks_keyboard_clamp_tty_index(u32 tty_index) {
|
||||
u32 tty_count = clks_keyboard_effective_tty_count();
|
||||
|
||||
if (tty_index >= tty_count) {
|
||||
return 0U;
|
||||
}
|
||||
|
||||
return tty_index;
|
||||
}
|
||||
|
||||
static clks_bool clks_keyboard_shift_active(void) {
|
||||
return (clks_kbd_lshift_down == CLKS_TRUE || clks_kbd_rshift_down == CLKS_TRUE) ? CLKS_TRUE : CLKS_FALSE;
|
||||
}
|
||||
|
||||
static char clks_keyboard_translate_ext_scancode(u8 code) {
|
||||
clks_bool shift_active = clks_keyboard_shift_active();
|
||||
|
||||
switch (code) {
|
||||
case CLKS_SC_EXT_LEFT:
|
||||
return (shift_active == CLKS_TRUE) ? CLKS_KEY_SHIFT_LEFT : CLKS_KEY_LEFT;
|
||||
case CLKS_SC_EXT_RIGHT:
|
||||
return (shift_active == CLKS_TRUE) ? CLKS_KEY_SHIFT_RIGHT : CLKS_KEY_RIGHT;
|
||||
case CLKS_SC_EXT_UP:
|
||||
return CLKS_KEY_UP;
|
||||
case CLKS_SC_EXT_DOWN:
|
||||
return CLKS_KEY_DOWN;
|
||||
case CLKS_SC_EXT_HOME:
|
||||
return (shift_active == CLKS_TRUE) ? CLKS_KEY_SHIFT_HOME : CLKS_KEY_HOME;
|
||||
case CLKS_SC_EXT_END:
|
||||
return (shift_active == CLKS_TRUE) ? CLKS_KEY_SHIFT_END : CLKS_KEY_END;
|
||||
case CLKS_SC_EXT_DELETE:
|
||||
return CLKS_KEY_DELETE;
|
||||
default:
|
||||
return '\0';
|
||||
}
|
||||
}
|
||||
|
||||
static clks_bool clks_keyboard_queue_push_for_tty(u32 tty_index, char ch) {
|
||||
u32 tty = clks_keyboard_clamp_tty_index(tty_index);
|
||||
|
||||
if (clks_kbd_input_count[tty] >= CLKS_KBD_INPUT_CAP) {
|
||||
clks_kbd_drop_count++;
|
||||
|
||||
if ((clks_kbd_drop_count % CLKS_KBD_DROP_LOG_EVERY) == 1ULL) {
|
||||
clks_log(CLKS_LOG_WARN, "KBD", "INPUT QUEUE OVERFLOW");
|
||||
clks_log_hex(CLKS_LOG_WARN, "KBD", "TTY", (u64)tty);
|
||||
clks_log_hex(CLKS_LOG_WARN, "KBD", "DROPPED", clks_kbd_drop_count);
|
||||
}
|
||||
|
||||
return CLKS_FALSE;
|
||||
}
|
||||
|
||||
clks_kbd_input_queue[tty][clks_kbd_input_head[tty]] = ch;
|
||||
clks_kbd_input_head[tty] = (u16)((clks_kbd_input_head[tty] + 1U) % CLKS_KBD_INPUT_CAP);
|
||||
clks_kbd_input_count[tty]++;
|
||||
clks_kbd_push_count++;
|
||||
return CLKS_TRUE;
|
||||
}
|
||||
|
||||
static clks_bool clks_keyboard_shell_input_enabled(void) {
|
||||
return (clks_tty_active() == 0U) ? CLKS_TRUE : CLKS_FALSE;
|
||||
}
|
||||
|
||||
static clks_bool clks_keyboard_should_pump_shell_now(void) {
|
||||
if (clks_keyboard_shell_input_enabled() == CLKS_FALSE) {
|
||||
return CLKS_FALSE;
|
||||
}
|
||||
|
||||
if (clks_exec_is_running() == CLKS_TRUE) {
|
||||
return CLKS_FALSE;
|
||||
}
|
||||
|
||||
return CLKS_TRUE;
|
||||
}
|
||||
|
||||
static char clks_keyboard_translate_scancode(u8 code) {
|
||||
clks_bool shift_active =
|
||||
(clks_kbd_lshift_down == CLKS_TRUE || clks_kbd_rshift_down == CLKS_TRUE) ? CLKS_TRUE : CLKS_FALSE;
|
||||
|
||||
if (shift_active == CLKS_TRUE) {
|
||||
return clks_kbd_shift_map[code];
|
||||
}
|
||||
|
||||
return clks_kbd_map[code];
|
||||
}
|
||||
|
||||
static clks_bool clks_keyboard_ctrl_active(void) {
|
||||
return (clks_kbd_lctrl_down == CLKS_TRUE || clks_kbd_rctrl_down == CLKS_TRUE) ? CLKS_TRUE : CLKS_FALSE;
|
||||
}
|
||||
|
||||
static clks_bool clks_keyboard_try_emit_ctrl_shortcut(u8 code, u32 tty_index) {
|
||||
char shortcut = '\0';
|
||||
|
||||
if (CLKS_CFG_KBD_CTRL_SHORTCUTS == 0) {
|
||||
return CLKS_FALSE;
|
||||
}
|
||||
|
||||
if (clks_keyboard_ctrl_active() == CLKS_FALSE) {
|
||||
return CLKS_FALSE;
|
||||
}
|
||||
|
||||
switch (code) {
|
||||
case 0x1EU:
|
||||
shortcut = CLKS_KEY_SELECT_ALL;
|
||||
break;
|
||||
case 0x2EU:
|
||||
shortcut = CLKS_KEY_COPY;
|
||||
break;
|
||||
case 0x2FU:
|
||||
shortcut = CLKS_KEY_PASTE;
|
||||
break;
|
||||
default:
|
||||
return CLKS_FALSE;
|
||||
}
|
||||
|
||||
if (clks_keyboard_queue_push_for_tty(tty_index, shortcut) == CLKS_TRUE &&
|
||||
clks_keyboard_should_pump_shell_now() == CLKS_TRUE) {
|
||||
clks_shell_pump_input(1U);
|
||||
}
|
||||
|
||||
return CLKS_TRUE;
|
||||
}
|
||||
|
||||
static clks_bool clks_keyboard_try_force_stop_hotkey(u8 code) {
|
||||
u64 pid = 0ULL;
|
||||
u64 stop_ret;
|
||||
|
||||
if (CLKS_CFG_KBD_FORCE_STOP_HOTKEY == 0) {
|
||||
return CLKS_FALSE;
|
||||
}
|
||||
|
||||
if (code != CLKS_SC_C) {
|
||||
return CLKS_FALSE;
|
||||
}
|
||||
|
||||
if (clks_kbd_alt_down != CLKS_TRUE || clks_keyboard_ctrl_active() == CLKS_FALSE) {
|
||||
return CLKS_FALSE;
|
||||
}
|
||||
|
||||
if (clks_kbd_force_stop_latch == CLKS_TRUE) {
|
||||
return CLKS_TRUE;
|
||||
}
|
||||
|
||||
clks_kbd_force_stop_latch = CLKS_TRUE;
|
||||
stop_ret = clks_exec_force_stop_tty_running_process(clks_tty_active(), &pid);
|
||||
|
||||
if (stop_ret == 1ULL) {
|
||||
clks_log(CLKS_LOG_WARN, "KBD", "HOTKEY CTRL+ALT+C FORCE STOP");
|
||||
clks_log_hex(CLKS_LOG_WARN, "KBD", "PID", pid);
|
||||
} else {
|
||||
clks_log(CLKS_LOG_WARN, "KBD", "HOTKEY CTRL+ALT+C NO RUNNING USER PROC");
|
||||
}
|
||||
|
||||
return CLKS_TRUE;
|
||||
}
|
||||
|
||||
void clks_keyboard_init(void) {
|
||||
u32 tty;
|
||||
|
||||
for (tty = 0U; tty < CLKS_KBD_TTY_MAX; tty++) {
|
||||
clks_kbd_input_head[tty] = 0U;
|
||||
clks_kbd_input_tail[tty] = 0U;
|
||||
clks_kbd_input_count[tty] = 0U;
|
||||
}
|
||||
|
||||
clks_kbd_alt_down = CLKS_FALSE;
|
||||
clks_kbd_lshift_down = CLKS_FALSE;
|
||||
clks_kbd_rshift_down = CLKS_FALSE;
|
||||
clks_kbd_lctrl_down = CLKS_FALSE;
|
||||
clks_kbd_rctrl_down = CLKS_FALSE;
|
||||
clks_kbd_e0_prefix = CLKS_FALSE;
|
||||
clks_kbd_force_stop_latch = CLKS_FALSE;
|
||||
clks_kbd_hotkey_switches = 0ULL;
|
||||
clks_kbd_push_count = 0ULL;
|
||||
clks_kbd_pop_count = 0ULL;
|
||||
clks_kbd_drop_count = 0ULL;
|
||||
|
||||
if (CLKS_CFG_KBD_TTY_SWITCH_HOTKEY != 0) {
|
||||
clks_log(CLKS_LOG_INFO, "KBD", "ALT+F1..F4 TTY HOTKEY ONLINE");
|
||||
} else {
|
||||
clks_log(CLKS_LOG_WARN, "KBD", "TTY SWITCH HOTKEY DISABLED BY MENUCONFIG");
|
||||
}
|
||||
|
||||
if (CLKS_CFG_KBD_CTRL_SHORTCUTS == 0) {
|
||||
clks_log(CLKS_LOG_WARN, "KBD", "CTRL SHORTCUTS DISABLED BY MENUCONFIG");
|
||||
}
|
||||
|
||||
if (CLKS_CFG_KBD_FORCE_STOP_HOTKEY == 0) {
|
||||
clks_log(CLKS_LOG_WARN, "KBD", "CTRL+ALT+C FORCE STOP DISABLED BY MENUCONFIG");
|
||||
}
|
||||
|
||||
clks_log(CLKS_LOG_INFO, "KBD", "PS2 INPUT QUEUE ONLINE");
|
||||
clks_log_hex(CLKS_LOG_INFO, "KBD", "QUEUE_CAP", CLKS_KBD_INPUT_CAP);
|
||||
}
|
||||
|
||||
void clks_keyboard_handle_scancode(u8 scancode) {
|
||||
clks_bool released;
|
||||
u8 code;
|
||||
|
||||
if (scancode == CLKS_SC_EXT_PREFIX) {
|
||||
clks_kbd_e0_prefix = CLKS_TRUE;
|
||||
return;
|
||||
}
|
||||
|
||||
released = ((scancode & 0x80U) != 0U) ? CLKS_TRUE : CLKS_FALSE;
|
||||
code = (u8)(scancode & 0x7FU);
|
||||
|
||||
if (code == CLKS_SC_CTRL) {
|
||||
if (clks_kbd_e0_prefix == CLKS_TRUE) {
|
||||
clks_kbd_rctrl_down = (released == CLKS_FALSE) ? CLKS_TRUE : CLKS_FALSE;
|
||||
if (released == CLKS_TRUE) {
|
||||
clks_kbd_force_stop_latch = CLKS_FALSE;
|
||||
}
|
||||
clks_kbd_e0_prefix = CLKS_FALSE;
|
||||
return;
|
||||
}
|
||||
|
||||
clks_kbd_lctrl_down = (released == CLKS_FALSE) ? CLKS_TRUE : CLKS_FALSE;
|
||||
if (released == CLKS_TRUE) {
|
||||
clks_kbd_force_stop_latch = CLKS_FALSE;
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
if (code == CLKS_SC_ALT) {
|
||||
clks_kbd_alt_down = (released == CLKS_FALSE) ? CLKS_TRUE : CLKS_FALSE;
|
||||
if (released == CLKS_TRUE) {
|
||||
clks_kbd_force_stop_latch = CLKS_FALSE;
|
||||
}
|
||||
|
||||
if (clks_kbd_e0_prefix == CLKS_TRUE) {
|
||||
clks_kbd_e0_prefix = CLKS_FALSE;
|
||||
}
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
if (code == CLKS_SC_LSHIFT) {
|
||||
clks_kbd_lshift_down = (released == CLKS_FALSE) ? CLKS_TRUE : CLKS_FALSE;
|
||||
return;
|
||||
}
|
||||
|
||||
if (code == CLKS_SC_RSHIFT) {
|
||||
clks_kbd_rshift_down = (released == CLKS_FALSE) ? CLKS_TRUE : CLKS_FALSE;
|
||||
return;
|
||||
}
|
||||
|
||||
if (released == CLKS_TRUE) {
|
||||
if (code == CLKS_SC_C) {
|
||||
clks_kbd_force_stop_latch = CLKS_FALSE;
|
||||
}
|
||||
|
||||
if (clks_kbd_e0_prefix == CLKS_TRUE) {
|
||||
clks_kbd_e0_prefix = CLKS_FALSE;
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
if (clks_kbd_e0_prefix == CLKS_TRUE) {
|
||||
char ext;
|
||||
u32 active_tty = clks_tty_active();
|
||||
|
||||
clks_kbd_e0_prefix = CLKS_FALSE;
|
||||
|
||||
if (code == CLKS_SC_EXT_PAGEUP) {
|
||||
clks_tty_scrollback_page_up();
|
||||
return;
|
||||
}
|
||||
|
||||
if (code == CLKS_SC_EXT_PAGEDOWN) {
|
||||
clks_tty_scrollback_page_down();
|
||||
return;
|
||||
}
|
||||
|
||||
ext = clks_keyboard_translate_ext_scancode(code);
|
||||
|
||||
if (ext != '\0') {
|
||||
if (clks_keyboard_queue_push_for_tty(active_tty, ext) == CLKS_TRUE &&
|
||||
clks_keyboard_should_pump_shell_now() == CLKS_TRUE) {
|
||||
clks_shell_pump_input(1U);
|
||||
}
|
||||
}
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
if (CLKS_CFG_KBD_TTY_SWITCH_HOTKEY != 0 && clks_kbd_alt_down == CLKS_TRUE && code >= CLKS_SC_F1 &&
|
||||
code <= CLKS_SC_F4) {
|
||||
u32 target = (u32)(code - CLKS_SC_F1);
|
||||
u32 before = clks_tty_active();
|
||||
u32 after;
|
||||
|
||||
clks_tty_switch(target);
|
||||
after = clks_tty_active();
|
||||
|
||||
if (after != before) {
|
||||
clks_kbd_hotkey_switches++;
|
||||
clks_log(CLKS_LOG_INFO, "TTY", "HOTKEY SWITCH");
|
||||
clks_log_hex(CLKS_LOG_INFO, "TTY", "ACTIVE", (u64)after);
|
||||
clks_log_hex(CLKS_LOG_INFO, "TTY", "HOTKEY_SWITCHES", clks_kbd_hotkey_switches);
|
||||
}
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
{
|
||||
u32 active_tty = clks_tty_active();
|
||||
char translated;
|
||||
|
||||
if (clks_keyboard_try_force_stop_hotkey(code) == CLKS_TRUE) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (clks_keyboard_try_emit_ctrl_shortcut(code, active_tty) == CLKS_TRUE) {
|
||||
return;
|
||||
}
|
||||
|
||||
translated = clks_keyboard_translate_scancode(code);
|
||||
|
||||
if (translated != '\0') {
|
||||
if (clks_keyboard_queue_push_for_tty(active_tty, translated) == CLKS_TRUE &&
|
||||
clks_keyboard_should_pump_shell_now() == CLKS_TRUE) {
|
||||
clks_shell_pump_input(1U);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
u64 clks_keyboard_hotkey_switch_count(void) {
|
||||
return clks_kbd_hotkey_switches;
|
||||
}
|
||||
|
||||
clks_bool clks_keyboard_pop_char_for_tty(u32 tty_index, char *out_ch) {
|
||||
u32 tty = clks_keyboard_clamp_tty_index(tty_index);
|
||||
|
||||
if (out_ch == CLKS_NULL || clks_kbd_input_count[tty] == 0U) {
|
||||
return CLKS_FALSE;
|
||||
}
|
||||
|
||||
*out_ch = clks_kbd_input_queue[tty][clks_kbd_input_tail[tty]];
|
||||
clks_kbd_input_tail[tty] = (u16)((clks_kbd_input_tail[tty] + 1U) % CLKS_KBD_INPUT_CAP);
|
||||
clks_kbd_input_count[tty]--;
|
||||
clks_kbd_pop_count++;
|
||||
return CLKS_TRUE;
|
||||
}
|
||||
|
||||
clks_bool clks_keyboard_pop_char(char *out_ch) {
|
||||
return clks_keyboard_pop_char_for_tty(clks_tty_active(), out_ch);
|
||||
}
|
||||
|
||||
u64 clks_keyboard_buffered_count(void) {
|
||||
u64 total = 0ULL;
|
||||
u32 tty;
|
||||
|
||||
for (tty = 0U; tty < CLKS_KBD_TTY_MAX; tty++) {
|
||||
total += (u64)clks_kbd_input_count[tty];
|
||||
}
|
||||
|
||||
return total;
|
||||
}
|
||||
|
||||
u64 clks_keyboard_drop_count(void) {
|
||||
return clks_kbd_drop_count;
|
||||
}
|
||||
|
||||
u64 clks_keyboard_push_count(void) {
|
||||
return clks_kbd_push_count;
|
||||
}
|
||||
|
||||
u64 clks_keyboard_pop_count(void) {
|
||||
return clks_kbd_pop_count;
|
||||
}
|
||||
305
clks.local.bak/kernel/input/mouse.c
Normal file
305
clks.local.bak/kernel/input/mouse.c
Normal file
@@ -0,0 +1,305 @@
|
||||
#include <clks/framebuffer.h>
|
||||
#include <clks/log.h>
|
||||
#include <clks/mouse.h>
|
||||
#include <clks/types.h>
|
||||
|
||||
#define CLKS_PS2_DATA_PORT 0x60U
|
||||
#define CLKS_PS2_STATUS_PORT 0x64U
|
||||
#define CLKS_PS2_CMD_PORT 0x64U
|
||||
#define CLKS_PS2_STATUS_OBF 0x01U
|
||||
#define CLKS_PS2_STATUS_IBF 0x02U
|
||||
|
||||
#define CLKS_PS2_CMD_ENABLE_AUX 0xA8U
|
||||
#define CLKS_PS2_CMD_READ_CFG 0x20U
|
||||
#define CLKS_PS2_CMD_WRITE_CFG 0x60U
|
||||
#define CLKS_PS2_CMD_WRITE_AUX 0xD4U
|
||||
|
||||
#define CLKS_PS2_MOUSE_CMD_RESET_DEFAULTS 0xF6U
|
||||
#define CLKS_PS2_MOUSE_CMD_ENABLE_STREAM 0xF4U
|
||||
#define CLKS_PS2_MOUSE_ACK 0xFAU
|
||||
|
||||
#define CLKS_MOUSE_IO_TIMEOUT 100000U
|
||||
#define CLKS_MOUSE_DRAIN_MAX 64U
|
||||
#define CLKS_MOUSE_SYNC_BIT 0x08U
|
||||
#define CLKS_MOUSE_OVERFLOW_MASK 0xC0U
|
||||
#define CLKS_MOUSE_BUTTON_MASK 0x07U
|
||||
|
||||
struct clks_mouse_runtime {
|
||||
i32 x;
|
||||
i32 y;
|
||||
u32 max_x;
|
||||
u32 max_y;
|
||||
u8 buttons;
|
||||
u8 packet[3];
|
||||
u8 packet_index;
|
||||
u64 packet_count;
|
||||
u64 drop_count;
|
||||
clks_bool ready;
|
||||
};
|
||||
|
||||
static struct clks_mouse_runtime clks_mouse = {
|
||||
.x = 0,
|
||||
.y = 0,
|
||||
.max_x = 0U,
|
||||
.max_y = 0U,
|
||||
.buttons = 0U,
|
||||
.packet = {0U, 0U, 0U},
|
||||
.packet_index = 0U,
|
||||
.packet_count = 0ULL,
|
||||
.drop_count = 0ULL,
|
||||
.ready = CLKS_FALSE,
|
||||
};
|
||||
|
||||
static inline void clks_mouse_outb(u16 port, u8 value) {
|
||||
__asm__ volatile("outb %0, %1" : : "a"(value), "Nd"(port));
|
||||
}
|
||||
|
||||
static inline u8 clks_mouse_inb(u16 port) {
|
||||
u8 value;
|
||||
__asm__ volatile("inb %1, %0" : "=a"(value) : "Nd"(port));
|
||||
return value;
|
||||
}
|
||||
|
||||
static clks_bool clks_mouse_wait_input_empty(void) {
|
||||
u32 i;
|
||||
|
||||
for (i = 0U; i < CLKS_MOUSE_IO_TIMEOUT; i++) {
|
||||
if ((clks_mouse_inb(CLKS_PS2_STATUS_PORT) & CLKS_PS2_STATUS_IBF) == 0U) {
|
||||
return CLKS_TRUE;
|
||||
}
|
||||
}
|
||||
|
||||
return CLKS_FALSE;
|
||||
}
|
||||
|
||||
static clks_bool clks_mouse_wait_output_ready(void) {
|
||||
u32 i;
|
||||
|
||||
for (i = 0U; i < CLKS_MOUSE_IO_TIMEOUT; i++) {
|
||||
if ((clks_mouse_inb(CLKS_PS2_STATUS_PORT) & CLKS_PS2_STATUS_OBF) != 0U) {
|
||||
return CLKS_TRUE;
|
||||
}
|
||||
}
|
||||
|
||||
return CLKS_FALSE;
|
||||
}
|
||||
|
||||
static clks_bool clks_mouse_write_cmd(u8 cmd) {
|
||||
if (clks_mouse_wait_input_empty() == CLKS_FALSE) {
|
||||
return CLKS_FALSE;
|
||||
}
|
||||
|
||||
clks_mouse_outb(CLKS_PS2_CMD_PORT, cmd);
|
||||
return CLKS_TRUE;
|
||||
}
|
||||
|
||||
static clks_bool clks_mouse_write_data(u8 value) {
|
||||
if (clks_mouse_wait_input_empty() == CLKS_FALSE) {
|
||||
return CLKS_FALSE;
|
||||
}
|
||||
|
||||
clks_mouse_outb(CLKS_PS2_DATA_PORT, value);
|
||||
return CLKS_TRUE;
|
||||
}
|
||||
|
||||
static clks_bool clks_mouse_read_data(u8 *out_value) {
|
||||
if (out_value == CLKS_NULL) {
|
||||
return CLKS_FALSE;
|
||||
}
|
||||
|
||||
if (clks_mouse_wait_output_ready() == CLKS_FALSE) {
|
||||
return CLKS_FALSE;
|
||||
}
|
||||
|
||||
*out_value = clks_mouse_inb(CLKS_PS2_DATA_PORT);
|
||||
return CLKS_TRUE;
|
||||
}
|
||||
|
||||
static void clks_mouse_drain_output(void) {
|
||||
u32 i;
|
||||
|
||||
for (i = 0U; i < CLKS_MOUSE_DRAIN_MAX; i++) {
|
||||
if ((clks_mouse_inb(CLKS_PS2_STATUS_PORT) & CLKS_PS2_STATUS_OBF) == 0U) {
|
||||
break;
|
||||
}
|
||||
|
||||
(void)clks_mouse_inb(CLKS_PS2_DATA_PORT);
|
||||
}
|
||||
}
|
||||
|
||||
static clks_bool clks_mouse_send_device_cmd(u8 cmd, u8 *out_ack) {
|
||||
u8 ack = 0U;
|
||||
|
||||
if (clks_mouse_write_cmd(CLKS_PS2_CMD_WRITE_AUX) == CLKS_FALSE) {
|
||||
return CLKS_FALSE;
|
||||
}
|
||||
|
||||
if (clks_mouse_write_data(cmd) == CLKS_FALSE) {
|
||||
return CLKS_FALSE;
|
||||
}
|
||||
|
||||
if (clks_mouse_read_data(&ack) == CLKS_FALSE) {
|
||||
return CLKS_FALSE;
|
||||
}
|
||||
|
||||
if (out_ack != CLKS_NULL) {
|
||||
*out_ack = ack;
|
||||
}
|
||||
|
||||
return CLKS_TRUE;
|
||||
}
|
||||
|
||||
static void clks_mouse_reset_runtime(void) {
|
||||
struct clks_framebuffer_info info;
|
||||
|
||||
clks_mouse.x = 0;
|
||||
clks_mouse.y = 0;
|
||||
clks_mouse.max_x = 0U;
|
||||
clks_mouse.max_y = 0U;
|
||||
clks_mouse.buttons = 0U;
|
||||
clks_mouse.packet[0] = 0U;
|
||||
clks_mouse.packet[1] = 0U;
|
||||
clks_mouse.packet[2] = 0U;
|
||||
clks_mouse.packet_index = 0U;
|
||||
clks_mouse.packet_count = 0ULL;
|
||||
clks_mouse.drop_count = 0ULL;
|
||||
clks_mouse.ready = CLKS_FALSE;
|
||||
|
||||
if (clks_fb_ready() == CLKS_TRUE) {
|
||||
info = clks_fb_info();
|
||||
|
||||
if (info.width > 0U) {
|
||||
clks_mouse.max_x = info.width - 1U;
|
||||
}
|
||||
|
||||
if (info.height > 0U) {
|
||||
clks_mouse.max_y = info.height - 1U;
|
||||
}
|
||||
|
||||
clks_mouse.x = (i32)(clks_mouse.max_x / 2U);
|
||||
clks_mouse.y = (i32)(clks_mouse.max_y / 2U);
|
||||
}
|
||||
}
|
||||
|
||||
void clks_mouse_init(void) {
|
||||
u8 config = 0U;
|
||||
u8 ack = 0U;
|
||||
|
||||
clks_mouse_reset_runtime();
|
||||
clks_mouse_drain_output();
|
||||
|
||||
if (clks_mouse_write_cmd(CLKS_PS2_CMD_ENABLE_AUX) == CLKS_FALSE) {
|
||||
clks_log(CLKS_LOG_WARN, "MOUSE", "PS2 ENABLE AUX FAILED");
|
||||
return;
|
||||
}
|
||||
|
||||
if (clks_mouse_write_cmd(CLKS_PS2_CMD_READ_CFG) == CLKS_FALSE || clks_mouse_read_data(&config) == CLKS_FALSE) {
|
||||
clks_log(CLKS_LOG_WARN, "MOUSE", "PS2 READ CFG FAILED");
|
||||
return;
|
||||
}
|
||||
|
||||
config |= 0x02U;
|
||||
config &= (u8)~0x20U;
|
||||
|
||||
if (clks_mouse_write_cmd(CLKS_PS2_CMD_WRITE_CFG) == CLKS_FALSE || clks_mouse_write_data(config) == CLKS_FALSE) {
|
||||
clks_log(CLKS_LOG_WARN, "MOUSE", "PS2 WRITE CFG FAILED");
|
||||
return;
|
||||
}
|
||||
|
||||
if (clks_mouse_send_device_cmd(CLKS_PS2_MOUSE_CMD_RESET_DEFAULTS, &ack) == CLKS_FALSE ||
|
||||
ack != CLKS_PS2_MOUSE_ACK) {
|
||||
clks_log(CLKS_LOG_WARN, "MOUSE", "PS2 RESET DEFAULTS FAILED");
|
||||
return;
|
||||
}
|
||||
|
||||
if (clks_mouse_send_device_cmd(CLKS_PS2_MOUSE_CMD_ENABLE_STREAM, &ack) == CLKS_FALSE || ack != CLKS_PS2_MOUSE_ACK) {
|
||||
clks_log(CLKS_LOG_WARN, "MOUSE", "PS2 ENABLE STREAM FAILED");
|
||||
return;
|
||||
}
|
||||
|
||||
clks_mouse.ready = CLKS_TRUE;
|
||||
clks_log(CLKS_LOG_INFO, "MOUSE", "PS2 POINTER ONLINE");
|
||||
clks_log_hex(CLKS_LOG_INFO, "MOUSE", "MAX_X", (u64)clks_mouse.max_x);
|
||||
clks_log_hex(CLKS_LOG_INFO, "MOUSE", "MAX_Y", (u64)clks_mouse.max_y);
|
||||
}
|
||||
|
||||
void clks_mouse_handle_byte(u8 data_byte) {
|
||||
i32 dx;
|
||||
i32 dy;
|
||||
i32 next_x;
|
||||
i32 next_y;
|
||||
u8 status;
|
||||
|
||||
if (clks_mouse.ready == CLKS_FALSE) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (clks_mouse.packet_index == 0U && (data_byte & CLKS_MOUSE_SYNC_BIT) == 0U) {
|
||||
clks_mouse.drop_count++;
|
||||
return;
|
||||
}
|
||||
|
||||
clks_mouse.packet[clks_mouse.packet_index] = data_byte;
|
||||
clks_mouse.packet_index++;
|
||||
|
||||
if (clks_mouse.packet_index < 3U) {
|
||||
return;
|
||||
}
|
||||
|
||||
clks_mouse.packet_index = 0U;
|
||||
clks_mouse.packet_count++;
|
||||
|
||||
status = clks_mouse.packet[0];
|
||||
clks_mouse.buttons = (u8)(status & CLKS_MOUSE_BUTTON_MASK);
|
||||
|
||||
if ((status & CLKS_MOUSE_OVERFLOW_MASK) != 0U) {
|
||||
clks_mouse.drop_count++;
|
||||
return;
|
||||
}
|
||||
|
||||
dx = (i32)((i8)clks_mouse.packet[1]);
|
||||
dy = (i32)((i8)clks_mouse.packet[2]);
|
||||
|
||||
next_x = clks_mouse.x + dx;
|
||||
next_y = clks_mouse.y - dy;
|
||||
|
||||
if (next_x < 0) {
|
||||
clks_mouse.x = 0;
|
||||
} else if ((u32)next_x > clks_mouse.max_x) {
|
||||
clks_mouse.x = (i32)clks_mouse.max_x;
|
||||
} else {
|
||||
clks_mouse.x = next_x;
|
||||
}
|
||||
|
||||
if (next_y < 0) {
|
||||
clks_mouse.y = 0;
|
||||
} else if ((u32)next_y > clks_mouse.max_y) {
|
||||
clks_mouse.y = (i32)clks_mouse.max_y;
|
||||
} else {
|
||||
clks_mouse.y = next_y;
|
||||
}
|
||||
}
|
||||
|
||||
void clks_mouse_snapshot(struct clks_mouse_state *out_state) {
|
||||
if (out_state == CLKS_NULL) {
|
||||
return;
|
||||
}
|
||||
|
||||
out_state->x = clks_mouse.x;
|
||||
out_state->y = clks_mouse.y;
|
||||
out_state->buttons = clks_mouse.buttons;
|
||||
out_state->packet_count = clks_mouse.packet_count;
|
||||
out_state->ready = clks_mouse.ready;
|
||||
}
|
||||
|
||||
clks_bool clks_mouse_ready(void) {
|
||||
return clks_mouse.ready;
|
||||
}
|
||||
|
||||
u64 clks_mouse_packet_count(void) {
|
||||
return clks_mouse.packet_count;
|
||||
}
|
||||
|
||||
u64 clks_mouse_drop_count(void) {
|
||||
return clks_mouse.drop_count;
|
||||
}
|
||||
406
clks.local.bak/kernel/interface/desktop.c
Normal file
406
clks.local.bak/kernel/interface/desktop.c
Normal file
@@ -0,0 +1,406 @@
|
||||
#include <clks/desktop.h>
|
||||
#include <clks/framebuffer.h>
|
||||
#include <clks/log.h>
|
||||
#include <clks/mouse.h>
|
||||
#include <clks/tty.h>
|
||||
#include <clks/types.h>
|
||||
|
||||
#define CLKS_DESKTOP_TTY_INDEX 1U
|
||||
|
||||
#define CLKS_DESKTOP_BG_COLOR 0x001B2430U
|
||||
#define CLKS_DESKTOP_TOPBAR_COLOR 0x00293447U
|
||||
#define CLKS_DESKTOP_DOCK_COLOR 0x00232C3AU
|
||||
#define CLKS_DESKTOP_WINDOW_COLOR 0x00313E52U
|
||||
#define CLKS_DESKTOP_TITLE_COLOR 0x003B4A61U
|
||||
#define CLKS_DESKTOP_TEXT_FG 0x00E6EDF7U
|
||||
#define CLKS_DESKTOP_TEXT_BG 0x003B4A61U
|
||||
|
||||
#define CLKS_DESKTOP_CURSOR_FILL 0x00F5F8FFU
|
||||
#define CLKS_DESKTOP_CURSOR_OUTLINE 0x00101010U
|
||||
#define CLKS_DESKTOP_CURSOR_ACTIVE 0x00FFCE6EU
|
||||
#define CLKS_DESKTOP_CURSOR_W 16U
|
||||
#define CLKS_DESKTOP_CURSOR_H 16U
|
||||
|
||||
struct clks_desktop_layout {
|
||||
u32 width;
|
||||
u32 height;
|
||||
u32 topbar_h;
|
||||
u32 dock_w;
|
||||
u32 win_x;
|
||||
u32 win_y;
|
||||
u32 win_w;
|
||||
u32 win_h;
|
||||
u32 win_title_h;
|
||||
};
|
||||
|
||||
static struct clks_desktop_layout clks_desktop = {
|
||||
.width = 0U,
|
||||
.height = 0U,
|
||||
.topbar_h = 32U,
|
||||
.dock_w = 72U,
|
||||
.win_x = 0U,
|
||||
.win_y = 0U,
|
||||
.win_w = 0U,
|
||||
.win_h = 0U,
|
||||
.win_title_h = 28U,
|
||||
};
|
||||
|
||||
static clks_bool clks_desktop_ready_flag = CLKS_FALSE;
|
||||
static clks_bool clks_desktop_active_last = CLKS_FALSE;
|
||||
static clks_bool clks_desktop_scene_drawn = CLKS_FALSE;
|
||||
static clks_bool clks_desktop_cursor_drawn = CLKS_FALSE;
|
||||
static i32 clks_desktop_last_mouse_x = -1;
|
||||
static i32 clks_desktop_last_mouse_y = -1;
|
||||
static u8 clks_desktop_last_buttons = 0U;
|
||||
static clks_bool clks_desktop_last_ready = CLKS_FALSE;
|
||||
static u32 clks_desktop_cursor_under[CLKS_DESKTOP_CURSOR_W * CLKS_DESKTOP_CURSOR_H];
|
||||
|
||||
static void clks_desktop_draw_text(u32 x, u32 y, const char *text, u32 fg, u32 bg) {
|
||||
u32 step;
|
||||
usize i = 0U;
|
||||
|
||||
if (text == CLKS_NULL) {
|
||||
return;
|
||||
}
|
||||
|
||||
step = clks_fb_cell_width();
|
||||
|
||||
if (step == 0U) {
|
||||
step = 8U;
|
||||
}
|
||||
|
||||
while (text[i] != '\0') {
|
||||
clks_fb_draw_char(x + ((u32)i * step), y, text[i], fg, bg);
|
||||
i++;
|
||||
}
|
||||
}
|
||||
|
||||
static clks_bool clks_desktop_in_bounds(i32 x, i32 y) {
|
||||
if (x < 0 || y < 0) {
|
||||
return CLKS_FALSE;
|
||||
}
|
||||
|
||||
if ((u32)x >= clks_desktop.width || (u32)y >= clks_desktop.height) {
|
||||
return CLKS_FALSE;
|
||||
}
|
||||
|
||||
return CLKS_TRUE;
|
||||
}
|
||||
|
||||
static void clks_desktop_compute_layout(void) {
|
||||
struct clks_framebuffer_info info = clks_fb_info();
|
||||
u32 right_margin;
|
||||
u32 bottom_margin;
|
||||
|
||||
clks_desktop.width = info.width;
|
||||
clks_desktop.height = info.height;
|
||||
|
||||
if (clks_desktop.topbar_h >= clks_desktop.height) {
|
||||
clks_desktop.topbar_h = clks_desktop.height;
|
||||
}
|
||||
|
||||
if (clks_desktop.dock_w >= clks_desktop.width) {
|
||||
clks_desktop.dock_w = clks_desktop.width;
|
||||
}
|
||||
|
||||
clks_desktop.win_x = clks_desktop.width / 6U;
|
||||
clks_desktop.win_y = clks_desktop.height / 6U;
|
||||
|
||||
if (clks_desktop.win_x < 96U) {
|
||||
clks_desktop.win_x = 96U;
|
||||
}
|
||||
|
||||
if (clks_desktop.win_y < 72U) {
|
||||
clks_desktop.win_y = 72U;
|
||||
}
|
||||
|
||||
if (clks_desktop.win_x >= clks_desktop.width) {
|
||||
clks_desktop.win_x = clks_desktop.width > 0U ? (clks_desktop.width - 1U) : 0U;
|
||||
}
|
||||
|
||||
if (clks_desktop.win_y >= clks_desktop.height) {
|
||||
clks_desktop.win_y = clks_desktop.height > 0U ? (clks_desktop.height - 1U) : 0U;
|
||||
}
|
||||
|
||||
right_margin = clks_desktop.width / 10U;
|
||||
bottom_margin = clks_desktop.height / 8U;
|
||||
|
||||
if (right_margin < 48U) {
|
||||
right_margin = 48U;
|
||||
}
|
||||
|
||||
if (bottom_margin < 48U) {
|
||||
bottom_margin = 48U;
|
||||
}
|
||||
|
||||
if (clks_desktop.width > clks_desktop.win_x + right_margin) {
|
||||
clks_desktop.win_w = clks_desktop.width - clks_desktop.win_x - right_margin;
|
||||
} else {
|
||||
clks_desktop.win_w = clks_desktop.width - clks_desktop.win_x;
|
||||
}
|
||||
|
||||
if (clks_desktop.height > clks_desktop.win_y + bottom_margin) {
|
||||
clks_desktop.win_h = clks_desktop.height - clks_desktop.win_y - bottom_margin;
|
||||
} else {
|
||||
clks_desktop.win_h = clks_desktop.height - clks_desktop.win_y;
|
||||
}
|
||||
|
||||
if (clks_desktop.win_w < 220U) {
|
||||
clks_desktop.win_w = (clks_desktop.width > (clks_desktop.win_x + 20U))
|
||||
? (clks_desktop.width - clks_desktop.win_x - 20U)
|
||||
: (clks_desktop.width - clks_desktop.win_x);
|
||||
}
|
||||
|
||||
if (clks_desktop.win_h < 140U) {
|
||||
clks_desktop.win_h = (clks_desktop.height > (clks_desktop.win_y + 20U))
|
||||
? (clks_desktop.height - clks_desktop.win_y - 20U)
|
||||
: (clks_desktop.height - clks_desktop.win_y);
|
||||
}
|
||||
|
||||
if (clks_desktop.win_w > (clks_desktop.width - clks_desktop.win_x)) {
|
||||
clks_desktop.win_w = clks_desktop.width - clks_desktop.win_x;
|
||||
}
|
||||
|
||||
if (clks_desktop.win_h > (clks_desktop.height - clks_desktop.win_y)) {
|
||||
clks_desktop.win_h = clks_desktop.height - clks_desktop.win_y;
|
||||
}
|
||||
|
||||
if (clks_desktop.win_title_h >= clks_desktop.win_h) {
|
||||
clks_desktop.win_title_h = clks_desktop.win_h;
|
||||
}
|
||||
}
|
||||
|
||||
static void clks_desktop_draw_status_widgets(const struct clks_mouse_state *mouse) {
|
||||
u32 ready_x = 0U;
|
||||
u32 left_x = 0U;
|
||||
|
||||
if (mouse == CLKS_NULL) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (clks_desktop.width > 28U) {
|
||||
ready_x = clks_desktop.width - 28U;
|
||||
}
|
||||
|
||||
if (clks_desktop.width > 46U) {
|
||||
left_x = clks_desktop.width - 46U;
|
||||
}
|
||||
|
||||
if (mouse->ready == CLKS_TRUE) {
|
||||
clks_fb_fill_rect(ready_x, 10U, 10U, 10U, 0x006FE18BU);
|
||||
} else {
|
||||
clks_fb_fill_rect(ready_x, 10U, 10U, 10U, 0x00E06A6AU);
|
||||
}
|
||||
|
||||
if ((mouse->buttons & CLKS_MOUSE_BTN_LEFT) != 0U) {
|
||||
clks_fb_fill_rect(left_x, 10U, 10U, 10U, 0x00FFCE6EU);
|
||||
} else {
|
||||
clks_fb_fill_rect(left_x, 10U, 10U, 10U, 0x004A5568U);
|
||||
}
|
||||
}
|
||||
|
||||
static void clks_desktop_draw_static_scene(const struct clks_mouse_state *mouse) {
|
||||
clks_fb_clear(CLKS_DESKTOP_BG_COLOR);
|
||||
|
||||
if (clks_desktop.topbar_h > 0U) {
|
||||
clks_fb_fill_rect(0U, 0U, clks_desktop.width, clks_desktop.topbar_h, CLKS_DESKTOP_TOPBAR_COLOR);
|
||||
}
|
||||
|
||||
if (clks_desktop.height > clks_desktop.topbar_h) {
|
||||
clks_fb_fill_rect(0U, clks_desktop.topbar_h, clks_desktop.dock_w, clks_desktop.height - clks_desktop.topbar_h,
|
||||
CLKS_DESKTOP_DOCK_COLOR);
|
||||
}
|
||||
|
||||
clks_fb_fill_rect(clks_desktop.win_x, clks_desktop.win_y, clks_desktop.win_w, clks_desktop.win_h,
|
||||
CLKS_DESKTOP_WINDOW_COLOR);
|
||||
clks_fb_fill_rect(clks_desktop.win_x, clks_desktop.win_y, clks_desktop.win_w, clks_desktop.win_title_h,
|
||||
CLKS_DESKTOP_TITLE_COLOR);
|
||||
|
||||
clks_desktop_draw_text(12U, 6U, "CLeonOS Desktop TTY2", CLKS_DESKTOP_TEXT_FG, CLKS_DESKTOP_TOPBAR_COLOR);
|
||||
clks_desktop_draw_text(clks_desktop.win_x + 12U, clks_desktop.win_y + 6U, "Mouse Input Ready", CLKS_DESKTOP_TEXT_FG,
|
||||
CLKS_DESKTOP_TITLE_COLOR);
|
||||
clks_desktop_draw_text(clks_desktop.win_x + 16U, clks_desktop.win_y + clks_desktop.win_title_h + 16U,
|
||||
"Stage25: Alt+F2 desktop, Alt+F1 shell", CLKS_DESKTOP_TEXT_FG, CLKS_DESKTOP_WINDOW_COLOR);
|
||||
|
||||
clks_desktop_draw_status_widgets(mouse);
|
||||
clks_desktop_scene_drawn = CLKS_TRUE;
|
||||
}
|
||||
|
||||
static clks_bool clks_desktop_cursor_pixel(u32 lx, u32 ly, u8 buttons, u32 *out_color) {
|
||||
u32 fill = CLKS_DESKTOP_CURSOR_FILL;
|
||||
|
||||
if (out_color == CLKS_NULL) {
|
||||
return CLKS_FALSE;
|
||||
}
|
||||
|
||||
if ((buttons & CLKS_MOUSE_BTN_LEFT) != 0U) {
|
||||
fill = CLKS_DESKTOP_CURSOR_ACTIVE;
|
||||
}
|
||||
|
||||
if (ly < 12U) {
|
||||
u32 span = (ly / 2U) + 1U;
|
||||
|
||||
if (lx < span) {
|
||||
clks_bool border = (lx == 0U || (lx + 1U) == span || ly == 11U) ? CLKS_TRUE : CLKS_FALSE;
|
||||
*out_color = (border == CLKS_TRUE) ? CLKS_DESKTOP_CURSOR_OUTLINE : fill;
|
||||
return CLKS_TRUE;
|
||||
}
|
||||
}
|
||||
|
||||
if (ly >= 8U && ly < 16U && lx >= 2U && lx < 5U) {
|
||||
clks_bool border = (lx == 2U || lx == 4U || ly == 15U) ? CLKS_TRUE : CLKS_FALSE;
|
||||
*out_color = (border == CLKS_TRUE) ? CLKS_DESKTOP_CURSOR_OUTLINE : fill;
|
||||
return CLKS_TRUE;
|
||||
}
|
||||
|
||||
return CLKS_FALSE;
|
||||
}
|
||||
|
||||
static void clks_desktop_capture_cursor_under(i32 x, i32 y) {
|
||||
u32 ly;
|
||||
|
||||
for (ly = 0U; ly < CLKS_DESKTOP_CURSOR_H; ly++) {
|
||||
u32 lx;
|
||||
|
||||
for (lx = 0U; lx < CLKS_DESKTOP_CURSOR_W; lx++) {
|
||||
i32 gx = x + (i32)lx;
|
||||
i32 gy = y + (i32)ly;
|
||||
usize idx = ((usize)ly * (usize)CLKS_DESKTOP_CURSOR_W) + (usize)lx;
|
||||
u32 pixel = CLKS_DESKTOP_BG_COLOR;
|
||||
|
||||
if (clks_desktop_in_bounds(gx, gy) == CLKS_TRUE) {
|
||||
(void)clks_fb_read_pixel((u32)gx, (u32)gy, &pixel);
|
||||
}
|
||||
|
||||
clks_desktop_cursor_under[idx] = pixel;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static void clks_desktop_restore_cursor_under(void) {
|
||||
u32 ly;
|
||||
|
||||
if (clks_desktop_cursor_drawn == CLKS_FALSE) {
|
||||
return;
|
||||
}
|
||||
|
||||
for (ly = 0U; ly < CLKS_DESKTOP_CURSOR_H; ly++) {
|
||||
u32 lx;
|
||||
|
||||
for (lx = 0U; lx < CLKS_DESKTOP_CURSOR_W; lx++) {
|
||||
i32 gx = clks_desktop_last_mouse_x + (i32)lx;
|
||||
i32 gy = clks_desktop_last_mouse_y + (i32)ly;
|
||||
usize idx = ((usize)ly * (usize)CLKS_DESKTOP_CURSOR_W) + (usize)lx;
|
||||
|
||||
if (clks_desktop_in_bounds(gx, gy) == CLKS_TRUE) {
|
||||
clks_fb_draw_pixel((u32)gx, (u32)gy, clks_desktop_cursor_under[idx]);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
clks_desktop_cursor_drawn = CLKS_FALSE;
|
||||
}
|
||||
|
||||
static void clks_desktop_draw_cursor(i32 x, i32 y, u8 buttons) {
|
||||
u32 ly;
|
||||
|
||||
for (ly = 0U; ly < CLKS_DESKTOP_CURSOR_H; ly++) {
|
||||
u32 lx;
|
||||
|
||||
for (lx = 0U; lx < CLKS_DESKTOP_CURSOR_W; lx++) {
|
||||
i32 gx = x + (i32)lx;
|
||||
i32 gy = y + (i32)ly;
|
||||
u32 color = 0U;
|
||||
|
||||
if (clks_desktop_cursor_pixel(lx, ly, buttons, &color) == CLKS_FALSE) {
|
||||
continue;
|
||||
}
|
||||
|
||||
if (clks_desktop_in_bounds(gx, gy) == CLKS_TRUE) {
|
||||
clks_fb_draw_pixel((u32)gx, (u32)gy, color);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
clks_desktop_cursor_drawn = CLKS_TRUE;
|
||||
}
|
||||
|
||||
static void clks_desktop_present_cursor(const struct clks_mouse_state *mouse) {
|
||||
if (mouse == CLKS_NULL) {
|
||||
return;
|
||||
}
|
||||
|
||||
clks_desktop_restore_cursor_under();
|
||||
clks_desktop_capture_cursor_under(mouse->x, mouse->y);
|
||||
clks_desktop_draw_cursor(mouse->x, mouse->y, mouse->buttons);
|
||||
|
||||
clks_desktop_last_mouse_x = mouse->x;
|
||||
clks_desktop_last_mouse_y = mouse->y;
|
||||
clks_desktop_last_buttons = mouse->buttons;
|
||||
clks_desktop_last_ready = mouse->ready;
|
||||
}
|
||||
|
||||
void clks_desktop_init(void) {
|
||||
if (clks_fb_ready() == CLKS_FALSE) {
|
||||
clks_desktop_ready_flag = CLKS_FALSE;
|
||||
clks_log(CLKS_LOG_WARN, "DESK", "FRAMEBUFFER NOT READY; DESKTOP DISABLED");
|
||||
return;
|
||||
}
|
||||
|
||||
clks_desktop_compute_layout();
|
||||
clks_desktop_ready_flag = CLKS_TRUE;
|
||||
clks_desktop_active_last = CLKS_FALSE;
|
||||
clks_desktop_scene_drawn = CLKS_FALSE;
|
||||
clks_desktop_cursor_drawn = CLKS_FALSE;
|
||||
clks_desktop_last_mouse_x = -1;
|
||||
clks_desktop_last_mouse_y = -1;
|
||||
clks_desktop_last_buttons = 0U;
|
||||
clks_desktop_last_ready = CLKS_FALSE;
|
||||
|
||||
clks_log(CLKS_LOG_INFO, "DESK", "TTY2 DESKTOP ONLINE");
|
||||
clks_log(CLKS_LOG_INFO, "DESK", "MOUSE-FIRST MODE ENABLED");
|
||||
}
|
||||
|
||||
void clks_desktop_tick(u64 tick) {
|
||||
struct clks_mouse_state mouse = {0, 0, 0U, 0ULL, CLKS_FALSE};
|
||||
|
||||
(void)tick;
|
||||
|
||||
if (clks_desktop_ready_flag == CLKS_FALSE) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (clks_tty_active() != CLKS_DESKTOP_TTY_INDEX) {
|
||||
clks_desktop_active_last = CLKS_FALSE;
|
||||
clks_desktop_scene_drawn = CLKS_FALSE;
|
||||
clks_desktop_cursor_drawn = CLKS_FALSE;
|
||||
return;
|
||||
}
|
||||
|
||||
clks_mouse_snapshot(&mouse);
|
||||
|
||||
if (clks_desktop_active_last == CLKS_FALSE || clks_desktop_scene_drawn == CLKS_FALSE) {
|
||||
clks_desktop_compute_layout();
|
||||
clks_desktop_draw_static_scene(&mouse);
|
||||
clks_desktop_present_cursor(&mouse);
|
||||
clks_desktop_active_last = CLKS_TRUE;
|
||||
return;
|
||||
}
|
||||
|
||||
if (mouse.ready != clks_desktop_last_ready || mouse.buttons != clks_desktop_last_buttons) {
|
||||
clks_desktop_draw_status_widgets(&mouse);
|
||||
}
|
||||
|
||||
if (mouse.x != clks_desktop_last_mouse_x || mouse.y != clks_desktop_last_mouse_y ||
|
||||
mouse.buttons != clks_desktop_last_buttons) {
|
||||
clks_desktop_present_cursor(&mouse);
|
||||
} else {
|
||||
clks_desktop_last_ready = mouse.ready;
|
||||
}
|
||||
|
||||
clks_desktop_active_last = CLKS_TRUE;
|
||||
}
|
||||
|
||||
clks_bool clks_desktop_ready(void) {
|
||||
return clks_desktop_ready_flag;
|
||||
}
|
||||
1549
clks.local.bak/kernel/interface/shell.c
Normal file
1549
clks.local.bak/kernel/interface/shell.c
Normal file
File diff suppressed because it is too large
Load Diff
1432
clks.local.bak/kernel/interface/tty.c
Normal file
1432
clks.local.bak/kernel/interface/tty.c
Normal file
File diff suppressed because it is too large
Load Diff
180
clks.local.bak/kernel/memory/heap.c
Normal file
180
clks.local.bak/kernel/memory/heap.c
Normal file
@@ -0,0 +1,180 @@
|
||||
#include <clks/heap.h>
|
||||
#include <clks/string.h>
|
||||
#include <clks/types.h>
|
||||
|
||||
#ifndef CLKS_CFG_HEAP_ARENA_SIZE
|
||||
#define CLKS_CFG_HEAP_ARENA_SIZE (64ULL * 1024ULL * 1024ULL)
|
||||
#endif
|
||||
|
||||
#define CLKS_HEAP_ARENA_SIZE CLKS_CFG_HEAP_ARENA_SIZE
|
||||
#define CLKS_HEAP_ALIGN 16ULL
|
||||
#define CLKS_HEAP_MAGIC 0x434C454F4E4F534FULL
|
||||
|
||||
struct clks_heap_block {
|
||||
usize size;
|
||||
clks_bool is_free;
|
||||
struct clks_heap_block *next;
|
||||
struct clks_heap_block *prev;
|
||||
u64 magic;
|
||||
};
|
||||
|
||||
static u8 clks_heap_arena[CLKS_HEAP_ARENA_SIZE] __attribute__((aligned(16)));
|
||||
static struct clks_heap_block *clks_heap_head = CLKS_NULL;
|
||||
static clks_bool clks_heap_ready = CLKS_FALSE;
|
||||
|
||||
static usize clks_heap_used_bytes = 0;
|
||||
static u64 clks_heap_alloc_count = 0;
|
||||
static u64 clks_heap_free_count = 0;
|
||||
|
||||
static usize clks_heap_align_up(usize value) {
|
||||
return (value + (CLKS_HEAP_ALIGN - 1ULL)) & ~(CLKS_HEAP_ALIGN - 1ULL);
|
||||
}
|
||||
|
||||
static void clks_heap_split_block(struct clks_heap_block *block, usize need_size) {
|
||||
usize min_tail_size = sizeof(struct clks_heap_block) + CLKS_HEAP_ALIGN;
|
||||
|
||||
if (block->size < (need_size + min_tail_size)) {
|
||||
return;
|
||||
}
|
||||
|
||||
{
|
||||
u8 *new_block_addr = (u8 *)block + sizeof(struct clks_heap_block) + need_size;
|
||||
struct clks_heap_block *new_block = (struct clks_heap_block *)new_block_addr;
|
||||
|
||||
new_block->size = block->size - need_size - sizeof(struct clks_heap_block);
|
||||
new_block->is_free = CLKS_TRUE;
|
||||
new_block->next = block->next;
|
||||
new_block->prev = block;
|
||||
new_block->magic = CLKS_HEAP_MAGIC;
|
||||
|
||||
if (block->next != CLKS_NULL) {
|
||||
block->next->prev = new_block;
|
||||
}
|
||||
|
||||
block->next = new_block;
|
||||
block->size = need_size;
|
||||
}
|
||||
}
|
||||
|
||||
static void clks_heap_merge_next(struct clks_heap_block *block) {
|
||||
struct clks_heap_block *next = block->next;
|
||||
|
||||
if (next == CLKS_NULL) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (next->is_free == CLKS_FALSE) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (next->magic != CLKS_HEAP_MAGIC) {
|
||||
return;
|
||||
}
|
||||
|
||||
block->size += sizeof(struct clks_heap_block) + next->size;
|
||||
block->next = next->next;
|
||||
|
||||
if (next->next != CLKS_NULL) {
|
||||
next->next->prev = block;
|
||||
}
|
||||
}
|
||||
|
||||
void clks_heap_init(void) {
|
||||
clks_memset(clks_heap_arena, 0, sizeof(clks_heap_arena));
|
||||
|
||||
clks_heap_head = (struct clks_heap_block *)clks_heap_arena;
|
||||
clks_heap_head->size = CLKS_HEAP_ARENA_SIZE - sizeof(struct clks_heap_block);
|
||||
clks_heap_head->is_free = CLKS_TRUE;
|
||||
clks_heap_head->next = CLKS_NULL;
|
||||
clks_heap_head->prev = CLKS_NULL;
|
||||
clks_heap_head->magic = CLKS_HEAP_MAGIC;
|
||||
|
||||
clks_heap_used_bytes = 0;
|
||||
clks_heap_alloc_count = 0;
|
||||
clks_heap_free_count = 0;
|
||||
clks_heap_ready = CLKS_TRUE;
|
||||
}
|
||||
|
||||
void *clks_kmalloc(usize size) {
|
||||
struct clks_heap_block *current;
|
||||
usize aligned_size;
|
||||
|
||||
if (clks_heap_ready == CLKS_FALSE) {
|
||||
return CLKS_NULL;
|
||||
}
|
||||
|
||||
if (size == 0) {
|
||||
return CLKS_NULL;
|
||||
}
|
||||
|
||||
aligned_size = clks_heap_align_up(size);
|
||||
current = clks_heap_head;
|
||||
|
||||
while (current != CLKS_NULL) {
|
||||
if (current->magic != CLKS_HEAP_MAGIC) {
|
||||
return CLKS_NULL;
|
||||
}
|
||||
|
||||
if (current->is_free == CLKS_TRUE && current->size >= aligned_size) {
|
||||
clks_heap_split_block(current, aligned_size);
|
||||
current->is_free = CLKS_FALSE;
|
||||
clks_heap_used_bytes += current->size;
|
||||
clks_heap_alloc_count++;
|
||||
return (void *)((u8 *)current + sizeof(struct clks_heap_block));
|
||||
}
|
||||
|
||||
current = current->next;
|
||||
}
|
||||
|
||||
return CLKS_NULL;
|
||||
}
|
||||
|
||||
void clks_kfree(void *ptr) {
|
||||
struct clks_heap_block *block;
|
||||
|
||||
if (clks_heap_ready == CLKS_FALSE) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (ptr == CLKS_NULL) {
|
||||
return;
|
||||
}
|
||||
|
||||
block = (struct clks_heap_block *)((u8 *)ptr - sizeof(struct clks_heap_block));
|
||||
|
||||
if (block->magic != CLKS_HEAP_MAGIC) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (block->is_free == CLKS_TRUE) {
|
||||
return;
|
||||
}
|
||||
|
||||
block->is_free = CLKS_TRUE;
|
||||
|
||||
if (clks_heap_used_bytes >= block->size) {
|
||||
clks_heap_used_bytes -= block->size;
|
||||
} else {
|
||||
clks_heap_used_bytes = 0;
|
||||
}
|
||||
|
||||
clks_heap_free_count++;
|
||||
|
||||
clks_heap_merge_next(block);
|
||||
|
||||
if (block->prev != CLKS_NULL && block->prev->is_free == CLKS_TRUE) {
|
||||
clks_heap_merge_next(block->prev);
|
||||
}
|
||||
}
|
||||
|
||||
struct clks_heap_stats clks_heap_get_stats(void) {
|
||||
struct clks_heap_stats stats;
|
||||
|
||||
stats.total_bytes = CLKS_HEAP_ARENA_SIZE - sizeof(struct clks_heap_block);
|
||||
stats.used_bytes = clks_heap_used_bytes;
|
||||
stats.free_bytes = stats.total_bytes - stats.used_bytes;
|
||||
stats.alloc_count = clks_heap_alloc_count;
|
||||
stats.free_count = clks_heap_free_count;
|
||||
|
||||
return stats;
|
||||
}
|
||||
105
clks.local.bak/kernel/memory/pmm.c
Normal file
105
clks.local.bak/kernel/memory/pmm.c
Normal file
@@ -0,0 +1,105 @@
|
||||
#include <clks/pmm.h>
|
||||
#include <clks/string.h>
|
||||
#include <clks/types.h>
|
||||
|
||||
#define CLKS_PMM_MAX_TRACKED_PAGES 262144ULL
|
||||
#define CLKS_PMM_MIN_USABLE_ADDR 0x100000ULL
|
||||
|
||||
static u64 clks_pmm_free_stack[CLKS_PMM_MAX_TRACKED_PAGES];
|
||||
static u64 clks_pmm_free_top = 0;
|
||||
static u64 clks_pmm_managed_pages = 0;
|
||||
static u64 clks_pmm_dropped_pages = 0;
|
||||
|
||||
static u64 clks_align_up_u64(u64 value, u64 alignment) {
|
||||
return (value + alignment - 1ULL) & ~(alignment - 1ULL);
|
||||
}
|
||||
|
||||
static u64 clks_align_down_u64(u64 value, u64 alignment) {
|
||||
return value & ~(alignment - 1ULL);
|
||||
}
|
||||
|
||||
void clks_pmm_init(const struct limine_memmap_response *memmap) {
|
||||
u64 i;
|
||||
|
||||
clks_pmm_free_top = 0;
|
||||
clks_pmm_managed_pages = 0;
|
||||
clks_pmm_dropped_pages = 0;
|
||||
clks_memset(clks_pmm_free_stack, 0, sizeof(clks_pmm_free_stack));
|
||||
|
||||
if (memmap == CLKS_NULL) {
|
||||
return;
|
||||
}
|
||||
|
||||
for (i = 0; i < memmap->entry_count; i++) {
|
||||
const struct limine_memmap_entry *entry = memmap->entries[i];
|
||||
u64 start;
|
||||
u64 end;
|
||||
u64 addr;
|
||||
|
||||
if (entry == CLKS_NULL) {
|
||||
continue;
|
||||
}
|
||||
|
||||
if (entry->type != LIMINE_MEMMAP_USABLE) {
|
||||
continue;
|
||||
}
|
||||
|
||||
start = clks_align_up_u64(entry->base, CLKS_PAGE_SIZE);
|
||||
end = clks_align_down_u64(entry->base + entry->length, CLKS_PAGE_SIZE);
|
||||
|
||||
if (end <= start) {
|
||||
continue;
|
||||
}
|
||||
|
||||
for (addr = start; addr < end; addr += CLKS_PAGE_SIZE) {
|
||||
if (addr < CLKS_PMM_MIN_USABLE_ADDR) {
|
||||
continue;
|
||||
}
|
||||
|
||||
if (clks_pmm_free_top < CLKS_PMM_MAX_TRACKED_PAGES) {
|
||||
clks_pmm_free_stack[clks_pmm_free_top] = addr;
|
||||
clks_pmm_free_top++;
|
||||
clks_pmm_managed_pages++;
|
||||
} else {
|
||||
clks_pmm_dropped_pages++;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
u64 clks_pmm_alloc_page(void) {
|
||||
if (clks_pmm_free_top == 0) {
|
||||
return 0ULL;
|
||||
}
|
||||
|
||||
clks_pmm_free_top--;
|
||||
return clks_pmm_free_stack[clks_pmm_free_top];
|
||||
}
|
||||
|
||||
void clks_pmm_free_page(u64 phys_addr) {
|
||||
if (phys_addr == 0ULL) {
|
||||
return;
|
||||
}
|
||||
|
||||
if ((phys_addr & (CLKS_PAGE_SIZE - 1ULL)) != 0ULL) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (clks_pmm_free_top >= CLKS_PMM_MAX_TRACKED_PAGES) {
|
||||
return;
|
||||
}
|
||||
|
||||
clks_pmm_free_stack[clks_pmm_free_top] = phys_addr;
|
||||
clks_pmm_free_top++;
|
||||
}
|
||||
|
||||
struct clks_pmm_stats clks_pmm_get_stats(void) {
|
||||
struct clks_pmm_stats stats;
|
||||
|
||||
stats.managed_pages = clks_pmm_managed_pages;
|
||||
stats.free_pages = clks_pmm_free_top;
|
||||
stats.used_pages = clks_pmm_managed_pages - clks_pmm_free_top;
|
||||
stats.dropped_pages = clks_pmm_dropped_pages;
|
||||
|
||||
return stats;
|
||||
}
|
||||
214
clks.local.bak/kernel/runtime/driver.c
Normal file
214
clks.local.bak/kernel/runtime/driver.c
Normal file
@@ -0,0 +1,214 @@
|
||||
#include <clks/driver.h>
|
||||
#include <clks/audio.h>
|
||||
#include <clks/elf64.h>
|
||||
#include <clks/framebuffer.h>
|
||||
#include <clks/fs.h>
|
||||
#include <clks/log.h>
|
||||
#include <clks/string.h>
|
||||
#include <clks/types.h>
|
||||
|
||||
#define CLKS_DRIVER_MAX 32U
|
||||
#define CLKS_DRIVER_CHILD_NAME_MAX 96U
|
||||
#define CLKS_DRIVER_PATH_MAX 224U
|
||||
|
||||
static struct clks_driver_info clks_driver_table[CLKS_DRIVER_MAX];
|
||||
static u64 clks_driver_table_count = 0ULL;
|
||||
static u64 clks_driver_table_elf_count = 0ULL;
|
||||
|
||||
static void clks_driver_copy_name(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 clks_bool clks_driver_has_elf_suffix(const char *name) {
|
||||
usize len;
|
||||
|
||||
if (name == CLKS_NULL) {
|
||||
return CLKS_FALSE;
|
||||
}
|
||||
|
||||
len = clks_strlen(name);
|
||||
|
||||
if (len < 4U) {
|
||||
return CLKS_FALSE;
|
||||
}
|
||||
|
||||
return (name[len - 4U] == '.' && name[len - 3U] == 'e' && name[len - 2U] == 'l' && name[len - 1U] == 'f')
|
||||
? CLKS_TRUE
|
||||
: CLKS_FALSE;
|
||||
}
|
||||
|
||||
static clks_bool clks_driver_build_path(const char *child_name, char *out_path, usize out_size) {
|
||||
static const char prefix[] = "/driver/";
|
||||
usize prefix_len = sizeof(prefix) - 1U;
|
||||
usize child_len;
|
||||
|
||||
if (child_name == CLKS_NULL || out_path == CLKS_NULL || out_size == 0U) {
|
||||
return CLKS_FALSE;
|
||||
}
|
||||
|
||||
child_len = clks_strlen(child_name);
|
||||
|
||||
if (prefix_len + child_len + 1U > out_size) {
|
||||
return CLKS_FALSE;
|
||||
}
|
||||
|
||||
clks_memcpy(out_path, prefix, prefix_len);
|
||||
clks_memcpy(out_path + prefix_len, child_name, child_len);
|
||||
out_path[prefix_len + child_len] = '\0';
|
||||
return CLKS_TRUE;
|
||||
}
|
||||
|
||||
static clks_bool clks_driver_push(const char *name, enum clks_driver_kind kind, enum clks_driver_state state,
|
||||
clks_bool from_elf, u64 image_size, u64 elf_entry) {
|
||||
struct clks_driver_info *slot;
|
||||
|
||||
if (clks_driver_table_count >= CLKS_DRIVER_MAX) {
|
||||
return CLKS_FALSE;
|
||||
}
|
||||
|
||||
slot = &clks_driver_table[clks_driver_table_count];
|
||||
clks_memset(slot, 0, sizeof(*slot));
|
||||
|
||||
clks_driver_copy_name(slot->name, sizeof(slot->name), name);
|
||||
slot->kind = kind;
|
||||
slot->state = state;
|
||||
slot->from_elf = from_elf;
|
||||
slot->image_size = image_size;
|
||||
slot->elf_entry = elf_entry;
|
||||
|
||||
clks_driver_table_count++;
|
||||
|
||||
if (from_elf == CLKS_TRUE) {
|
||||
clks_driver_table_elf_count++;
|
||||
}
|
||||
|
||||
return CLKS_TRUE;
|
||||
}
|
||||
|
||||
static void clks_driver_register_builtins(void) {
|
||||
clks_driver_push("serial", CLKS_DRIVER_KIND_BUILTIN_CHAR, CLKS_DRIVER_STATE_READY, CLKS_FALSE, 0ULL, 0ULL);
|
||||
|
||||
if (clks_fb_ready() == CLKS_TRUE) {
|
||||
clks_driver_push("framebuffer", CLKS_DRIVER_KIND_BUILTIN_VIDEO, CLKS_DRIVER_STATE_READY, CLKS_FALSE, 0ULL,
|
||||
0ULL);
|
||||
clks_driver_push("tty", CLKS_DRIVER_KIND_BUILTIN_TTY, CLKS_DRIVER_STATE_READY, CLKS_FALSE, 0ULL, 0ULL);
|
||||
} else {
|
||||
clks_driver_push("framebuffer", CLKS_DRIVER_KIND_BUILTIN_VIDEO, CLKS_DRIVER_STATE_FAILED, CLKS_FALSE, 0ULL,
|
||||
0ULL);
|
||||
clks_driver_push("tty", CLKS_DRIVER_KIND_BUILTIN_TTY, CLKS_DRIVER_STATE_FAILED, CLKS_FALSE, 0ULL, 0ULL);
|
||||
}
|
||||
|
||||
if (clks_audio_available() == CLKS_TRUE) {
|
||||
clks_driver_push("pcspeaker", CLKS_DRIVER_KIND_BUILTIN_AUDIO, CLKS_DRIVER_STATE_READY, CLKS_FALSE, 0ULL, 0ULL);
|
||||
} else {
|
||||
clks_driver_push("pcspeaker", CLKS_DRIVER_KIND_BUILTIN_AUDIO, CLKS_DRIVER_STATE_FAILED, CLKS_FALSE, 0ULL, 0ULL);
|
||||
}
|
||||
}
|
||||
|
||||
static void clks_driver_probe_driver_dir(void) {
|
||||
u64 child_count;
|
||||
u64 i;
|
||||
|
||||
if (clks_fs_is_ready() == CLKS_FALSE) {
|
||||
clks_log(CLKS_LOG_ERROR, "DRV", "FS NOT READY FOR DRIVER PROBE");
|
||||
return;
|
||||
}
|
||||
|
||||
child_count = clks_fs_count_children("/driver");
|
||||
|
||||
for (i = 0ULL; i < child_count; i++) {
|
||||
char child_name[CLKS_DRIVER_CHILD_NAME_MAX];
|
||||
char full_path[CLKS_DRIVER_PATH_MAX];
|
||||
const void *image;
|
||||
u64 image_size = 0ULL;
|
||||
struct clks_elf64_info info;
|
||||
|
||||
clks_memset(child_name, 0, sizeof(child_name));
|
||||
clks_memset(full_path, 0, sizeof(full_path));
|
||||
|
||||
if (clks_fs_get_child_name("/driver", i, child_name, sizeof(child_name)) == CLKS_FALSE) {
|
||||
continue;
|
||||
}
|
||||
|
||||
if (clks_driver_has_elf_suffix(child_name) == CLKS_FALSE) {
|
||||
continue;
|
||||
}
|
||||
|
||||
if (clks_driver_build_path(child_name, full_path, sizeof(full_path)) == CLKS_FALSE) {
|
||||
clks_driver_push(child_name, CLKS_DRIVER_KIND_ELF, CLKS_DRIVER_STATE_FAILED, CLKS_TRUE, 0ULL, 0ULL);
|
||||
continue;
|
||||
}
|
||||
|
||||
image = clks_fs_read_all(full_path, &image_size);
|
||||
|
||||
if (image == CLKS_NULL) {
|
||||
clks_log(CLKS_LOG_ERROR, "DRV", "DRIVER ELF MISSING");
|
||||
clks_log(CLKS_LOG_ERROR, "DRV", full_path);
|
||||
clks_driver_push(child_name, CLKS_DRIVER_KIND_ELF, CLKS_DRIVER_STATE_FAILED, CLKS_TRUE, 0ULL, 0ULL);
|
||||
continue;
|
||||
}
|
||||
|
||||
if (clks_elf64_inspect(image, image_size, &info) == CLKS_FALSE) {
|
||||
clks_log(CLKS_LOG_ERROR, "DRV", "DRIVER ELF INVALID");
|
||||
clks_log(CLKS_LOG_ERROR, "DRV", full_path);
|
||||
clks_driver_push(child_name, CLKS_DRIVER_KIND_ELF, CLKS_DRIVER_STATE_FAILED, CLKS_TRUE, image_size, 0ULL);
|
||||
continue;
|
||||
}
|
||||
|
||||
clks_log(CLKS_LOG_INFO, "DRV", "DRIVER ELF READY");
|
||||
clks_log(CLKS_LOG_INFO, "DRV", full_path);
|
||||
clks_log_hex(CLKS_LOG_INFO, "DRV", "ENTRY", info.entry);
|
||||
|
||||
clks_driver_push(child_name, CLKS_DRIVER_KIND_ELF, CLKS_DRIVER_STATE_READY, CLKS_TRUE, image_size, info.entry);
|
||||
}
|
||||
}
|
||||
|
||||
void clks_driver_init(void) {
|
||||
clks_memset(clks_driver_table, 0, sizeof(clks_driver_table));
|
||||
clks_driver_table_count = 0ULL;
|
||||
clks_driver_table_elf_count = 0ULL;
|
||||
|
||||
clks_driver_register_builtins();
|
||||
clks_driver_probe_driver_dir();
|
||||
|
||||
clks_log(CLKS_LOG_INFO, "DRV", "DRIVER MANAGER ONLINE");
|
||||
clks_log_hex(CLKS_LOG_INFO, "DRV", "REGISTERED", clks_driver_table_count);
|
||||
clks_log_hex(CLKS_LOG_INFO, "DRV", "ELF_DRIVERS", clks_driver_table_elf_count);
|
||||
}
|
||||
|
||||
u64 clks_driver_count(void) {
|
||||
return clks_driver_table_count;
|
||||
}
|
||||
|
||||
u64 clks_driver_elf_count(void) {
|
||||
return clks_driver_table_elf_count;
|
||||
}
|
||||
|
||||
clks_bool clks_driver_get(u64 index, struct clks_driver_info *out_info) {
|
||||
if (out_info == CLKS_NULL) {
|
||||
return CLKS_FALSE;
|
||||
}
|
||||
|
||||
if (index >= clks_driver_table_count) {
|
||||
return CLKS_FALSE;
|
||||
}
|
||||
|
||||
*out_info = clks_driver_table[index];
|
||||
return CLKS_TRUE;
|
||||
}
|
||||
363
clks.local.bak/kernel/runtime/elf64.c
Normal file
363
clks.local.bak/kernel/runtime/elf64.c
Normal file
@@ -0,0 +1,363 @@
|
||||
#include <clks/elf64.h>
|
||||
#include <clks/heap.h>
|
||||
#include <clks/log.h>
|
||||
#include <clks/string.h>
|
||||
#include <clks/types.h>
|
||||
|
||||
#define CLKS_ELF64_MAGIC_0 0x7FU
|
||||
#define CLKS_ELF64_MAGIC_1 'E'
|
||||
#define CLKS_ELF64_MAGIC_2 'L'
|
||||
#define CLKS_ELF64_MAGIC_3 'F'
|
||||
|
||||
#define CLKS_ELF64_CLASS_64 2U
|
||||
#define CLKS_ELF64_DATA_LSB 1U
|
||||
#define CLKS_ELF64_VERSION 1U
|
||||
|
||||
#define CLKS_ELF64_ET_EXEC 2U
|
||||
#define CLKS_ELF64_ET_DYN 3U
|
||||
|
||||
#define CLKS_ELF64_EM_X86_64 62U
|
||||
|
||||
#define CLKS_ELF64_PF_X 0x1U
|
||||
|
||||
struct clks_elf64_ehdr {
|
||||
u8 e_ident[16];
|
||||
u16 e_type;
|
||||
u16 e_machine;
|
||||
u32 e_version;
|
||||
u64 e_entry;
|
||||
u64 e_phoff;
|
||||
u64 e_shoff;
|
||||
u32 e_flags;
|
||||
u16 e_ehsize;
|
||||
u16 e_phentsize;
|
||||
u16 e_phnum;
|
||||
u16 e_shentsize;
|
||||
u16 e_shnum;
|
||||
u16 e_shstrndx;
|
||||
};
|
||||
|
||||
struct clks_elf64_phdr {
|
||||
u32 p_type;
|
||||
u32 p_flags;
|
||||
u64 p_offset;
|
||||
u64 p_vaddr;
|
||||
u64 p_paddr;
|
||||
u64 p_filesz;
|
||||
u64 p_memsz;
|
||||
u64 p_align;
|
||||
};
|
||||
|
||||
static clks_bool clks_elf64_header_ok(const struct clks_elf64_ehdr *eh) {
|
||||
if (eh->e_ident[0] != CLKS_ELF64_MAGIC_0 || eh->e_ident[1] != CLKS_ELF64_MAGIC_1 ||
|
||||
eh->e_ident[2] != CLKS_ELF64_MAGIC_2 || eh->e_ident[3] != CLKS_ELF64_MAGIC_3) {
|
||||
return CLKS_FALSE;
|
||||
}
|
||||
|
||||
if (eh->e_ident[4] != CLKS_ELF64_CLASS_64 || eh->e_ident[5] != CLKS_ELF64_DATA_LSB) {
|
||||
return CLKS_FALSE;
|
||||
}
|
||||
|
||||
if (eh->e_ident[6] != CLKS_ELF64_VERSION || eh->e_version != CLKS_ELF64_VERSION) {
|
||||
return CLKS_FALSE;
|
||||
}
|
||||
|
||||
if (eh->e_type != CLKS_ELF64_ET_EXEC && eh->e_type != CLKS_ELF64_ET_DYN) {
|
||||
return CLKS_FALSE;
|
||||
}
|
||||
|
||||
if (eh->e_machine != CLKS_ELF64_EM_X86_64) {
|
||||
return CLKS_FALSE;
|
||||
}
|
||||
|
||||
if (eh->e_ehsize != sizeof(struct clks_elf64_ehdr)) {
|
||||
return CLKS_FALSE;
|
||||
}
|
||||
|
||||
if (eh->e_phentsize != sizeof(struct clks_elf64_phdr)) {
|
||||
return CLKS_FALSE;
|
||||
}
|
||||
|
||||
return CLKS_TRUE;
|
||||
}
|
||||
|
||||
static clks_bool clks_elf64_range_ok(u64 off, u64 len, u64 total) {
|
||||
if (off > total) {
|
||||
return CLKS_FALSE;
|
||||
}
|
||||
|
||||
if (len > (total - off)) {
|
||||
return CLKS_FALSE;
|
||||
}
|
||||
|
||||
return CLKS_TRUE;
|
||||
}
|
||||
|
||||
static void clks_elf64_rebase_exec_pointers(struct clks_elf64_loaded_image *loaded, u64 old_base, u64 old_end,
|
||||
u64 delta) {
|
||||
u16 seg_index;
|
||||
|
||||
if (loaded == CLKS_NULL || delta == 0ULL || old_end <= old_base) {
|
||||
return;
|
||||
}
|
||||
|
||||
for (seg_index = 0U; seg_index < loaded->segment_count; seg_index++) {
|
||||
struct clks_elf64_loaded_segment *seg = &loaded->segments[seg_index];
|
||||
u64 scan_len;
|
||||
u64 off;
|
||||
|
||||
/* Skip executable segments to avoid patching instruction bytes. */
|
||||
if ((seg->flags & CLKS_ELF64_PF_X) != 0U) {
|
||||
continue;
|
||||
}
|
||||
|
||||
scan_len = seg->filesz;
|
||||
if (scan_len < sizeof(u64)) {
|
||||
continue;
|
||||
}
|
||||
|
||||
scan_len -= (scan_len % sizeof(u64));
|
||||
|
||||
for (off = 0ULL; off < scan_len; off += sizeof(u64)) {
|
||||
u64 *slot = (u64 *)((u8 *)seg->base + (usize)off);
|
||||
u64 value = *slot;
|
||||
|
||||
if (value >= old_base && value < old_end) {
|
||||
*slot = value + delta;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
clks_bool clks_elf64_validate(const void *image, u64 size) {
|
||||
const struct clks_elf64_ehdr *eh;
|
||||
u64 ph_table_size;
|
||||
u16 i;
|
||||
|
||||
if (image == CLKS_NULL) {
|
||||
return CLKS_FALSE;
|
||||
}
|
||||
|
||||
if (size < sizeof(struct clks_elf64_ehdr)) {
|
||||
return CLKS_FALSE;
|
||||
}
|
||||
|
||||
eh = (const struct clks_elf64_ehdr *)image;
|
||||
|
||||
if (clks_elf64_header_ok(eh) == CLKS_FALSE) {
|
||||
return CLKS_FALSE;
|
||||
}
|
||||
|
||||
ph_table_size = (u64)eh->e_phnum * (u64)eh->e_phentsize;
|
||||
|
||||
if (clks_elf64_range_ok(eh->e_phoff, ph_table_size, size) == CLKS_FALSE) {
|
||||
return CLKS_FALSE;
|
||||
}
|
||||
|
||||
for (i = 0; i < eh->e_phnum; i++) {
|
||||
const struct clks_elf64_phdr *ph =
|
||||
(const struct clks_elf64_phdr *)((const u8 *)image + eh->e_phoff + ((u64)i * eh->e_phentsize));
|
||||
|
||||
if (ph->p_type != CLKS_ELF64_PT_LOAD) {
|
||||
continue;
|
||||
}
|
||||
|
||||
if (ph->p_filesz > ph->p_memsz) {
|
||||
return CLKS_FALSE;
|
||||
}
|
||||
|
||||
if (clks_elf64_range_ok(ph->p_offset, ph->p_filesz, size) == CLKS_FALSE) {
|
||||
return CLKS_FALSE;
|
||||
}
|
||||
}
|
||||
|
||||
return CLKS_TRUE;
|
||||
}
|
||||
|
||||
clks_bool clks_elf64_inspect(const void *image, u64 size, struct clks_elf64_info *out_info) {
|
||||
const struct clks_elf64_ehdr *eh;
|
||||
u16 i;
|
||||
|
||||
if (out_info == CLKS_NULL) {
|
||||
return CLKS_FALSE;
|
||||
}
|
||||
|
||||
clks_memset(out_info, 0, sizeof(*out_info));
|
||||
|
||||
if (clks_elf64_validate(image, size) == CLKS_FALSE) {
|
||||
return CLKS_FALSE;
|
||||
}
|
||||
|
||||
eh = (const struct clks_elf64_ehdr *)image;
|
||||
|
||||
out_info->entry = eh->e_entry;
|
||||
out_info->phnum = eh->e_phnum;
|
||||
|
||||
for (i = 0; i < eh->e_phnum; i++) {
|
||||
const struct clks_elf64_phdr *ph =
|
||||
(const struct clks_elf64_phdr *)((const u8 *)image + eh->e_phoff + ((u64)i * eh->e_phentsize));
|
||||
|
||||
if (ph->p_type != CLKS_ELF64_PT_LOAD) {
|
||||
continue;
|
||||
}
|
||||
|
||||
out_info->loadable_segments++;
|
||||
out_info->total_load_memsz += ph->p_memsz;
|
||||
}
|
||||
|
||||
return CLKS_TRUE;
|
||||
}
|
||||
|
||||
clks_bool clks_elf64_load(const void *image, u64 size, struct clks_elf64_loaded_image *out_loaded) {
|
||||
const struct clks_elf64_ehdr *eh;
|
||||
u16 i;
|
||||
u16 load_count = 0U;
|
||||
u64 min_vaddr = 0ULL;
|
||||
u64 max_vaddr_end = 0ULL;
|
||||
u64 span;
|
||||
void *image_base;
|
||||
|
||||
if (out_loaded == CLKS_NULL) {
|
||||
return CLKS_FALSE;
|
||||
}
|
||||
|
||||
clks_memset(out_loaded, 0, sizeof(*out_loaded));
|
||||
|
||||
if (clks_elf64_validate(image, size) == CLKS_FALSE) {
|
||||
return CLKS_FALSE;
|
||||
}
|
||||
|
||||
eh = (const struct clks_elf64_ehdr *)image;
|
||||
|
||||
for (i = 0; i < eh->e_phnum; i++) {
|
||||
const struct clks_elf64_phdr *ph =
|
||||
(const struct clks_elf64_phdr *)((const u8 *)image + eh->e_phoff + ((u64)i * eh->e_phentsize));
|
||||
u64 seg_end;
|
||||
|
||||
if (ph->p_type != CLKS_ELF64_PT_LOAD || ph->p_memsz == 0ULL) {
|
||||
continue;
|
||||
}
|
||||
|
||||
if (load_count == 0U || ph->p_vaddr < min_vaddr) {
|
||||
min_vaddr = ph->p_vaddr;
|
||||
}
|
||||
|
||||
seg_end = ph->p_vaddr + ph->p_memsz;
|
||||
if (seg_end < ph->p_vaddr) {
|
||||
return CLKS_FALSE;
|
||||
}
|
||||
|
||||
if (load_count == 0U || seg_end > max_vaddr_end) {
|
||||
max_vaddr_end = seg_end;
|
||||
}
|
||||
|
||||
load_count++;
|
||||
}
|
||||
|
||||
if (load_count == 0U) {
|
||||
return CLKS_FALSE;
|
||||
}
|
||||
|
||||
if (load_count > CLKS_ELF64_MAX_SEGMENTS) {
|
||||
return CLKS_FALSE;
|
||||
}
|
||||
|
||||
span = max_vaddr_end - min_vaddr;
|
||||
if (span == 0ULL) {
|
||||
return CLKS_FALSE;
|
||||
}
|
||||
|
||||
image_base = clks_kmalloc((usize)span);
|
||||
if (image_base == CLKS_NULL) {
|
||||
clks_log(CLKS_LOG_WARN, "ELF", "LOAD ALLOC FAILED");
|
||||
clks_log_hex(CLKS_LOG_WARN, "ELF", "SPAN", span);
|
||||
clks_log_hex(CLKS_LOG_WARN, "ELF", "MIN_VADDR", min_vaddr);
|
||||
clks_log_hex(CLKS_LOG_WARN, "ELF", "MAX_VADDR_END", max_vaddr_end);
|
||||
return CLKS_FALSE;
|
||||
}
|
||||
|
||||
clks_memset(image_base, 0, (usize)span);
|
||||
|
||||
out_loaded->entry = eh->e_entry;
|
||||
out_loaded->image_base = image_base;
|
||||
out_loaded->image_size = span;
|
||||
out_loaded->image_vaddr_base = min_vaddr;
|
||||
out_loaded->segment_count = 0U;
|
||||
|
||||
for (i = 0; i < eh->e_phnum; i++) {
|
||||
const struct clks_elf64_phdr *ph =
|
||||
(const struct clks_elf64_phdr *)((const u8 *)image + eh->e_phoff + ((u64)i * eh->e_phentsize));
|
||||
u64 seg_off;
|
||||
u8 *seg_dst;
|
||||
|
||||
if (ph->p_type != CLKS_ELF64_PT_LOAD || ph->p_memsz == 0ULL) {
|
||||
continue;
|
||||
}
|
||||
|
||||
if (out_loaded->segment_count >= CLKS_ELF64_MAX_SEGMENTS) {
|
||||
clks_elf64_unload(out_loaded);
|
||||
return CLKS_FALSE;
|
||||
}
|
||||
|
||||
seg_off = ph->p_vaddr - min_vaddr;
|
||||
if (seg_off > span || ph->p_memsz > (span - seg_off)) {
|
||||
clks_elf64_unload(out_loaded);
|
||||
return CLKS_FALSE;
|
||||
}
|
||||
|
||||
seg_dst = (u8 *)image_base + (usize)seg_off;
|
||||
clks_memcpy(seg_dst, (const void *)((const u8 *)image + ph->p_offset), (usize)ph->p_filesz);
|
||||
|
||||
out_loaded->segments[out_loaded->segment_count].base = seg_dst;
|
||||
out_loaded->segments[out_loaded->segment_count].vaddr = ph->p_vaddr;
|
||||
out_loaded->segments[out_loaded->segment_count].memsz = ph->p_memsz;
|
||||
out_loaded->segments[out_loaded->segment_count].filesz = ph->p_filesz;
|
||||
out_loaded->segments[out_loaded->segment_count].flags = ph->p_flags;
|
||||
out_loaded->segment_count++;
|
||||
}
|
||||
|
||||
if (eh->e_type == CLKS_ELF64_ET_EXEC) {
|
||||
u64 new_base = (u64)(usize)image_base;
|
||||
u64 old_base = min_vaddr;
|
||||
u64 old_end = max_vaddr_end;
|
||||
|
||||
if (new_base != old_base) {
|
||||
u64 delta = new_base - old_base;
|
||||
clks_elf64_rebase_exec_pointers(out_loaded, old_base, old_end, delta);
|
||||
}
|
||||
}
|
||||
|
||||
return CLKS_TRUE;
|
||||
}
|
||||
|
||||
void clks_elf64_unload(struct clks_elf64_loaded_image *loaded) {
|
||||
if (loaded == CLKS_NULL) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (loaded->image_base != CLKS_NULL) {
|
||||
clks_kfree(loaded->image_base);
|
||||
}
|
||||
|
||||
clks_memset(loaded, 0, sizeof(*loaded));
|
||||
}
|
||||
|
||||
void *clks_elf64_entry_pointer(const struct clks_elf64_loaded_image *loaded, u64 entry) {
|
||||
u64 off;
|
||||
|
||||
if (loaded == CLKS_NULL || loaded->image_base == CLKS_NULL) {
|
||||
return CLKS_NULL;
|
||||
}
|
||||
|
||||
if (entry < loaded->image_vaddr_base) {
|
||||
return CLKS_NULL;
|
||||
}
|
||||
|
||||
off = entry - loaded->image_vaddr_base;
|
||||
|
||||
if (off >= loaded->image_size) {
|
||||
return CLKS_NULL;
|
||||
}
|
||||
|
||||
return (void *)((u8 *)loaded->image_base + (usize)off);
|
||||
}
|
||||
38
clks.local.bak/kernel/runtime/elfrunner.c
Normal file
38
clks.local.bak/kernel/runtime/elfrunner.c
Normal file
@@ -0,0 +1,38 @@
|
||||
#include <clks/boot.h>
|
||||
#include <clks/elf64.h>
|
||||
#include <clks/elfrunner.h>
|
||||
#include <clks/log.h>
|
||||
#include <clks/types.h>
|
||||
|
||||
static clks_bool clks_elfrunner_ready = CLKS_FALSE;
|
||||
|
||||
void clks_elfrunner_init(void) {
|
||||
clks_elfrunner_ready = CLKS_TRUE;
|
||||
clks_log(CLKS_LOG_INFO, "ELF", "ELFRUNNER FRAMEWORK ONLINE");
|
||||
}
|
||||
|
||||
clks_bool clks_elfrunner_probe_kernel_executable(void) {
|
||||
const struct limine_file *exe = clks_boot_get_executable_file();
|
||||
struct clks_elf64_info info;
|
||||
|
||||
if (clks_elfrunner_ready == CLKS_FALSE) {
|
||||
return CLKS_FALSE;
|
||||
}
|
||||
|
||||
if (exe == CLKS_NULL || exe->address == CLKS_NULL || exe->size == 0ULL) {
|
||||
clks_log(CLKS_LOG_ERROR, "ELF", "NO EXECUTABLE FILE FROM LIMINE");
|
||||
return CLKS_FALSE;
|
||||
}
|
||||
|
||||
if (clks_elf64_inspect(exe->address, exe->size, &info) == CLKS_FALSE) {
|
||||
clks_log(CLKS_LOG_ERROR, "ELF", "KERNEL ELF INSPECT FAILED");
|
||||
return CLKS_FALSE;
|
||||
}
|
||||
|
||||
clks_log_hex(CLKS_LOG_INFO, "ELF", "ENTRY", info.entry);
|
||||
clks_log_hex(CLKS_LOG_INFO, "ELF", "PHNUM", info.phnum);
|
||||
clks_log_hex(CLKS_LOG_INFO, "ELF", "LOAD_SEGMENTS", info.loadable_segments);
|
||||
clks_log_hex(CLKS_LOG_INFO, "ELF", "TOTAL_MEMSZ", info.total_load_memsz);
|
||||
|
||||
return CLKS_TRUE;
|
||||
}
|
||||
2782
clks.local.bak/kernel/runtime/exec.c
Normal file
2782
clks.local.bak/kernel/runtime/exec.c
Normal file
File diff suppressed because it is too large
Load Diff
250
clks.local.bak/kernel/runtime/kelf.c
Normal file
250
clks.local.bak/kernel/runtime/kelf.c
Normal file
@@ -0,0 +1,250 @@
|
||||
#include <clks/elf64.h>
|
||||
#include <clks/fs.h>
|
||||
#include <clks/heap.h>
|
||||
#include <clks/kelf.h>
|
||||
#include <clks/log.h>
|
||||
#include <clks/string.h>
|
||||
#include <clks/types.h>
|
||||
|
||||
#define CLKS_KELF_MAX_APPS 8U
|
||||
#define CLKS_ELF64_PT_LOAD 1U
|
||||
|
||||
struct clks_elf64_ehdr {
|
||||
u8 e_ident[16];
|
||||
u16 e_type;
|
||||
u16 e_machine;
|
||||
u32 e_version;
|
||||
u64 e_entry;
|
||||
u64 e_phoff;
|
||||
u64 e_shoff;
|
||||
u32 e_flags;
|
||||
u16 e_ehsize;
|
||||
u16 e_phentsize;
|
||||
u16 e_phnum;
|
||||
u16 e_shentsize;
|
||||
u16 e_shnum;
|
||||
u16 e_shstrndx;
|
||||
};
|
||||
|
||||
struct clks_elf64_phdr {
|
||||
u32 p_type;
|
||||
u32 p_flags;
|
||||
u64 p_offset;
|
||||
u64 p_vaddr;
|
||||
u64 p_paddr;
|
||||
u64 p_filesz;
|
||||
u64 p_memsz;
|
||||
u64 p_align;
|
||||
};
|
||||
|
||||
struct clks_kelf_app {
|
||||
clks_bool loaded;
|
||||
char path[64];
|
||||
void *runtime_image;
|
||||
u64 runtime_size;
|
||||
clks_kelf_entry_fn entry;
|
||||
u64 run_count;
|
||||
u64 last_run_tick;
|
||||
u64 last_ret;
|
||||
};
|
||||
|
||||
static struct clks_kelf_app clks_kelf_apps[CLKS_KELF_MAX_APPS];
|
||||
static u64 clks_kelf_app_count = 0ULL;
|
||||
static u64 clks_kelf_total_runs_count = 0ULL;
|
||||
static u64 clks_kelf_rr_index = 0ULL;
|
||||
static u64 clks_kelf_last_dispatch_tick = 0ULL;
|
||||
|
||||
static void clks_kelf_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 clks_bool clks_kelf_load_runtime_image(const void *image, u64 size, void **out_runtime, u64 *out_runtime_size,
|
||||
clks_kelf_entry_fn *out_entry) {
|
||||
const struct clks_elf64_ehdr *eh;
|
||||
u64 min_vaddr = 0xffffffffffffffffULL;
|
||||
u64 max_vaddr = 0ULL;
|
||||
u16 i;
|
||||
u8 *runtime;
|
||||
|
||||
if (out_runtime == CLKS_NULL || out_runtime_size == CLKS_NULL || out_entry == CLKS_NULL) {
|
||||
return CLKS_FALSE;
|
||||
}
|
||||
|
||||
if (clks_elf64_validate(image, size) == CLKS_FALSE) {
|
||||
return CLKS_FALSE;
|
||||
}
|
||||
|
||||
eh = (const struct clks_elf64_ehdr *)image;
|
||||
|
||||
for (i = 0; i < eh->e_phnum; i++) {
|
||||
const struct clks_elf64_phdr *ph =
|
||||
(const struct clks_elf64_phdr *)((const u8 *)image + eh->e_phoff + ((u64)i * eh->e_phentsize));
|
||||
u64 seg_end;
|
||||
|
||||
if (ph->p_type != CLKS_ELF64_PT_LOAD || ph->p_memsz == 0ULL) {
|
||||
continue;
|
||||
}
|
||||
|
||||
if (ph->p_filesz > ph->p_memsz) {
|
||||
return CLKS_FALSE;
|
||||
}
|
||||
|
||||
if (ph->p_offset > size || ph->p_filesz > (size - ph->p_offset)) {
|
||||
return CLKS_FALSE;
|
||||
}
|
||||
|
||||
seg_end = ph->p_vaddr + ph->p_memsz;
|
||||
|
||||
if (seg_end < ph->p_vaddr) {
|
||||
return CLKS_FALSE;
|
||||
}
|
||||
|
||||
if (ph->p_vaddr < min_vaddr) {
|
||||
min_vaddr = ph->p_vaddr;
|
||||
}
|
||||
|
||||
if (seg_end > max_vaddr) {
|
||||
max_vaddr = seg_end;
|
||||
}
|
||||
}
|
||||
|
||||
if (max_vaddr <= min_vaddr) {
|
||||
return CLKS_FALSE;
|
||||
}
|
||||
|
||||
*out_runtime_size = max_vaddr - min_vaddr;
|
||||
runtime = (u8 *)clks_kmalloc((usize)(*out_runtime_size));
|
||||
|
||||
if (runtime == CLKS_NULL) {
|
||||
return CLKS_FALSE;
|
||||
}
|
||||
|
||||
clks_memset(runtime, 0, (usize)(*out_runtime_size));
|
||||
|
||||
for (i = 0; i < eh->e_phnum; i++) {
|
||||
const struct clks_elf64_phdr *ph =
|
||||
(const struct clks_elf64_phdr *)((const u8 *)image + eh->e_phoff + ((u64)i * eh->e_phentsize));
|
||||
|
||||
if (ph->p_type != CLKS_ELF64_PT_LOAD || ph->p_memsz == 0ULL) {
|
||||
continue;
|
||||
}
|
||||
|
||||
clks_memcpy(runtime + (usize)(ph->p_vaddr - min_vaddr), (const u8 *)image + ph->p_offset, (usize)ph->p_filesz);
|
||||
}
|
||||
|
||||
if (eh->e_entry < min_vaddr || eh->e_entry >= max_vaddr) {
|
||||
clks_kfree(runtime);
|
||||
return CLKS_FALSE;
|
||||
}
|
||||
|
||||
*out_entry = (clks_kelf_entry_fn)(void *)(runtime + (usize)(eh->e_entry - min_vaddr));
|
||||
*out_runtime = runtime;
|
||||
return CLKS_TRUE;
|
||||
}
|
||||
|
||||
static void clks_kelf_probe_path(const char *path) {
|
||||
const void *image;
|
||||
u64 size = 0ULL;
|
||||
void *runtime = CLKS_NULL;
|
||||
u64 runtime_size = 0ULL;
|
||||
clks_kelf_entry_fn entry = CLKS_NULL;
|
||||
struct clks_kelf_app *slot;
|
||||
|
||||
if (clks_kelf_app_count >= CLKS_KELF_MAX_APPS) {
|
||||
return;
|
||||
}
|
||||
|
||||
image = clks_fs_read_all(path, &size);
|
||||
|
||||
if (image == CLKS_NULL || size == 0ULL) {
|
||||
clks_log(CLKS_LOG_WARN, "KELF", "APP FILE NOT FOUND");
|
||||
clks_log(CLKS_LOG_WARN, "KELF", path);
|
||||
return;
|
||||
}
|
||||
|
||||
if (clks_kelf_load_runtime_image(image, size, &runtime, &runtime_size, &entry) == CLKS_FALSE) {
|
||||
clks_log(CLKS_LOG_ERROR, "KELF", "APP LOAD FAILED");
|
||||
clks_log(CLKS_LOG_ERROR, "KELF", path);
|
||||
return;
|
||||
}
|
||||
|
||||
slot = &clks_kelf_apps[clks_kelf_app_count];
|
||||
clks_memset(slot, 0, sizeof(*slot));
|
||||
|
||||
slot->loaded = CLKS_TRUE;
|
||||
clks_kelf_copy_name(slot->path, sizeof(slot->path), path);
|
||||
slot->runtime_image = runtime;
|
||||
slot->runtime_size = runtime_size;
|
||||
slot->entry = entry;
|
||||
|
||||
clks_kelf_app_count++;
|
||||
|
||||
clks_log(CLKS_LOG_INFO, "KELF", "APP READY");
|
||||
clks_log(CLKS_LOG_INFO, "KELF", path);
|
||||
clks_log_hex(CLKS_LOG_INFO, "KELF", "RUNTIME_SIZE", runtime_size);
|
||||
}
|
||||
|
||||
void clks_kelf_init(void) {
|
||||
clks_memset(clks_kelf_apps, 0, sizeof(clks_kelf_apps));
|
||||
clks_kelf_app_count = 0ULL;
|
||||
clks_kelf_total_runs_count = 0ULL;
|
||||
clks_kelf_rr_index = 0ULL;
|
||||
clks_kelf_last_dispatch_tick = 0ULL;
|
||||
|
||||
clks_kelf_probe_path("/system/elfrunner.elf");
|
||||
clks_kelf_probe_path("/system/memc.elf");
|
||||
|
||||
clks_log(CLKS_LOG_INFO, "KELF", "EXECUTOR ONLINE");
|
||||
clks_log_hex(CLKS_LOG_INFO, "KELF", "APP_COUNT", clks_kelf_app_count);
|
||||
}
|
||||
|
||||
void clks_kelf_tick(u64 tick) {
|
||||
struct clks_kelf_app *app;
|
||||
|
||||
if (clks_kelf_app_count == 0ULL) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (tick - clks_kelf_last_dispatch_tick < 200ULL) {
|
||||
return;
|
||||
}
|
||||
|
||||
clks_kelf_last_dispatch_tick = tick;
|
||||
app = &clks_kelf_apps[clks_kelf_rr_index % clks_kelf_app_count];
|
||||
clks_kelf_rr_index++;
|
||||
|
||||
if (app->loaded == CLKS_FALSE || app->entry == CLKS_NULL) {
|
||||
return;
|
||||
}
|
||||
|
||||
app->run_count++;
|
||||
app->last_run_tick = tick;
|
||||
/* NX-safe stage mode: keep dispatch accounting without jumping into runtime image. */
|
||||
app->last_ret = (tick ^ (app->run_count << 8)) + clks_kelf_rr_index;
|
||||
clks_kelf_total_runs_count++;
|
||||
|
||||
if ((app->run_count & 0x7ULL) == 1ULL) {
|
||||
clks_log(CLKS_LOG_DEBUG, "KELF", "APP DISPATCHED");
|
||||
clks_log(CLKS_LOG_DEBUG, "KELF", app->path);
|
||||
clks_log_hex(CLKS_LOG_DEBUG, "KELF", "RET", app->last_ret);
|
||||
}
|
||||
}
|
||||
|
||||
u64 clks_kelf_count(void) {
|
||||
return clks_kelf_app_count;
|
||||
}
|
||||
|
||||
u64 clks_kelf_total_runs(void) {
|
||||
return clks_kelf_total_runs_count;
|
||||
}
|
||||
2672
clks.local.bak/kernel/runtime/syscall.c
Normal file
2672
clks.local.bak/kernel/runtime/syscall.c
Normal file
File diff suppressed because it is too large
Load Diff
183
clks.local.bak/kernel/runtime/userland.c
Normal file
183
clks.local.bak/kernel/runtime/userland.c
Normal file
@@ -0,0 +1,183 @@
|
||||
#include <clks/elf64.h>
|
||||
#include <clks/exec.h>
|
||||
#include <clks/fs.h>
|
||||
#include <clks/log.h>
|
||||
#include <clks/types.h>
|
||||
#include <clks/userland.h>
|
||||
|
||||
#define CLKS_USERLAND_RETRY_INTERVAL 500ULL
|
||||
|
||||
#ifndef CLKS_CFG_USERLAND_AUTO_EXEC
|
||||
#define CLKS_CFG_USERLAND_AUTO_EXEC 1
|
||||
#endif
|
||||
|
||||
#ifndef CLKS_CFG_USER_INIT_SCRIPT_PROBE
|
||||
#define CLKS_CFG_USER_INIT_SCRIPT_PROBE 1
|
||||
#endif
|
||||
|
||||
#ifndef CLKS_CFG_USER_SYSTEM_APP_PROBE
|
||||
#define CLKS_CFG_USER_SYSTEM_APP_PROBE 1
|
||||
#endif
|
||||
|
||||
static clks_bool clks_user_shell_ready = CLKS_FALSE;
|
||||
static clks_bool clks_user_shell_exec_requested_flag = CLKS_FALSE;
|
||||
static clks_bool clks_user_shell_exec_enabled = CLKS_FALSE;
|
||||
static u64 clks_user_launch_attempt_count = 0ULL;
|
||||
static u64 clks_user_launch_success_count = 0ULL;
|
||||
static u64 clks_user_launch_fail_count = 0ULL;
|
||||
static u64 clks_user_last_try_tick = 0ULL;
|
||||
static clks_bool clks_user_first_try_pending = CLKS_FALSE;
|
||||
|
||||
static clks_bool clks_userland_probe_elf(const char *path, const char *tag) {
|
||||
const void *image;
|
||||
u64 size = 0ULL;
|
||||
struct clks_elf64_info info;
|
||||
|
||||
image = clks_fs_read_all(path, &size);
|
||||
|
||||
if (image == CLKS_NULL) {
|
||||
clks_log(CLKS_LOG_ERROR, "USER", "ELF FILE MISSING");
|
||||
clks_log(CLKS_LOG_ERROR, "USER", path);
|
||||
return CLKS_FALSE;
|
||||
}
|
||||
|
||||
if (clks_elf64_inspect(image, size, &info) == CLKS_FALSE) {
|
||||
clks_log(CLKS_LOG_ERROR, "USER", "ELF INSPECT FAILED");
|
||||
clks_log(CLKS_LOG_ERROR, "USER", path);
|
||||
return CLKS_FALSE;
|
||||
}
|
||||
|
||||
clks_log(CLKS_LOG_INFO, "USER", tag);
|
||||
clks_log_hex(CLKS_LOG_INFO, "USER", "ELF_SIZE", size);
|
||||
clks_log_hex(CLKS_LOG_INFO, "USER", "ENTRY", info.entry);
|
||||
return CLKS_TRUE;
|
||||
}
|
||||
|
||||
#if CLKS_CFG_USER_INIT_SCRIPT_PROBE
|
||||
static void clks_userland_probe_init_script(void) {
|
||||
const void *data;
|
||||
u64 size = 0ULL;
|
||||
|
||||
data = clks_fs_read_all("/shell/init.cmd", &size);
|
||||
|
||||
if (data == CLKS_NULL || size == 0ULL) {
|
||||
clks_log(CLKS_LOG_WARN, "USER", "INIT SCRIPT NOT FOUND /SHELL/INIT.CMD");
|
||||
return;
|
||||
}
|
||||
|
||||
clks_log(CLKS_LOG_INFO, "USER", "INIT SCRIPT READY /SHELL/INIT.CMD");
|
||||
clks_log_hex(CLKS_LOG_INFO, "USER", "INIT_SCRIPT_SIZE", size);
|
||||
}
|
||||
#endif
|
||||
|
||||
static clks_bool clks_userland_request_shell_exec(void) {
|
||||
u64 status = (u64)-1;
|
||||
|
||||
if (clks_user_shell_ready == CLKS_FALSE) {
|
||||
return CLKS_FALSE;
|
||||
}
|
||||
|
||||
clks_user_launch_attempt_count++;
|
||||
|
||||
if (clks_exec_run_path("/shell/shell.elf", &status) == CLKS_TRUE && status == 0ULL) {
|
||||
clks_user_shell_exec_requested_flag = CLKS_TRUE;
|
||||
clks_user_launch_success_count++;
|
||||
|
||||
clks_log(CLKS_LOG_INFO, "USER", "SHELL EXEC REQUESTED");
|
||||
clks_log_hex(CLKS_LOG_INFO, "USER", "SHELL_STATUS", status);
|
||||
return CLKS_TRUE;
|
||||
}
|
||||
|
||||
clks_user_launch_fail_count++;
|
||||
clks_log(CLKS_LOG_WARN, "USER", "SHELL EXEC REQUEST FAILED");
|
||||
return CLKS_FALSE;
|
||||
}
|
||||
|
||||
clks_bool clks_userland_init(void) {
|
||||
clks_log(CLKS_LOG_INFO, "USER", "USERLAND FRAMEWORK ONLINE");
|
||||
|
||||
clks_user_shell_ready = CLKS_FALSE;
|
||||
clks_user_shell_exec_requested_flag = CLKS_FALSE;
|
||||
clks_user_shell_exec_enabled = (CLKS_CFG_USERLAND_AUTO_EXEC != 0) ? CLKS_TRUE : CLKS_FALSE;
|
||||
clks_user_launch_attempt_count = 0ULL;
|
||||
clks_user_launch_success_count = 0ULL;
|
||||
clks_user_launch_fail_count = 0ULL;
|
||||
clks_user_last_try_tick = 0ULL;
|
||||
clks_user_first_try_pending = CLKS_TRUE;
|
||||
|
||||
if (clks_userland_probe_elf("/shell/shell.elf", "SHELL ELF READY") == CLKS_FALSE) {
|
||||
return CLKS_FALSE;
|
||||
}
|
||||
|
||||
clks_user_shell_ready = CLKS_TRUE;
|
||||
clks_log(CLKS_LOG_INFO, "USER", "SHELL COMMAND ABI READY");
|
||||
#if CLKS_CFG_USER_INIT_SCRIPT_PROBE
|
||||
clks_userland_probe_init_script();
|
||||
#else
|
||||
clks_log(CLKS_LOG_WARN, "USER", "INIT SCRIPT PROBE DISABLED BY MENUCONFIG");
|
||||
#endif
|
||||
|
||||
#if CLKS_CFG_USER_SYSTEM_APP_PROBE
|
||||
if (clks_userland_probe_elf("/system/elfrunner.elf", "ELFRUNNER ELF READY") == CLKS_FALSE) {
|
||||
return CLKS_FALSE;
|
||||
}
|
||||
|
||||
if (clks_userland_probe_elf("/system/memc.elf", "MEMC ELF READY") == CLKS_FALSE) {
|
||||
return CLKS_FALSE;
|
||||
}
|
||||
#else
|
||||
clks_log(CLKS_LOG_WARN, "USER", "SYSTEM APP PROBE DISABLED BY MENUCONFIG");
|
||||
#endif
|
||||
|
||||
if (clks_user_shell_exec_enabled == CLKS_TRUE) {
|
||||
clks_log(CLKS_LOG_INFO, "USER", "USER SHELL AUTO EXEC ENABLED");
|
||||
} else {
|
||||
clks_log(CLKS_LOG_WARN, "USER", "USER SHELL AUTO EXEC DISABLED BY MENUCONFIG");
|
||||
}
|
||||
return CLKS_TRUE;
|
||||
}
|
||||
|
||||
void clks_userland_tick(u64 tick) {
|
||||
if (clks_user_shell_exec_enabled == CLKS_FALSE || clks_user_shell_ready == CLKS_FALSE ||
|
||||
clks_user_shell_exec_requested_flag == CLKS_TRUE) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (clks_user_first_try_pending == CLKS_TRUE) {
|
||||
clks_user_first_try_pending = CLKS_FALSE;
|
||||
clks_user_last_try_tick = tick;
|
||||
(void)clks_userland_request_shell_exec();
|
||||
return;
|
||||
}
|
||||
|
||||
if (tick - clks_user_last_try_tick < CLKS_USERLAND_RETRY_INTERVAL) {
|
||||
return;
|
||||
}
|
||||
|
||||
clks_user_last_try_tick = tick;
|
||||
(void)clks_userland_request_shell_exec();
|
||||
}
|
||||
|
||||
clks_bool clks_userland_shell_ready(void) {
|
||||
return clks_user_shell_ready;
|
||||
}
|
||||
|
||||
clks_bool clks_userland_shell_exec_requested(void) {
|
||||
return clks_user_shell_exec_requested_flag;
|
||||
}
|
||||
|
||||
clks_bool clks_userland_shell_auto_exec_enabled(void) {
|
||||
return clks_user_shell_exec_enabled;
|
||||
}
|
||||
|
||||
u64 clks_userland_launch_attempts(void) {
|
||||
return clks_user_launch_attempt_count;
|
||||
}
|
||||
|
||||
u64 clks_userland_launch_success(void) {
|
||||
return clks_user_launch_success_count;
|
||||
}
|
||||
|
||||
u64 clks_userland_launch_failures(void) {
|
||||
return clks_user_launch_fail_count;
|
||||
}
|
||||
1856
clks.local.bak/kernel/storage/disk.c
Normal file
1856
clks.local.bak/kernel/storage/disk.c
Normal file
File diff suppressed because it is too large
Load Diff
967
clks.local.bak/kernel/storage/fs.c
Normal file
967
clks.local.bak/kernel/storage/fs.c
Normal file
@@ -0,0 +1,967 @@
|
||||
#include <clks/boot.h>
|
||||
#include <clks/disk.h>
|
||||
#include <clks/fs.h>
|
||||
#include <clks/heap.h>
|
||||
#include <clks/log.h>
|
||||
#include <clks/ramdisk.h>
|
||||
#include <clks/string.h>
|
||||
#include <clks/types.h>
|
||||
|
||||
/* Tiny in-memory FS: simple enough to reason about, still easy to screw up. */
|
||||
|
||||
#define CLKS_FS_MAX_NODES 512U
|
||||
#define CLKS_FS_PATH_MAX CLKS_RAMDISK_PATH_MAX
|
||||
|
||||
#define CLKS_FS_NODE_FLAG_HEAP_DATA 0x0001U
|
||||
|
||||
struct clks_fs_node {
|
||||
clks_bool used;
|
||||
enum clks_fs_node_type type;
|
||||
u16 parent;
|
||||
u16 reserved;
|
||||
const void *data;
|
||||
u64 size;
|
||||
char path[CLKS_FS_PATH_MAX];
|
||||
};
|
||||
|
||||
struct clks_fs_build_stats {
|
||||
u64 file_count;
|
||||
u64 dir_count;
|
||||
};
|
||||
|
||||
static struct clks_fs_node clks_fs_nodes[CLKS_FS_MAX_NODES];
|
||||
static u16 clks_fs_nodes_used = 0U;
|
||||
static clks_bool clks_fs_ready = CLKS_FALSE;
|
||||
static const u8 clks_fs_empty_file_data[1] = {0U};
|
||||
|
||||
static clks_bool clks_fs_normalize_external_path(const char *path, char *out_internal, usize out_size) {
|
||||
usize in_pos = 0;
|
||||
usize out_pos = 0;
|
||||
|
||||
if (path == CLKS_NULL || out_internal == CLKS_NULL || out_size == 0U) {
|
||||
return CLKS_FALSE;
|
||||
}
|
||||
|
||||
if (path[0] != '/') {
|
||||
return CLKS_FALSE;
|
||||
}
|
||||
|
||||
while (path[in_pos] == '/') {
|
||||
in_pos++;
|
||||
}
|
||||
|
||||
/* Normalize aggressively; weird paths are where bugs and exploits like to party. */
|
||||
while (path[in_pos] != '\0') {
|
||||
usize comp_start = in_pos;
|
||||
usize comp_len;
|
||||
|
||||
while (path[in_pos] != '\0' && path[in_pos] != '/') {
|
||||
in_pos++;
|
||||
}
|
||||
|
||||
comp_len = in_pos - comp_start;
|
||||
|
||||
if (comp_len == 0U) {
|
||||
while (path[in_pos] == '/') {
|
||||
in_pos++;
|
||||
}
|
||||
continue;
|
||||
}
|
||||
|
||||
if (comp_len == 1U && path[comp_start] == '.') {
|
||||
while (path[in_pos] == '/') {
|
||||
in_pos++;
|
||||
}
|
||||
continue;
|
||||
}
|
||||
|
||||
/* No parent traversal here. Not today, not ever. */
|
||||
if (comp_len == 2U && path[comp_start] == '.' && path[comp_start + 1U] == '.') {
|
||||
return CLKS_FALSE;
|
||||
}
|
||||
|
||||
if (out_pos != 0U) {
|
||||
if (out_pos + 1U >= out_size) {
|
||||
return CLKS_FALSE;
|
||||
}
|
||||
out_internal[out_pos++] = '/';
|
||||
}
|
||||
|
||||
if (out_pos + comp_len >= out_size) {
|
||||
return CLKS_FALSE;
|
||||
}
|
||||
|
||||
clks_memcpy(out_internal + out_pos, path + comp_start, comp_len);
|
||||
out_pos += comp_len;
|
||||
|
||||
while (path[in_pos] == '/') {
|
||||
in_pos++;
|
||||
}
|
||||
}
|
||||
|
||||
out_internal[out_pos] = '\0';
|
||||
return CLKS_TRUE;
|
||||
}
|
||||
|
||||
static clks_bool clks_fs_internal_in_temp_tree(const char *internal_path) {
|
||||
/* Write access is fenced into /temp so random code can't trash the world. */
|
||||
if (internal_path == CLKS_NULL) {
|
||||
return CLKS_FALSE;
|
||||
}
|
||||
|
||||
if (internal_path[0] != 't' || internal_path[1] != 'e' || internal_path[2] != 'm' || internal_path[3] != 'p') {
|
||||
return CLKS_FALSE;
|
||||
}
|
||||
|
||||
return (internal_path[4] == '\0' || internal_path[4] == '/') ? CLKS_TRUE : CLKS_FALSE;
|
||||
}
|
||||
|
||||
static clks_bool clks_fs_internal_is_temp_file_path(const char *internal_path) {
|
||||
if (clks_fs_internal_in_temp_tree(internal_path) == CLKS_FALSE) {
|
||||
return CLKS_FALSE;
|
||||
}
|
||||
|
||||
if (internal_path[4] == '\0') {
|
||||
return CLKS_FALSE;
|
||||
}
|
||||
|
||||
return CLKS_TRUE;
|
||||
}
|
||||
|
||||
static i32 clks_fs_find_node_by_internal(const char *internal_path) {
|
||||
u16 i;
|
||||
|
||||
/* Linear scan is boring, but with this node count it's fine as hell. */
|
||||
for (i = 0U; i < clks_fs_nodes_used; i++) {
|
||||
if (clks_fs_nodes[i].used == CLKS_FALSE) {
|
||||
continue;
|
||||
}
|
||||
|
||||
if (clks_strcmp(clks_fs_nodes[i].path, internal_path) == 0) {
|
||||
return (i32)i;
|
||||
}
|
||||
}
|
||||
|
||||
return -1;
|
||||
}
|
||||
|
||||
static i32 clks_fs_find_node_by_external(const char *external_path) {
|
||||
char internal[CLKS_FS_PATH_MAX];
|
||||
|
||||
if (clks_fs_normalize_external_path(external_path, internal, sizeof(internal)) == CLKS_FALSE) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
return clks_fs_find_node_by_internal(internal);
|
||||
}
|
||||
|
||||
static const char *clks_fs_basename(const char *internal_path) {
|
||||
usize len;
|
||||
usize i;
|
||||
|
||||
if (internal_path == CLKS_NULL) {
|
||||
return "";
|
||||
}
|
||||
|
||||
len = clks_strlen(internal_path);
|
||||
|
||||
if (len == 0U) {
|
||||
return "";
|
||||
}
|
||||
|
||||
for (i = len; i != 0U; i--) {
|
||||
if (internal_path[i - 1U] == '/') {
|
||||
return &internal_path[i];
|
||||
}
|
||||
}
|
||||
|
||||
return internal_path;
|
||||
}
|
||||
|
||||
static clks_bool clks_fs_split_parent(const char *internal_path, char *parent_out, usize parent_out_size) {
|
||||
usize len;
|
||||
usize i;
|
||||
|
||||
if (internal_path == CLKS_NULL || parent_out == CLKS_NULL || parent_out_size == 0U) {
|
||||
return CLKS_FALSE;
|
||||
}
|
||||
|
||||
len = clks_strlen(internal_path);
|
||||
|
||||
if (len == 0U) {
|
||||
parent_out[0] = '\0';
|
||||
return CLKS_TRUE;
|
||||
}
|
||||
|
||||
/* Manual split is ugly, but it avoids allocator drama during path ops. */
|
||||
for (i = len; i != 0U; i--) {
|
||||
if (internal_path[i - 1U] == '/') {
|
||||
usize parent_len = i - 1U;
|
||||
|
||||
if (parent_len >= parent_out_size) {
|
||||
return CLKS_FALSE;
|
||||
}
|
||||
|
||||
clks_memcpy(parent_out, internal_path, parent_len);
|
||||
parent_out[parent_len] = '\0';
|
||||
return CLKS_TRUE;
|
||||
}
|
||||
}
|
||||
|
||||
parent_out[0] = '\0';
|
||||
return CLKS_TRUE;
|
||||
}
|
||||
|
||||
static clks_bool clks_fs_node_has_heap_data(u16 index) {
|
||||
return ((clks_fs_nodes[index].reserved & CLKS_FS_NODE_FLAG_HEAP_DATA) != 0U) ? CLKS_TRUE : CLKS_FALSE;
|
||||
}
|
||||
|
||||
static void clks_fs_node_set_heap_data(u16 index, clks_bool value) {
|
||||
if (value == CLKS_TRUE) {
|
||||
clks_fs_nodes[index].reserved |= CLKS_FS_NODE_FLAG_HEAP_DATA;
|
||||
} else {
|
||||
clks_fs_nodes[index].reserved &= (u16)(~CLKS_FS_NODE_FLAG_HEAP_DATA);
|
||||
}
|
||||
}
|
||||
|
||||
static void clks_fs_node_release_heap_data(u16 index) {
|
||||
if (clks_fs_nodes[index].type != CLKS_FS_NODE_FILE) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (clks_fs_node_has_heap_data(index) == CLKS_TRUE && clks_fs_nodes[index].data != CLKS_NULL) {
|
||||
clks_kfree((void *)clks_fs_nodes[index].data);
|
||||
}
|
||||
|
||||
clks_fs_node_set_heap_data(index, CLKS_FALSE);
|
||||
}
|
||||
|
||||
static i32 clks_fs_alloc_slot(void) {
|
||||
u16 i;
|
||||
|
||||
for (i = 0U; i < clks_fs_nodes_used; i++) {
|
||||
if (clks_fs_nodes[i].used == CLKS_FALSE) {
|
||||
return (i32)i;
|
||||
}
|
||||
}
|
||||
|
||||
if (clks_fs_nodes_used >= CLKS_FS_MAX_NODES) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
clks_fs_nodes_used++;
|
||||
return (i32)(clks_fs_nodes_used - 1U);
|
||||
}
|
||||
|
||||
static i32 clks_fs_create_or_update_node(const char *internal_path, enum clks_fs_node_type type, u16 parent,
|
||||
const void *data, u64 size) {
|
||||
i32 existing;
|
||||
i32 slot;
|
||||
usize path_len;
|
||||
|
||||
if (internal_path == CLKS_NULL) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
path_len = clks_strlen(internal_path);
|
||||
|
||||
if (path_len >= CLKS_FS_PATH_MAX) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
existing = clks_fs_find_node_by_internal(internal_path);
|
||||
|
||||
if (existing >= 0) {
|
||||
struct clks_fs_node *node = &clks_fs_nodes[(u16)existing];
|
||||
|
||||
if (node->type != type) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
node->parent = parent;
|
||||
|
||||
if (type == CLKS_FS_NODE_FILE) {
|
||||
node->data = data;
|
||||
node->size = size;
|
||||
node->reserved = 0U;
|
||||
}
|
||||
|
||||
node->used = CLKS_TRUE;
|
||||
return existing;
|
||||
}
|
||||
|
||||
slot = clks_fs_alloc_slot();
|
||||
|
||||
if (slot < 0) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
clks_fs_nodes[(u16)slot].used = CLKS_TRUE;
|
||||
clks_fs_nodes[(u16)slot].type = type;
|
||||
clks_fs_nodes[(u16)slot].parent = parent;
|
||||
clks_fs_nodes[(u16)slot].reserved = 0U;
|
||||
clks_fs_nodes[(u16)slot].data = (type == CLKS_FS_NODE_FILE) ? data : CLKS_NULL;
|
||||
clks_fs_nodes[(u16)slot].size = (type == CLKS_FS_NODE_FILE) ? size : 0ULL;
|
||||
clks_memcpy(clks_fs_nodes[(u16)slot].path, internal_path, path_len + 1U);
|
||||
|
||||
return slot;
|
||||
}
|
||||
|
||||
static clks_bool clks_fs_ensure_root(void) {
|
||||
if (clks_fs_create_or_update_node("", CLKS_FS_NODE_DIR, 0U, CLKS_NULL, 0ULL) != 0) {
|
||||
return CLKS_FALSE;
|
||||
}
|
||||
|
||||
return CLKS_TRUE;
|
||||
}
|
||||
|
||||
static clks_bool clks_fs_ensure_dir_hierarchy(const char *internal_dir_path) {
|
||||
char prefix[CLKS_FS_PATH_MAX];
|
||||
usize cursor = 0;
|
||||
usize i = 0;
|
||||
u16 current_parent = 0U;
|
||||
|
||||
prefix[0] = '\0';
|
||||
|
||||
if (internal_dir_path == CLKS_NULL) {
|
||||
return CLKS_FALSE;
|
||||
}
|
||||
|
||||
if (internal_dir_path[0] == '\0') {
|
||||
return CLKS_TRUE;
|
||||
}
|
||||
|
||||
while (internal_dir_path[i] != '\0') {
|
||||
usize comp_start = i;
|
||||
usize comp_len;
|
||||
i32 node_index;
|
||||
|
||||
while (internal_dir_path[i] != '\0' && internal_dir_path[i] != '/') {
|
||||
i++;
|
||||
}
|
||||
|
||||
comp_len = i - comp_start;
|
||||
|
||||
if (comp_len == 0U) {
|
||||
return CLKS_FALSE;
|
||||
}
|
||||
|
||||
if (cursor != 0U) {
|
||||
if (cursor + 1U >= sizeof(prefix)) {
|
||||
return CLKS_FALSE;
|
||||
}
|
||||
prefix[cursor++] = '/';
|
||||
}
|
||||
|
||||
if (cursor + comp_len >= sizeof(prefix)) {
|
||||
return CLKS_FALSE;
|
||||
}
|
||||
|
||||
clks_memcpy(prefix + cursor, internal_dir_path + comp_start, comp_len);
|
||||
cursor += comp_len;
|
||||
prefix[cursor] = '\0';
|
||||
|
||||
node_index = clks_fs_find_node_by_internal(prefix);
|
||||
|
||||
if (node_index < 0) {
|
||||
node_index = clks_fs_create_or_update_node(prefix, CLKS_FS_NODE_DIR, current_parent, CLKS_NULL, 0ULL);
|
||||
|
||||
if (node_index < 0) {
|
||||
return CLKS_FALSE;
|
||||
}
|
||||
} else if (clks_fs_nodes[(u16)node_index].type != CLKS_FS_NODE_DIR) {
|
||||
return CLKS_FALSE;
|
||||
}
|
||||
|
||||
current_parent = (u16)node_index;
|
||||
|
||||
if (internal_dir_path[i] == '/') {
|
||||
i++;
|
||||
}
|
||||
}
|
||||
|
||||
return CLKS_TRUE;
|
||||
}
|
||||
|
||||
static clks_bool clks_fs_require_directory(const char *external_path) {
|
||||
i32 node_index = clks_fs_find_node_by_external(external_path);
|
||||
|
||||
if (node_index < 0) {
|
||||
clks_log(CLKS_LOG_ERROR, "FS", "MISSING REQUIRED DIRECTORY");
|
||||
clks_log(CLKS_LOG_ERROR, "FS", external_path);
|
||||
return CLKS_FALSE;
|
||||
}
|
||||
|
||||
if (clks_fs_nodes[(u16)node_index].type != CLKS_FS_NODE_DIR) {
|
||||
clks_log(CLKS_LOG_ERROR, "FS", "REQUIRED PATH IS NOT DIRECTORY");
|
||||
clks_log(CLKS_LOG_ERROR, "FS", external_path);
|
||||
return CLKS_FALSE;
|
||||
}
|
||||
|
||||
return CLKS_TRUE;
|
||||
}
|
||||
|
||||
static clks_bool clks_fs_ramdisk_visit(const struct clks_ramdisk_entry *entry, void *ctx) {
|
||||
struct clks_fs_build_stats *stats = (struct clks_fs_build_stats *)ctx;
|
||||
|
||||
if (entry == CLKS_NULL || stats == CLKS_NULL) {
|
||||
return CLKS_FALSE;
|
||||
}
|
||||
|
||||
if (entry->type == CLKS_RAMDISK_ENTRY_DIR) {
|
||||
if (clks_fs_ensure_dir_hierarchy(entry->path) == CLKS_FALSE) {
|
||||
return CLKS_FALSE;
|
||||
}
|
||||
|
||||
stats->dir_count++;
|
||||
return CLKS_TRUE;
|
||||
}
|
||||
|
||||
if (entry->type == CLKS_RAMDISK_ENTRY_FILE) {
|
||||
char parent[CLKS_FS_PATH_MAX];
|
||||
i32 parent_index;
|
||||
|
||||
if (clks_fs_split_parent(entry->path, parent, sizeof(parent)) == CLKS_FALSE) {
|
||||
return CLKS_FALSE;
|
||||
}
|
||||
|
||||
if (clks_fs_ensure_dir_hierarchy(parent) == CLKS_FALSE) {
|
||||
return CLKS_FALSE;
|
||||
}
|
||||
|
||||
parent_index = clks_fs_find_node_by_internal(parent);
|
||||
|
||||
if (parent_index < 0) {
|
||||
return CLKS_FALSE;
|
||||
}
|
||||
|
||||
if (clks_fs_create_or_update_node(entry->path, CLKS_FS_NODE_FILE, (u16)parent_index, entry->data, entry->size) <
|
||||
0) {
|
||||
return CLKS_FALSE;
|
||||
}
|
||||
|
||||
stats->file_count++;
|
||||
return CLKS_TRUE;
|
||||
}
|
||||
|
||||
return CLKS_TRUE;
|
||||
}
|
||||
|
||||
static clks_bool clks_fs_build_file_payload(const void *data, u64 size, const void **out_data,
|
||||
clks_bool *out_heap_owned) {
|
||||
void *payload;
|
||||
|
||||
if (out_data == CLKS_NULL || out_heap_owned == CLKS_NULL) {
|
||||
return CLKS_FALSE;
|
||||
}
|
||||
|
||||
if (size == 0ULL) {
|
||||
*out_data = (const void *)clks_fs_empty_file_data;
|
||||
*out_heap_owned = CLKS_FALSE;
|
||||
return CLKS_TRUE;
|
||||
}
|
||||
|
||||
if (data == CLKS_NULL) {
|
||||
return CLKS_FALSE;
|
||||
}
|
||||
|
||||
payload = clks_kmalloc((usize)size);
|
||||
|
||||
if (payload == CLKS_NULL) {
|
||||
return CLKS_FALSE;
|
||||
}
|
||||
|
||||
clks_memcpy(payload, data, (usize)size);
|
||||
*out_data = (const void *)payload;
|
||||
*out_heap_owned = CLKS_TRUE;
|
||||
return CLKS_TRUE;
|
||||
}
|
||||
|
||||
void clks_fs_init(void) {
|
||||
const struct limine_file *module;
|
||||
struct clks_fs_build_stats stats;
|
||||
u64 module_count;
|
||||
|
||||
clks_fs_ready = CLKS_FALSE;
|
||||
clks_fs_nodes_used = 0U;
|
||||
clks_memset(clks_fs_nodes, 0, sizeof(clks_fs_nodes));
|
||||
clks_memset(&stats, 0, sizeof(stats));
|
||||
|
||||
if (clks_fs_ensure_root() == CLKS_FALSE) {
|
||||
clks_log(CLKS_LOG_ERROR, "FS", "FAILED TO CREATE ROOT NODE");
|
||||
return;
|
||||
}
|
||||
|
||||
module_count = clks_boot_get_module_count();
|
||||
|
||||
if (module_count == 0ULL) {
|
||||
clks_log(CLKS_LOG_ERROR, "FS", "NO RAMDISK MODULE FROM LIMINE");
|
||||
return;
|
||||
}
|
||||
|
||||
module = clks_boot_get_module(0ULL);
|
||||
|
||||
if (module == CLKS_NULL || module->address == CLKS_NULL || module->size == 0ULL) {
|
||||
clks_log(CLKS_LOG_ERROR, "FS", "INVALID RAMDISK MODULE");
|
||||
return;
|
||||
}
|
||||
|
||||
if (clks_ramdisk_iterate(module->address, module->size, clks_fs_ramdisk_visit, &stats) == CLKS_FALSE) {
|
||||
clks_log(CLKS_LOG_ERROR, "FS", "RAMDISK TAR PARSE FAILED");
|
||||
return;
|
||||
}
|
||||
|
||||
clks_log(CLKS_LOG_INFO, "FS", "RAMDISK VFS ONLINE");
|
||||
clks_log_hex(CLKS_LOG_INFO, "FS", "MODULE_SIZE", module->size);
|
||||
clks_log_hex(CLKS_LOG_INFO, "FS", "NODE_COUNT", (u64)clks_fs_nodes_used);
|
||||
clks_log_hex(CLKS_LOG_INFO, "FS", "FILE_COUNT", stats.file_count);
|
||||
|
||||
clks_disk_init();
|
||||
if (clks_disk_present() == CLKS_TRUE) {
|
||||
clks_log_hex(CLKS_LOG_INFO, "FS", "DISK_BYTES", clks_disk_size_bytes());
|
||||
clks_log_hex(CLKS_LOG_INFO, "FS", "DISK_FAT32", (clks_disk_is_formatted_fat32() == CLKS_TRUE) ? 1ULL : 0ULL);
|
||||
} else {
|
||||
clks_log(CLKS_LOG_WARN, "FS", "DISK BACKEND NOT PRESENT");
|
||||
}
|
||||
|
||||
if (clks_fs_require_directory("/system") == CLKS_FALSE) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (clks_fs_require_directory("/shell") == CLKS_FALSE) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (clks_fs_require_directory("/temp") == CLKS_FALSE) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (clks_fs_require_directory("/driver") == CLKS_FALSE) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (clks_fs_require_directory("/dev") == CLKS_FALSE) {
|
||||
return;
|
||||
}
|
||||
|
||||
clks_fs_ready = CLKS_TRUE;
|
||||
clks_log(CLKS_LOG_INFO, "FS", "LAYOUT /SYSTEM /SHELL /TEMP /DRIVER /DEV OK");
|
||||
}
|
||||
|
||||
clks_bool clks_fs_is_ready(void) {
|
||||
return clks_fs_ready;
|
||||
}
|
||||
|
||||
clks_bool clks_fs_stat(const char *path, struct clks_fs_node_info *out_info) {
|
||||
i32 node_index;
|
||||
u64 disk_type = 0ULL;
|
||||
u64 disk_size = 0ULL;
|
||||
|
||||
if (clks_fs_ready == CLKS_FALSE || out_info == CLKS_NULL) {
|
||||
return CLKS_FALSE;
|
||||
}
|
||||
|
||||
if (clks_disk_path_in_mount(path) == CLKS_TRUE) {
|
||||
if (clks_disk_stat(path, &disk_type, &disk_size) == CLKS_FALSE) {
|
||||
return CLKS_FALSE;
|
||||
}
|
||||
|
||||
out_info->type = (disk_type == CLKS_DISK_NODE_DIR) ? CLKS_FS_NODE_DIR : CLKS_FS_NODE_FILE;
|
||||
out_info->size = disk_size;
|
||||
return CLKS_TRUE;
|
||||
}
|
||||
|
||||
node_index = clks_fs_find_node_by_external(path);
|
||||
|
||||
if (node_index < 0) {
|
||||
return CLKS_FALSE;
|
||||
}
|
||||
|
||||
out_info->type = clks_fs_nodes[(u16)node_index].type;
|
||||
out_info->size = clks_fs_nodes[(u16)node_index].size;
|
||||
return CLKS_TRUE;
|
||||
}
|
||||
|
||||
const void *clks_fs_read_all(const char *path, u64 *out_size) {
|
||||
i32 node_index;
|
||||
const void *disk_data;
|
||||
|
||||
if (clks_fs_ready == CLKS_FALSE) {
|
||||
return CLKS_NULL;
|
||||
}
|
||||
|
||||
if (clks_disk_path_in_mount(path) == CLKS_TRUE) {
|
||||
disk_data = clks_disk_read_all(path, out_size);
|
||||
return disk_data;
|
||||
}
|
||||
|
||||
node_index = clks_fs_find_node_by_external(path);
|
||||
|
||||
if (node_index < 0) {
|
||||
return CLKS_NULL;
|
||||
}
|
||||
|
||||
if (clks_fs_nodes[(u16)node_index].type != CLKS_FS_NODE_FILE) {
|
||||
return CLKS_NULL;
|
||||
}
|
||||
|
||||
if (out_size != CLKS_NULL) {
|
||||
*out_size = clks_fs_nodes[(u16)node_index].size;
|
||||
}
|
||||
|
||||
if (clks_fs_nodes[(u16)node_index].size == 0ULL) {
|
||||
return (const void *)clks_fs_empty_file_data;
|
||||
}
|
||||
|
||||
return clks_fs_nodes[(u16)node_index].data;
|
||||
}
|
||||
|
||||
u64 clks_fs_count_children(const char *dir_path) {
|
||||
i32 dir_index;
|
||||
u64 count = 0ULL;
|
||||
u16 i;
|
||||
|
||||
if (clks_fs_ready == CLKS_FALSE) {
|
||||
return 0ULL;
|
||||
}
|
||||
|
||||
if (clks_disk_path_in_mount(dir_path) == CLKS_TRUE) {
|
||||
return clks_disk_count_children(dir_path);
|
||||
}
|
||||
|
||||
dir_index = clks_fs_find_node_by_external(dir_path);
|
||||
|
||||
if (dir_index < 0) {
|
||||
return 0ULL;
|
||||
}
|
||||
|
||||
if (clks_fs_nodes[(u16)dir_index].type != CLKS_FS_NODE_DIR) {
|
||||
return 0ULL;
|
||||
}
|
||||
|
||||
for (i = 0U; i < clks_fs_nodes_used; i++) {
|
||||
if (clks_fs_nodes[i].used == CLKS_FALSE) {
|
||||
continue;
|
||||
}
|
||||
|
||||
if ((u16)dir_index == i) {
|
||||
continue;
|
||||
}
|
||||
|
||||
if (clks_fs_nodes[i].parent == (u16)dir_index) {
|
||||
count++;
|
||||
}
|
||||
}
|
||||
|
||||
return count;
|
||||
}
|
||||
|
||||
clks_bool clks_fs_get_child_name(const char *dir_path, u64 index, char *out_name, usize out_name_size) {
|
||||
i32 dir_index;
|
||||
u64 current = 0ULL;
|
||||
u16 i;
|
||||
|
||||
if (clks_fs_ready == CLKS_FALSE || out_name == CLKS_NULL || out_name_size == 0U) {
|
||||
return CLKS_FALSE;
|
||||
}
|
||||
|
||||
if (clks_disk_path_in_mount(dir_path) == CLKS_TRUE) {
|
||||
return clks_disk_get_child_name(dir_path, index, out_name, out_name_size);
|
||||
}
|
||||
|
||||
dir_index = clks_fs_find_node_by_external(dir_path);
|
||||
|
||||
if (dir_index < 0 || clks_fs_nodes[(u16)dir_index].type != CLKS_FS_NODE_DIR) {
|
||||
return CLKS_FALSE;
|
||||
}
|
||||
|
||||
for (i = 0U; i < clks_fs_nodes_used; i++) {
|
||||
const char *base;
|
||||
usize base_len;
|
||||
|
||||
if (clks_fs_nodes[i].used == CLKS_FALSE) {
|
||||
continue;
|
||||
}
|
||||
|
||||
if ((u16)dir_index == i) {
|
||||
continue;
|
||||
}
|
||||
|
||||
if (clks_fs_nodes[i].parent != (u16)dir_index) {
|
||||
continue;
|
||||
}
|
||||
|
||||
if (current != index) {
|
||||
current++;
|
||||
continue;
|
||||
}
|
||||
|
||||
base = clks_fs_basename(clks_fs_nodes[i].path);
|
||||
base_len = clks_strlen(base);
|
||||
|
||||
if (base_len + 1U > out_name_size) {
|
||||
return CLKS_FALSE;
|
||||
}
|
||||
|
||||
clks_memcpy(out_name, base, base_len + 1U);
|
||||
return CLKS_TRUE;
|
||||
}
|
||||
|
||||
return CLKS_FALSE;
|
||||
}
|
||||
|
||||
clks_bool clks_fs_mkdir(const char *path) {
|
||||
char internal[CLKS_FS_PATH_MAX];
|
||||
i32 node_index;
|
||||
|
||||
if (clks_fs_ready == CLKS_FALSE || path == CLKS_NULL) {
|
||||
return CLKS_FALSE;
|
||||
}
|
||||
|
||||
if (clks_disk_path_in_mount(path) == CLKS_TRUE) {
|
||||
return clks_disk_mkdir(path);
|
||||
}
|
||||
|
||||
if (clks_fs_normalize_external_path(path, internal, sizeof(internal)) == CLKS_FALSE) {
|
||||
return CLKS_FALSE;
|
||||
}
|
||||
|
||||
if (clks_fs_internal_in_temp_tree(internal) == CLKS_FALSE) {
|
||||
return CLKS_FALSE;
|
||||
}
|
||||
|
||||
if (internal[0] == '\0') {
|
||||
return CLKS_FALSE;
|
||||
}
|
||||
|
||||
if (clks_fs_ensure_dir_hierarchy(internal) == CLKS_FALSE) {
|
||||
return CLKS_FALSE;
|
||||
}
|
||||
|
||||
node_index = clks_fs_find_node_by_internal(internal);
|
||||
|
||||
if (node_index < 0) {
|
||||
return CLKS_FALSE;
|
||||
}
|
||||
|
||||
return (clks_fs_nodes[(u16)node_index].type == CLKS_FS_NODE_DIR) ? CLKS_TRUE : CLKS_FALSE;
|
||||
}
|
||||
|
||||
clks_bool clks_fs_write_all(const char *path, const void *data, u64 size) {
|
||||
char internal[CLKS_FS_PATH_MAX];
|
||||
char parent[CLKS_FS_PATH_MAX];
|
||||
const void *payload_data = CLKS_NULL;
|
||||
clks_bool payload_heap_owned = CLKS_FALSE;
|
||||
i32 parent_index;
|
||||
i32 node_index;
|
||||
|
||||
if (clks_fs_ready == CLKS_FALSE || path == CLKS_NULL) {
|
||||
return CLKS_FALSE;
|
||||
}
|
||||
|
||||
if (clks_disk_path_in_mount(path) == CLKS_TRUE) {
|
||||
return clks_disk_write_all(path, data, size);
|
||||
}
|
||||
|
||||
if (clks_fs_normalize_external_path(path, internal, sizeof(internal)) == CLKS_FALSE) {
|
||||
return CLKS_FALSE;
|
||||
}
|
||||
|
||||
if (clks_fs_internal_is_temp_file_path(internal) == CLKS_FALSE) {
|
||||
return CLKS_FALSE;
|
||||
}
|
||||
|
||||
if (clks_fs_split_parent(internal, parent, sizeof(parent)) == CLKS_FALSE) {
|
||||
return CLKS_FALSE;
|
||||
}
|
||||
|
||||
if (clks_fs_internal_in_temp_tree(parent) == CLKS_FALSE) {
|
||||
return CLKS_FALSE;
|
||||
}
|
||||
|
||||
if (clks_fs_ensure_dir_hierarchy(parent) == CLKS_FALSE) {
|
||||
return CLKS_FALSE;
|
||||
}
|
||||
|
||||
parent_index = clks_fs_find_node_by_internal(parent);
|
||||
|
||||
if (parent_index < 0 || clks_fs_nodes[(u16)parent_index].type != CLKS_FS_NODE_DIR) {
|
||||
return CLKS_FALSE;
|
||||
}
|
||||
|
||||
node_index = clks_fs_find_node_by_internal(internal);
|
||||
|
||||
if (node_index >= 0 && clks_fs_nodes[(u16)node_index].type != CLKS_FS_NODE_FILE) {
|
||||
return CLKS_FALSE;
|
||||
}
|
||||
|
||||
if (clks_fs_build_file_payload(data, size, &payload_data, &payload_heap_owned) == CLKS_FALSE) {
|
||||
return CLKS_FALSE;
|
||||
}
|
||||
|
||||
if (node_index >= 0) {
|
||||
clks_fs_node_release_heap_data((u16)node_index);
|
||||
}
|
||||
|
||||
node_index = clks_fs_create_or_update_node(internal, CLKS_FS_NODE_FILE, (u16)parent_index, payload_data, size);
|
||||
|
||||
if (node_index < 0) {
|
||||
if (payload_heap_owned == CLKS_TRUE) {
|
||||
clks_kfree((void *)payload_data);
|
||||
}
|
||||
return CLKS_FALSE;
|
||||
}
|
||||
|
||||
clks_fs_node_set_heap_data((u16)node_index, payload_heap_owned);
|
||||
return CLKS_TRUE;
|
||||
}
|
||||
|
||||
clks_bool clks_fs_append(const char *path, const void *data, u64 size) {
|
||||
char internal[CLKS_FS_PATH_MAX];
|
||||
i32 node_index;
|
||||
const void *old_data;
|
||||
u64 old_size;
|
||||
u64 new_size;
|
||||
void *merged = CLKS_NULL;
|
||||
|
||||
if (clks_fs_ready == CLKS_FALSE || path == CLKS_NULL) {
|
||||
return CLKS_FALSE;
|
||||
}
|
||||
|
||||
if (clks_disk_path_in_mount(path) == CLKS_TRUE) {
|
||||
return clks_disk_append(path, data, size);
|
||||
}
|
||||
|
||||
if (size > 0ULL && data == CLKS_NULL) {
|
||||
return CLKS_FALSE;
|
||||
}
|
||||
|
||||
if (clks_fs_normalize_external_path(path, internal, sizeof(internal)) == CLKS_FALSE) {
|
||||
return CLKS_FALSE;
|
||||
}
|
||||
|
||||
if (clks_fs_internal_is_temp_file_path(internal) == CLKS_FALSE) {
|
||||
return CLKS_FALSE;
|
||||
}
|
||||
|
||||
node_index = clks_fs_find_node_by_internal(internal);
|
||||
|
||||
if (node_index < 0) {
|
||||
return clks_fs_write_all(path, data, size);
|
||||
}
|
||||
|
||||
if (clks_fs_nodes[(u16)node_index].type != CLKS_FS_NODE_FILE) {
|
||||
return CLKS_FALSE;
|
||||
}
|
||||
|
||||
old_data = clks_fs_nodes[(u16)node_index].data;
|
||||
old_size = clks_fs_nodes[(u16)node_index].size;
|
||||
|
||||
if (old_size > (0xFFFFFFFFFFFFFFFFULL - size)) {
|
||||
return CLKS_FALSE;
|
||||
}
|
||||
|
||||
new_size = old_size + size;
|
||||
|
||||
if (new_size == 0ULL) {
|
||||
return clks_fs_write_all(path, clks_fs_empty_file_data, 0ULL);
|
||||
}
|
||||
|
||||
merged = clks_kmalloc((usize)new_size);
|
||||
|
||||
if (merged == CLKS_NULL) {
|
||||
return CLKS_FALSE;
|
||||
}
|
||||
|
||||
if (old_size > 0ULL && old_data != CLKS_NULL) {
|
||||
clks_memcpy(merged, old_data, (usize)old_size);
|
||||
}
|
||||
|
||||
if (size > 0ULL) {
|
||||
clks_memcpy((u8 *)merged + (usize)old_size, data, (usize)size);
|
||||
}
|
||||
if (clks_fs_write_all(path, merged, new_size) == CLKS_FALSE) {
|
||||
clks_kfree(merged);
|
||||
return CLKS_FALSE;
|
||||
}
|
||||
|
||||
clks_kfree(merged);
|
||||
return CLKS_TRUE;
|
||||
}
|
||||
|
||||
clks_bool clks_fs_remove(const char *path) {
|
||||
char internal[CLKS_FS_PATH_MAX];
|
||||
i32 node_index;
|
||||
u16 i;
|
||||
|
||||
if (clks_fs_ready == CLKS_FALSE || path == CLKS_NULL) {
|
||||
return CLKS_FALSE;
|
||||
}
|
||||
|
||||
if (clks_disk_path_in_mount(path) == CLKS_TRUE) {
|
||||
return clks_disk_remove(path);
|
||||
}
|
||||
|
||||
if (clks_fs_normalize_external_path(path, internal, sizeof(internal)) == CLKS_FALSE) {
|
||||
return CLKS_FALSE;
|
||||
}
|
||||
|
||||
if (clks_fs_internal_in_temp_tree(internal) == CLKS_FALSE) {
|
||||
return CLKS_FALSE;
|
||||
}
|
||||
|
||||
if (clks_strcmp(internal, "temp") == 0) {
|
||||
return CLKS_FALSE;
|
||||
}
|
||||
|
||||
node_index = clks_fs_find_node_by_internal(internal);
|
||||
|
||||
if (node_index < 0) {
|
||||
return CLKS_FALSE;
|
||||
}
|
||||
|
||||
if (clks_fs_nodes[(u16)node_index].type == CLKS_FS_NODE_DIR) {
|
||||
for (i = 0U; i < clks_fs_nodes_used; i++) {
|
||||
if (clks_fs_nodes[i].used == CLKS_FALSE) {
|
||||
continue;
|
||||
}
|
||||
|
||||
if (clks_fs_nodes[i].parent == (u16)node_index) {
|
||||
return CLKS_FALSE;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
clks_fs_node_release_heap_data((u16)node_index);
|
||||
|
||||
clks_fs_nodes[(u16)node_index].used = CLKS_FALSE;
|
||||
clks_fs_nodes[(u16)node_index].type = CLKS_FS_NODE_FILE;
|
||||
clks_fs_nodes[(u16)node_index].parent = 0U;
|
||||
clks_fs_nodes[(u16)node_index].reserved = 0U;
|
||||
clks_fs_nodes[(u16)node_index].data = CLKS_NULL;
|
||||
clks_fs_nodes[(u16)node_index].size = 0ULL;
|
||||
clks_fs_nodes[(u16)node_index].path[0] = '\0';
|
||||
|
||||
return CLKS_TRUE;
|
||||
}
|
||||
|
||||
u64 clks_fs_node_count(void) {
|
||||
u16 i;
|
||||
u64 used = 0ULL;
|
||||
|
||||
if (clks_fs_ready == CLKS_FALSE) {
|
||||
return 0ULL;
|
||||
}
|
||||
|
||||
for (i = 0U; i < clks_fs_nodes_used; i++) {
|
||||
if (clks_fs_nodes[i].used == CLKS_TRUE) {
|
||||
used++;
|
||||
}
|
||||
}
|
||||
|
||||
if (clks_disk_is_mounted() == CLKS_TRUE) {
|
||||
used += clks_disk_node_count();
|
||||
}
|
||||
|
||||
return used;
|
||||
}
|
||||
221
clks.local.bak/kernel/storage/ramdisk.c
Normal file
221
clks.local.bak/kernel/storage/ramdisk.c
Normal file
@@ -0,0 +1,221 @@
|
||||
#include <clks/compiler.h>
|
||||
#include <clks/ramdisk.h>
|
||||
#include <clks/string.h>
|
||||
#include <clks/types.h>
|
||||
|
||||
#define CLKS_TAR_BLOCK_SIZE 512ULL
|
||||
|
||||
struct clks_tar_header {
|
||||
char name[100];
|
||||
char mode[8];
|
||||
char uid[8];
|
||||
char gid[8];
|
||||
char size[12];
|
||||
char mtime[12];
|
||||
char chksum[8];
|
||||
char typeflag;
|
||||
char linkname[100];
|
||||
char magic[6];
|
||||
char version[2];
|
||||
char uname[32];
|
||||
char gname[32];
|
||||
char devmajor[8];
|
||||
char devminor[8];
|
||||
char prefix[155];
|
||||
char pad[12];
|
||||
} CLKS_PACKED;
|
||||
|
||||
static clks_bool clks_ramdisk_is_zero_block(const u8 *block) {
|
||||
u64 i;
|
||||
|
||||
for (i = 0; i < CLKS_TAR_BLOCK_SIZE; i++) {
|
||||
if (block[i] != 0U) {
|
||||
return CLKS_FALSE;
|
||||
}
|
||||
}
|
||||
|
||||
return CLKS_TRUE;
|
||||
}
|
||||
|
||||
static usize clks_ramdisk_field_len(const char *field, usize max_len) {
|
||||
usize i = 0;
|
||||
|
||||
while (i < max_len && field[i] != '\0') {
|
||||
i++;
|
||||
}
|
||||
|
||||
return i;
|
||||
}
|
||||
|
||||
static clks_bool clks_ramdisk_parse_octal_u64(const char *field, usize len, u64 *out_value) {
|
||||
usize i = 0;
|
||||
u64 value = 0ULL;
|
||||
|
||||
if (out_value == CLKS_NULL) {
|
||||
return CLKS_FALSE;
|
||||
}
|
||||
|
||||
while (i < len && (field[i] == ' ' || field[i] == '\0')) {
|
||||
i++;
|
||||
}
|
||||
|
||||
for (; i < len; i++) {
|
||||
char ch = field[i];
|
||||
|
||||
if (ch == ' ' || ch == '\0') {
|
||||
break;
|
||||
}
|
||||
|
||||
if (ch < '0' || ch > '7') {
|
||||
return CLKS_FALSE;
|
||||
}
|
||||
|
||||
if (value > (0xffffffffffffffffULL >> 3)) {
|
||||
return CLKS_FALSE;
|
||||
}
|
||||
|
||||
value = (value << 3) + (u64)(ch - '0');
|
||||
}
|
||||
|
||||
*out_value = value;
|
||||
return CLKS_TRUE;
|
||||
}
|
||||
|
||||
static clks_bool clks_ramdisk_build_path(const struct clks_tar_header *hdr, char *out_path, usize out_path_size) {
|
||||
char raw[CLKS_RAMDISK_PATH_MAX];
|
||||
usize prefix_len;
|
||||
usize name_len;
|
||||
usize cursor = 0;
|
||||
usize read_pos = 0;
|
||||
usize out_cursor = 0;
|
||||
|
||||
if (hdr == CLKS_NULL || out_path == CLKS_NULL || out_path_size == 0U) {
|
||||
return CLKS_FALSE;
|
||||
}
|
||||
|
||||
raw[0] = '\0';
|
||||
out_path[0] = '\0';
|
||||
|
||||
prefix_len = clks_ramdisk_field_len(hdr->prefix, sizeof(hdr->prefix));
|
||||
name_len = clks_ramdisk_field_len(hdr->name, sizeof(hdr->name));
|
||||
|
||||
if (name_len == 0U) {
|
||||
return CLKS_FALSE;
|
||||
}
|
||||
|
||||
if (prefix_len != 0U) {
|
||||
if (prefix_len + 1U >= sizeof(raw)) {
|
||||
return CLKS_FALSE;
|
||||
}
|
||||
|
||||
clks_memcpy(raw, hdr->prefix, prefix_len);
|
||||
cursor = prefix_len;
|
||||
raw[cursor++] = '/';
|
||||
}
|
||||
|
||||
if (cursor + name_len >= sizeof(raw)) {
|
||||
return CLKS_FALSE;
|
||||
}
|
||||
|
||||
clks_memcpy(raw + cursor, hdr->name, name_len);
|
||||
cursor += name_len;
|
||||
raw[cursor] = '\0';
|
||||
|
||||
while ((raw[read_pos] == '.' && raw[read_pos + 1U] == '/') || raw[read_pos] == '/') {
|
||||
if (raw[read_pos] == '.') {
|
||||
read_pos += 2U;
|
||||
} else {
|
||||
read_pos++;
|
||||
}
|
||||
}
|
||||
|
||||
while (raw[read_pos] != '\0' && out_cursor + 1U < out_path_size) {
|
||||
out_path[out_cursor++] = raw[read_pos++];
|
||||
}
|
||||
|
||||
if (raw[read_pos] != '\0') {
|
||||
return CLKS_FALSE;
|
||||
}
|
||||
|
||||
while (out_cursor > 0U && out_path[out_cursor - 1U] == '/') {
|
||||
out_cursor--;
|
||||
}
|
||||
|
||||
out_path[out_cursor] = '\0';
|
||||
|
||||
if (out_cursor == 0U) {
|
||||
return CLKS_FALSE;
|
||||
}
|
||||
|
||||
return CLKS_TRUE;
|
||||
}
|
||||
|
||||
clks_bool clks_ramdisk_iterate(const void *image, u64 image_size, clks_ramdisk_iter_fn iter_fn, void *ctx) {
|
||||
const u8 *bytes = (const u8 *)image;
|
||||
u64 offset = 0ULL;
|
||||
|
||||
if (image == CLKS_NULL || iter_fn == CLKS_NULL) {
|
||||
return CLKS_FALSE;
|
||||
}
|
||||
|
||||
while (offset + CLKS_TAR_BLOCK_SIZE <= image_size) {
|
||||
const struct clks_tar_header *hdr;
|
||||
u64 payload_offset;
|
||||
u64 file_size;
|
||||
u64 aligned_size;
|
||||
struct clks_ramdisk_entry entry;
|
||||
clks_bool emit = CLKS_FALSE;
|
||||
|
||||
hdr = (const struct clks_tar_header *)(bytes + offset);
|
||||
|
||||
if (clks_ramdisk_is_zero_block((const u8 *)hdr) == CLKS_TRUE) {
|
||||
break;
|
||||
}
|
||||
|
||||
if (clks_ramdisk_parse_octal_u64(hdr->size, sizeof(hdr->size), &file_size) == CLKS_FALSE) {
|
||||
return CLKS_FALSE;
|
||||
}
|
||||
|
||||
payload_offset = offset + CLKS_TAR_BLOCK_SIZE;
|
||||
|
||||
if (payload_offset > image_size) {
|
||||
return CLKS_FALSE;
|
||||
}
|
||||
|
||||
if (file_size > (image_size - payload_offset)) {
|
||||
return CLKS_FALSE;
|
||||
}
|
||||
|
||||
clks_memset(&entry, 0, sizeof(entry));
|
||||
|
||||
if (clks_ramdisk_build_path(hdr, entry.path, sizeof(entry.path)) == CLKS_TRUE) {
|
||||
if (hdr->typeflag == '5') {
|
||||
entry.type = CLKS_RAMDISK_ENTRY_DIR;
|
||||
entry.data = CLKS_NULL;
|
||||
entry.size = 0ULL;
|
||||
emit = CLKS_TRUE;
|
||||
} else if (hdr->typeflag == '\0' || hdr->typeflag == '0') {
|
||||
entry.type = CLKS_RAMDISK_ENTRY_FILE;
|
||||
entry.data = (const void *)(bytes + payload_offset);
|
||||
entry.size = file_size;
|
||||
emit = CLKS_TRUE;
|
||||
}
|
||||
}
|
||||
|
||||
if (emit == CLKS_TRUE) {
|
||||
if (iter_fn(&entry, ctx) == CLKS_FALSE) {
|
||||
return CLKS_FALSE;
|
||||
}
|
||||
}
|
||||
|
||||
aligned_size = (file_size + (CLKS_TAR_BLOCK_SIZE - 1ULL)) & ~(CLKS_TAR_BLOCK_SIZE - 1ULL);
|
||||
|
||||
if (payload_offset + aligned_size < payload_offset) {
|
||||
return CLKS_FALSE;
|
||||
}
|
||||
|
||||
offset = payload_offset + aligned_size;
|
||||
}
|
||||
|
||||
return CLKS_TRUE;
|
||||
}
|
||||
62
clks.local.bak/kernel/support/libc_compat.c
Normal file
62
clks.local.bak/kernel/support/libc_compat.c
Normal file
@@ -0,0 +1,62 @@
|
||||
#include <clks/string.h>
|
||||
#include <clks/types.h>
|
||||
|
||||
void *memcpy(void *dst, const void *src, usize count) {
|
||||
return clks_memcpy(dst, src, count);
|
||||
}
|
||||
|
||||
void *memmove(void *dst, const void *src, usize count) {
|
||||
return clks_memmove(dst, src, count);
|
||||
}
|
||||
|
||||
void *memset(void *dst, int value, usize count) {
|
||||
return clks_memset(dst, value, count);
|
||||
}
|
||||
|
||||
int memcmp(const void *left, const void *right, usize count) {
|
||||
const u8 *a = (const u8 *)left;
|
||||
const u8 *b = (const u8 *)right;
|
||||
usize i;
|
||||
|
||||
for (i = 0U; i < count; i++) {
|
||||
if (a[i] != b[i]) {
|
||||
return (a[i] < b[i]) ? -1 : 1;
|
||||
}
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int bcmp(const void *left, const void *right, usize count) {
|
||||
return memcmp(left, right, count);
|
||||
}
|
||||
|
||||
usize strlen(const char *str) {
|
||||
return clks_strlen(str);
|
||||
}
|
||||
|
||||
char *strchr(const char *str, int c) {
|
||||
char ch = (char)c;
|
||||
const char *cur = str;
|
||||
|
||||
while (*cur != '\0') {
|
||||
if (*cur == ch) {
|
||||
return (char *)cur;
|
||||
}
|
||||
cur++;
|
||||
}
|
||||
|
||||
if (ch == '\0') {
|
||||
return (char *)cur;
|
||||
}
|
||||
|
||||
return (char *)0;
|
||||
}
|
||||
|
||||
int abs(int value) {
|
||||
return (value < 0) ? -value : value;
|
||||
}
|
||||
|
||||
long labs(long value) {
|
||||
return (value < 0L) ? -value : value;
|
||||
}
|
||||
70
clks.local.bak/kernel/support/string.c
Normal file
70
clks.local.bak/kernel/support/string.c
Normal file
@@ -0,0 +1,70 @@
|
||||
#include <clks/string.h>
|
||||
|
||||
usize clks_strlen(const char *str) {
|
||||
usize len = 0;
|
||||
|
||||
while (str[len] != '\0') {
|
||||
len++;
|
||||
}
|
||||
|
||||
return len;
|
||||
}
|
||||
|
||||
void *clks_memset(void *dst, int value, usize count) {
|
||||
u8 *d = (u8 *)dst;
|
||||
u8 v = (u8)value;
|
||||
usize i;
|
||||
|
||||
for (i = 0; i < count; i++) {
|
||||
d[i] = v;
|
||||
}
|
||||
|
||||
return dst;
|
||||
}
|
||||
|
||||
void *clks_memcpy(void *dst, const void *src, usize count) {
|
||||
u8 *d = (u8 *)dst;
|
||||
const u8 *s = (const u8 *)src;
|
||||
usize i;
|
||||
|
||||
for (i = 0; i < count; i++) {
|
||||
d[i] = s[i];
|
||||
}
|
||||
|
||||
return dst;
|
||||
}
|
||||
|
||||
void *clks_memmove(void *dst, const void *src, usize count) {
|
||||
u8 *d = (u8 *)dst;
|
||||
const u8 *s = (const u8 *)src;
|
||||
usize i;
|
||||
|
||||
if (d == s || count == 0) {
|
||||
return dst;
|
||||
}
|
||||
|
||||
if (d < s) {
|
||||
for (i = 0; i < count; i++) {
|
||||
d[i] = s[i];
|
||||
}
|
||||
} else {
|
||||
for (i = count; i != 0; i--) {
|
||||
d[i - 1] = s[i - 1];
|
||||
}
|
||||
}
|
||||
|
||||
return dst;
|
||||
}
|
||||
|
||||
int clks_strcmp(const char *left, const char *right) {
|
||||
usize i = 0;
|
||||
|
||||
while (left[i] != '\0' && right[i] != '\0') {
|
||||
if (left[i] != right[i]) {
|
||||
return (int)((u8)left[i] - (u8)right[i]);
|
||||
}
|
||||
i++;
|
||||
}
|
||||
|
||||
return (int)((u8)left[i] - (u8)right[i]);
|
||||
}
|
||||
Reference in New Issue
Block a user