summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorNathan Lee <me@nwlee.tech>2026-09-25 23:24:31 -0500
committerNathan Lee <me@nwlee.tech>2026-09-25 23:24:31 -0500
commit548905a86473101325540446f35ffda8acd0c3bb (patch)
tree57e495fbdb302d83880bd36e7368cdb48cd23e25
parent6858c9e7c97f772eb357e3eee0c1fcfb8adcb699 (diff)
scaffold kernel from parts of wkern x86
-rw-r--r--.gitignore6
-rw-r--r--website-emu/Cargo.toml3
-rw-r--r--website-emu/src/lib.rs50
-rw-r--r--website-kernel/Makefile73
-rw-r--r--website-kernel/arch/kernel.c9
-rw-r--r--website-kernel/arch/linker.ld52
-rw-r--r--website-kernel/arch/log.c100
-rw-r--r--website-kernel/arch/start.S23
-rw-r--r--website-kernel/include/int.h8
-rw-r--r--website-kernel/include/log.h11
10 files changed, 334 insertions, 1 deletions
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,9 +11,42 @@ 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<u8, ()> {
+ 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 {
devices: Vec::new(),
@@ -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 <int.h>
+#include <log.h>
+
+#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 <log.h>
+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);
+