mirror of
https://github.com/panpaul/tiny_os
synced 2024-09-20 09:45:19 +08:00
Compare commits
No commits in common. "3f6f0ac18cba4fc1f1455fcaf7bc133dc87ad95c" and "7d5875cb0c44bbe5629a9ad291200581955cef07" have entirely different histories.
3f6f0ac18c
...
7d5875cb0c
16
.vscode/launch.json
vendored
16
.vscode/launch.json
vendored
@ -19,13 +19,7 @@
|
||||
{
|
||||
"text": "set output-radix 16"
|
||||
}
|
||||
],
|
||||
"sourceFileMap": {
|
||||
"${workspaceFolder}": {
|
||||
"editorPath": "${workspaceFolder}",
|
||||
"useForBreakpoints": true
|
||||
}
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"name": "Debug Kernel",
|
||||
@ -45,13 +39,7 @@
|
||||
{
|
||||
"text": "set output-radix 16"
|
||||
}
|
||||
],
|
||||
"sourceFileMap": {
|
||||
"${workspaceFolder}": {
|
||||
"editorPath": "${workspaceFolder}",
|
||||
"useForBreakpoints": true
|
||||
}
|
||||
}
|
||||
]
|
||||
},
|
||||
]
|
||||
}
|
1
Cargo.lock
generated
1
Cargo.lock
generated
@ -252,7 +252,6 @@ version = "0.1.0"
|
||||
dependencies = [
|
||||
"num-derive",
|
||||
"num-traits",
|
||||
"utils",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
|
@ -1,9 +1,8 @@
|
||||
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 crate::scheduler::SCHEDULER;
|
||||
use log::trace;
|
||||
use riscv::register::scause::{Exception as E, Interrupt as I, Trap as T};
|
||||
use riscv::register::stvec::TrapMode;
|
||||
@ -18,10 +17,54 @@ extern "C" {
|
||||
|
||||
#[no_mangle]
|
||||
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.handle_trap(true);
|
||||
trap_handler(tf, true)
|
||||
}
|
||||
|
||||
fn trap_handler(tf: &mut TrapContext, from_kernel: bool) {
|
||||
let scause = riscv::register::scause::read();
|
||||
trace!("[Trap] cpu@{} scause: {:?}", HART_ID.get(), scause.cause());
|
||||
|
||||
macro_rules! panic_fatal {
|
||||
($msg:expr) => {
|
||||
panic!(
|
||||
"[Trap] {}, scause: {:?}, bits: {:#x}, sepc: {:#x}, stval: {:#x}",
|
||||
$msg,
|
||||
scause.cause(),
|
||||
scause.bits(),
|
||||
tf.sepc,
|
||||
riscv::register::stval::read()
|
||||
)
|
||||
};
|
||||
}
|
||||
|
||||
match scause.cause() {
|
||||
T::Interrupt(I::SupervisorTimer) => {
|
||||
Timer::do_tick();
|
||||
|
||||
if !from_kernel {
|
||||
SCHEDULER.schedule()
|
||||
}
|
||||
},
|
||||
T::Exception(E::UserEnvCall) => {
|
||||
// TODO: handle syscall
|
||||
tf.sepc += 4;
|
||||
},
|
||||
T::Interrupt(I::SupervisorExternal) => {
|
||||
// TODO: handle external interrupt, e.g. plic
|
||||
},
|
||||
T::Exception(E::InstructionPageFault) | T::Exception(E::LoadPageFault) | T::Exception(E::StorePageFault) => {
|
||||
if from_kernel {
|
||||
panic_fatal!("Page Fault in Kernel");
|
||||
}
|
||||
// TODO: handle page fault
|
||||
},
|
||||
_ => panic_fatal!("Unhandled Trap"),
|
||||
}
|
||||
|
||||
Timer::set_next();
|
||||
trace!("[Trap] exiting...");
|
||||
}
|
||||
|
||||
impl TrapOps for Trap {
|
||||
@ -33,97 +76,13 @@ impl TrapOps for Trap {
|
||||
}
|
||||
}
|
||||
|
||||
#[naked]
|
||||
extern "C" fn idle_thread() {
|
||||
unsafe {
|
||||
core::arch::asm!(
|
||||
"
|
||||
1: wfi
|
||||
j 1b
|
||||
",
|
||||
options(noreturn)
|
||||
)
|
||||
};
|
||||
}
|
||||
|
||||
impl TrapContextOps for TrapContext {
|
||||
fn restore(&mut self) {
|
||||
unsafe { switch_to_user(self) }
|
||||
}
|
||||
|
||||
fn configure_idle_thread(&mut self) {
|
||||
self.sepc = idle_thread as usize;
|
||||
self.sstatus = (1 << 5) | (1 << 8); // SPIE + SPP
|
||||
}
|
||||
|
||||
fn handle_trap(&mut self, from_kernel: bool) {
|
||||
let scause = riscv::register::scause::read();
|
||||
trace!("[Trap] cpu@{} scause: {:?}", HART_ID.get(), scause.cause());
|
||||
|
||||
macro_rules! panic_fatal {
|
||||
($msg:expr) => {
|
||||
panic!(
|
||||
"[Trap] {}, scause: {:?}, bits: {:#x}, sepc: {:#x}, stval: {:#x}",
|
||||
$msg,
|
||||
scause.cause(),
|
||||
scause.bits(),
|
||||
self.sepc,
|
||||
riscv::register::stval::read()
|
||||
)
|
||||
};
|
||||
}
|
||||
|
||||
let tcb = self.as_object_mut();
|
||||
|
||||
match scause.cause() {
|
||||
T::Interrupt(I::SupervisorTimer) => {
|
||||
Timer::do_tick();
|
||||
if !from_kernel {
|
||||
tcb.timer_tick();
|
||||
}
|
||||
},
|
||||
T::Exception(E::UserEnvCall) => {
|
||||
tcb.handle_syscall();
|
||||
self.sepc += 4;
|
||||
},
|
||||
T::Interrupt(I::SupervisorExternal) => {
|
||||
// TODO: handle external interrupt, e.g. plic
|
||||
},
|
||||
T::Exception(E::InstructionPageFault) | T::Exception(E::LoadPageFault) | T::Exception(E::StorePageFault) => {
|
||||
if from_kernel {
|
||||
panic_fatal!("Page Fault in Kernel");
|
||||
}
|
||||
// TODO: handle page fault
|
||||
},
|
||||
_ => panic_fatal!("Unhandled Trap"),
|
||||
}
|
||||
|
||||
Timer::set_next();
|
||||
}
|
||||
|
||||
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;
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Debug, Default)]
|
||||
#[derive(Debug)]
|
||||
#[repr(C)]
|
||||
pub struct GeneralRegs {
|
||||
pub ra: usize,
|
||||
@ -159,25 +118,7 @@ pub struct GeneralRegs {
|
||||
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]) };
|
||||
®s[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)]
|
||||
#[repr(C)]
|
||||
pub struct TrapContext {
|
||||
// [0:30] GPRs exclude zero
|
||||
|
@ -1,5 +1,9 @@
|
||||
use crate::{arch::layout::*, vspace::TableLevel};
|
||||
use utils::{addr::*, MASK};
|
||||
use utils::{
|
||||
addr::{AddressOps, VirtAddr},
|
||||
MASK,
|
||||
};
|
||||
|
||||
use crate::vspace::TableLevel;
|
||||
|
||||
#[cfg(feature = "riscv.pagetable.sv39")]
|
||||
mod sv39;
|
||||
@ -23,13 +27,6 @@ trait GenericPhysAddrPage: AddressOps {
|
||||
const PA_PPN_MASK: usize = MASK!(Self::PPN_BITS) << Self::PG_OFFSET;
|
||||
const PTE_PPN_MASK: usize = MASK!(Self::PPN_BITS) << Self::PPN_OFFSET;
|
||||
|
||||
fn is_kernel(&self) -> bool {
|
||||
let kernel_start = unsafe { kernel_virt_to_phys(KERNEL_START.as_virt_addr()) };
|
||||
let kernel_end = unsafe { kernel_virt_to_phys(KERNEL_END.as_virt_addr()).align_up(PAGE_SIZE) };
|
||||
|
||||
self.as_usize() >= kernel_start.as_usize() && self.as_usize() < kernel_end.as_usize()
|
||||
}
|
||||
|
||||
fn extract_ppn(&self) -> usize {
|
||||
(self.as_usize() & Self::PA_PPN_MASK) >> Self::PG_OFFSET
|
||||
}
|
||||
@ -54,45 +51,16 @@ trait GenericVirtAddrPage: AddressOps {
|
||||
const PG_OFFSET: usize;
|
||||
const MAX_LEVEL: usize;
|
||||
|
||||
fn is_kernel(&self, bits: usize) -> bool {
|
||||
let mask = !MASK!(bits + 1);
|
||||
(self.as_usize() & mask) != 0
|
||||
}
|
||||
|
||||
fn extract_vpn<T: TableLevel>(&self) -> usize {
|
||||
let mask = MASK!(T::LEVEL_BITS);
|
||||
(self.as_usize() >> (Self::PG_OFFSET + T::LEVEL_BITS * (Self::MAX_LEVEL - T::LEVEL))) & mask
|
||||
}
|
||||
|
||||
fn merge_vpn<T: TableLevel>(&self, vpn: usize, bits: usize) -> VirtAddr {
|
||||
fn merge_vpn<T: TableLevel>(&self, vpn: usize) -> VirtAddr {
|
||||
let shift = Self::PG_OFFSET + T::LEVEL_BITS * (Self::MAX_LEVEL - T::LEVEL);
|
||||
let mask = MASK!(T::LEVEL_BITS);
|
||||
let addr = (self.as_usize() & !(mask << shift)) | ((vpn & mask) << shift);
|
||||
|
||||
VirtAddr(sign_extend(addr, bits))
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use super::*;
|
||||
|
||||
#[test_case]
|
||||
fn test_sign_extend() {
|
||||
assert_eq!(sign_extend(0b01010, 4), 0b01010);
|
||||
assert_eq!(sign_extend(0b01010, 3), !0b101);
|
||||
}
|
||||
|
||||
#[test_case]
|
||||
fn test_is_kernel() {
|
||||
let addr = PhysAddr(0x80200000);
|
||||
assert!(addr.is_kernel());
|
||||
let addr = PhysAddr(0x80000000);
|
||||
assert!(!addr.is_kernel());
|
||||
|
||||
let addr = VirtAddr(0x0000_0080_0000_0000);
|
||||
assert!(addr.is_kernel(39 - 1));
|
||||
let addr = VirtAddr(0x0000_007f_ffff_ffff);
|
||||
assert!(!addr.is_kernel(39 - 1));
|
||||
VirtAddr(sign_extend(addr, 39 - 1))
|
||||
}
|
||||
}
|
||||
|
@ -9,10 +9,6 @@ impl GenericPhysAddrPage for PhysAddr {
|
||||
}
|
||||
|
||||
impl PhysAddrPage for PhysAddr {
|
||||
fn is_kerenel(&self) -> bool {
|
||||
GenericPhysAddrPage::is_kernel(self)
|
||||
}
|
||||
|
||||
fn extract_ppn(&self) -> usize {
|
||||
GenericPhysAddrPage::extract_ppn(self)
|
||||
}
|
||||
@ -36,15 +32,11 @@ impl GenericVirtAddrPage for VirtAddr {
|
||||
}
|
||||
|
||||
impl VirtAddrPage for VirtAddr {
|
||||
fn is_kerenel(&self) -> bool {
|
||||
GenericVirtAddrPage::is_kernel(self, 39 - 1)
|
||||
}
|
||||
|
||||
fn extract_vpn<T: TableLevel>(&self) -> usize {
|
||||
GenericVirtAddrPage::extract_vpn::<T>(self)
|
||||
}
|
||||
|
||||
fn merge_vpn<T: TableLevel>(&self, vpn: usize) -> usize {
|
||||
GenericVirtAddrPage::merge_vpn::<T>(self, vpn, 39 - 1).into()
|
||||
GenericVirtAddrPage::merge_vpn::<T>(self, vpn).into()
|
||||
}
|
||||
}
|
||||
|
@ -2,23 +2,17 @@ use crate::plat::console::{set_console, ConsoleDevice, ConsoleDriver, CONSOLE};
|
||||
use crate::plat::lowlevel::{Hardware, LowLevel};
|
||||
use crate::plat::timer::{Timer, TimerOps};
|
||||
use crate::plat::trap::{Trap, TrapOps};
|
||||
use crate::scheduler::SCHEDULER;
|
||||
use core::cell::Cell;
|
||||
use core::sync::atomic::{AtomicUsize, Ordering};
|
||||
use fdt::Fdt;
|
||||
use log::{debug, error, info, warn};
|
||||
|
||||
#[thread_local]
|
||||
pub static HART_ID: Cell<usize> = Cell::new(0);
|
||||
|
||||
pub static N_CPUS: AtomicUsize = AtomicUsize::new(1);
|
||||
|
||||
pub fn rust_main() -> ! {
|
||||
let fdt_addr = crate::arch::FDT.load(Ordering::Acquire);
|
||||
let fdt_addr = crate::arch::FDT.load(core::sync::atomic::Ordering::Acquire);
|
||||
let fdt = unsafe { Fdt::from_ptr(fdt_addr).unwrap() };
|
||||
|
||||
N_CPUS.store(fdt.cpus().count(), Ordering::Release);
|
||||
|
||||
setup_console(&fdt);
|
||||
info!("Kernel Started");
|
||||
|
||||
@ -34,8 +28,7 @@ pub fn rust_main() -> ! {
|
||||
|
||||
Trap::init();
|
||||
Timer::init();
|
||||
|
||||
SCHEDULER.schedule();
|
||||
Hardware::enable_interrupt();
|
||||
|
||||
loop {
|
||||
let data = CONSOLE.lock().try_read();
|
||||
|
@ -1,7 +1,6 @@
|
||||
use crate::entry::HART_ID;
|
||||
use crate::plat::console::CONSOLE;
|
||||
use crate::{entry::HART_ID, plat::timer::CURRENT_TICK};
|
||||
use core::fmt::Write;
|
||||
use core::sync::atomic::Ordering;
|
||||
use log::{LevelFilter, Log, Metadata, Record};
|
||||
|
||||
struct SimpleLogger;
|
||||
@ -29,10 +28,9 @@ impl Log for SimpleLogger {
|
||||
CONSOLE
|
||||
.lock()
|
||||
.write_fmt(format_args!(
|
||||
"{color_prefix}[{}][HART{}][{}] {}{color_reset}\n",
|
||||
"{color_prefix}[{}][HART{}] {}{color_reset}\n",
|
||||
record.level(),
|
||||
HART_ID.get(),
|
||||
CURRENT_TICK.load(Ordering::Acquire),
|
||||
record.args(),
|
||||
))
|
||||
.unwrap();
|
||||
|
@ -10,10 +10,10 @@ 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],
|
||||
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.
|
||||
/// Kernel will not manage memory, userspace should pass PhysAddr to kernel
|
||||
|
@ -26,7 +26,6 @@ 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)
|
||||
|
@ -1,110 +0,0 @@
|
||||
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_tick: 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_tick: 0,
|
||||
link: Link::default(),
|
||||
}
|
||||
}
|
||||
|
||||
pub fn configure_idle_thread(&mut self) {
|
||||
self.trapframe.configure_idle_thread();
|
||||
self.state = ThreadState::Idle;
|
||||
}
|
||||
|
||||
pub fn timetick(&self) -> usize {
|
||||
self.time_tick
|
||||
}
|
||||
|
||||
pub fn set_timetick(&mut self, timeslice: usize) {
|
||||
self.time_tick = timeslice;
|
||||
}
|
||||
|
||||
pub fn timer_tick(&mut self) {
|
||||
self.time_tick = self.time_tick.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())
|
||||
}
|
||||
}
|
||||
}
|
@ -1,5 +1,3 @@
|
||||
use crate::objects::tcb::TcbObject;
|
||||
|
||||
pub struct Trap;
|
||||
|
||||
pub trait TrapOps {
|
||||
@ -8,12 +6,4 @@ pub trait TrapOps {
|
||||
|
||||
pub trait TrapContextOps {
|
||||
fn restore(&mut self);
|
||||
fn configure_idle_thread(&mut self);
|
||||
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);
|
||||
}
|
||||
|
@ -1,59 +0,0 @@
|
||||
use crate::objects::tcb::TcbObject;
|
||||
use core::ptr::NonNull;
|
||||
use log::error;
|
||||
use spin::lazy::Lazy;
|
||||
use utils::linked_list::Link;
|
||||
|
||||
#[thread_local]
|
||||
static IDLE_THREAD: Lazy<TcbObject> = Lazy::new(|| {
|
||||
let mut idle_thread = TcbObject::new();
|
||||
idle_thread.configure_idle_thread();
|
||||
idle_thread
|
||||
});
|
||||
|
||||
#[thread_local]
|
||||
pub static SCHEDULER: Lazy<Scheduler> = Lazy::new(|| Scheduler::new(&IDLE_THREAD));
|
||||
|
||||
// TODO: add a shared buffer to transfer TCB between cores
|
||||
|
||||
// one process can run for 10 ticks
|
||||
pub const TIME_SLICE: usize = 10;
|
||||
|
||||
pub struct Scheduler {
|
||||
head: Link<TcbObject>,
|
||||
}
|
||||
|
||||
impl Scheduler {
|
||||
pub fn new(idle_thread: &TcbObject) -> Self {
|
||||
// link idle_thread
|
||||
idle_thread.link.set_prev(Some(NonNull::from(idle_thread)));
|
||||
idle_thread.link.set_next(Some(NonNull::from(idle_thread)));
|
||||
|
||||
Self {
|
||||
head: idle_thread.link.clone(),
|
||||
}
|
||||
}
|
||||
|
||||
pub fn add(&self, tcb: &TcbObject) {
|
||||
self.head.prepend(tcb);
|
||||
}
|
||||
|
||||
pub fn schedule(&self) {
|
||||
while let Some(next) = self.head.next_mut() {
|
||||
// TODO: also need to check whether it is schedulable
|
||||
if next.timetick() > 0 {
|
||||
// Available to run, activate it
|
||||
next.activate();
|
||||
} else if next.timetick() == 0 {
|
||||
// No time left, refill time tick and move to the end of the queue
|
||||
next.set_timetick(TIME_SLICE);
|
||||
}
|
||||
|
||||
// put to the end of the queue
|
||||
next.link.detach();
|
||||
self.head.prepend(next);
|
||||
}
|
||||
|
||||
error!("[Scheduler] No thread to schedule! Where is IDLE thread?");
|
||||
}
|
||||
}
|
15
kernel/src/scheduler/mod.rs
Normal file
15
kernel/src/scheduler/mod.rs
Normal file
@ -0,0 +1,15 @@
|
||||
pub static SCHEDULER: Scheduler = Scheduler::new();
|
||||
|
||||
pub struct Scheduler {}
|
||||
|
||||
impl Scheduler {
|
||||
pub const fn new() -> Self {
|
||||
// TODO: implement Scheduler::new
|
||||
Self {}
|
||||
}
|
||||
|
||||
#[inline(never)]
|
||||
pub fn schedule(&self) {
|
||||
todo!("Scheduler::schedule");
|
||||
}
|
||||
}
|
@ -13,9 +13,6 @@ use super::TableLevel;
|
||||
use utils::addr::{AddressOps, PhysAddr, VirtAddr};
|
||||
|
||||
pub trait PhysAddrPage: AddressOps {
|
||||
/// Checks if the address is a kernel address.
|
||||
fn is_kerenel(&self) -> bool;
|
||||
|
||||
/// Extracts the Physical Page Number (PPN).
|
||||
fn extract_ppn(&self) -> usize;
|
||||
|
||||
@ -30,9 +27,6 @@ pub trait PhysAddrPage: AddressOps {
|
||||
}
|
||||
|
||||
pub trait VirtAddrPage: AddressOps {
|
||||
/// Checks if the address is a kernel address.
|
||||
fn is_kerenel(&self) -> bool;
|
||||
|
||||
/// Extracts the Virtual Page Number (VPN).
|
||||
fn extract_vpn<T: TableLevel>(&self) -> usize;
|
||||
|
||||
|
@ -4,6 +4,5 @@ version = "0.1.0"
|
||||
edition = "2021"
|
||||
|
||||
[dependencies]
|
||||
utils = { path = "../lib/utils" }
|
||||
num-traits = { version = "0.2", default-features = false }
|
||||
num-derive = "0.4"
|
||||
|
@ -6,5 +6,4 @@ extern crate num_derive;
|
||||
|
||||
pub mod cap;
|
||||
pub mod error;
|
||||
pub mod syscall;
|
||||
pub mod vspace;
|
||||
|
@ -1,71 +0,0 @@
|
||||
use core::fmt::Debug;
|
||||
|
||||
use num_traits::{FromPrimitive, ToPrimitive};
|
||||
use utils::MASK;
|
||||
|
||||
use crate::error::SysError;
|
||||
|
||||
#[derive(Clone, Copy, Debug, Eq, PartialEq, FromPrimitive, ToPrimitive)]
|
||||
pub enum Syscall {
|
||||
Invalid = 0,
|
||||
}
|
||||
|
||||
/* in vanilla seL4, MessageInfo layout:
|
||||
* > | label | caps | extra_caps | length |
|
||||
* > | [63:12] | [11:9] | [8:7] | [6:0] |
|
||||
*
|
||||
* in out implementation, MessageInfo layout:
|
||||
* > label: Syscall
|
||||
* > length: args.len()
|
||||
*
|
||||
* Syscall convention:
|
||||
* > Call:
|
||||
* > > [a0]: MessageInfo
|
||||
* > > [a1]: Capability Pointer
|
||||
* > > [a3..a7]: extra arguments
|
||||
* > > length = (a0..a?).len()
|
||||
* > Reply:
|
||||
* > TODO: figure out how vanilla seL4 handle reply
|
||||
*/
|
||||
|
||||
#[derive(Clone, Copy)]
|
||||
pub struct MessageInfo(usize);
|
||||
|
||||
impl MessageInfo {
|
||||
const LABEL_MASK: usize = MASK!(63 - 12 + 1);
|
||||
|
||||
pub fn new(label: Syscall, length: usize) -> Self {
|
||||
Self((label.to_usize().unwrap_or(0)) << 12 | (length & 0x7f))
|
||||
}
|
||||
|
||||
pub fn label(&self) -> Syscall {
|
||||
Syscall::from_usize((self.0 >> 12) & Self::LABEL_MASK).unwrap_or(Syscall::Invalid)
|
||||
}
|
||||
|
||||
pub fn length(&self) -> usize {
|
||||
self.0 & 0x7F
|
||||
}
|
||||
|
||||
pub fn as_usize(&self) -> usize {
|
||||
self.0
|
||||
}
|
||||
}
|
||||
|
||||
impl Debug for MessageInfo {
|
||||
fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
|
||||
f.debug_struct("MessageInfo")
|
||||
.field("label", &self.label())
|
||||
.field("length", &self.length())
|
||||
.finish()
|
||||
}
|
||||
}
|
||||
|
||||
impl TryFrom<usize> for MessageInfo {
|
||||
type Error = SysError;
|
||||
|
||||
fn try_from(value: usize) -> Result<Self, Self::Error> {
|
||||
let syscall = Syscall::from_usize((value >> 12) & MessageInfo::LABEL_MASK).ok_or(SysError::InvalidArgument)?;
|
||||
let length = value & 0x7F;
|
||||
Ok(Self::new(syscall, length))
|
||||
}
|
||||
}
|
Loading…
Reference in New Issue
Block a user