Compare commits

..

9 Commits

21 changed files with 119 additions and 81 deletions

View File

@ -1,4 +1,4 @@
pub const TIMER_TICKS: u64 = 100_000; // 100ms pub const TIMER_TICKS: u64 = 100_000;
// devices // devices
pub const UART0_BASE: usize = 0x1000_0000; pub const UART0_BASE: usize = 0x1000_0000;

View File

@ -79,7 +79,7 @@ impl TrapContextOps for TrapContext {
T::Interrupt(I::SupervisorTimer) => { T::Interrupt(I::SupervisorTimer) => {
Timer::do_tick(); Timer::do_tick();
if !from_kernel { if !from_kernel {
tcb.timer_tick(); tcb.do_tick();
} }
}, },
T::Exception(E::UserEnvCall) => { T::Exception(E::UserEnvCall) => {
@ -110,16 +110,16 @@ impl TrapContextOps for TrapContext {
} }
fn get_reg(&self, index: usize) -> usize { fn get_reg(&self, index: usize) -> usize {
// x10 ~ x17: Function arguments // x9(a0) ~ x16(a7): Function arguments
assert!(index < 8, "TrapContext get_reg index out of range"); assert!(index < 8, "TrapContext get_reg index out of range");
self.gprs[index + 10] self.gprs[index + 9]
} }
fn set_reg(&mut self, index: usize, value: usize) { fn set_reg(&mut self, index: usize, value: usize) {
// x10 ~ x17: Function arguments // x9(a0) ~ x16(a7): Function arguments
// x10 ~ x11: Function return values // x9(a0) ~ x10(a1): Function return values
assert!(index < 8, "TrapContext set_reg index out of range"); assert!(index < 8, "TrapContext set_reg index out of range");
self.gprs[index + 10] = value; self.gprs[index + 9] = value;
} }
} }

View File

