mirror of
https://github.com/Leonmmcoset/cleonos.git
synced 2026-04-21 10:40:00 +00:00
Stage 24
This commit is contained in:
@@ -19,7 +19,7 @@ static struct clks_fb_state clks_fb = {
|
||||
.address = CLKS_NULL,
|
||||
.info = {0, 0, 0, 0},
|
||||
.font = CLKS_NULL,
|
||||
.external_font = {0, 0, 0, 0, CLKS_NULL},
|
||||
.external_font = {0, 0, 0, 0, 0, CLKS_NULL},
|
||||
.external_font_active = CLKS_FALSE,
|
||||
.glyph_width = 8U,
|
||||
.glyph_height = 8U,
|
||||
@@ -149,6 +149,7 @@ void clks_fb_draw_char(u32 x, u32 y, char ch, u32 fg_rgb, u32 bg_rgb) {
|
||||
u32 col;
|
||||
u32 cols;
|
||||
u32 rows;
|
||||
u32 row_stride;
|
||||
|
||||
if (clks_fb.ready == CLKS_FALSE || clks_fb.font == CLKS_NULL) {
|
||||
return;
|
||||
@@ -167,15 +168,26 @@ void clks_fb_draw_char(u32 x, u32 y, char ch, u32 fg_rgb, u32 bg_rgb) {
|
||||
rows = 8U;
|
||||
}
|
||||
|
||||
if (cols > 8U) {
|
||||
cols = 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;
|
||||
}
|
||||
|
||||
for (row = 0U; row < rows; row++) {
|
||||
u8 bits = glyph[row];
|
||||
const u8 *row_bits = glyph + ((usize)row * (usize)row_stride);
|
||||
|
||||
for (col = 0U; col < cols; col++) {
|
||||
u8 mask = (u8)(1U << (7U - col));
|
||||
u8 bits = row_bits[col >> 3U];
|
||||
u8 mask = (u8)(0x80U >> (col & 7U));
|
||||
u32 color = (bits & mask) != 0U ? fg_rgb : bg_rgb;
|
||||
clks_fb_put_pixel(x + col, y + row, color);
|
||||
}
|
||||
@@ -183,7 +195,7 @@ void clks_fb_draw_char(u32 x, u32 y, char ch, u32 fg_rgb, u32 bg_rgb) {
|
||||
}
|
||||
|
||||
clks_bool clks_fb_load_psf_font(const void *blob, u64 blob_size) {
|
||||
struct clks_psf_font parsed = {0, 0, 0, 0, CLKS_NULL};
|
||||
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;
|
||||
@@ -201,4 +213,4 @@ u32 clks_fb_cell_width(void) {
|
||||
|
||||
u32 clks_fb_cell_height(void) {
|
||||
return clks_fb.glyph_height == 0U ? 8U : clks_fb.glyph_height;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -10,12 +10,26 @@
|
||||
#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];
|
||||
@@ -74,7 +88,7 @@ static const struct clks_psf_seed_glyph clks_psf_seed_table[] = {
|
||||
};
|
||||
|
||||
static u8 clks_psf_default_blob[CLKS_PSF1_BLOB_SIZE];
|
||||
static struct clks_psf_font clks_psf_default = {8U, 8U, 0U, 0U, CLKS_NULL};
|
||||
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) {
|
||||
@@ -114,10 +128,70 @@ static clks_bool clks_psf_parse_psf1(const u8 *blob, usize blob_size, struct clk
|
||||
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;
|
||||
@@ -157,6 +231,7 @@ const struct clks_psf_font *clks_psf_default_font(void) {
|
||||
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;
|
||||
}
|
||||
|
||||
@@ -185,9 +260,26 @@ 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) {
|
||||
if (blob_size == 0ULL) {
|
||||
const u8 *bytes;
|
||||
u32 magic32;
|
||||
|
||||
if (blob == CLKS_NULL || out_font == CLKS_NULL || blob_size == 0ULL) {
|
||||
return CLKS_FALSE;
|
||||
}
|
||||
|
||||
return clks_psf_parse_psf1((const u8 *)blob, (usize)blob_size, out_font);
|
||||
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);
|
||||
}
|
||||
|
||||
@@ -8,6 +8,7 @@ struct clks_psf_font {
|
||||
u32 height;
|
||||
u32 glyph_count;
|
||||
u32 bytes_per_glyph;
|
||||
u32 bytes_per_row;
|
||||
const u8 *glyphs;
|
||||
};
|
||||
|
||||
@@ -15,4 +16,4 @@ 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
|
||||
#endif
|
||||
|
||||
10
clks/include/clks/panic.h
Normal file
10
clks/include/clks/panic.h
Normal file
@@ -0,0 +1,10 @@
|
||||
#ifndef CLKS_PANIC_H
|
||||
#define CLKS_PANIC_H
|
||||
|
||||
#include <clks/compiler.h>
|
||||
#include <clks/types.h>
|
||||
|
||||
CLKS_NORETURN void clks_panic(const char *reason);
|
||||
CLKS_NORETURN void clks_panic_exception(const char *name, u64 vector, u64 error_code, u64 rip);
|
||||
|
||||
#endif
|
||||
@@ -3,6 +3,7 @@
|
||||
#include <clks/interrupts.h>
|
||||
#include <clks/log.h>
|
||||
#include <clks/keyboard.h>
|
||||
#include <clks/panic.h>
|
||||
#include <clks/scheduler.h>
|
||||
#include <clks/syscall.h>
|
||||
#include <clks/types.h>
|
||||
@@ -247,11 +248,7 @@ void clks_interrupt_dispatch(struct clks_interrupt_frame *frame) {
|
||||
}
|
||||
|
||||
if (vector < 32U) {
|
||||
clks_log(CLKS_LOG_ERROR, "EXC", clks_exception_names[vector]);
|
||||
clks_log_hex(CLKS_LOG_ERROR, "EXC", "VECTOR", vector);
|
||||
clks_log_hex(CLKS_LOG_ERROR, "EXC", "ERROR", frame->error_code);
|
||||
clks_log_hex(CLKS_LOG_ERROR, "EXC", "RIP", frame->rip);
|
||||
clks_cpu_halt_forever();
|
||||
clks_panic_exception(clks_exception_names[vector], vector, frame->error_code, frame->rip);
|
||||
}
|
||||
|
||||
if (vector == CLKS_IRQ_TIMER) {
|
||||
|
||||
@@ -96,7 +96,7 @@ void clks_kernel_main(void) {
|
||||
clks_tty_init();
|
||||
}
|
||||
|
||||
clks_log(CLKS_LOG_INFO, "BOOT", "CLEONOS Stage23 START");
|
||||
clks_log(CLKS_LOG_INFO, "BOOT", "CLEONOS Stage24 START");
|
||||
|
||||
if (boot_fb == CLKS_NULL) {
|
||||
clks_log(CLKS_LOG_WARN, "VIDEO", "NO FRAMEBUFFER FROM LIMINE");
|
||||
|
||||
239
clks/kernel/panic.c
Normal file
239
clks/kernel/panic.c
Normal file
@@ -0,0 +1,239 @@
|
||||
#include <clks/cpu.h>
|
||||
#include <clks/framebuffer.h>
|
||||
#include <clks/panic.h>
|
||||
#include <clks/serial.h>
|
||||
#include <clks/string.h>
|
||||
#include <clks/types.h>
|
||||
|
||||
#define CLKS_PANIC_BG 0x00200000U
|
||||
#define CLKS_PANIC_FG 0x00FFE0E0U
|
||||
|
||||
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 inline void clks_panic_disable_interrupts(void) {
|
||||
#if defined(CLKS_ARCH_X86_64)
|
||||
__asm__ volatile("cli");
|
||||
#elif defined(CLKS_ARCH_AARCH64)
|
||||
__asm__ volatile("msr daifset, #0xf");
|
||||
#endif
|
||||
}
|
||||
|
||||
static void clks_panic_u64_to_hex(u64 value, char out[19]) {
|
||||
int nibble;
|
||||
|
||||
out[0] = '0';
|
||||
out[1] = 'X';
|
||||
|
||||
for (nibble = 0; nibble < 16; nibble++) {
|
||||
u8 current = (u8)((value >> ((15 - nibble) * 4)) & 0x0FULL);
|
||||
out[2 + nibble] = (current < 10U) ? (char)('0' + current) : (char)('A' + (current - 10U));
|
||||
}
|
||||
|
||||
out[18] = '\0';
|
||||
}
|
||||
|
||||
static 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(struct clks_panic_console *console, const char *text) {
|
||||
usize i = 0U;
|
||||
|
||||
if (console == CLKS_NULL || text == CLKS_NULL) {
|
||||
return;
|
||||
}
|
||||
|
||||
while (text[i] != '\0') {
|
||||
clks_panic_console_put_char(console, 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_NORETURN void clks_panic_halt_loop(void) {
|
||||
clks_cpu_halt_forever();
|
||||
}
|
||||
|
||||
CLKS_NORETURN void clks_panic(const char *reason) {
|
||||
struct clks_panic_console console;
|
||||
|
||||
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] CLeonOS KERNEL PANIC");
|
||||
|
||||
if (reason != CLKS_NULL) {
|
||||
clks_panic_serial_write_line(reason);
|
||||
}
|
||||
|
||||
if (clks_panic_console_init(&console) == CLKS_TRUE) {
|
||||
clks_fb_clear(CLKS_PANIC_BG);
|
||||
|
||||
clks_panic_console_write(&console, "CLeonOS KERNEL PANIC\n");
|
||||
clks_panic_console_write(&console, "====================\n\n");
|
||||
|
||||
if (reason != CLKS_NULL) {
|
||||
clks_panic_console_write(&console, "REASON: ");
|
||||
clks_panic_console_write(&console, reason);
|
||||
clks_panic_console_write(&console, "\n");
|
||||
}
|
||||
|
||||
clks_panic_console_write(&console, "\nSystem halted. Please reboot the VM.\n");
|
||||
}
|
||||
|
||||
clks_panic_halt_loop();
|
||||
}
|
||||
|
||||
CLKS_NORETURN void clks_panic_exception(const char *name, u64 vector, u64 error_code, u64 rip) {
|
||||
struct clks_panic_console console;
|
||||
char hex_buf[19];
|
||||
|
||||
clks_panic_disable_interrupts();
|
||||
|
||||
if (clks_panic_active == CLKS_TRUE) {
|
||||
clks_panic_halt_loop();
|
||||
}
|
||||
|
||||
clks_panic_active = CLKS_TRUE;
|
||||
|
||||
clks_panic_serial_write_line("[PANIC] CPU EXCEPTION");
|
||||
|
||||
if (name != CLKS_NULL) {
|
||||
clks_panic_serial_write_line(name);
|
||||
}
|
||||
|
||||
clks_panic_u64_to_hex(vector, hex_buf);
|
||||
clks_panic_serial_write_line(hex_buf);
|
||||
clks_panic_u64_to_hex(error_code, hex_buf);
|
||||
clks_panic_serial_write_line(hex_buf);
|
||||
clks_panic_u64_to_hex(rip, hex_buf);
|
||||
clks_panic_serial_write_line(hex_buf);
|
||||
|
||||
if (clks_panic_console_init(&console) == CLKS_TRUE) {
|
||||
clks_fb_clear(CLKS_PANIC_BG);
|
||||
|
||||
clks_panic_console_write(&console, "CLeonOS KERNEL PANIC\n");
|
||||
clks_panic_console_write(&console, "====================\n\n");
|
||||
clks_panic_console_write(&console, "TYPE: CPU EXCEPTION\n");
|
||||
|
||||
if (name != CLKS_NULL) {
|
||||
clks_panic_console_write(&console, "NAME: ");
|
||||
clks_panic_console_write(&console, name);
|
||||
clks_panic_console_write(&console, "\n");
|
||||
}
|
||||
|
||||
clks_panic_u64_to_hex(vector, hex_buf);
|
||||
clks_panic_console_write(&console, "VECTOR: ");
|
||||
clks_panic_console_write(&console, hex_buf);
|
||||
clks_panic_console_write(&console, "\n");
|
||||
|
||||
clks_panic_u64_to_hex(error_code, hex_buf);
|
||||
clks_panic_console_write(&console, "ERROR: ");
|
||||
clks_panic_console_write(&console, hex_buf);
|
||||
clks_panic_console_write(&console, "\n");
|
||||
|
||||
clks_panic_u64_to_hex(rip, hex_buf);
|
||||
clks_panic_console_write(&console, "RIP: ");
|
||||
clks_panic_console_write(&console, hex_buf);
|
||||
clks_panic_console_write(&console, "\n\n");
|
||||
|
||||
clks_panic_console_write(&console, "System halted. Please reboot the VM.\n");
|
||||
}
|
||||
|
||||
clks_panic_halt_loop();
|
||||
}
|
||||
@@ -3,6 +3,7 @@
|
||||
#include <clks/heap.h>
|
||||
#include <clks/keyboard.h>
|
||||
#include <clks/log.h>
|
||||
#include <clks/panic.h>
|
||||
#include <clks/pmm.h>
|
||||
#include <clks/scheduler.h>
|
||||
#include <clks/shell.h>
|
||||
@@ -696,6 +697,7 @@ static clks_bool clks_shell_cmd_help(void) {
|
||||
clks_shell_writeln(" dmesg [n]");
|
||||
clks_shell_writeln(" shstat");
|
||||
clks_shell_writeln(" rusttest");
|
||||
clks_shell_writeln(" panic");
|
||||
clks_shell_writeln(" exec <path|name>");
|
||||
clks_shell_writeln(" clear");
|
||||
clks_shell_writeln(" kbdstat");
|
||||
@@ -1209,6 +1211,11 @@ static clks_bool clks_shell_cmd_rusttest(void) {
|
||||
return CLKS_TRUE;
|
||||
}
|
||||
|
||||
static clks_bool clks_shell_cmd_panic(void) {
|
||||
clks_panic("MANUAL PANIC FROM KERNEL SHELL");
|
||||
return CLKS_FALSE;
|
||||
}
|
||||
|
||||
static void clks_shell_execute_line(const char *line) {
|
||||
char line_buf[CLKS_SHELL_LINE_MAX];
|
||||
char cmd[CLKS_SHELL_CMD_MAX];
|
||||
@@ -1271,6 +1278,8 @@ static void clks_shell_execute_line(const char *line) {
|
||||
success = clks_shell_cmd_shstat();
|
||||
} else if (clks_shell_streq(cmd, "rusttest") == CLKS_TRUE) {
|
||||
success = clks_shell_cmd_rusttest();
|
||||
} else if (clks_shell_streq(cmd, "panic") == CLKS_TRUE) {
|
||||
success = clks_shell_cmd_panic();
|
||||
} else if (clks_shell_streq(cmd, "exec") == CLKS_TRUE || clks_shell_streq(cmd, "run") == CLKS_TRUE) {
|
||||
success = clks_shell_cmd_exec(arg);
|
||||
} else if (clks_shell_streq(cmd, "clear") == CLKS_TRUE) {
|
||||
|
||||
@@ -20,6 +20,7 @@
|
||||
- `stage21.md`
|
||||
- `stage22.md`
|
||||
- `stage23.md`
|
||||
- `stage24.md`
|
||||
|
||||
## Notes
|
||||
- Stage docs use a fixed template: goal, implementation, acceptance criteria, build targets, QEMU command, and debugging notes.
|
||||
|
||||
48
docs/stage24.md
Normal file
48
docs/stage24.md
Normal file
@@ -0,0 +1,48 @@
|
||||
# CLeonOS Stage24
|
||||
|
||||
## Stage Goal
|
||||
- Add a kernel shell command `panic`.
|
||||
- Trigger a deliberate kernel panic from shell command input.
|
||||
- Show a dedicated panic screen in framebuffer mode for manual panic and CPU exceptions.
|
||||
|
||||
## What Was Implemented
|
||||
- New panic subsystem:
|
||||
- `clks/include/clks/panic.h`
|
||||
- `clks/kernel/panic.c`
|
||||
- Panic subsystem behavior:
|
||||
- disable interrupts before panic halt
|
||||
- write panic summary to serial (`-serial stdio`)
|
||||
- draw full-screen panic page on framebuffer
|
||||
- halt forever after panic
|
||||
- Exception path integration:
|
||||
- `clks/kernel/interrupts.c` now routes `vector < 32` to `clks_panic_exception(...)`
|
||||
- Shell integration:
|
||||
- `clks/kernel/shell.c` adds `panic` command
|
||||
- `panic` command calls `clks_panic("MANUAL PANIC FROM KERNEL SHELL")`
|
||||
- `help` output includes `panic`
|
||||
- Stage banner updated:
|
||||
- `CLEONOS Stage24 START`
|
||||
|
||||
## Acceptance Criteria
|
||||
- Kernel boots and prints `CLEONOS Stage24 START`.
|
||||
- `help` lists `panic`.
|
||||
- Typing `panic` in kernel shell shows panic page and system halts.
|
||||
- Triggering CPU exceptions (if any) also enters the same panic screen flow.
|
||||
|
||||
## Build Targets
|
||||
- `make setup`
|
||||
- `make userapps`
|
||||
- `make iso`
|
||||
- `make run`
|
||||
- `make debug`
|
||||
|
||||
## QEMU Command
|
||||
- `qemu-system-x86_64 -M q35 -m 1024M -cdrom build/CLeonOS-x86_64.iso -serial stdio`
|
||||
|
||||
## Common Bugs and Debugging
|
||||
- `panic` command not found:
|
||||
- Confirm `help` output contains `panic` and shell dispatch includes `clks_shell_cmd_panic()`.
|
||||
- Panic screen not visible but serial has panic logs:
|
||||
- Ensure framebuffer is available from Limine and `clks_fb_ready()` is true.
|
||||
- Exception still prints old logs instead of panic page:
|
||||
- Check `clks_interrupt_dispatch()` exception branch routes to `clks_panic_exception(...)`.
|
||||
Binary file not shown.
@@ -1,24 +1,35 @@
|
||||
param(
|
||||
[string]$OutputPath = "ramdisk/system/tty.psf"
|
||||
[string]$OutputPath = "ramdisk/system/tty.psf",
|
||||
[int]$Width = 12,
|
||||
[int]$Height = 24,
|
||||
[int]$GlyphCount = 256,
|
||||
[int]$FontSize = 20,
|
||||
[int]$OffsetX = 0,
|
||||
[int]$OffsetY = 0,
|
||||
[int]$AutoCenter = 1
|
||||
)
|
||||
|
||||
Add-Type -AssemblyName System.Drawing
|
||||
|
||||
$width = 8
|
||||
$height = 16
|
||||
$glyphCount = 256
|
||||
$headerSize = 4
|
||||
$bytesPerGlyph = $height
|
||||
$totalSize = $headerSize + ($glyphCount * $bytesPerGlyph)
|
||||
if ($Width -le 0 -or $Height -le 0) {
|
||||
throw "Width and Height must be positive"
|
||||
}
|
||||
|
||||
$fontCandidates = @("Consolas", "Lucida Console", "Courier New")
|
||||
if ($GlyphCount -le 0) {
|
||||
throw "GlyphCount must be positive"
|
||||
}
|
||||
|
||||
$fontCandidates = @("Cascadia Mono", "Consolas", "Lucida Console")
|
||||
$font = $null
|
||||
|
||||
foreach ($name in $fontCandidates) {
|
||||
try {
|
||||
$font = New-Object System.Drawing.Font($name, 14, [System.Drawing.FontStyle]::Regular, [System.Drawing.GraphicsUnit]::Pixel)
|
||||
if ($font.Name -eq $name) {
|
||||
$candidate = New-Object System.Drawing.Font($name, $FontSize, [System.Drawing.FontStyle]::Regular, [System.Drawing.GraphicsUnit]::Pixel)
|
||||
if ($candidate.Name -eq $name) {
|
||||
$font = $candidate
|
||||
break
|
||||
}
|
||||
$candidate.Dispose()
|
||||
} catch {
|
||||
$font = $null
|
||||
}
|
||||
@@ -28,57 +39,170 @@ if ($null -eq $font) {
|
||||
throw "No usable monospace font found for PSF generation"
|
||||
}
|
||||
|
||||
$bytes = New-Object byte[] $totalSize
|
||||
$bytes[0] = 0x36
|
||||
$bytes[1] = 0x04
|
||||
$bytes[2] = 0x00
|
||||
$bytes[3] = [byte]$bytesPerGlyph
|
||||
function Set-U32LE {
|
||||
param(
|
||||
[byte[]]$Buffer,
|
||||
[int]$Offset,
|
||||
[uint32]$Value
|
||||
)
|
||||
|
||||
$Buffer[$Offset + 0] = [byte]($Value -band 0xFF)
|
||||
$Buffer[$Offset + 1] = [byte](($Value -shr 8) -band 0xFF)
|
||||
$Buffer[$Offset + 2] = [byte](($Value -shr 16) -band 0xFF)
|
||||
$Buffer[$Offset + 3] = [byte](($Value -shr 24) -band 0xFF)
|
||||
}
|
||||
|
||||
function Pixel-On {
|
||||
param([System.Drawing.Color]$Pixel)
|
||||
return (($Pixel.R + $Pixel.G + $Pixel.B) -ge 384)
|
||||
}
|
||||
|
||||
function Render-NormalizedGlyph {
|
||||
param(
|
||||
[char]$Char,
|
||||
[System.Drawing.Font]$Font,
|
||||
[int]$GlyphWidth,
|
||||
[int]$GlyphHeight,
|
||||
[int]$ShiftX,
|
||||
[int]$ShiftY,
|
||||
[int]$DoCenter
|
||||
)
|
||||
|
||||
$workW = [Math]::Max($GlyphWidth * 4, 64)
|
||||
$workH = [Math]::Max($GlyphHeight * 4, 64)
|
||||
|
||||
$src = New-Object System.Drawing.Bitmap $workW, $workH
|
||||
$g = [System.Drawing.Graphics]::FromImage($src)
|
||||
$g.Clear([System.Drawing.Color]::Black)
|
||||
$g.TextRenderingHint = [System.Drawing.Text.TextRenderingHint]::SingleBitPerPixelGridFit
|
||||
|
||||
$fmt = New-Object System.Drawing.StringFormat
|
||||
$fmt.FormatFlags = [System.Drawing.StringFormatFlags]::NoClip
|
||||
$fmt.Alignment = [System.Drawing.StringAlignment]::Near
|
||||
$fmt.LineAlignment = [System.Drawing.StringAlignment]::Near
|
||||
|
||||
$size = $g.MeasureString([string]$Char, $Font, 1000, $fmt)
|
||||
$drawX = [int][Math]::Floor(($workW - $size.Width) / 2.0)
|
||||
$drawY = [int][Math]::Floor(($workH - $size.Height) / 2.0)
|
||||
|
||||
$g.DrawString([string]$Char, $Font, [System.Drawing.Brushes]::White, $drawX, $drawY, $fmt)
|
||||
$g.Dispose()
|
||||
$fmt.Dispose()
|
||||
|
||||
$minX = $workW
|
||||
$minY = $workH
|
||||
$maxX = -1
|
||||
$maxY = -1
|
||||
|
||||
for ($y = 0; $y -lt $workH; $y++) {
|
||||
for ($x = 0; $x -lt $workW; $x++) {
|
||||
if (Pixel-On ($src.GetPixel($x, $y))) {
|
||||
if ($x -lt $minX) { $minX = $x }
|
||||
if ($y -lt $minY) { $minY = $y }
|
||||
if ($x -gt $maxX) { $maxX = $x }
|
||||
if ($y -gt $maxY) { $maxY = $y }
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
$dst = New-Object System.Drawing.Bitmap $GlyphWidth, $GlyphHeight
|
||||
for ($y = 0; $y -lt $GlyphHeight; $y++) {
|
||||
for ($x = 0; $x -lt $GlyphWidth; $x++) {
|
||||
$dst.SetPixel($x, $y, [System.Drawing.Color]::Black)
|
||||
}
|
||||
}
|
||||
|
||||
if ($maxX -ge $minX -and $maxY -ge $minY) {
|
||||
$contentW = $maxX - $minX + 1
|
||||
$contentH = $maxY - $minY + 1
|
||||
|
||||
if ($DoCenter -ne 0) {
|
||||
$baseX = [int][Math]::Floor(($GlyphWidth - $contentW) / 2.0)
|
||||
$baseY = [int][Math]::Floor(($GlyphHeight - $contentH) / 2.0)
|
||||
} else {
|
||||
$baseX = 0
|
||||
$baseY = 0
|
||||
}
|
||||
|
||||
$targetX = $baseX + $ShiftX
|
||||
$targetY = $baseY + $ShiftY
|
||||
|
||||
for ($y = $minY; $y -le $maxY; $y++) {
|
||||
for ($x = $minX; $x -le $maxX; $x++) {
|
||||
if (-not (Pixel-On ($src.GetPixel($x, $y)))) {
|
||||
continue
|
||||
}
|
||||
|
||||
$nx = $targetX + ($x - $minX)
|
||||
$ny = $targetY + ($y - $minY)
|
||||
|
||||
if ($nx -ge 0 -and $nx -lt $GlyphWidth -and $ny -ge 0 -and $ny -lt $GlyphHeight) {
|
||||
$dst.SetPixel($nx, $ny, [System.Drawing.Color]::White)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
$src.Dispose()
|
||||
return $dst
|
||||
}
|
||||
|
||||
$headerSize = 32
|
||||
$bytesPerRow = (($Width + 7) -shr 3)
|
||||
$bytesPerGlyph = $bytesPerRow * $Height
|
||||
$totalSize = $headerSize + ($GlyphCount * $bytesPerGlyph)
|
||||
|
||||
$bytes = New-Object byte[] $totalSize
|
||||
|
||||
# PSF2 header
|
||||
Set-U32LE -Buffer $bytes -Offset 0 -Value ([Convert]::ToUInt32("864AB572", 16))
|
||||
Set-U32LE -Buffer $bytes -Offset 4 -Value 0
|
||||
Set-U32LE -Buffer $bytes -Offset 8 -Value ([uint32]$headerSize)
|
||||
Set-U32LE -Buffer $bytes -Offset 12 -Value 0
|
||||
Set-U32LE -Buffer $bytes -Offset 16 -Value ([uint32]$GlyphCount)
|
||||
Set-U32LE -Buffer $bytes -Offset 20 -Value ([uint32]$bytesPerGlyph)
|
||||
Set-U32LE -Buffer $bytes -Offset 24 -Value ([uint32]$Height)
|
||||
Set-U32LE -Buffer $bytes -Offset 28 -Value ([uint32]$Width)
|
||||
|
||||
# default all glyphs to blank, avoids noisy '?' for undefined chars.
|
||||
for ($i = $headerSize; $i -lt $totalSize; $i++) {
|
||||
$bytes[$i] = 0x00
|
||||
}
|
||||
|
||||
$white = [System.Drawing.Brushes]::White
|
||||
$black = [System.Drawing.Color]::Black
|
||||
|
||||
for ($code = 32; $code -le 126; $code++) {
|
||||
for ($code = 32; $code -le [Math]::Min(126, $GlyphCount - 1); $code++) {
|
||||
$ch = [char]$code
|
||||
|
||||
$bmp = New-Object System.Drawing.Bitmap $width, $height
|
||||
$g = [System.Drawing.Graphics]::FromImage($bmp)
|
||||
$g.Clear($black)
|
||||
$g.TextRenderingHint = [System.Drawing.Text.TextRenderingHint]::SingleBitPerPixelGridFit
|
||||
|
||||
# Small negative offset keeps glyph centered in 8x16 cell for common monospace fonts.
|
||||
$g.DrawString([string]$ch, $font, $white, -1, -2)
|
||||
$glyphBmp = Render-NormalizedGlyph -Char $ch -Font $font -GlyphWidth $Width -GlyphHeight $Height -ShiftX $OffsetX -ShiftY $OffsetY -DoCenter $AutoCenter
|
||||
|
||||
$glyphOffset = $headerSize + ($code * $bytesPerGlyph)
|
||||
|
||||
for ($y = 0; $y -lt $height; $y++) {
|
||||
[byte]$rowBits = 0
|
||||
for ($y = 0; $y -lt $Height; $y++) {
|
||||
$rowOffset = $glyphOffset + ($y * $bytesPerRow)
|
||||
|
||||
for ($x = 0; $x -lt $width; $x++) {
|
||||
$p = $bmp.GetPixel($x, $y)
|
||||
if (($p.R + $p.G + $p.B) -ge 384) {
|
||||
$rowBits = [byte]($rowBits -bor (1 -shl (7 - $x)))
|
||||
for ($x = 0; $x -lt $Width; $x++) {
|
||||
$p = $glyphBmp.GetPixel($x, $y)
|
||||
if (Pixel-On $p) {
|
||||
$byteIndex = ($x -shr 3)
|
||||
$bitIndex = 7 - ($x -band 7)
|
||||
$target = $rowOffset + $byteIndex
|
||||
$bytes[$target] = [byte]($bytes[$target] -bor (1 -shl $bitIndex))
|
||||
}
|
||||
}
|
||||
|
||||
$bytes[$glyphOffset + $y] = $rowBits
|
||||
}
|
||||
|
||||
$g.Dispose()
|
||||
$bmp.Dispose()
|
||||
$glyphBmp.Dispose()
|
||||
}
|
||||
|
||||
$font.Dispose()
|
||||
|
||||
$dir = Split-Path -Parent $OutputPath
|
||||
if ([System.IO.Path]::IsPathRooted($OutputPath)) {
|
||||
$fullOutput = $OutputPath
|
||||
} else {
|
||||
$fullOutput = Join-Path (Resolve-Path '.') $OutputPath
|
||||
}
|
||||
|
||||
$dir = Split-Path -Parent $fullOutput
|
||||
if (-not [string]::IsNullOrWhiteSpace($dir)) {
|
||||
New-Item -ItemType Directory -Force -Path $dir | Out-Null
|
||||
}
|
||||
|
||||
$fullOutput = Join-Path (Resolve-Path '.') $OutputPath
|
||||
[System.IO.File]::WriteAllBytes($fullOutput, $bytes)
|
||||
Write-Output "Generated $OutputPath ($($bytes.Length) bytes)"
|
||||
Write-Output "Generated PSF2: $OutputPath (w=$Width, h=$Height, glyphs=$GlyphCount, bytes=$($bytes.Length), center=$AutoCenter)"
|
||||
|
||||
Reference in New Issue
Block a user