From 548905a86473101325540446f35ffda8acd0c3bb Mon Sep 17 00:00:00 2001 From: Nathan Lee Date: Fri, 25 Sep 2026 23:24:31 -0500 Subject: scaffold kernel from parts of wkern x86 --- .gitignore | 6 ++- website-emu/Cargo.toml | 3 ++ website-emu/src/lib.rs | 50 +++++++++++++++++++++ website-kernel/Makefile | 73 ++++++++++++++++++++++++++++++ website-kernel/arch/kernel.c | 9 ++++ website-kernel/arch/linker.ld | 52 ++++++++++++++++++++++ website-kernel/arch/log.c | 100 ++++++++++++++++++++++++++++++++++++++++++ website-kernel/arch/start.S | 23 ++++++++++ website-kernel/include/int.h | 8 ++++ website-kernel/include/log.h | 11 +++++ 10 files changed, 334 insertions(+), 1 deletion(-) create mode 100644 website-kernel/Makefile create mode 100644 website-kernel/arch/kernel.c create mode 100644 website-kernel/arch/linker.ld create mode 100644 website-kernel/arch/log.c create mode 100644 website-kernel/arch/start.S create mode 100644 website-kernel/include/int.h create mode 100644 website-kernel/include/log.h diff --git a/.gitignore b/.gitignore index 92d2735..be664a6 100644 --- a/.gitignore +++ b/.gitignore @@ -1,3 +1,7 @@ website-emu/target website-emu/Cargo.lock -.idea/ \ No newline at end of file +website-emu/pkg + +website-kernel/compile_commands.json + +.idea/ diff --git a/website-emu/Cargo.toml b/website-emu/Cargo.toml index 575b12b..9dc8fcd 100644 --- a/website-emu/Cargo.toml +++ b/website-emu/Cargo.toml @@ -3,5 +3,8 @@ name = "website-emu" version = "0.1.0" edition = "2024" +[lib] +crate-type = ["cdylib", "rlib"] + [dependencies] wasm-bindgen = "0.2" diff --git a/website-emu/src/lib.rs b/website-emu/src/lib.rs index 7c1a285..ffaa677 100644 --- a/website-emu/src/lib.rs +++ b/website-emu/src/lib.rs @@ -11,8 +11,41 @@ const REGISTER_NAME_WIDTH: u32 = 0b11111; const DRAM_LOAD: u32 = 0x20000000; const OS_LOAD: u32 = 0x80000000; + +const CONSOLE_LOAD: u32 = 0x70000000; + const INITRD_LOAD: u32 = 0; +#[wasm_bindgen] +extern "C" { + #[wasm_bindgen(js_namespace = console)] + fn log(s: &str); +} + +pub struct Uart { + pub addr: u32, + pub value: u8 +} + +impl MemoryDevice for Uart { + fn read(&self, address: u32) -> Result { + if (address == self.addr) { + Ok(self.value) + } else { + Err(()) + } + } + + fn write(&mut self, address: u32, value: u8) -> Result<(), ()> { + if (address == self.addr) { + self.value = value; + Ok(()) + } else { + Err(()) + } + } +} + #[wasm_bindgen] pub fn boot(image: &[u8], initrd: &[u8], memory: &[u8]) { let mut cpu_memory = CpuMemory { @@ -41,10 +74,27 @@ pub fn boot(image: &[u8], initrd: &[u8], memory: &[u8]) { dram: initrd.to_vec().into_boxed_slice(), }; + let uart = Uart { + addr: CONSOLE_LOAD, + value: 0 + }; + cpu_memory.register_device( DRAM_LOAD..DRAM_LOAD + memory_len as u32, Box::new(ram_device) ); + cpu_memory.register_device( + OS_LOAD..OS_LOAD + os_size as u32, + Box::new(os_image) + ); + cpu_memory.register_device( + INITRD_LOAD..INITRD_LOAD + initrd_size as u32, + Box::new(initrd_image) + ); + cpu_memory.register_device( + CONSOLE_LOAD..CONSOLE_LOAD + 1, + Box::new(uart) + ); let mut state = CpuState::new(cpu_memory); diff --git a/website-kernel/Makefile b/website-kernel/Makefile new file mode 100644 index 0000000..eb5a76e --- /dev/null +++ b/website-kernel/Makefile @@ -0,0 +1,73 @@ +CC = clang +LD = ld.lld +OBJCOPY = llvm-objcopy + +COMPILER = $(shell $(CC) --version | head -n 1) +LINKER = $(shell $(LD) --version | head -n 1) +ARCH_NAME = 32-bit RISC-V, IM_Zicsr ISA, little endian, unknown ELF, System V ABI + +CFLAGS = \ + --target=riscv32-unknown-elf \ + -march=rv32im_zicsr \ + -mabi=ilp32 \ + -ffreestanding \ + -fno-builtin \ + -nostdlib \ + -nostdinc \ + -nodefaultlibs \ + -DVERSION='"$(VERSION)"' \ + -DCOMPILER_NAME='"$(COMPILER)"' \ + -DLINKER_NAME='"$(LINKER)"' \ + -DARCH_NAME='"$(ARCH_NAME)"' \ + -static \ + -ffunction-sections -fdata-sections -fno-common \ + -Iinclude -O2 -g3 \ + -Wall -Wextra -Werror -Wundef + +LD_FLAGS = \ + -T $(LINKER_SCRIPT) -nostdlib -m elf32lriscv --gc-sections + +OBJCOPY_FLAGS = \ + -O binary \ + --strip-all \ + --remove-section=.comment \ + --remove-section=.debug* \ + --remove-section=.note* \ + --remove-section=.eh_frame \ + --remove-section=.eh_frame_ptr \ + --remove-section=.eh_frame_hdr + +C_SRCS = $(shell find . -name '*.c') +S_SRCS = $(shell find . -name '*.S') +C_OBJECTS = $(C_SRCS:.c=.o) +S_OBJECTS = $(S_SRCS:.S=.o) +ALL_OBJECTS = $(C_OBJECTS) $(S_OBJECTS) +LINKER_SCRIPT = arch/linker.ld + +KERNEL_BINARY = Image.bin +KERNEL_ELF = arch/webos-kernel.elf + +$(V).SILENT: + +%.o: %.c + @echo " CC $<" + $(CC) $(CFLAGS) -c $< -o $@ +%.o: %.S + @echo " AS $<" + $(CC) $(CFLAGS) -c $< -o $@ +$(KERNEL_ELF): $(ALL_OBJECTS) $(LINKER_SCRIPT) + @echo " LD $@" + $(LD) $(LD_FLAGS) -o $@ $(ALL_OBJECTS) +$(KERNEL_BINARY): $(KERNEL_ELF) + @echo " OBJCOPY $@" + $(OBJCOPY) $(OBJCOPY_FLAGS) $(KERNEL_ELF) $(KERNEL_BIN) +clean: + @echo " CLEAN $(ALL_OBJECTS)" + $(RM) $(ALL_OBJECTS) + @echo " CLEAN $(KERNEL_ELF)" + $(RM) $(KERNEL_ELF) + @echo " CLEAN $(KERNEL_BINARY)" + $(RM) $(KERNEL_BINARY) + +.PHONY: all clean +all: $(KERNEL_BINARY) diff --git a/website-kernel/arch/kernel.c b/website-kernel/arch/kernel.c new file mode 100644 index 0000000..28c94d3 --- /dev/null +++ b/website-kernel/arch/kernel.c @@ -0,0 +1,9 @@ +#include +#include + +#define SERIAL_PORT 0x70000000 + +void kernel_main(size_t hart) { + (void)hart; + printk("wkern version %s (Compiler %s, Linker %s) on %s\n", VERSION, COMPILER_NAME, LINKER_NAME, ARCH_NAME); +} diff --git a/website-kernel/arch/linker.ld b/website-kernel/arch/linker.ld new file mode 100644 index 0000000..52a3a05 --- /dev/null +++ b/website-kernel/arch/linker.ld @@ -0,0 +1,52 @@ +OUTPUT_ARCH(riscv) +ENTRY(_start) + +MEMORY +{ + ROM (rx) : ORIGIN = 0x80000000, LENGTH = 1M + RAM (rwx) : ORIGIN = 0x20000000, LENGTH = 4M +} + +SECTIONS +{ + .text : { + KEEP(*(.text._start)) + KEEP(*(.text.start)) + *(.text) + *(.text.*) + } > ROM + .rodata : { + *(.rodata) + *(.rodata.*) + } > ROM + + .init_array : { + __init_array_start = .; + KEEP(*(.init_array)) + KEEP(*(.init_array.*)) + __init_array_end = .; + } > ROM + + .data : { + __data_start = .; + *(.data) + *(.data.*) + __data_end = .; + } > RAM AT> ROM + __data_load = LOADADDR(.data); + + .bss : { + __bss_start = .; + *(.bss) + *(.bss.*) + *(COMMON) + __bss_end = .; + } > RAM + + .stack (NOLOAD) : { + . = ALIGN(16); + __stack_bottom = .; + . += 8K; + __stack_top = .; + } > RAM +} diff --git a/website-kernel/arch/log.c b/website-kernel/arch/log.c new file mode 100644 index 0000000..63e0615 --- /dev/null +++ b/website-kernel/arch/log.c @@ -0,0 +1,100 @@ +#include +void stub(char c) { + (void)c; + return; +} + +console_callback_t callback = stub; + +void put_char(char c) { + callback(c); +} + +void put_string(const char *s) { + while (*s) + put_char(*s++); +} + +void put_uint(unsigned int value, unsigned int radix) { + char tmp[16]; + const char digits[] = "0123456789abcdef"; + int i = 0; + + if (value == 0) { + put_char('0'); + return; + } + + while (value) { + tmp[i++] = digits[value % radix]; + value /= radix; + } + + while (i--) + put_char(tmp[i]); +} + +void put_int(int value) { + if (value < 0) { + put_char('-'); + put_uint((unsigned int)(-value), 10); + } else { + put_uint((unsigned int)value, 10); + } +} + +void vprintk(const char *fmt, __builtin_va_list args) { + while (*fmt) { + if (*fmt != '%') { + put_char(*fmt++); + continue; + } + + fmt++; + + switch (*fmt) { + case '%': + put_char('%'); + break; + + case 'c': + put_char((char)__builtin_va_arg(args, int)); + break; + + case 's': + put_string(__builtin_va_arg(args, const char *)); + break; + + case 'd': + case 'i': + put_int(__builtin_va_arg(args, int)); + break; + + case 'u': + put_uint(__builtin_va_arg(args, unsigned int), 10); + break; + + case 'x': + put_uint(__builtin_va_arg(args, unsigned int), 16); + break; + + default: + put_char('%'); + put_char(*fmt); + break; + } + + fmt++; + } +} + +void printk(const char *fmt, ...) { + __builtin_va_list args; + __builtin_va_start(args, fmt); + vprintk(fmt, args); + __builtin_va_end(args); +} + +void register_console_callback(console_callback_t cb) { + callback = cb; +} diff --git a/website-kernel/arch/start.S b/website-kernel/arch/start.S new file mode 100644 index 0000000..8248ab9 --- /dev/null +++ b/website-kernel/arch/start.S @@ -0,0 +1,23 @@ +.section .text._start +.global _start +.type _start, @function + +.extern user_regs + +_start: + csrw sstatus, zero + csrw sie, zero + + la sp, __stack_top + + la t0, __bss_start + la t1, __bss_end + beq t0, t1, 2f +1: + sw zero, 0(t0) + addi t0, t0, 4 + bltu t0, t1, 1b +2: + call kernel_main + wfi + diff --git a/website-kernel/include/int.h b/website-kernel/include/int.h new file mode 100644 index 0000000..2a378e7 --- /dev/null +++ b/website-kernel/include/int.h @@ -0,0 +1,8 @@ +#pragma once +#define NULL (void*)0 + +typedef __UINTPTR_TYPE__ size_t; +typedef __UINT8_TYPE__ uint8_t; +typedef __UINT16_TYPE__ uint16_t; +typedef __UINT32_TYPE__ uint32_t; +typedef __UINT64_TYPE__ uint64_t; diff --git a/website-kernel/include/log.h b/website-kernel/include/log.h new file mode 100644 index 0000000..4312baf --- /dev/null +++ b/website-kernel/include/log.h @@ -0,0 +1,11 @@ +#pragma once + +#define RINGBUF_SIZE 64 * 1024 + +typedef void (*console_callback_t)(char); + +void vprintk(const char *message, __builtin_va_list args); +void printk(const char *message, ...); + +void register_console_callback(console_callback_t callback); + -- cgit v1.2.3