feat(adapter-riscv): add RiscVPlatform, PLIC driver, and kernel boot on QEMU
This commit is contained in:
@@ -29,7 +29,7 @@ SECTIONS {
|
|||||||
|
|
||||||
. = ALIGN(4096);
|
. = ALIGN(4096);
|
||||||
_stack_bottom = .;
|
_stack_bottom = .;
|
||||||
. += 0x10000;
|
. += 0x80000;
|
||||||
_stack_top = .;
|
_stack_top = .;
|
||||||
|
|
||||||
_heap_start = .;
|
_heap_start = .;
|
||||||
|
|||||||
@@ -2,6 +2,8 @@
|
|||||||
#![no_main]
|
#![no_main]
|
||||||
|
|
||||||
mod page_table;
|
mod page_table;
|
||||||
|
mod platform;
|
||||||
|
mod plic;
|
||||||
mod timer;
|
mod timer;
|
||||||
mod trap;
|
mod trap;
|
||||||
mod uart;
|
mod uart;
|
||||||
@@ -52,8 +54,28 @@ extern "C" fn kmain() -> ! {
|
|||||||
|
|
||||||
trap::init_trap();
|
trap::init_trap();
|
||||||
timer::init_timer();
|
timer::init_timer();
|
||||||
|
plic::Plic::init();
|
||||||
uart.write_str("k-os: traps and timer initialized\n");
|
uart.write_str("k-os: traps and timer initialized\n");
|
||||||
|
|
||||||
|
let riscv_platform = platform::RiscVPlatform::new();
|
||||||
|
let pool = domain::memory::page_pool::PagePool::new(
|
||||||
|
types::address::PhysicalAddress::from_raw(0x84000000),
|
||||||
|
256,
|
||||||
|
);
|
||||||
|
let mut kern = kernel::Kernel::new(riscv_platform, pool);
|
||||||
|
let (pid, tid) = kern
|
||||||
|
.boot(
|
||||||
|
types::bounded::Priority::new(16).unwrap_or_else(|| unreachable!()),
|
||||||
|
types::time::TimeSlice::new(100),
|
||||||
|
)
|
||||||
|
.unwrap_or_else(|_| loop { unsafe { core::arch::asm!("wfi") }; });
|
||||||
|
|
||||||
|
uart.write_str("k-os: kernel started (pid=");
|
||||||
|
uart.write_dec(pid.raw() as usize);
|
||||||
|
uart.write_str(", tid=");
|
||||||
|
uart.write_dec(tid.raw() as usize);
|
||||||
|
uart.write_str(")\n");
|
||||||
|
|
||||||
loop {
|
loop {
|
||||||
unsafe { core::arch::asm!("wfi") };
|
unsafe { core::arch::asm!("wfi") };
|
||||||
}
|
}
|
||||||
|
|||||||
77
crates/adapter-riscv/src/platform.rs
Normal file
77
crates/adapter-riscv/src/platform.rs
Normal file
@@ -0,0 +1,77 @@
|
|||||||
|
use domain::memory::MemoryRegion;
|
||||||
|
use domain::thread::SavedContext;
|
||||||
|
use platform::Platform;
|
||||||
|
use types::{
|
||||||
|
address::{EntryPoint, PhysicalAddress, StackPointer},
|
||||||
|
bounded::PageCount,
|
||||||
|
id::{CoreId, IrqId, ProcessId},
|
||||||
|
permission::PermissionSet,
|
||||||
|
time::{Ticks, TimerDuration},
|
||||||
|
};
|
||||||
|
|
||||||
|
use crate::plic::Plic;
|
||||||
|
use crate::timer;
|
||||||
|
|
||||||
|
pub struct RiscVPlatform {
|
||||||
|
num_cores: u8,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl RiscVPlatform {
|
||||||
|
pub fn new() -> Self {
|
||||||
|
Self { num_cores: 1 }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Platform for RiscVPlatform {
|
||||||
|
fn configure_protection(&mut self, _process: ProcessId, _regions: &[MemoryRegion]) {
|
||||||
|
// page table activation happens separately per context switch
|
||||||
|
}
|
||||||
|
|
||||||
|
fn context_switch(&mut self, _from: &mut SavedContext, _to: &SavedContext) {
|
||||||
|
// context switch is handled by the trap vector assembly
|
||||||
|
}
|
||||||
|
|
||||||
|
fn enable_user_mode(&mut self, _entry: EntryPoint, _stack: StackPointer) -> ! {
|
||||||
|
// handled by setting up TrapFrame and sret in the main loop
|
||||||
|
loop { unsafe { core::arch::asm!("wfi") }; }
|
||||||
|
}
|
||||||
|
|
||||||
|
fn set_timer(&mut self, _duration: TimerDuration) {
|
||||||
|
let now = timer::read_time();
|
||||||
|
timer::set_next_timer(now + 10_000_000);
|
||||||
|
}
|
||||||
|
|
||||||
|
fn current_ticks(&self) -> Ticks {
|
||||||
|
Ticks::from_raw(timer::read_time())
|
||||||
|
}
|
||||||
|
|
||||||
|
fn mask_irq(&mut self, irq: IrqId) {
|
||||||
|
Plic::disable(irq.raw() as u32);
|
||||||
|
}
|
||||||
|
|
||||||
|
fn unmask_irq(&mut self, irq: IrqId) {
|
||||||
|
Plic::enable(irq.raw() as u32);
|
||||||
|
}
|
||||||
|
|
||||||
|
fn send_ipi(&mut self, _target: CoreId) {
|
||||||
|
// single core — no-op
|
||||||
|
}
|
||||||
|
|
||||||
|
fn core_id(&self) -> CoreId {
|
||||||
|
CoreId::from_raw(0)
|
||||||
|
}
|
||||||
|
|
||||||
|
fn num_cores(&self) -> u8 {
|
||||||
|
self.num_cores
|
||||||
|
}
|
||||||
|
|
||||||
|
fn map_shared(
|
||||||
|
&mut self,
|
||||||
|
_process: ProcessId,
|
||||||
|
_base: PhysicalAddress,
|
||||||
|
_size: PageCount,
|
||||||
|
_permissions: PermissionSet,
|
||||||
|
) {
|
||||||
|
// page table mapping for shared memory — deferred to full MMU integration
|
||||||
|
}
|
||||||
|
}
|
||||||
45
crates/adapter-riscv/src/plic.rs
Normal file
45
crates/adapter-riscv/src/plic.rs
Normal file
@@ -0,0 +1,45 @@
|
|||||||
|
const PLIC_BASE: usize = 0x0C000000;
|
||||||
|
const PLIC_PRIORITY: usize = PLIC_BASE;
|
||||||
|
const PLIC_S_ENABLE: usize = PLIC_BASE + 0x2080; // S-mode hart 0 context = 1
|
||||||
|
const PLIC_S_THRESHOLD: usize = PLIC_BASE + 0x201000;
|
||||||
|
const PLIC_S_CLAIM: usize = PLIC_BASE + 0x201004;
|
||||||
|
|
||||||
|
pub struct Plic;
|
||||||
|
|
||||||
|
impl Plic {
|
||||||
|
pub fn init() {
|
||||||
|
// set threshold to 0 (accept all priorities)
|
||||||
|
unsafe { core::ptr::write_volatile(PLIC_S_THRESHOLD as *mut u32, 0) };
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn enable(irq: u32) {
|
||||||
|
let word = (irq / 32) as usize;
|
||||||
|
let bit = irq % 32;
|
||||||
|
let addr = PLIC_S_ENABLE + word * 4;
|
||||||
|
unsafe {
|
||||||
|
let current = core::ptr::read_volatile(addr as *const u32);
|
||||||
|
core::ptr::write_volatile(addr as *mut u32, current | (1 << bit));
|
||||||
|
}
|
||||||
|
// set priority > 0
|
||||||
|
let prio_addr = PLIC_PRIORITY + (irq as usize) * 4;
|
||||||
|
unsafe { core::ptr::write_volatile(prio_addr as *mut u32, 1) };
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn disable(irq: u32) {
|
||||||
|
let word = (irq / 32) as usize;
|
||||||
|
let bit = irq % 32;
|
||||||
|
let addr = PLIC_S_ENABLE + word * 4;
|
||||||
|
unsafe {
|
||||||
|
let current = core::ptr::read_volatile(addr as *const u32);
|
||||||
|
core::ptr::write_volatile(addr as *mut u32, current & !(1 << bit));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn claim() -> u32 {
|
||||||
|
unsafe { core::ptr::read_volatile(PLIC_S_CLAIM as *const u32) }
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn complete(irq: u32) {
|
||||||
|
unsafe { core::ptr::write_volatile(PLIC_S_CLAIM as *mut u32, irq) };
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -22,6 +22,10 @@ pub fn init_timer() {
|
|||||||
sbi_set_timer(now + TICK_INTERVAL);
|
sbi_set_timer(now + TICK_INTERVAL);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn set_next_timer(deadline: u64) {
|
||||||
|
sbi_set_timer(deadline);
|
||||||
|
}
|
||||||
|
|
||||||
pub fn handle_timer_interrupt() {
|
pub fn handle_timer_interrupt() {
|
||||||
let now = read_time();
|
let now = read_time();
|
||||||
sbi_set_timer(now + TICK_INTERVAL);
|
sbi_set_timer(now + TICK_INTERVAL);
|
||||||
|
|||||||
Reference in New Issue
Block a user