From 8897e6467cde50c5c3b46c98c93af45a4c224f85 Mon Sep 17 00:00:00 2001 From: Paul Pan Date: Mon, 20 May 2024 16:15:00 +0800 Subject: [PATCH] feat: objects: add initial support for TcbObj --- kernel/src/arch/riscv/trap.rs | 57 ++++++++++++++++-- kernel/src/objects/cap.rs | 2 +- kernel/src/objects/mod.rs | 1 + kernel/src/objects/tcb.rs | 110 ++++++++++++++++++++++++++++++++++ kernel/src/plat/trap.rs | 10 +++- 5 files changed, 173 insertions(+), 7 deletions(-) create mode 100644 kernel/src/objects/tcb.rs diff --git a/kernel/src/arch/riscv/trap.rs b/kernel/src/arch/riscv/trap.rs index 939a9cf..d0400ea 100644 --- a/kernel/src/arch/riscv/trap.rs +++ b/kernel/src/arch/riscv/trap.rs @@ -1,7 +1,9 @@ use crate::entry::HART_ID; +use crate::objects::tcb::TcbObject; use crate::plat::console::CONSOLE; use crate::plat::timer::{Timer, TimerOps}; use crate::plat::trap::{Trap, TrapContextOps, TrapOps}; +use core::ops::{Index, IndexMut}; use log::trace; use riscv::register::scause::{Exception as E, Interrupt as I, Trap as T}; use riscv::register::stvec::TrapMode; @@ -19,7 +21,7 @@ extern "C" fn kernel_trap_handler(tf: &mut TrapContext) { // No trap in kernel, except from IDLE thread // TODO: Replace CONSOLE Mutex to ReentrantLock unsafe { CONSOLE.force_unlock() } - tf.trap_handler(true); + tf.handle_trap(true); } impl TrapOps for Trap { @@ -54,7 +56,7 @@ impl TrapContextOps for TrapContext { self.sstatus = (1 << 5) | (1 << 8); // SPIE + SPP } - fn trap_handler(&mut self, from_kernel: bool) { + fn handle_trap(&mut self, from_kernel: bool) { let scause = riscv::register::scause::read(); trace!("[Trap] cpu@{} scause: {:?}", HART_ID.get(), scause.cause()); @@ -71,10 +73,17 @@ impl TrapContextOps for TrapContext { }; } + let tcb = self.as_object_mut(); + match scause.cause() { - T::Interrupt(I::SupervisorTimer) => Timer::do_tick(), + T::Interrupt(I::SupervisorTimer) => { + Timer::do_tick(); + if !from_kernel { + tcb.timer_tick(); + } + }, T::Exception(E::UserEnvCall) => { - // TODO: handle syscall + tcb.handle_syscall(); self.sepc += 4; }, T::Interrupt(I::SupervisorExternal) => { @@ -90,7 +99,27 @@ impl TrapContextOps for TrapContext { } Timer::set_next(); - trace!("[Trap] exiting..."); + } + + fn as_object(&self) -> &TcbObject { + unsafe { &*(self as *const TrapContext as *const TcbObject) } + } + + fn as_object_mut(&mut self) -> &mut TcbObject { + unsafe { &mut *(self as *mut TrapContext as *mut TcbObject) } + } + + fn get_reg(&self, index: usize) -> usize { + // x10 ~ x17: Function arguments + assert!(index < 8, "TrapContext get_reg index out of range"); + self.gprs[index + 10] + } + + fn set_reg(&mut self, index: usize, value: usize) { + // x10 ~ x17: Function arguments + // x10 ~ x11: Function return values + assert!(index < 8, "TrapContext set_reg index out of range"); + self.gprs[index + 10] = value; } } @@ -130,6 +159,24 @@ pub struct GeneralRegs { pub t6: usize, } +impl Index for GeneralRegs { + type Output = usize; + + fn index(&self, index: usize) -> &Self::Output { + assert!(index < 32, "GeneralRegs index out of range"); + let regs = unsafe { &*(self as *const _ as *const [usize; 32]) }; + ®s[index] + } +} + +impl IndexMut for GeneralRegs { + fn index_mut(&mut self, index: usize) -> &mut Self::Output { + assert!(index < 32, "GeneralRegs index out of range"); + let regs = unsafe { &mut *(self as *mut _ as *mut [usize; 32]) }; + &mut regs[index] + } +} + #[derive(Debug, Default)] #[repr(C)] pub struct TrapContext { diff --git a/kernel/src/objects/cap.rs b/kernel/src/objects/cap.rs index 51e5db4..ce859e3 100644 --- a/kernel/src/objects/cap.rs +++ b/kernel/src/objects/cap.rs @@ -10,9 +10,9 @@ use utils::{ /// RawCap is the specific implementation of capability which stores in CNode #[derive(Copy, Clone, Default, PartialEq, Eq)] pub struct RawCap { - // TODO: this could be an enum, figure out a way to do this /// args: in vanilla seL4 implementation, a cap use two 64-bit words to store all information, /// but we'll waste some space rather than using bitfield to simplify the implementation + // TODO: use u64 rather than usize pub args: [usize; 2], /// ptr: vanilla seL4 stores the pointer with either higher bits or lower bits cut off, /// which limits the address space. Use an independent field to store the pointer. diff --git a/kernel/src/objects/mod.rs b/kernel/src/objects/mod.rs index 781ce96..f517caa 100644 --- a/kernel/src/objects/mod.rs +++ b/kernel/src/objects/mod.rs @@ -26,6 +26,7 @@ pub mod cnode; pub mod frame; pub mod null; pub mod table; +pub mod tcb; pub mod untyped; /// Cap is the high-level wrapper of RawCap, it's a typed reference to RawCap (which is untyped in Rust) diff --git a/kernel/src/objects/tcb.rs b/kernel/src/objects/tcb.rs new file mode 100644 index 0000000..bad0c05 --- /dev/null +++ b/kernel/src/objects/tcb.rs @@ -0,0 +1,110 @@ +use super::{ + cap::{CapEntry, RawCap}, + null::NullCap, + Cap, KernelObject, +}; +use crate::{ + arch::{layout::mmap_phys_to_virt, trap::TrapContext}, + plat::trap::TrapContextOps, +}; +use uapi::cap::ObjectType; +use utils::{ + addr::*, + linked_list::{Link, LinkHelper}, + LinkHelperImpl, +}; + +#[derive(Clone, Copy)] +pub enum ThreadState { + Inactive, + Running, + Restart, + Blocked, + Idle, +} + +#[repr(C)] +pub struct TcbObject { + pub trapframe: TrapContext, // must be the first field + + cspace: CapEntry, + vspace: CapEntry, + + // TODO: add reply, buffer, fault, caller ... priority, dom + state: ThreadState, + time_slice: usize, + pub link: Link, +} + +LinkHelperImpl!(TcbObject:link); + +impl TcbObject { + pub fn new() -> Self { + Self { + trapframe: TrapContext::default(), + cspace: CapEntry::new(NullCap::mint()), + vspace: CapEntry::new(NullCap::mint()), + state: ThreadState::Inactive, + time_slice: 0, + link: Link::default(), + } + } + + pub fn configure_idle_thread(&mut self) { + self.trapframe.configure_idle_thread(); + self.state = ThreadState::Idle; + } + + pub fn timeslice(&self) -> usize { + self.time_slice + } + + pub fn set_timeslice(&mut self, timeslice: usize) { + self.time_slice = timeslice; + } + + pub fn timer_tick(&mut self) { + self.time_slice = self.time_slice.saturating_sub(1); + } + + pub fn install_vspace(&self) { + // setup pagetable + todo!("TcbObject::install_vspace"); + } + + pub fn activate(&mut self) { + self.install_vspace(); + self.trapframe.restore(); + self.trapframe.handle_trap(false); + } + + pub fn handle_syscall(&mut self) { + todo!("TcbObject::handle_syscall"); + } +} + +impl KernelObject for TcbObject { + const OBJ_TYPE: ObjectType = ObjectType::TCB; +} + +pub type TcbCap<'a> = Cap<'a, TcbObject>; + +impl<'a> TcbCap<'a> { + pub fn mint(ptr: PhysAddr) -> RawCap { + RawCap::new(0, 0, ptr, ObjectType::TCB) + } + + pub fn as_object(&self) -> &TcbObject { + unsafe { + let virt = mmap_phys_to_virt(self.cte.cap.get().ptr); + &*(virt.as_const_ptr()) + } + } + + pub fn as_object_mut(&mut self) -> &mut TcbObject { + unsafe { + let virt = mmap_phys_to_virt(self.cte.cap.get().ptr); + &mut *(virt.as_mut_ptr()) + } + } +} diff --git a/kernel/src/plat/trap.rs b/kernel/src/plat/trap.rs index 0b4d780..29d7a44 100644 --- a/kernel/src/plat/trap.rs +++ b/kernel/src/plat/trap.rs @@ -1,3 +1,5 @@ +use crate::objects::tcb::TcbObject; + pub struct Trap; pub trait TrapOps { @@ -7,5 +9,11 @@ pub trait TrapOps { pub trait TrapContextOps { fn restore(&mut self); fn configure_idle_thread(&mut self); - fn trap_handler(&mut self, from_kernel: bool); + fn handle_trap(&mut self, from_kernel: bool); + + fn as_object(&self) -> &TcbObject; + fn as_object_mut(&mut self) -> &mut TcbObject; + + fn get_reg(&self, index: usize) -> usize; + fn set_reg(&mut self, index: usize, value: usize); }