refactor(adapter-riscv): restructure into hw/, mmu/, trap/ modules with board constants
Add Priority::DEFAULT and TimeSlice::DEFAULT to types crate. All QEMU virt addresses consolidated in board.rs. Structure mirrors future adapter-arm/ layout.
This commit is contained in:
8
crates/adapter-riscv/src/board.rs
Normal file
8
crates/adapter-riscv/src/board.rs
Normal file
@@ -0,0 +1,8 @@
|
|||||||
|
pub const RAM_BASE: usize = 0x80000000;
|
||||||
|
pub const RAM_SIZE: usize = 128 * 1024 * 1024;
|
||||||
|
pub const UART_BASE: usize = 0x10000000;
|
||||||
|
pub const PLIC_BASE: usize = 0x0C000000;
|
||||||
|
pub const CLINT_BASE: usize = 0x02000000;
|
||||||
|
pub const USER_POOL_BASE: usize = 0x84000000;
|
||||||
|
pub const USER_POOL_PAGES: usize = 256;
|
||||||
|
pub const TICK_INTERVAL: u64 = 10_000_000;
|
||||||
3
crates/adapter-riscv/src/hw/mod.rs
Normal file
3
crates/adapter-riscv/src/hw/mod.rs
Normal file
@@ -0,0 +1,3 @@
|
|||||||
|
pub mod plic;
|
||||||
|
pub mod timer;
|
||||||
|
pub mod uart;
|
||||||
@@ -1,14 +1,14 @@
|
|||||||
const PLIC_BASE: usize = 0x0C000000;
|
use crate::board;
|
||||||
const PLIC_PRIORITY: usize = PLIC_BASE;
|
|
||||||
const PLIC_S_ENABLE: usize = PLIC_BASE + 0x2080; // S-mode hart 0 context = 1
|
const PLIC_PRIORITY: usize = board::PLIC_BASE;
|
||||||
const PLIC_S_THRESHOLD: usize = PLIC_BASE + 0x201000;
|
const PLIC_S_ENABLE: usize = board::PLIC_BASE + 0x2080;
|
||||||
const PLIC_S_CLAIM: usize = PLIC_BASE + 0x201004;
|
const PLIC_S_THRESHOLD: usize = board::PLIC_BASE + 0x201000;
|
||||||
|
const PLIC_S_CLAIM: usize = board::PLIC_BASE + 0x201004;
|
||||||
|
|
||||||
pub struct Plic;
|
pub struct Plic;
|
||||||
|
|
||||||
impl Plic {
|
impl Plic {
|
||||||
pub fn init() {
|
pub fn init() {
|
||||||
// set threshold to 0 (accept all priorities)
|
|
||||||
unsafe { core::ptr::write_volatile(PLIC_S_THRESHOLD as *mut u32, 0) };
|
unsafe { core::ptr::write_volatile(PLIC_S_THRESHOLD as *mut u32, 0) };
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -20,7 +20,6 @@ impl Plic {
|
|||||||
let current = core::ptr::read_volatile(addr as *const u32);
|
let current = core::ptr::read_volatile(addr as *const u32);
|
||||||
core::ptr::write_volatile(addr as *mut u32, current | (1 << bit));
|
core::ptr::write_volatile(addr as *mut u32, current | (1 << bit));
|
||||||
}
|
}
|
||||||
// set priority > 0
|
|
||||||
let prio_addr = PLIC_PRIORITY + (irq as usize) * 4;
|
let prio_addr = PLIC_PRIORITY + (irq as usize) * 4;
|
||||||
unsafe { core::ptr::write_volatile(prio_addr as *mut u32, 1) };
|
unsafe { core::ptr::write_volatile(prio_addr as *mut u32, 1) };
|
||||||
}
|
}
|
||||||
@@ -1,4 +1,4 @@
|
|||||||
const TICK_INTERVAL: u64 = 10_000_000; // 1 second at 10MHz
|
use crate::board;
|
||||||
|
|
||||||
pub fn read_time() -> u64 {
|
pub fn read_time() -> u64 {
|
||||||
let time: u64;
|
let time: u64;
|
||||||
@@ -12,21 +12,21 @@ fn sbi_set_timer(stime: u64) {
|
|||||||
"ecall",
|
"ecall",
|
||||||
in("a0") stime,
|
in("a0") stime,
|
||||||
in("a6") 0usize,
|
in("a6") 0usize,
|
||||||
in("a7") 0x54494D45usize, // SBI Timer extension ID
|
in("a7") 0x54494D45usize,
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn init_timer() {
|
pub fn init() {
|
||||||
let now = read_time();
|
let now = read_time();
|
||||||
sbi_set_timer(now + TICK_INTERVAL);
|
sbi_set_timer(now + board::TICK_INTERVAL);
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn set_next_timer(deadline: u64) {
|
pub fn set_next(deadline: u64) {
|
||||||
sbi_set_timer(deadline);
|
sbi_set_timer(deadline);
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn handle_timer_interrupt() {
|
pub fn handle_interrupt() {
|
||||||
let now = read_time();
|
let now = read_time();
|
||||||
sbi_set_timer(now + TICK_INTERVAL);
|
sbi_set_timer(now + board::TICK_INTERVAL);
|
||||||
}
|
}
|
||||||
@@ -1,4 +1,4 @@
|
|||||||
const UART_BASE: usize = 0x10000000;
|
use crate::board;
|
||||||
|
|
||||||
pub struct Uart {
|
pub struct Uart {
|
||||||
base: usize,
|
base: usize,
|
||||||
@@ -6,7 +6,7 @@ pub struct Uart {
|
|||||||
|
|
||||||
impl Uart {
|
impl Uart {
|
||||||
pub fn new() -> Self {
|
pub fn new() -> Self {
|
||||||
Self { base: UART_BASE }
|
Self { base: board::UART_BASE }
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn put_char(&self, byte: u8) {
|
pub fn put_char(&self, byte: u8) {
|
||||||
@@ -1,15 +1,14 @@
|
|||||||
#![no_std]
|
#![no_std]
|
||||||
#![no_main]
|
#![no_main]
|
||||||
|
|
||||||
mod page_table;
|
mod board;
|
||||||
|
mod hw;
|
||||||
|
mod mmu;
|
||||||
mod platform;
|
mod platform;
|
||||||
mod plic;
|
|
||||||
mod timer;
|
|
||||||
mod trap;
|
mod trap;
|
||||||
mod uart;
|
|
||||||
|
|
||||||
use core::arch::global_asm;
|
use core::arch::global_asm;
|
||||||
use uart::Uart;
|
use hw::uart::Uart;
|
||||||
|
|
||||||
global_asm!(
|
global_asm!(
|
||||||
r#"
|
r#"
|
||||||
@@ -47,27 +46,24 @@ extern "C" fn kmain() -> ! {
|
|||||||
uart.write_str("k-os: booted on RISC-V\n");
|
uart.write_str("k-os: booted on RISC-V\n");
|
||||||
|
|
||||||
let heap_start = unsafe { &_heap_start as *const u8 as usize };
|
let heap_start = unsafe { &_heap_start as *const u8 as usize };
|
||||||
page_table::init_page_allocator(heap_start);
|
mmu::init_allocator(heap_start);
|
||||||
let kernel_pt = page_table::init_kernel_page_table();
|
let kernel_pt = mmu::init_kernel_page_table();
|
||||||
page_table::activate(kernel_pt);
|
mmu::activate(kernel_pt);
|
||||||
uart.write_str("k-os: MMU enabled (Sv39)\n");
|
uart.write_str("k-os: MMU enabled (Sv39)\n");
|
||||||
|
|
||||||
trap::init_trap();
|
trap::init();
|
||||||
timer::init_timer();
|
hw::timer::init();
|
||||||
plic::Plic::init();
|
hw::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 riscv_platform = platform::RiscVPlatform::new();
|
||||||
let pool = domain::memory::page_pool::PagePool::new(
|
let pool = domain::memory::page_pool::PagePool::new(
|
||||||
types::address::PhysicalAddress::from_raw(0x84000000),
|
types::address::PhysicalAddress::from_raw(board::USER_POOL_BASE),
|
||||||
256,
|
board::USER_POOL_PAGES,
|
||||||
);
|
);
|
||||||
let mut kern = kernel::Kernel::new(riscv_platform, pool);
|
let mut kern = kernel::Kernel::new(riscv_platform, pool);
|
||||||
let (pid, tid) = kern
|
let (pid, tid) = kern
|
||||||
.boot(
|
.boot(types::bounded::Priority::DEFAULT, types::time::TimeSlice::DEFAULT)
|
||||||
types::bounded::Priority::new(16).unwrap_or_else(|| unreachable!()),
|
|
||||||
types::time::TimeSlice::new(100),
|
|
||||||
)
|
|
||||||
.unwrap_or_else(|_| loop { unsafe { core::arch::asm!("wfi") }; });
|
.unwrap_or_else(|_| loop { unsafe { core::arch::asm!("wfi") }; });
|
||||||
|
|
||||||
uart.write_str("k-os: kernel started (pid=");
|
uart.write_str("k-os: kernel started (pid=");
|
||||||
@@ -100,8 +96,7 @@ fn ipc_demo(
|
|||||||
|
|
||||||
uart.write_str("k-os: --- IPC demo ---\n");
|
uart.write_str("k-os: --- IPC demo ---\n");
|
||||||
|
|
||||||
// Create process B using init's ProcessCreate cap (slot 0)
|
let _proc_b_slot = match kern.handle_syscall(Syscall::CreateProcess {
|
||||||
let proc_b_slot = match kern.handle_syscall(Syscall::CreateProcess {
|
|
||||||
create_cap: CapSlot::new(0).unwrap_or_else(|| unreachable!()),
|
create_cap: CapSlot::new(0).unwrap_or_else(|| unreachable!()),
|
||||||
image: DataRef::empty(),
|
image: DataRef::empty(),
|
||||||
}) {
|
}) {
|
||||||
@@ -115,10 +110,8 @@ fn ipc_demo(
|
|||||||
let tid_b = ThreadId::from_raw(1);
|
let tid_b = ThreadId::from_raw(1);
|
||||||
uart.write_str("k-os: process B created\n");
|
uart.write_str("k-os: process B created\n");
|
||||||
|
|
||||||
// Create an endpoint
|
|
||||||
let ep_id = kern.create_endpoint().unwrap_or_else(|_| unreachable!());
|
let ep_id = kern.create_endpoint().unwrap_or_else(|_| unreachable!());
|
||||||
|
|
||||||
// Grant endpoint caps to both processes
|
|
||||||
let ep_cap_a = kern.grant_capability(
|
let ep_cap_a = kern.grant_capability(
|
||||||
init_pid,
|
init_pid,
|
||||||
Resource::Endpoint(ep_id),
|
Resource::Endpoint(ep_id),
|
||||||
@@ -137,10 +130,8 @@ fn ipc_demo(
|
|||||||
|
|
||||||
uart.write_str("k-os: endpoint created, caps granted\n");
|
uart.write_str("k-os: endpoint created, caps granted\n");
|
||||||
|
|
||||||
// Process B calls Receive (blocks — no sender yet)
|
|
||||||
kern.switch_to_thread(tid_b);
|
kern.switch_to_thread(tid_b);
|
||||||
let outcome = kern.handle_syscall(Syscall::Receive { endpoint: ep_cap_b });
|
match kern.handle_syscall(Syscall::Receive { endpoint: ep_cap_b }) {
|
||||||
match &outcome {
|
|
||||||
SyscallOutcome::BlockCaller(_) => {
|
SyscallOutcome::BlockCaller(_) => {
|
||||||
uart.write_str("k-os: process B blocked on Receive\n");
|
uart.write_str("k-os: process B blocked on Receive\n");
|
||||||
}
|
}
|
||||||
@@ -150,15 +141,13 @@ fn ipc_demo(
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Process A calls Send (finds B waiting → delivers message)
|
|
||||||
let tid_a = ThreadId::from_raw(0);
|
let tid_a = ThreadId::from_raw(0);
|
||||||
kern.switch_to_thread(tid_a);
|
kern.switch_to_thread(tid_a);
|
||||||
let msg = Message::from_words([42, 7, 0, 0]);
|
let msg = Message::from_words([42, 7, 0, 0]);
|
||||||
let outcome = kern.handle_syscall(Syscall::Send {
|
match kern.handle_syscall(Syscall::Send {
|
||||||
endpoint: ep_cap_a,
|
endpoint: ep_cap_a,
|
||||||
message: msg,
|
message: msg,
|
||||||
});
|
}) {
|
||||||
match &outcome {
|
|
||||||
SyscallOutcome::SwitchTo(target) => {
|
SyscallOutcome::SwitchTo(target) => {
|
||||||
uart.write_str("k-os: Send delivered, switching to thread ");
|
uart.write_str("k-os: Send delivered, switching to thread ");
|
||||||
uart.write_dec(target.raw() as usize);
|
uart.write_dec(target.raw() as usize);
|
||||||
@@ -170,7 +159,6 @@ fn ipc_demo(
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Check B's pending result
|
|
||||||
match kern.pending_result(tid_b) {
|
match kern.pending_result(tid_b) {
|
||||||
Some(SyscallResult::Message(m)) => {
|
Some(SyscallResult::Message(m)) => {
|
||||||
uart.write_str("k-os: IPC complete — received: [");
|
uart.write_str("k-os: IPC complete — received: [");
|
||||||
|
|||||||
19
crates/adapter-riscv/src/mmu/allocator.rs
Normal file
19
crates/adapter-riscv/src/mmu/allocator.rs
Normal file
@@ -0,0 +1,19 @@
|
|||||||
|
use super::page_table::{PageTable, PAGE_SIZE};
|
||||||
|
|
||||||
|
// Boot-time bump allocator for page tables.
|
||||||
|
// Only used during init before the scheduler starts.
|
||||||
|
static mut NEXT_FREE: usize = 0;
|
||||||
|
|
||||||
|
pub fn init_allocator(start: usize) {
|
||||||
|
unsafe { NEXT_FREE = start; }
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn alloc_page_table() -> &'static mut PageTable {
|
||||||
|
unsafe {
|
||||||
|
let addr = NEXT_FREE;
|
||||||
|
NEXT_FREE += PAGE_SIZE;
|
||||||
|
let table = &mut *(addr as *mut PageTable);
|
||||||
|
table.zero();
|
||||||
|
table
|
||||||
|
}
|
||||||
|
}
|
||||||
5
crates/adapter-riscv/src/mmu/mod.rs
Normal file
5
crates/adapter-riscv/src/mmu/mod.rs
Normal file
@@ -0,0 +1,5 @@
|
|||||||
|
pub mod allocator;
|
||||||
|
pub mod page_table;
|
||||||
|
|
||||||
|
pub use allocator::init_allocator;
|
||||||
|
pub use page_table::{activate, init_kernel_page_table, create_user_page_table, PageTable, PAGE_SIZE};
|
||||||
@@ -1,4 +1,8 @@
|
|||||||
|
use crate::board;
|
||||||
|
use super::allocator::alloc_page_table;
|
||||||
|
|
||||||
pub const PAGE_SIZE: usize = 4096;
|
pub const PAGE_SIZE: usize = 4096;
|
||||||
|
|
||||||
const PTE_V: u64 = 1 << 0;
|
const PTE_V: u64 = 1 << 0;
|
||||||
const PTE_R: u64 = 1 << 1;
|
const PTE_R: u64 = 1 << 1;
|
||||||
const PTE_W: u64 = 1 << 2;
|
const PTE_W: u64 = 1 << 2;
|
||||||
@@ -53,22 +57,6 @@ impl PageTable {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
static mut PAGE_ALLOC_NEXT: usize = 0;
|
|
||||||
|
|
||||||
pub fn init_page_allocator(start: usize) {
|
|
||||||
unsafe { PAGE_ALLOC_NEXT = start; }
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn alloc_page_table() -> &'static mut PageTable {
|
|
||||||
unsafe {
|
|
||||||
let addr = PAGE_ALLOC_NEXT;
|
|
||||||
PAGE_ALLOC_NEXT += PAGE_SIZE;
|
|
||||||
let table = &mut *(addr as *mut PageTable);
|
|
||||||
table.zero();
|
|
||||||
table
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
fn vpn(va: usize, level: usize) -> usize {
|
fn vpn(va: usize, level: usize) -> usize {
|
||||||
(va >> (12 + 9 * level)) & 0x1FF
|
(va >> (12 + 9 * level)) & 0x1FF
|
||||||
}
|
}
|
||||||
@@ -110,27 +98,23 @@ fn map_range(root: &mut PageTable, va_start: usize, pa_start: usize, pages: usiz
|
|||||||
pub fn init_kernel_page_table() -> &'static mut PageTable {
|
pub fn init_kernel_page_table() -> &'static mut PageTable {
|
||||||
let root = alloc_page_table();
|
let root = alloc_page_table();
|
||||||
|
|
||||||
let ram_start = 0x80000000usize;
|
let ram_pages = board::RAM_SIZE / PAGE_SIZE;
|
||||||
let ram_pages = 128 * 1024 * 1024 / PAGE_SIZE; // 128 MiB
|
map_range(root, board::RAM_BASE, board::RAM_BASE, ram_pages, true, true, true, false, true);
|
||||||
map_range(root, ram_start, ram_start, ram_pages, true, true, true, false, true);
|
|
||||||
|
|
||||||
let uart_start = 0x10000000usize;
|
map_range(root, board::UART_BASE, board::UART_BASE, 1, true, true, false, false, true);
|
||||||
map_range(root, uart_start, uart_start, 1, true, true, false, false, true);
|
|
||||||
|
|
||||||
let plic_start = 0x0C000000usize;
|
|
||||||
let plic_pages = 0x400000 / PAGE_SIZE;
|
let plic_pages = 0x400000 / PAGE_SIZE;
|
||||||
map_range(root, plic_start, plic_start, plic_pages, true, true, false, false, true);
|
map_range(root, board::PLIC_BASE, board::PLIC_BASE, plic_pages, true, true, false, false, true);
|
||||||
|
|
||||||
let clint_start = 0x02000000usize;
|
|
||||||
let clint_pages = 0x10000 / PAGE_SIZE;
|
let clint_pages = 0x10000 / PAGE_SIZE;
|
||||||
map_range(root, clint_start, clint_start, clint_pages, true, true, false, false, true);
|
map_range(root, board::CLINT_BASE, board::CLINT_BASE, clint_pages, true, true, false, false, true);
|
||||||
|
|
||||||
root
|
root
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn activate(root: &PageTable) {
|
pub fn activate(root: &PageTable) {
|
||||||
let ppn = (root as *const PageTable as u64) >> 12;
|
let ppn = (root as *const PageTable as u64) >> 12;
|
||||||
let satp = (8u64 << 60) | ppn; // mode=8 (Sv39), ASID=0
|
let satp = (8u64 << 60) | ppn;
|
||||||
unsafe {
|
unsafe {
|
||||||
core::arch::asm!(
|
core::arch::asm!(
|
||||||
"csrw satp, {0}",
|
"csrw satp, {0}",
|
||||||
@@ -148,18 +132,14 @@ pub fn create_user_page_table(
|
|||||||
) -> &'static mut PageTable {
|
) -> &'static mut PageTable {
|
||||||
let root = alloc_page_table();
|
let root = alloc_page_table();
|
||||||
|
|
||||||
// Copy kernel mappings (upper half — entries 256-511 cover high VA space)
|
|
||||||
// For identity mapping, copy all valid entries from kernel root
|
|
||||||
for i in 0..512 {
|
for i in 0..512 {
|
||||||
if kernel_root.entries[i].is_valid() {
|
if kernel_root.entries[i].is_valid() {
|
||||||
root.entries[i] = kernel_root.entries[i];
|
root.entries[i] = kernel_root.entries[i];
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Map user program pages
|
|
||||||
map_range(root, user_va, program_pa, program_pages, true, false, true, true, false);
|
map_range(root, user_va, program_pa, program_pages, true, false, true, true, false);
|
||||||
|
|
||||||
// Map user stack (1 page at user_va - PAGE_SIZE)
|
|
||||||
let stack_va = user_va.wrapping_sub(PAGE_SIZE);
|
let stack_va = user_va.wrapping_sub(PAGE_SIZE);
|
||||||
let stack_table = alloc_page_table();
|
let stack_table = alloc_page_table();
|
||||||
let stack_pa = stack_table as *const PageTable as usize;
|
let stack_pa = stack_table as *const PageTable as usize;
|
||||||
@@ -9,8 +9,8 @@ use types::{
|
|||||||
time::{Ticks, TimerDuration},
|
time::{Ticks, TimerDuration},
|
||||||
};
|
};
|
||||||
|
|
||||||
use crate::plic::Plic;
|
use crate::board;
|
||||||
use crate::timer;
|
use crate::hw::{plic::Plic, timer};
|
||||||
|
|
||||||
pub struct RiscVPlatform {
|
pub struct RiscVPlatform {
|
||||||
num_cores: u8,
|
num_cores: u8,
|
||||||
@@ -23,22 +23,17 @@ impl RiscVPlatform {
|
|||||||
}
|
}
|
||||||
|
|
||||||
impl Platform for RiscVPlatform {
|
impl Platform for RiscVPlatform {
|
||||||
fn configure_protection(&mut self, _process: ProcessId, _regions: &[MemoryRegion]) {
|
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) {
|
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) -> ! {
|
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") }; }
|
loop { unsafe { core::arch::asm!("wfi") }; }
|
||||||
}
|
}
|
||||||
|
|
||||||
fn set_timer(&mut self, _duration: TimerDuration) {
|
fn set_timer(&mut self, _duration: TimerDuration) {
|
||||||
let now = timer::read_time();
|
let now = timer::read_time();
|
||||||
timer::set_next_timer(now + 10_000_000);
|
timer::set_next(now + board::TICK_INTERVAL);
|
||||||
}
|
}
|
||||||
|
|
||||||
fn current_ticks(&self) -> Ticks {
|
fn current_ticks(&self) -> Ticks {
|
||||||
@@ -53,9 +48,7 @@ impl Platform for RiscVPlatform {
|
|||||||
Plic::enable(irq.raw() as u32);
|
Plic::enable(irq.raw() as u32);
|
||||||
}
|
}
|
||||||
|
|
||||||
fn send_ipi(&mut self, _target: CoreId) {
|
fn send_ipi(&mut self, _target: CoreId) {}
|
||||||
// single core — no-op
|
|
||||||
}
|
|
||||||
|
|
||||||
fn core_id(&self) -> CoreId {
|
fn core_id(&self) -> CoreId {
|
||||||
CoreId::from_raw(0)
|
CoreId::from_raw(0)
|
||||||
@@ -72,6 +65,5 @@ impl Platform for RiscVPlatform {
|
|||||||
_size: PageCount,
|
_size: PageCount,
|
||||||
_permissions: PermissionSet,
|
_permissions: PermissionSet,
|
||||||
) {
|
) {
|
||||||
// page table mapping for shared memory — deferred to full MMU integration
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -2,7 +2,7 @@ use core::arch::global_asm;
|
|||||||
|
|
||||||
#[repr(C)]
|
#[repr(C)]
|
||||||
pub struct TrapFrame {
|
pub struct TrapFrame {
|
||||||
pub regs: [usize; 32], // x0-x31
|
pub regs: [usize; 32],
|
||||||
pub sepc: usize,
|
pub sepc: usize,
|
||||||
pub sstatus: usize,
|
pub sstatus: usize,
|
||||||
}
|
}
|
||||||
@@ -17,7 +17,7 @@ impl TrapFrame {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// sscratch = 0 when in S-mode, = kernel_stack_top when in U-mode
|
// sscratch = 0 when in S-mode, = kernel_stack_top when in U-mode.
|
||||||
// On trap: swap sp/sscratch. If sp==0 after swap, we came from S-mode (undo swap).
|
// On trap: swap sp/sscratch. If sp==0 after swap, we came from S-mode (undo swap).
|
||||||
global_asm!(r#"
|
global_asm!(r#"
|
||||||
.align 4
|
.align 4
|
||||||
@@ -25,10 +25,8 @@ global_asm!(r#"
|
|||||||
trap_vector:
|
trap_vector:
|
||||||
csrrw sp, sscratch, sp
|
csrrw sp, sscratch, sp
|
||||||
bnez sp, _from_user
|
bnez sp, _from_user
|
||||||
# came from S-mode: sscratch had 0, sp is now 0, old sp is in sscratch
|
csrrw sp, sscratch, sp
|
||||||
csrrw sp, sscratch, sp # undo: sp = old kernel sp, sscratch = 0
|
|
||||||
_from_user:
|
_from_user:
|
||||||
# sp is now a valid kernel stack (either kept or swapped in)
|
|
||||||
addi sp, sp, -272
|
addi sp, sp, -272
|
||||||
|
|
||||||
sd x1, 8(sp)
|
sd x1, 8(sp)
|
||||||
@@ -62,7 +60,6 @@ _from_user:
|
|||||||
sd x30, 240(sp)
|
sd x30, 240(sp)
|
||||||
sd x31, 248(sp)
|
sd x31, 248(sp)
|
||||||
|
|
||||||
# save user sp from sscratch (0 if from S-mode, user sp if from U-mode)
|
|
||||||
csrr t0, sscratch
|
csrr t0, sscratch
|
||||||
sd t0, 16(sp)
|
sd t0, 16(sp)
|
||||||
|
|
||||||
@@ -79,12 +76,9 @@ _from_user:
|
|||||||
ld t0, 264(sp)
|
ld t0, 264(sp)
|
||||||
csrw sstatus, t0
|
csrw sstatus, t0
|
||||||
|
|
||||||
# check if returning to U-mode: sstatus.SPP (bit 8)
|
|
||||||
# if SPP=0 (user mode), restore sscratch with user sp
|
|
||||||
andi t1, t0, 0x100
|
andi t1, t0, 0x100
|
||||||
bnez t1, _restore_smode
|
bnez t1, _restore_smode
|
||||||
|
|
||||||
# returning to U-mode: put user sp in sscratch
|
|
||||||
ld t0, 16(sp)
|
ld t0, 16(sp)
|
||||||
csrw sscratch, t0
|
csrw sscratch, t0
|
||||||
|
|
||||||
@@ -122,11 +116,10 @@ _restore_smode:
|
|||||||
|
|
||||||
addi sp, sp, 272
|
addi sp, sp, 272
|
||||||
|
|
||||||
# if returning to U-mode, swap sp/sscratch to restore user sp
|
|
||||||
csrr t0, sstatus
|
csrr t0, sstatus
|
||||||
andi t0, t0, 0x100
|
andi t0, t0, 0x100
|
||||||
bnez t0, _sret_smode
|
bnez t0, _sret_smode
|
||||||
csrrw sp, sscratch, sp # sp = user sp, sscratch = kernel sp (for next trap)
|
csrrw sp, sscratch, sp
|
||||||
_sret_smode:
|
_sret_smode:
|
||||||
sret
|
sret
|
||||||
"#);
|
"#);
|
||||||
@@ -136,21 +129,15 @@ const CAUSE_S_TIMER: usize = 5;
|
|||||||
const CAUSE_S_EXTERNAL: usize = 9;
|
const CAUSE_S_EXTERNAL: usize = 9;
|
||||||
const CAUSE_ECALL_U: usize = 8;
|
const CAUSE_ECALL_U: usize = 8;
|
||||||
|
|
||||||
pub fn init_trap() {
|
pub fn init() {
|
||||||
unsafe extern "C" {
|
unsafe extern "C" {
|
||||||
fn trap_vector();
|
fn trap_vector();
|
||||||
}
|
}
|
||||||
unsafe {
|
unsafe {
|
||||||
let addr = trap_vector as usize;
|
let addr = trap_vector as usize;
|
||||||
core::arch::asm!("csrw stvec, {0}", in(reg) addr);
|
core::arch::asm!("csrw stvec, {0}", in(reg) addr);
|
||||||
|
|
||||||
// sscratch = 0 means "currently in S-mode"
|
|
||||||
core::arch::asm!("csrw sscratch, zero");
|
core::arch::asm!("csrw sscratch, zero");
|
||||||
|
|
||||||
// enable supervisor interrupts
|
|
||||||
core::arch::asm!("csrs sstatus, {0}", in(reg) 1usize << 1);
|
core::arch::asm!("csrs sstatus, {0}", in(reg) 1usize << 1);
|
||||||
|
|
||||||
// enable timer + external + software interrupts in sie
|
|
||||||
let sie_bits = (1usize << 5) | (1usize << 9) | (1usize << 1);
|
let sie_bits = (1usize << 5) | (1usize << 9) | (1usize << 1);
|
||||||
core::arch::asm!("csrs sie, {0}", in(reg) sie_bits);
|
core::arch::asm!("csrs sie, {0}", in(reg) sie_bits);
|
||||||
}
|
}
|
||||||
@@ -167,13 +154,13 @@ extern "C" fn trap_handler_rust(frame: &mut TrapFrame) {
|
|||||||
let scause: usize;
|
let scause: usize;
|
||||||
unsafe { core::arch::asm!("csrr {0}, scause", out(reg) scause) };
|
unsafe { core::arch::asm!("csrr {0}, scause", out(reg) scause) };
|
||||||
|
|
||||||
let uart = crate::uart::Uart::new();
|
let uart = crate::hw::uart::Uart::new();
|
||||||
|
|
||||||
if scause & CAUSE_INTERRUPT_BIT != 0 {
|
if scause & CAUSE_INTERRUPT_BIT != 0 {
|
||||||
let cause = scause & !CAUSE_INTERRUPT_BIT;
|
let cause = scause & !CAUSE_INTERRUPT_BIT;
|
||||||
match cause {
|
match cause {
|
||||||
CAUSE_S_TIMER => {
|
CAUSE_S_TIMER => {
|
||||||
crate::timer::handle_timer_interrupt();
|
crate::hw::timer::handle_interrupt();
|
||||||
}
|
}
|
||||||
CAUSE_S_EXTERNAL => {
|
CAUSE_S_EXTERNAL => {
|
||||||
uart.write_str("[EXT]");
|
uart.write_str("[EXT]");
|
||||||
@@ -3,3 +3,8 @@ use crate::macros::bounded;
|
|||||||
bounded!(CapSlot, u8, 0, 63);
|
bounded!(CapSlot, u8, 0, 63);
|
||||||
bounded!(Priority, u8, 0, 31);
|
bounded!(Priority, u8, 0, 31);
|
||||||
bounded!(PageCount, u16, 1, 1024);
|
bounded!(PageCount, u16, 1, 1024);
|
||||||
|
|
||||||
|
impl Priority {
|
||||||
|
pub const DEFAULT: Self = Self(16);
|
||||||
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -25,6 +25,11 @@ pub struct TimeSlice {
|
|||||||
}
|
}
|
||||||
|
|
||||||
impl TimeSlice {
|
impl TimeSlice {
|
||||||
|
pub const DEFAULT: Self = Self {
|
||||||
|
remaining: 100,
|
||||||
|
quantum: 100,
|
||||||
|
};
|
||||||
|
|
||||||
pub fn new(quantum: u32) -> Self {
|
pub fn new(quantum: u32) -> Self {
|
||||||
Self {
|
Self {
|
||||||
remaining: quantum,
|
remaining: quantum,
|
||||||
|
|||||||
Reference in New Issue
Block a user