feat(adapter-riscv): boot on QEMU virt with UART hello world

This commit is contained in:
2026-10-18 01:46:47 +02:00
parent dcadb83088
commit 44a0ead7f2
6 changed files with 182 additions and 0 deletions

3
.cargo/config.toml Normal file
View File

@@ -0,0 +1,3 @@
[target.riscv64gc-unknown-none-elf]
runner = "qemu-system-riscv64 -machine virt -nographic -bios default -kernel"
rustflags = ["-C", "link-arg=-Tcrates/adapter-riscv/linker.ld", "-C", "panic=abort"]

View File

@@ -1,5 +1,6 @@
[workspace] [workspace]
members = [ members = [
"crates/adapter-riscv",
"crates/apps/snake", "crates/apps/snake",
"crates/domain", "crates/domain",
"crates/elf", "crates/elf",
@@ -84,3 +85,7 @@ snake = { path = "crates/apps/snake" }
strip = true strip = true
lto = true lto = true
opt-level = "z" opt-level = "z"
panic = "abort"
[profile.dev]
panic = "abort"

View File

@@ -0,0 +1,17 @@
[package]
name = "adapter-riscv"
version = "0.1.0"
edition = "2024"
[dependencies]
types = { workspace = true }
domain = { workspace = true }
platform = { workspace = true }
kernel = { workspace = true }
[profile.release]
panic = "abort"
opt-level = "s"
[profile.dev]
panic = "abort"

View File

@@ -0,0 +1,36 @@
OUTPUT_ARCH(riscv)
ENTRY(_start)
SECTIONS {
. = 0x80200000;
.text : {
*(.text.entry)
*(.text .text.*)
}
. = ALIGN(4096);
.rodata : {
*(.rodata .rodata.*)
}
. = ALIGN(4096);
.data : {
*(.data .data.*)
}
. = ALIGN(4096);
.bss : {
_bss_start = .;
*(.bss .bss.*)
*(.sbss .sbss.*)
_bss_end = .;
}
. = ALIGN(4096);
_stack_bottom = .;
. += 0x10000;
_stack_top = .;
_heap_start = .;
}

View File

@@ -0,0 +1,61 @@
#![no_std]
#![no_main]
mod uart;
use core::arch::global_asm;
use uart::Uart;
global_asm!(
r#"
.section .text.entry
.globl _start
_start:
la sp, _stack_top
call kmain
spin:
wfi
j spin
"#
);
unsafe extern "C" {
static _bss_start: u8;
static _bss_end: u8;
}
fn zero_bss() {
unsafe {
let start = &_bss_start as *const u8 as *mut u8;
let end = &_bss_end as *const u8 as *mut u8;
let len = end as usize - start as usize;
core::ptr::write_bytes(start, 0, len);
}
}
#[unsafe(no_mangle)]
extern "C" fn kmain() -> ! {
zero_bss();
let uart = Uart::new();
uart.write_str("k-os: booted on RISC-V\n");
loop {
unsafe { core::arch::asm!("wfi") };
}
}
#[panic_handler]
fn panic(info: &core::panic::PanicInfo) -> ! {
let uart = Uart::new();
uart.write_str("PANIC: ");
if let Some(location) = info.location() {
uart.write_str(location.file());
uart.put_char(b':');
uart.write_dec(location.line() as usize);
}
uart.put_char(b'\n');
loop {
unsafe { core::arch::asm!("wfi") };
}
}

View File

@@ -0,0 +1,60 @@
const UART_BASE: usize = 0x10000000;
pub struct Uart {
base: usize,
}
impl Uart {
pub fn new() -> Self {
Self { base: UART_BASE }
}
pub fn put_char(&self, byte: u8) {
let ptr = self.base as *mut u8;
unsafe { core::ptr::write_volatile(ptr, byte) };
}
pub fn write_str(&self, s: &str) {
for byte in s.bytes() {
self.put_char(byte);
}
}
pub fn write_hex(&self, mut value: usize) {
self.write_str("0x");
if value == 0 {
self.put_char(b'0');
return;
}
let mut buf = [0u8; 16];
let mut i = 0;
while value > 0 {
let digit = (value & 0xF) as u8;
buf[i] = if digit < 10 { b'0' + digit } else { b'a' + digit - 10 };
value >>= 4;
i += 1;
}
while i > 0 {
i -= 1;
self.put_char(buf[i]);
}
}
pub fn write_dec(&self, mut value: usize) {
if value == 0 {
self.put_char(b'0');
return;
}
let mut buf = [0u8; 20];
let mut i = 0;
while value > 0 {
buf[i] = b'0' + (value % 10) as u8;
value /= 10;
i += 1;
}
while i > 0 {
i -= 1;
self.put_char(buf[i]);
}
}
}