@ -38,6 +38,12 @@ trait GenericPhysAddrPage: AddressOps {
self.extract_ppn() << Self::PPN_OFFSET self.extract_ppn() << Self::PPN_OFFSET
} }
fn from_ppn(ppn: usize) -> usize {
let addr = ppn << Self::PG_OFFSET;
let bits = Self::PG_OFFSET + Self::PPN_BITS;
sign_extend(addr, bits)
}
fn from_pte(pte: usize) -> usize { fn from_pte(pte: usize) -> usize {
let addr = ((pte & Self::PTE_PPN_MASK) >> Self::PPN_OFFSET) << Self::PG_OFFSET; let addr = ((pte & Self::PTE_PPN_MASK) >> Self::PPN_OFFSET) << Self::PG_OFFSET;
let bits = Self::PPN_BITS + Self::PG_OFFSET; let bits = Self::PPN_BITS + Self::PG_OFFSET;

View File

@ -21,6 +21,10 @@ impl PhysAddrPage for PhysAddr {
GenericPhysAddrPage::extract_ppn_shifted(self) GenericPhysAddrPage::extract_ppn_shifted(self)
} }
fn from_ppn(ppn: usize) -> PhysAddr {
PhysAddr::from(<PhysAddr as GenericPhysAddrPage>::from_ppn(ppn))
}
fn from_pte(pte: usize) -> PhysAddr { fn from_pte(pte: usize) -> PhysAddr {
PhysAddr::from(<PhysAddr as GenericPhysAddrPage>::from_pte(pte)) PhysAddr::from(<PhysAddr as GenericPhysAddrPage>::from_pte(pte))
} }

View File

@ -150,9 +150,7 @@ pub unsafe fn setup_kernel_paging() {
pub unsafe fn install_kernel_pagetable() { pub unsafe fn install_kernel_pagetable() {
info!("Setting up new kernel pagetable"); info!("Setting up new kernel pagetable");
let vaddr = KERNEL_PAGETABLE.lock().as_ref().expect("No kernel pagetable found").vaddr(); let paddr = KERNEL_PAGETABLE.lock().as_ref().expect("No kernel pagetable found").paddr();
let paddr = mmap_virt_to_phys(vaddr);
install_pagetable(paddr) install_pagetable(paddr)
} }
@ -174,7 +172,7 @@ pub fn copy_kernel_pagetable(root: &CapEntry) {
let mut root = TableCap::try_from(root).expect("Invalid vspace cap"); let mut root = TableCap::try_from(root).expect("Invalid vspace cap");
let to: Table<Level0> = root.as_object_mut(); let to: Table<Level0> = root.as_object_mut();
for (i, (from, to)) in from.entries.iter().zip(to.entries.iter_mut()).enumerate() { for (from, to) in from.entries.iter().zip(to.entries.iter_mut()) {
if !from.is_valid() { if !from.is_valid() {
to.clear(); to.clear();
continue; continue;

View File

@ -1,4 +1,7 @@
use crate::{arch::layout::PAGE_SIZE, vspace::*}; use crate::{
arch::layout::{mmap_virt_to_phys, PAGE_SIZE},
vspace::*,
};
use utils::addr::*; use utils::addr::*;
impl<'a, T: TableLevel> TableOps<'a, T> for Table<'a, T> { impl<'a, T: TableLevel> TableOps<'a, T> for Table<'a, T> {
@ -15,6 +18,10 @@ impl<'a, T: TableLevel> TableOps<'a, T> for Table<'a, T> {
VirtAddr::from(self.entries.as_ptr()) VirtAddr::from(self.entries.as_ptr())
} }
fn paddr(&self) -> PhysAddr {
unsafe { mmap_virt_to_phys(self.vaddr()) }
}
fn map(&mut self, from: VirtAddr, to: PhysAddr, attr: MapAttr) -> PageResult { fn map(&mut self, from: VirtAddr, to: PhysAddr, attr: MapAttr) -> PageResult {
if !from.is_aligned(T::LEVEL_SIZE) || !to.is_aligned(PAGE_SIZE) { if !from.is_aligned(T::LEVEL_SIZE) || !to.is_aligned(PAGE_SIZE) {
return Err(PageError::NotAligned); return Err(PageError::NotAligned);

View File

@ -12,7 +12,7 @@ pub static ALLOC_COUNT: core::sync::atomic::AtomicUsize = core::sync::atomic::At
#[cfg(debug_assertions)] #[cfg(debug_assertions)]
fn alloc_callback() { fn alloc_callback() {
let cnt = ALLOC_COUNT.fetch_add(1, core::sync::atomic::Ordering::SeqCst); ALLOC_COUNT.fetch_add(1, core::sync::atomic::Ordering::SeqCst);
} }
#[cfg_attr(debug_assertions, tracer::trace_callback(log = true, callback = alloc_callback))] #[cfg_attr(debug_assertions, tracer::trace_callback(log = true, callback = alloc_callback))]
@ -100,3 +100,12 @@ pub unsafe fn install_pagetable(addr: PhysAddr) {
riscv::register::satp::set(page_table_mode(), 0, addr.extract_ppn()); riscv::register::satp::set(page_table_mode(), 0, addr.extract_ppn());
riscv::asm::sfence_vma_all(); riscv::asm::sfence_vma_all();
} }
pub unsafe fn get_current_pagetable() -> Table<'static, Level0> {
let satp = riscv::register::satp::read();
let paddr = PhysAddr::from_ppn(satp.ppn());
if paddr == PhysAddr(0) {
panic!("get_current_pagetable() could only be called with MMU enabled!");
}
Table::new(mmap_phys_to_virt(paddr))
}

View File

@ -2,7 +2,7 @@ use crate::plat::console::{set_console, ConsoleDevice, ConsoleDriver, CONSOLE};
use crate::plat::lowlevel::{Hardware, LowLevel}; use crate::plat::lowlevel::{Hardware, LowLevel};
use crate::plat::timer::{Timer, TimerOps}; use crate::plat::timer::{Timer, TimerOps};
use crate::plat::trap::{Trap, TrapOps}; use crate::plat::trap::{Trap, TrapOps};
use crate::scheduler::SCHEDULER; use crate::scheduler::{IDLE_THREAD, SCHEDULER};
use core::cell::Cell; use core::cell::Cell;
use core::sync::atomic::{AtomicUsize, Ordering}; use core::sync::atomic::{AtomicUsize, Ordering};
use fdt::Fdt; use fdt::Fdt;
@ -35,6 +35,9 @@ pub fn rust_main() -> ! {
Trap::init(); Trap::init();
Timer::init(); Timer::init();
SCHEDULER.init();
SCHEDULER.add(&IDLE_THREAD);
SCHEDULER.schedule(); SCHEDULER.schedule();
loop { loop {

View File

@ -4,6 +4,21 @@ use core::fmt::Write;
use core::sync::atomic::Ordering; use core::sync::atomic::Ordering;
use log::{LevelFilter, Log, Metadata, Record}; use log::{LevelFilter, Log, Metadata, Record};
#[macro_export]
macro_rules! print {
($($arg:tt)*) => {{
use core::fmt::Write;
use crate::plat::console::CONSOLE;
CONSOLE.lock().write_fmt(format_args!($($arg)*)).unwrap();
}};
}
#[macro_export]
macro_rules! println {
($msg:expr) => { print!(concat!($msg, "\n")) };
($fmt:expr, $($arg:tt)*) => { print!(concat!($fmt, "\n"), $($arg)*) };
}
struct SimpleLogger; struct SimpleLogger;
impl Log for SimpleLogger { impl Log for SimpleLogger {

View File

@ -1,6 +1,6 @@
use crate::objects::*; use crate::objects::*;
use core::cell::Cell; use core::cell::Cell;
use core::fmt::{write, Debug}; use core::fmt::Debug;
use uapi::cap::ObjectType; use uapi::cap::ObjectType;
use utils::addr::PhysAddr; use utils::addr::PhysAddr;
use utils::{ use utils::{

View File

@ -1,8 +1,5 @@
use super::{
cap::{CapEntry, RawCap},
Cap, KernelObject,
};
use crate::arch::layout::mmap_phys_to_virt; use crate::arch::layout::mmap_phys_to_virt;
use crate::objects::*;
use core::fmt::Debug; use core::fmt::Debug;
use uapi::{cap::ObjectType, fault::LookupFailure}; use uapi::{cap::ObjectType, fault::LookupFailure};
use utils::addr::{AddressOps, PhysAddr}; use utils::addr::{AddressOps, PhysAddr};

View File

@ -1,9 +1,4 @@
use super::{cap::RawCap, Cap, KernelObject}; use crate::{arch::layout::mmap_phys_to_virt, objects::*, vspace::*};
use crate::{
arch::layout::{mmap_phys_to_virt, PAGE_SIZE},
objects::cap::CapEntry,
vspace::*,
};
use core::fmt::Debug; use core::fmt::Debug;
use uapi::{ use uapi::{
cap::ObjectType, cap::ObjectType,

View File

@ -31,10 +31,10 @@ pub mod untyped;
pub use cap::{CapEntry, RawCap}; pub use cap::{CapEntry, RawCap};
pub use cnode::{CNodeCap, CNodeObject}; pub use cnode::{CNodeCap, CNodeObject};
pub use frame::{FrameCap, FrameObject}; pub use frame::{FrameCap, FrameObject};
pub use null::{NullCap, NullObject}; pub use null::NullCap;
pub use table::{TableCap, TableObject}; pub use table::{TableCap, TableObject};
pub use tcb::{TcbCap, TcbObject}; pub use tcb::{TcbCap, TcbObject};
pub use untyped::{UntypedCap, UntypedObject}; pub use untyped::UntypedCap;
/// 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)
/// For the typed objects, we should bound it with an empty traits `KernelObject` /// For the typed objects, we should bound it with an empty traits `KernelObject`

View File

@ -1,5 +1,4 @@
use super::cap::RawCap; use crate::objects::*;
use super::{Cap, KernelObject};
use core::fmt::Debug; use core::fmt::Debug;
use uapi::cap::ObjectType; use uapi::cap::ObjectType;
use utils::addr::PhysAddr; use utils::addr::PhysAddr;

View File

@ -1,5 +1,4 @@
use super::{cap::RawCap, Cap, KernelObject}; use crate::{arch::layout::mmap_phys_to_virt, objects::*, vspace::*};
use crate::{arch::layout::mmap_phys_to_virt, vspace::*};
use core::fmt::Debug; use core::fmt::Debug;
use uapi::{ use uapi::{
cap::ObjectType, cap::ObjectType,

View File

@ -1,14 +1,8 @@
use super::{ use crate::arch::{layout::mmap_phys_to_virt, trap::TrapContext, vspace::*};
cap::{CapEntry, RawCap}, use crate::{objects::*, plat::trap::TrapContextOps, vspace::*};
cnode::CNodeCap,
null::NullCap,
Cap, KernelObject,
};
use crate::{
arch::{layout::mmap_phys_to_virt, trap::TrapContext},
plat::trap::TrapContextOps,
};
use core::fmt::Debug; use core::fmt::Debug;
use core::sync::atomic::{AtomicUsize, Ordering};
use log::debug;
use uapi::{cap::ObjectType, error::SysResult, fault::Fault, syscall::MessageInfo}; use uapi::{cap::ObjectType, error::SysResult, fault::Fault, syscall::MessageInfo};
use utils::{ use utils::{
addr::*, addr::*,
@ -16,7 +10,9 @@ use utils::{
LinkHelperImpl, LinkHelperImpl,
}; };
#[derive(Clone, Copy, Debug)] pub static TID_ALLOCATOR: AtomicUsize = AtomicUsize::new(0);
#[derive(Clone, Copy, Debug, PartialEq, Eq)]
pub enum ThreadState { pub enum ThreadState {
Inactive, Inactive,
Running, Running,
@ -38,6 +34,7 @@ pub struct TcbObject {
state: ThreadState, state: ThreadState,
time_tick: usize, time_tick: usize,
tid: usize,
pub link: Link<Self>, pub link: Link<Self>,
} }
@ -58,19 +55,29 @@ impl TcbObject {
fault_handler: CapEntry::new(NullCap::mint()), fault_handler: CapEntry::new(NullCap::mint()),
state: ThreadState::Inactive, state: ThreadState::Inactive,
time_tick: 0, time_tick: 0,
tid: TID_ALLOCATOR.fetch_add(1, Ordering::SeqCst),
link: Link::default(), link: Link::default(),
} }
} }
pub fn configure_idle_thread(&mut self) { pub fn configure_idle_thread(&mut self) {
self.trapframe.configure_idle_thread(); self.trapframe.configure_idle_thread();
self.vspace = CapEntry::new(TableCap::mint(unsafe { get_current_pagetable().paddr() }));
self.state = ThreadState::Idle; self.state = ThreadState::Idle;
} }
pub fn tid(&self) -> usize {
self.tid
}
pub fn state(&self) -> ThreadState { pub fn state(&self) -> ThreadState {
self.state self.state
} }
pub fn schedulable(&self) -> bool {
self.state != ThreadState::Blocked && self.state != ThreadState::Inactive
}
pub fn set_state(&mut self, state: ThreadState) { pub fn set_state(&mut self, state: ThreadState) {
self.state = state; self.state = state;
} }
@ -83,17 +90,18 @@ impl TcbObject {
self.time_tick = timeslice; self.time_tick = timeslice;
} }
pub fn timer_tick(&mut self) { pub fn do_tick(&mut self) {
self.time_tick = self.time_tick.saturating_sub(1); self.time_tick = self.time_tick.saturating_sub(1);
} }
pub fn install_vspace(&self) { pub fn activate_vspace(&self) {
// setup pagetable let cap = TableCap::try_from(&self.vspace).expect("activate_vspace: invalid cap");
todo!("TcbObject::install_vspace"); let paddr = cap.as_object::<Level0>().paddr();
unsafe { install_pagetable(paddr) }
} }
pub fn activate(&mut self) { pub fn activate(&mut self) {
self.install_vspace(); self.activate_vspace();
self.trapframe.restore(); self.trapframe.restore();
self.trapframe.handle_trap(false); self.trapframe.handle_trap(false);
} }
@ -106,9 +114,9 @@ impl TcbObject {
let cap_ptr = self.trapframe.get_reg(1); let cap_ptr = self.trapframe.get_reg(1);
let cap = cspace.resolve_address_bits(cap_ptr, usize::BITS as usize); let cap = cspace.resolve_address_bits(cap_ptr, usize::BITS as usize);
todo!("handle_syscall"); debug!("handle_syscall: info={:?}, cap={:?}", info, cap);
Ok(()) todo!("handle_syscall");
}; };
handle_syscall_inner().unwrap(); handle_syscall_inner().unwrap();

View File

@ -1,7 +1,4 @@
use super::cap::RawCap; use crate::objects::*;
use super::cnode::{CNodeCap, CNodeObject};
use super::null::NullCap;
use super::{Cap, FrameCap, KernelObject, TableCap, TcbCap};
use crate::vspace::MapAttr; use crate::vspace::MapAttr;
use core::fmt::Debug; use core::fmt::Debug;
use uapi::cap::ObjectType; use uapi::cap::ObjectType;

View File

@ -12,7 +12,7 @@ use utils::{addr::*, bin::prev_power_of_two};
const ROOT_CNODE_SIZE: usize = 128; const ROOT_CNODE_SIZE: usize = 128;
static mut ROOT_CNODE: Lazy<[CapEntry; ROOT_CNODE_SIZE]> = static mut ROOT_CNODE: Lazy<[CapEntry; ROOT_CNODE_SIZE]> =
Lazy::new(|| core::array::from_fn(|i| CapEntry::new(NullCap::mint()))); Lazy::new(|| core::array::from_fn(|_| CapEntry::new(NullCap::mint())));
pub fn setup_root_server(fdt: &Fdt) { pub fn setup_root_server(fdt: &Fdt) {
// Root Server is using statically allocated ROOT_CNODE // Root Server is using statically allocated ROOT_CNODE
@ -216,9 +216,13 @@ fn create_objects(cnode_obj: &mut CNodeObject, end_idx: usize) {
} }
fn load_root_server(cnode_obj: &mut CNodeObject, end_idx: usize, fdt: &Fdt) -> usize { fn load_root_server(cnode_obj: &mut CNodeObject, end_idx: usize, fdt: &Fdt) -> usize {
let table: Table<Level0> = TableCap::try_from(&cnode_obj[CNodeSlot::VSpaceCap as usize]) let mut table = {
.unwrap() let root = &cnode_obj[CNodeSlot::VSpaceCap as usize];
.as_object_mut(); let root_vaddr = TableCap::try_from(root).unwrap().as_object::<Level0>().vaddr();
// use unsafe to workaround borrow checker
unsafe { Table::new(root_vaddr) }
};
let mut rootfs = unsafe { let mut rootfs = unsafe {
let chosen = fdt.find_node("/chosen").expect("/chosen is required"); let chosen = fdt.find_node("/chosen").expect("/chosen is required");
@ -255,7 +259,6 @@ fn load_root_server(cnode_obj: &mut CNodeObject, end_idx: usize, fdt: &Fdt) -> u
}) })
.expect("init: root server not found"); .expect("init: root server not found");
let root_start = VirtAddr::from(root_entry.data().as_ptr());
let root_elf = ElfBytes::<AnyEndian>::minimal_parse(root_entry.data()).expect("init: invalid root server"); let root_elf = ElfBytes::<AnyEndian>::minimal_parse(root_entry.data()).expect("init: invalid root server");
let mut nxt_slot = end_idx; let mut nxt_slot = end_idx;
@ -272,7 +275,6 @@ fn load_root_server(cnode_obj: &mut CNodeObject, end_idx: usize, fdt: &Fdt) -> u
phdr.p_vaddr + phdr.p_memsz phdr.p_vaddr + phdr.p_memsz
); );
let seg_start = root_start + phdr.p_offset as usize;
let seg_addr = VirtAddr::from(phdr.p_vaddr); let seg_addr = VirtAddr::from(phdr.p_vaddr);
// Currently, we only support loading segments that are aligned to PAGE_SIZE // Currently, we only support loading segments that are aligned to PAGE_SIZE
@ -286,6 +288,7 @@ fn load_root_server(cnode_obj: &mut CNodeObject, end_idx: usize, fdt: &Fdt) -> u
dest.fill(0); dest.fill(0);
} else { } else {
let len = min(phdr.p_filesz as usize - offset, dest.len()); let len = min(phdr.p_filesz as usize - offset, dest.len());
let offset = phdr.p_offset as usize + offset;
let src = &root_entry.data()[offset..offset + len]; let src = &root_entry.data()[offset..offset + len];
dest[..len].copy_from_slice(src); dest[..len].copy_from_slice(src);
dest[len..].fill(0); dest[len..].fill(0);
@ -313,10 +316,6 @@ fn load_root_server(cnode_obj: &mut CNodeObject, end_idx: usize, fdt: &Fdt) -> u
copy(cur, mem); copy(cur, mem);
// map frame to vspace // map frame to vspace
let root = &cnode_obj[CNodeSlot::VSpaceCap as usize];
let root_vaddr = TableCap::try_from(root).unwrap().as_object::<Level0>().vaddr();
let mut root = unsafe { Table::new(root_vaddr) }; // use unsafe to workaround borrow checker
let vaddr = seg_addr + cur; let vaddr = seg_addr + cur;
let paddr = unsafe { mmap_virt_to_phys(VirtAddr::from(mem as *const _ as *const u8)) }; let paddr = unsafe { mmap_virt_to_phys(VirtAddr::from(mem as *const _ as *const u8)) };
let attr = { let attr = {
@ -348,7 +347,7 @@ fn load_root_server(cnode_obj: &mut CNodeObject, end_idx: usize, fdt: &Fdt) -> u
unsafe { mmap_virt_to_phys(table.vaddr()) } unsafe { mmap_virt_to_phys(table.vaddr()) }
}; };
map_range(alloc_page, &mut root, vaddr, paddr, block_size, attr); map_range(alloc_page, &mut table, vaddr, paddr, block_size, attr);
// update pointer // update pointer
cur += block_size; cur += block_size;

View File

@ -2,17 +2,17 @@ use crate::objects::*;
use core::ptr::NonNull; use core::ptr::NonNull;
use log::error; use log::error;
use spin::lazy::Lazy; use spin::lazy::Lazy;
use utils::linked_list::Link; use utils::{container_of, linked_list::Link};
#[thread_local] #[thread_local]
static IDLE_THREAD: Lazy<TcbObject> = Lazy::new(|| { pub static IDLE_THREAD: Lazy<TcbObject> = Lazy::new(|| {
let mut idle_thread = TcbObject::new(); let mut idle_thread = TcbObject::new();
idle_thread.configure_idle_thread(); idle_thread.configure_idle_thread();
idle_thread idle_thread
}); });
#[thread_local] #[thread_local]
pub static SCHEDULER: Lazy<Scheduler> = Lazy::new(|| Scheduler::new(&IDLE_THREAD)); pub static SCHEDULER: Scheduler = Scheduler::new();
// TODO: add a shared buffer to transfer TCB between cores // TODO: add a shared buffer to transfer TCB between cores
@ -24,14 +24,14 @@ pub struct Scheduler {
} }
impl Scheduler { impl Scheduler {
pub fn new(idle_thread: &TcbObject) -> Self { pub const fn new() -> Self {
// link idle_thread Self { head: Link::new() }
idle_thread.link.set_prev(Some(NonNull::from(idle_thread))); }
idle_thread.link.set_next(Some(NonNull::from(idle_thread)));
Self { pub fn init(&self) {
head: idle_thread.link.clone(), let head = unsafe { Some(NonNull::from(&*container_of!(&self.head, TcbObject, link))) };
} self.head.set_next(head);
self.head.set_prev(head);
} }
pub fn add(&self, tcb: &TcbObject) { pub fn add(&self, tcb: &TcbObject) {
@ -40,19 +40,17 @@ impl Scheduler {
pub fn schedule(&self) { pub fn schedule(&self) {
while let Some(next) = self.head.next_mut() { while let Some(next) = self.head.next_mut() {
// TODO: also need to check whether it is schedulable if next.timetick() > 0 && next.schedulable() {
if next.timetick() > 0 {
// Available to run, activate it
next.activate(); next.activate();
} else if next.timetick() == 0 { } else if next.timetick() == 0 {
// No time left, refill time tick and move to the end of the queue
next.set_timetick(TIME_SLICE); next.set_timetick(TIME_SLICE);
} }
// put to the end of the queue // put to the end of the queue
// todo: only move blocked and time expired threads to the end if next.timetick() == 0 || !next.schedulable() {
next.link.detach(); next.link.detach();
self.head.prepend(next); self.head.prepend(next);
}
} }
error!("[Scheduler] No thread to schedule! Where is IDLE thread?"); error!("[Scheduler] No thread to schedule! Where is IDLE thread?");

View File

@ -22,6 +22,9 @@ pub trait PhysAddrPage: AddressOps {
/// Almost the same as `paddr_extract_ppn`, but the PPN remains shifted in the address. /// Almost the same as `paddr_extract_ppn`, but the PPN remains shifted in the address.
fn extract_ppn_shifted(&self) -> usize; fn extract_ppn_shifted(&self) -> usize;
/// Converts a Physical Page Number (PPN) into a Physical Address.
fn from_ppn(ppn: usize) -> Self;
/// Converts a PTE into a Physical Address. /// Converts a PTE into a Physical Address.
fn from_pte(pte: usize) -> Self; fn from_pte(pte: usize) -> Self;

View File

@ -6,6 +6,7 @@ pub trait TableOps<'a, T: TableLevel> {
/// `location` must be a page-aligned virtual address and will not be dropped. /// `location` must be a page-aligned virtual address and will not be dropped.
unsafe fn new(location: VirtAddr) -> Self; unsafe fn new(location: VirtAddr) -> Self;
fn vaddr(&self) -> VirtAddr; fn vaddr(&self) -> VirtAddr;
fn paddr(&self) -> PhysAddr;
// following methods only works at current level // following methods only works at current level