From f87b00b46f1e4cf42b194cb5da76e8d294bc11ba Mon Sep 17 00:00:00 2001 From: Martin Petr Date: Wed, 19 Nov 2025 21:23:25 +0100 Subject: [PATCH] Add basic vga kernel module --- .gitignore | 2 +- scripts/build-kernel.sh | 5 ++- scripts/build_js.js | 9 ++++ src/kernel/kernel.c | 20 ++------- src/os/kernel/index.ts | 33 --------------- src/os/src/index.ts | 8 ++++ src/os/src/kernel/index.ts | 12 ++++++ src/os/src/kernel/modules/graphics/config.ts | 3 ++ .../kernel/modules/graphics/graphics.kmod.ts | 1 + src/os/src/kernel/modules/graphics/vga.ts | 41 +++++++++++++++++++ src/os/src/kernel/panic.ts | 21 ++++++++++ src/os/src/lib/libts/byte.ts | 3 ++ src/os/src/types/c/bindings.d.ts | 1 + src/os/types/kernel/functions.d.ts | 1 - 14 files changed, 108 insertions(+), 52 deletions(-) create mode 100755 scripts/build_js.js delete mode 100644 src/os/kernel/index.ts create mode 100644 src/os/src/index.ts create mode 100644 src/os/src/kernel/index.ts create mode 100644 src/os/src/kernel/modules/graphics/config.ts create mode 100644 src/os/src/kernel/modules/graphics/graphics.kmod.ts create mode 100644 src/os/src/kernel/modules/graphics/vga.ts create mode 100644 src/os/src/kernel/panic.ts create mode 100644 src/os/src/lib/libts/byte.ts create mode 100644 src/os/src/types/c/bindings.d.ts delete mode 100644 src/os/types/kernel/functions.d.ts diff --git a/.gitignore b/.gitignore index b3a181c..85766cd 100644 --- a/.gitignore +++ b/.gitignore @@ -2,4 +2,4 @@ _o/ build/ picolibc/ picolibc-install/ -lib/ \ No newline at end of file +/lib/ \ No newline at end of file diff --git a/scripts/build-kernel.sh b/scripts/build-kernel.sh index 7686f86..4061c58 100755 --- a/scripts/build-kernel.sh +++ b/scripts/build-kernel.sh @@ -26,16 +26,19 @@ mkdir -p "$OUT_DIR" # Build TypeScript to JavaScript cd src/os echo "Compiling TypeScript to JavaScript..." -bun build --outdir ../../build --target node --bundle kernel/index.ts +bun build --outdir ../../build --target node --bundle src/index.ts cd ../../ # Generate embedded JavaScript header echo "Generating embedded JavaScript..." +bun scripts/build_js.js python3 scripts/embed_js.py build/index.js > "$BUILD_DIR/embedded_js.h" + # Compiler flags CFLAGS="-m32 -march=i686 -ffreestanding -nostdlib -fno-builtin" CFLAGS="$CFLAGS -I$PICOLIBC_INSTALL/include" +CFLAGS="$CFLAGS -I./lib/duktape/src" CFLAGS="$CFLAGS -I./src/lib" CFLAGS="$CFLAGS -I./src" CFLAGS="$CFLAGS -I$BUILD_DIR" diff --git a/scripts/build_js.js b/scripts/build_js.js new file mode 100755 index 0000000..ea9a214 --- /dev/null +++ b/scripts/build_js.js @@ -0,0 +1,9 @@ +#! /usr/bin/env bun +import { readFileSync, writeFileSync } from "fs"; + +writeFileSync( + "build/index.js", + readFileSync("build/index.js", "utf-8") + .replaceAll("let ", "var ") + .replaceAll("const ", "var ") +); diff --git a/src/kernel/kernel.c b/src/kernel/kernel.c index 92a0654..997142f 100644 --- a/src/kernel/kernel.c +++ b/src/kernel/kernel.c @@ -1,6 +1,6 @@ #include #include -#include <../lib/duktape/src/duktape.h> +#include #include "embedded_js.h" #define WHITE_TXT 0x0F @@ -10,15 +10,7 @@ unsigned int k_printf(char *message, unsigned int line); duk_context *ctx; -duk_ret_t native_print(duk_context *ctx) -{ - const char *msg = duk_to_string(ctx, 0); - // k_clear_screen(); - k_printf((char *)msg, 0); - return 0; -} - -duk_ret_t native_write_memory(duk_context *ctx) +duk_ret_t native_addrw(duk_context *ctx) { // Get the address (first argument) uint32_t address = (uint32_t)duk_to_uint32(ctx, 0); @@ -38,13 +30,9 @@ void kmain() // Initialize Duktape heap ctx = duk_create_heap_default(); - // Register native print function - duk_push_c_function(ctx, native_print, DUK_VARARGS); - duk_put_global_string(ctx, "print"); - // Register native memory write function - duk_push_c_function(ctx, native_write_memory, 2); - duk_put_global_string(ctx, "writeMemory"); + duk_push_c_function(ctx, native_addrw, 2); + duk_put_global_string(ctx, "$addrw"); // Execute embedded JavaScript code from build/index.js duk_push_string(ctx, embedded_js_code); diff --git a/src/os/kernel/index.ts b/src/os/kernel/index.ts deleted file mode 100644 index b4212d1..0000000 --- a/src/os/kernel/index.ts +++ /dev/null @@ -1,33 +0,0 @@ -const SCREEN_WIDTH = 80; -const SCREEN_HEIGHT = 25; -const VIDEO_MEMORY_START = 0xb8000; - -clearScreen(); -print("Welcome to Lints OS!", 0, 0, 0x0a); // Light green on black - -function clearScreen(): void { - for (var row = 0; row < SCREEN_HEIGHT; row++) { - for (var col = 0; col < SCREEN_WIDTH; col++) { - const address = VIDEO_MEMORY_START + 2 * (row * SCREEN_WIDTH + col); - writeMemory(address, 0x20); // ASCII space - writeMemory(address + 1, 0x07); // Light grey on black - } - } -} - -function writeChar( - row: number, - col: number, - char: string, - color: number -): void { - const address = VIDEO_MEMORY_START + 2 * (row * SCREEN_WIDTH + col); - writeMemory(address, char.charCodeAt(0)); - writeMemory(address + 1, color); -} - -function print(text: string, row: number, col: number, color: number): void { - for (var i = 0; i < text.length; i++) { - writeChar(row, col + i, text[i]!, color); - } -} diff --git a/src/os/src/index.ts b/src/os/src/index.ts new file mode 100644 index 0000000..f911b92 --- /dev/null +++ b/src/os/src/index.ts @@ -0,0 +1,8 @@ +import { kmain } from "./kernel"; +import { kpanic } from "./kernel/panic"; + +try { + kmain(); +} catch (e) { + kpanic(e instanceof Error ? e.message : String(e)); +} diff --git a/src/os/src/kernel/index.ts b/src/os/src/kernel/index.ts new file mode 100644 index 0000000..f20d0a8 --- /dev/null +++ b/src/os/src/kernel/index.ts @@ -0,0 +1,12 @@ +import { + kmod_graphics_vga_clear, + kmod_graphics_vga_writeChar, +} from "./modules/graphics/vga"; + +export function kmain() { + kmod_graphics_vga_clear(); + kmod_graphics_vga_writeChar(0, 0, "H", 0x0f); + kmod_graphics_vga_writeChar(1, 0, "i", 0x0f); + + throw new Error("Simulated kernel panic"); +} diff --git a/src/os/src/kernel/modules/graphics/config.ts b/src/os/src/kernel/modules/graphics/config.ts new file mode 100644 index 0000000..177c4f9 --- /dev/null +++ b/src/os/src/kernel/modules/graphics/config.ts @@ -0,0 +1,3 @@ +export const CFG_KMOD_GRAPHICS_VGA_WIDTH = 80; +export const CFG_KMOD_GRAPHICS_VGA_HEIGHT = 25; +export const CFG_KMOD_GRAPGICS_VGA_MEM_ADDR = 0xb8000; diff --git a/src/os/src/kernel/modules/graphics/graphics.kmod.ts b/src/os/src/kernel/modules/graphics/graphics.kmod.ts new file mode 100644 index 0000000..bbe204f --- /dev/null +++ b/src/os/src/kernel/modules/graphics/graphics.kmod.ts @@ -0,0 +1 @@ +export * from "./vga"; diff --git a/src/os/src/kernel/modules/graphics/vga.ts b/src/os/src/kernel/modules/graphics/vga.ts new file mode 100644 index 0000000..cb28aaa --- /dev/null +++ b/src/os/src/kernel/modules/graphics/vga.ts @@ -0,0 +1,41 @@ +import { charc } from "../../../lib/libts/byte"; +import { + CFG_KMOD_GRAPGICS_VGA_MEM_ADDR, + CFG_KMOD_GRAPHICS_VGA_HEIGHT, + CFG_KMOD_GRAPHICS_VGA_WIDTH, +} from "./config"; + +export function kmod_graphics_vga_getCharAddr(x: number, y: number): number { + return ( + CFG_KMOD_GRAPGICS_VGA_MEM_ADDR + (y * CFG_KMOD_GRAPHICS_VGA_WIDTH + x) * 2 + ); +} + +export function kmod_graphics_vga_getColorAddr(x: number, y: number): number { + return ( + CFG_KMOD_GRAPGICS_VGA_MEM_ADDR + + (y * CFG_KMOD_GRAPHICS_VGA_WIDTH + x) * 2 + + 1 + ); +} + +export function kmod_graphics_vga_clear() { + for (let y = 0; y < CFG_KMOD_GRAPHICS_VGA_HEIGHT; y++) { + for (let x = 0; x < CFG_KMOD_GRAPHICS_VGA_WIDTH; x++) { + kmod_graphics_vga_writeChar(x, y, " ", 0x07); + } + } +} + +export function kmod_graphics_vga_writeChar( + x: number, + y: number, + char: string, + color: number +) { + const charAddr = kmod_graphics_vga_getCharAddr(x, y); + const colorAddr = kmod_graphics_vga_getColorAddr(x, y); + + $addrw(charAddr, charc(char)); + $addrw(colorAddr, color); +} diff --git a/src/os/src/kernel/panic.ts b/src/os/src/kernel/panic.ts new file mode 100644 index 0000000..98bba40 --- /dev/null +++ b/src/os/src/kernel/panic.ts @@ -0,0 +1,21 @@ +import { + kmod_graphics_vga_clear, + kmod_graphics_vga_writeChar, +} from "./modules/graphics/vga"; + +export function kpanic(reason?: string) { + kmod_graphics_vga_clear(); + + const l1 = "KERNEL PANIC!"; + let l2 = "Unknown: Kernel crashed."; + + if (reason) l2 = "Reason: " + reason; + + for (let i = 0; i < l1.length; i++) { + kmod_graphics_vga_writeChar(i, 0, l1[i]!, 0x0c); + } + + for (let i = 0; i < l2.length; i++) { + kmod_graphics_vga_writeChar(i, 1, l2[i]!, 0x0c); + } +} diff --git a/src/os/src/lib/libts/byte.ts b/src/os/src/lib/libts/byte.ts new file mode 100644 index 0000000..24fe79e --- /dev/null +++ b/src/os/src/lib/libts/byte.ts @@ -0,0 +1,3 @@ +export function charc(char: string): number { + return char.charCodeAt(0); +} diff --git a/src/os/src/types/c/bindings.d.ts b/src/os/src/types/c/bindings.d.ts new file mode 100644 index 0000000..4e2e3cb --- /dev/null +++ b/src/os/src/types/c/bindings.d.ts @@ -0,0 +1 @@ +declare function $addrw(address: number, value: number): void; diff --git a/src/os/types/kernel/functions.d.ts b/src/os/types/kernel/functions.d.ts deleted file mode 100644 index a2a361b..0000000 --- a/src/os/types/kernel/functions.d.ts +++ /dev/null @@ -1 +0,0 @@ -declare function writeMemory(address: number, value: number): void;