feat: objects: add initial support for TcbObj

This commit is contained in:
Paul Pan 2024-05-20 16:15:00 +08:00
parent f005c8254b
commit 8897e6467c
5 changed files with 173 additions and 7 deletions

View File

@ -1,7 +1,9 @@
use crate::entry::HART_ID; use crate::entry::HART_ID;
use crate::objects::tcb::TcbObject;
use crate::plat::console::CONSOLE; use crate::plat::console::CONSOLE;
use crate::plat::timer::{Timer, TimerOps}; use crate::plat::timer::{Timer, TimerOps};
use crate::plat::trap::{Trap, TrapContextOps, TrapOps}; use crate::plat::trap::{Trap, TrapContextOps, TrapOps};
use core::ops::{Index, IndexMut};
use log::trace; use log::trace;
use riscv::register::scause::{Exception as E, Interrupt as I, Trap as T}; use riscv::register::scause::{Exception as E, Interrupt as I, Trap as T};
use riscv::register::stvec::TrapMode; 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 // No trap in kernel, except from IDLE thread
// TODO: Replace CONSOLE Mutex to ReentrantLock // TODO: Replace CONSOLE Mutex to ReentrantLock
unsafe { CONSOLE.force_unlock() } unsafe { CONSOLE.force_unlock() }
tf.trap_handler(true); tf.handle_trap(true);
} }
impl TrapOps for Trap { impl TrapOps for Trap {
@ -54,7 +56,7 @@ impl TrapContextOps for TrapContext {
self.sstatus = (1 << 5) | (1 << 8); // SPIE + SPP 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(); let scause = riscv::register::scause::read();
trace!("[Trap] cpu@{} scause: {:?}", HART_ID.get(), scause.cause()); 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() { 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) => { T::Exception(E::UserEnvCall) => {
// TODO: handle syscall tcb.handle_syscall();
self.sepc += 4; self.sepc += 4;
}, },
T::Interrupt(I::SupervisorExternal) => { T::Interrupt(I::SupervisorExternal) => {
@ -90,7 +99,27 @@ impl TrapContextOps for TrapContext {
} }
Timer::set_next(); 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, pub t6: usize,
} }
impl Index<usize> 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]) };
&regs[index]
}
}
impl IndexMut<usize> 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)] #[derive(Debug, Default)]
#[repr(C)] #[repr(C)]
pub struct TrapContext { pub struct TrapContext {

View File

@ -10,9 +10,9 @@ use utils::{
/// RawCap is the specific implementation of capability which stores in CNode /// RawCap is the specific implementation of capability which stores in CNode
#[derive(Copy, Clone, Default, PartialEq, Eq)] #[derive(Copy, Clone, Default, PartialEq, Eq)]
pub struct RawCap { 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, /// 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 /// but we'll waste some space rather than using bitfield to simplify the implementation
// TODO: use u64 rather than usize
pub args: [usize; 2], pub args: [usize; 2],
/// ptr: vanilla seL4 stores the pointer with either higher bits or lower bits cut off, /// 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. /// which limits the address space. Use an independent field to store the pointer.

View File

@ -26,6 +26,7 @@ pub mod cnode;
pub mod frame; pub mod frame;
pub mod null; pub mod null;
pub mod table; pub mod table;
pub mod tcb;
pub mod untyped; pub mod untyped;
/// Cap is the high-level wrapper of RawCap, it's a typed reference to RawCap (which is untyped in Rust) /// Cap is the high-level wrapper of RawCap, it's a typed reference to RawCap (which is untyped in Rust)

110
kernel/src/objects/tcb.rs Normal file
View File

@ -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<Self>,
}
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())
}
}
}

View File

@ -1,3 +1,5 @@
use crate::objects::tcb::TcbObject;
pub struct Trap; pub struct Trap;
pub trait TrapOps { pub trait TrapOps {
@ -7,5 +9,11 @@ pub trait TrapOps {
pub trait TrapContextOps { pub trait TrapContextOps {
fn restore(&mut self); fn restore(&mut self);
fn configure_idle_thread(&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);
} }