mirror of
https://github.com/panpaul/tiny_os
synced 2024-09-20 09:45:19 +08:00
Compare commits
5 Commits
4ce9cceb3e
...
120e5087e3
Author | SHA1 | Date | |
---|---|---|---|
120e5087e3 | |||
668c9b142c | |||
0012091cd5 | |||
cc5049353a | |||
c899797fa0 |
8
kernel/Cargo.lock
generated
8
kernel/Cargo.lock
generated
@ -75,7 +75,6 @@ dependencies = [
|
|||||||
"spin 0.9.8",
|
"spin 0.9.8",
|
||||||
"static_assertions",
|
"static_assertions",
|
||||||
"uart_16550",
|
"uart_16550",
|
||||||
"vspace",
|
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
@ -236,13 +235,6 @@ version = "1.0.12"
|
|||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "3354b9ac3fae1ff6755cb6db53683adb661634f67557942dea4facebec0fee4b"
|
checksum = "3354b9ac3fae1ff6755cb6db53683adb661634f67557942dea4facebec0fee4b"
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "vspace"
|
|
||||||
version = "0.1.0"
|
|
||||||
dependencies = [
|
|
||||||
"bitflags 2.5.0",
|
|
||||||
]
|
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "x86"
|
name = "x86"
|
||||||
version = "0.52.0"
|
version = "0.52.0"
|
||||||
|
@ -6,14 +6,20 @@ edition = "2021"
|
|||||||
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
|
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
|
||||||
|
|
||||||
[features]
|
[features]
|
||||||
default = ["arch_riscv64", "board_virt", "log_color"]
|
default = ["riscv.board.virt", "log_color"]
|
||||||
|
|
||||||
arch_riscv64 = ["vspace/riscv_sv39"]
|
riscv = []
|
||||||
# TODO: riscv32 not supported yet
|
|
||||||
arch_riscv32 = []
|
|
||||||
|
|
||||||
board_default = []
|
"riscv.pagetable.sv32" = []
|
||||||
board_virt = []
|
"riscv.pagetable.sv39" = []
|
||||||
|
"riscv.pagetable.sv48" = []
|
||||||
|
"riscv.pagetable.sv57" = []
|
||||||
|
|
||||||
|
"riscv.riscv64" = ["riscv", "riscv.pagetable.sv39"]
|
||||||
|
"riscv.riscv32" = ["riscv", "riscv.pagetable.sv32"]
|
||||||
|
|
||||||
|
"riscv.board.default" = ["riscv.riscv64"]
|
||||||
|
"riscv.board.virt" = ["riscv.riscv64"]
|
||||||
|
|
||||||
log_color = []
|
log_color = []
|
||||||
|
|
||||||
@ -26,7 +32,6 @@ lto = "thin"
|
|||||||
|
|
||||||
[dependencies]
|
[dependencies]
|
||||||
api = { path = "../api" }
|
api = { path = "../api" }
|
||||||
vspace = { path = "../lib/vspace", default-features = false }
|
|
||||||
|
|
||||||
bitflags = "2.4"
|
bitflags = "2.4"
|
||||||
cfg-if = "1.0"
|
cfg-if = "1.0"
|
||||||
@ -35,8 +40,10 @@ lazy_static = { version = "1.4", features = ["spin_no_std"] }
|
|||||||
log = "0.4"
|
log = "0.4"
|
||||||
num-derive = "0.4"
|
num-derive = "0.4"
|
||||||
num-traits = { version = "0.2", default-features = false }
|
num-traits = { version = "0.2", default-features = false }
|
||||||
riscv = { version = "0.11", features = ["s-mode"] }
|
|
||||||
sbi-rt = { version = "0.0" }
|
|
||||||
spin = "0.9"
|
spin = "0.9"
|
||||||
static_assertions = "1.1"
|
static_assertions = "1.1"
|
||||||
uart_16550 = "0.3"
|
uart_16550 = "0.3"
|
||||||
|
|
||||||
|
[target.'cfg(any(target_arch = "riscv32", target_arch = "riscv64"))'.dependencies]
|
||||||
|
riscv = { version = "0.11", features = ["s-mode"] }
|
||||||
|
sbi-rt = { version = "0.0" }
|
||||||
|
@ -1,7 +1,7 @@
|
|||||||
pub use arch::*;
|
pub use arch::*;
|
||||||
|
|
||||||
// Arch Level
|
// Arch Level
|
||||||
#[cfg(any(feature = "arch_riscv64", feature = "arch_riscv32"))]
|
#[cfg(feature = "riscv")]
|
||||||
#[path = "riscv/mod.rs"]
|
#[path = "riscv/mod.rs"]
|
||||||
#[allow(clippy::module_inception)]
|
#[allow(clippy::module_inception)]
|
||||||
mod arch;
|
mod arch;
|
||||||
|
@ -1,4 +1,4 @@
|
|||||||
use log::{error, warn};
|
use log::error;
|
||||||
|
|
||||||
use crate::plat::lowlevel::{Hardware, LowLevel};
|
use crate::plat::lowlevel::{Hardware, LowLevel};
|
||||||
|
|
||||||
|
@ -1,10 +1,11 @@
|
|||||||
use cfg_if::cfg_if;
|
use cfg_if::cfg_if;
|
||||||
|
|
||||||
cfg_if! {
|
cfg_if! {
|
||||||
if #[cfg(feature = "board_virt")] {
|
if #[cfg(feature = "riscv.board.virt")] {
|
||||||
#[path = "board/virt/mod.rs"]
|
#[path = "board/virt/mod.rs"]
|
||||||
mod board;
|
mod board;
|
||||||
} else {
|
} else {
|
||||||
|
// fall back to default
|
||||||
#[path = "board/default/mod.rs"]
|
#[path = "board/default/mod.rs"]
|
||||||
mod board;
|
mod board;
|
||||||
}
|
}
|
||||||
@ -19,3 +20,4 @@ mod lowlevel;
|
|||||||
mod timer;
|
mod timer;
|
||||||
mod tls;
|
mod tls;
|
||||||
pub mod trap;
|
pub mod trap;
|
||||||
|
pub mod vspace;
|
||||||
|
@ -9,9 +9,9 @@ use crate::plat::timer::{Timer, TimerOps};
|
|||||||
use crate::plat::trap::{Trap, TrapContextOps, TrapOps};
|
use crate::plat::trap::{Trap, TrapContextOps, TrapOps};
|
||||||
|
|
||||||
cfg_if! {
|
cfg_if! {
|
||||||
if #[cfg(feature = "arch_riscv64")] {
|
if #[cfg(feature = "riscv.riscv64")] {
|
||||||
core::arch::global_asm!(include_str!("./asm/trap64.S"));
|
core::arch::global_asm!(include_str!("./asm/trap64.S"));
|
||||||
} else if #[cfg(feature = "arch_riscv32")] {
|
} else if #[cfg(feature = "riscv.riscv32")] {
|
||||||
core::arch::global_asm!(include_str!("./asm/trap32.S"));
|
core::arch::global_asm!(include_str!("./asm/trap32.S"));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1,10 +1,10 @@
|
|||||||
use crate::addr::{AddressOps, PhysAddr};
|
use crate::vspace::addr::{AddressOps, PhysAddr};
|
||||||
use crate::paging::{MapAttr, PageTableEntryOps};
|
use crate::vspace::paging::{EntryOps, MapAttr};
|
||||||
use bitflags::bitflags;
|
use bitflags::bitflags;
|
||||||
|
|
||||||
bitflags! {
|
bitflags! {
|
||||||
#[derive(Debug)]
|
#[derive(Debug)]
|
||||||
pub struct PTEFlags : u64 {
|
pub struct PTEFlags : usize {
|
||||||
const VALID = 1 << 0;
|
const VALID = 1 << 0;
|
||||||
const READABLE = 1 << 1;
|
const READABLE = 1 << 1;
|
||||||
const WRITABLE = 1 << 2;
|
const WRITABLE = 1 << 2;
|
||||||
@ -73,46 +73,52 @@ impl From<MapAttr> for PTEFlags {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#[cfg(feature = "riscv_sv39")]
|
#[cfg(not(feature = "riscv.pagetable.sv32"))]
|
||||||
|
assert_eq_size!(Entry, u64);
|
||||||
|
|
||||||
|
#[cfg(feature = "riscv.pagetable.sv32")]
|
||||||
|
assert_eq_size!(Entry, u32);
|
||||||
|
|
||||||
|
#[cfg(feature = "riscv.pagetable.sv39")]
|
||||||
impl PhysAddr {
|
impl PhysAddr {
|
||||||
const PA_PPN_MASK: u64 = ((1 << Self::PPN_BITS) - 1) << Self::PG_OFFSET;
|
const PA_PPN_MASK: usize = ((1 << Self::PPN_BITS) - 1) << Self::PG_OFFSET;
|
||||||
const PG_OFFSET: u64 = 12;
|
const PG_OFFSET: usize = 12;
|
||||||
const PPN_BITS: u64 = 44;
|
const PPN_BITS: usize = 44;
|
||||||
const PPN_OFFSET: u64 = 10;
|
const PPN_OFFSET: usize = 10;
|
||||||
const PTE_PPN_MASK: u64 = ((1 << Self::PPN_BITS) - 1) << Self::PPN_OFFSET;
|
const PTE_PPN_MASK: usize = ((1 << Self::PPN_BITS) - 1) << Self::PPN_OFFSET;
|
||||||
}
|
}
|
||||||
|
|
||||||
impl PhysAddr {
|
impl PhysAddr {
|
||||||
fn to_ppn_shifted(self) -> u64 {
|
fn to_ppn_shifted(self) -> usize {
|
||||||
((self.as_u64() & Self::PA_PPN_MASK) >> Self::PG_OFFSET) << Self::PPN_OFFSET
|
((self.as_usize() & Self::PA_PPN_MASK) >> Self::PG_OFFSET) << Self::PPN_OFFSET
|
||||||
}
|
}
|
||||||
|
|
||||||
fn from_pte(pte: u64) -> Self {
|
fn from_pte(pte: usize) -> Self {
|
||||||
let ppn = (pte & Self::PTE_PPN_MASK) >> Self::PPN_OFFSET;
|
let ppn = (pte & Self::PTE_PPN_MASK) >> Self::PPN_OFFSET;
|
||||||
let paddr = ppn << Self::PG_OFFSET;
|
let paddr = ppn << Self::PG_OFFSET;
|
||||||
PhysAddr::from(paddr as usize)
|
PhysAddr::from(paddr)
|
||||||
}
|
}
|
||||||
|
|
||||||
fn merge_pte(self, pte: u64) -> u64 {
|
fn merge_pte(self, pte: usize) -> usize {
|
||||||
let ppn = self.to_ppn_shifted();
|
let ppn = self.to_ppn_shifted();
|
||||||
(pte & !Self::PTE_PPN_MASK) | ppn
|
(pte & !Self::PTE_PPN_MASK) | ppn
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Clone, Copy, Default)]
|
#[derive(Clone, Copy, Default)]
|
||||||
pub struct PageTableEntry(u64);
|
pub struct Entry(usize);
|
||||||
|
|
||||||
impl PageTableEntryOps for PageTableEntry {
|
impl EntryOps for Entry {
|
||||||
fn new_page(paddr: PhysAddr, attr: MapAttr) -> Self {
|
fn new_page(phys_addr: PhysAddr, attr: MapAttr) -> Self {
|
||||||
let flags = PTEFlags::from(attr);
|
let flags = PTEFlags::from(attr);
|
||||||
let ppn = paddr.to_ppn_shifted();
|
let ppn = phys_addr.to_ppn_shifted();
|
||||||
|
|
||||||
Self(ppn | flags.bits())
|
Self(ppn | flags.bits())
|
||||||
}
|
}
|
||||||
|
|
||||||
fn new_table(paddr: PhysAddr) -> Self {
|
fn new_table(phys_addr: PhysAddr) -> Self {
|
||||||
let flags = PTEFlags::VALID;
|
let flags = PTEFlags::VALID;
|
||||||
let ppn = paddr.to_ppn_shifted();
|
let ppn = phys_addr.to_ppn_shifted();
|
||||||
|
|
||||||
Self(ppn | flags.bits())
|
Self(ppn | flags.bits())
|
||||||
}
|
}
|
||||||
@ -148,7 +154,7 @@ impl PageTableEntryOps for PageTableEntry {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl core::fmt::Debug for PageTableEntry {
|
impl core::fmt::Debug for Entry {
|
||||||
fn fmt(&self, f: &mut core::fmt::Formatter) -> core::fmt::Result {
|
fn fmt(&self, f: &mut core::fmt::Formatter) -> core::fmt::Result {
|
||||||
f.debug_struct("PageTableEntry")
|
f.debug_struct("PageTableEntry")
|
||||||
.field("addr", &self.addr())
|
.field("addr", &self.addr())
|
6
kernel/src/arch/riscv/vspace/mod.rs
Normal file
6
kernel/src/arch/riscv/vspace/mod.rs
Normal file
@ -0,0 +1,6 @@
|
|||||||
|
mod entry;
|
||||||
|
mod table;
|
||||||
|
mod utils;
|
||||||
|
|
||||||
|
pub use entry::Entry;
|
||||||
|
pub use table::Table;
|
@ -1,11 +1,11 @@
|
|||||||
use crate::addr::{AddressOps, PhysAddr, VirtAddr};
|
use crate::utils::size::*;
|
||||||
use crate::paging::{
|
use crate::vspace::addr::*;
|
||||||
MapAttr, PageError, PageResult, PageSize, PageTableEntry, PageTableEntryOps, PageTableOps,
|
use crate::vspace::paging::*;
|
||||||
};
|
use num_traits::ToPrimitive;
|
||||||
|
|
||||||
const PAGE_SIZE: usize = 4096;
|
const PAGE_SIZE: usize = 4096;
|
||||||
|
|
||||||
#[cfg(feature = "riscv_sv39")]
|
#[cfg(feature = "riscv.pagetable.sv39")]
|
||||||
impl VirtAddr {
|
impl VirtAddr {
|
||||||
const PG_OFFSET: usize = 12;
|
const PG_OFFSET: usize = 12;
|
||||||
const VPN_BITS: usize = 9;
|
const VPN_BITS: usize = 9;
|
||||||
@ -13,14 +13,12 @@ impl VirtAddr {
|
|||||||
}
|
}
|
||||||
|
|
||||||
impl VirtAddr {
|
impl VirtAddr {
|
||||||
fn to_vpn(self, size: PageSize) -> usize {
|
fn to_vpn(self, level: TableLevel) -> usize {
|
||||||
let level = size.to_level();
|
self.0 >> (Self::PG_OFFSET + Self::VPN_BITS * level.to_usize().unwrap()) & Self::VPN_MASK
|
||||||
assert!(level <= 3, "invalid level: {}", level);
|
|
||||||
self.0 >> (Self::PG_OFFSET + Self::VPN_BITS * level) & Self::VPN_MASK
|
|
||||||
}
|
}
|
||||||
|
|
||||||
fn merge_vpn(&self, vpn: usize, size: PageSize) -> Self {
|
fn merge_vpn(&self, vpn: usize, size: TableLevel) -> Self {
|
||||||
let shift = Self::PG_OFFSET + Self::VPN_BITS * size.to_level();
|
let shift = Self::PG_OFFSET + Self::VPN_BITS * size.to_usize().unwrap();
|
||||||
let mask = Self::VPN_MASK << shift;
|
let mask = Self::VPN_MASK << shift;
|
||||||
VirtAddr((self.0 & !mask) | ((vpn & Self::VPN_MASK) << shift))
|
VirtAddr((self.0 & !mask) | ((vpn & Self::VPN_MASK) << shift))
|
||||||
}
|
}
|
||||||
@ -30,14 +28,30 @@ impl VirtAddr {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#[repr(C, align(4096))]
|
impl TableLevel {
|
||||||
pub struct PageTable {
|
pub fn is_aligned<A: AddressOps>(&self, addr: A) -> bool {
|
||||||
// Assume at least SV39 paging
|
match self {
|
||||||
entries: [PageTableEntry; 512],
|
Self::Level0 => addr.is_aligned(4 * KIB),
|
||||||
|
#[cfg(feature = "riscv.pagetable.sv32")]
|
||||||
|
Self::Level1 => addr.is_aligned(4 * MIB),
|
||||||
|
#[cfg(not(feature = "riscv.pagetable.sv32"))]
|
||||||
|
Self::Level1 => addr.is_aligned(2 * MIB),
|
||||||
|
Self::Level2 => addr.is_aligned(1 * GIB),
|
||||||
|
Self::Level3 => addr.is_aligned(512 * GIB),
|
||||||
|
Self::Level4 => addr.is_aligned(256 * TIB),
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl PageTable {
|
#[repr(C, align(4096))]
|
||||||
fn lookup_mut_internal(&mut self, vaddr: VirtAddr) -> (&mut PageTableEntry, PageSize) {
|
pub struct Table {
|
||||||
|
entries: [Entry; PAGE_SIZE / core::mem::size_of::<Entry>()],
|
||||||
|
}
|
||||||
|
|
||||||
|
assert_eq_size!(Table, [u8; PAGE_SIZE]);
|
||||||
|
|
||||||
|
impl Table {
|
||||||
|
fn lookup_mut_internal(&mut self, vaddr: VirtAddr) -> (&mut Entry, TableLevel) {
|
||||||
// NOTE: we assume that this page table is the root page table
|
// NOTE: we assume that this page table is the root page table
|
||||||
let mut cur = Self::MAX_PAGE_SIZE;
|
let mut cur = Self::MAX_PAGE_SIZE;
|
||||||
let mut table = self;
|
let mut table = self;
|
||||||
@ -53,39 +67,46 @@ impl PageTable {
|
|||||||
cur = cur.next().unwrap();
|
cur = cur.next().unwrap();
|
||||||
table = unsafe {
|
table = unsafe {
|
||||||
// NOTE: we assume that kernel space is 1:1 mapped
|
// NOTE: we assume that kernel space is 1:1 mapped
|
||||||
Self::from_va(entry.addr().as_usize().into())
|
Self::new(entry.addr().as_usize().into())
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl PageTableOps for PageTable {
|
impl TableOps for Table {
|
||||||
type Entry = PageTableEntry;
|
type Entry = Entry;
|
||||||
|
|
||||||
#[cfg(feature = "riscv_sv39")]
|
#[cfg(feature = "riscv.pagetable.sv39")]
|
||||||
const MAX_PAGE_SIZE: PageSize = PageSize::Giga;
|
const MAX_PAGE_SIZE: TableLevel = TableLevel::Level2;
|
||||||
|
|
||||||
unsafe fn from_va(from: VirtAddr) -> &'static mut Self {
|
unsafe fn new(location: PhysAddr) -> &'static mut Self {
|
||||||
let ptr: *mut Self = from.into();
|
assert!(location.is_aligned(PAGE_SIZE));
|
||||||
|
let ptr: *mut Self = location.into();
|
||||||
&mut *ptr
|
&mut *ptr
|
||||||
}
|
}
|
||||||
|
|
||||||
fn map(&mut self, from: VirtAddr, to: PhysAddr, attr: MapAttr, size: PageSize) -> PageResult {
|
fn map(
|
||||||
|
&mut self,
|
||||||
|
from: VirtAddr,
|
||||||
|
to: PhysAddr,
|
||||||
|
attr: MapAttr,
|
||||||
|
level: TableLevel,
|
||||||
|
) -> PageResult {
|
||||||
assert!(from.is_aligned(PAGE_SIZE));
|
assert!(from.is_aligned(PAGE_SIZE));
|
||||||
assert!(to.is_aligned(PAGE_SIZE));
|
assert!(to.is_aligned(PAGE_SIZE));
|
||||||
assert!(size.is_aligned(from.as_usize()));
|
assert!(level.is_aligned(from));
|
||||||
if !attr.contains(MapAttr::PAGE_TABLE) {
|
if !attr.contains(MapAttr::PAGE_TABLE) {
|
||||||
assert!(size.is_aligned(to.as_usize()));
|
assert!(level.is_aligned(to));
|
||||||
}
|
}
|
||||||
|
|
||||||
let (entry, cur) = self.lookup_mut_internal(from);
|
let (entry, cur) = self.lookup_mut_internal(from);
|
||||||
|
|
||||||
if cur.to_level() < size.to_level() {
|
if cur < level {
|
||||||
return Err(PageError::MissingEntry);
|
return Err(PageError::MissingEntry(cur));
|
||||||
}
|
}
|
||||||
|
|
||||||
if entry.is_valid() || cur.to_level() > size.to_level() {
|
if entry.is_valid() || cur > level {
|
||||||
return Err(PageError::AlreadyMapped);
|
return Err(PageError::AlreadyMapped(cur));
|
||||||
}
|
}
|
||||||
|
|
||||||
entry.set_addr(to);
|
entry.set_addr(to);
|
||||||
@ -95,10 +116,10 @@ impl PageTableOps for PageTable {
|
|||||||
}
|
}
|
||||||
|
|
||||||
fn unmap(&mut self, vaddr: VirtAddr) -> PageResult {
|
fn unmap(&mut self, vaddr: VirtAddr) -> PageResult {
|
||||||
let (entry, _) = self.lookup_mut_internal(vaddr);
|
let (entry, level) = self.lookup_mut_internal(vaddr);
|
||||||
|
|
||||||
if !entry.is_valid() {
|
if !entry.is_valid() {
|
||||||
return Err(PageError::MissingEntry);
|
return Err(PageError::MissingEntry(level));
|
||||||
}
|
}
|
||||||
|
|
||||||
entry.set_addr(PhysAddr::default());
|
entry.set_addr(PhysAddr::default());
|
||||||
@ -107,9 +128,9 @@ impl PageTableOps for PageTable {
|
|||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
fn lookup(&mut self, vaddr: VirtAddr) -> Option<Self::Entry> {
|
fn lookup(&mut self, vaddr: VirtAddr) -> Option<&Self::Entry> {
|
||||||
let (entry, _) = self.lookup_mut_internal(vaddr);
|
let (entry, _) = self.lookup_mut_internal(vaddr);
|
||||||
entry.is_valid().then_some(*entry)
|
entry.is_valid().then_some(entry)
|
||||||
}
|
}
|
||||||
|
|
||||||
fn lookup_mut(&mut self, vaddr: VirtAddr) -> Option<&mut Self::Entry> {
|
fn lookup_mut(&mut self, vaddr: VirtAddr) -> Option<&mut Self::Entry> {
|
||||||
@ -118,26 +139,26 @@ impl PageTableOps for PageTable {
|
|||||||
}
|
}
|
||||||
|
|
||||||
fn translate(&mut self, vaddr: VirtAddr) -> Option<PhysAddr> {
|
fn translate(&mut self, vaddr: VirtAddr) -> Option<PhysAddr> {
|
||||||
let (entry, size) = self.lookup_mut_internal(vaddr);
|
let (entry, level) = self.lookup_mut_internal(vaddr);
|
||||||
|
|
||||||
entry
|
entry
|
||||||
.is_valid()
|
.is_valid()
|
||||||
.then_some(entry.addr())
|
.then_some(entry.addr())
|
||||||
.map(|p| p.as_usize() | vaddr.lower_bits(size.to_level()))
|
.map(|p| p.as_usize() | vaddr.lower_bits(level.to_usize().unwrap()))
|
||||||
.map(|p| p.into())
|
.map(|p| p.into())
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl PageTable {
|
impl Table {
|
||||||
fn debug_walk(
|
fn debug_walk(
|
||||||
&self,
|
&self,
|
||||||
f: &mut core::fmt::Formatter,
|
f: &mut core::fmt::Formatter,
|
||||||
base: VirtAddr,
|
base: VirtAddr,
|
||||||
size: PageSize,
|
level: TableLevel,
|
||||||
) -> core::fmt::Result {
|
) -> core::fmt::Result {
|
||||||
macro_rules! w {
|
macro_rules! print_one {
|
||||||
($($arg:tt)*) => {
|
($($arg:tt)*) => {
|
||||||
for _ in size.to_level()..Self::MAX_PAGE_SIZE.to_level() {
|
for _ in level.to_usize().unwrap()..Self::MAX_PAGE_SIZE.to_usize().unwrap() {
|
||||||
write!(f, "\t")?;
|
write!(f, "\t")?;
|
||||||
}
|
}
|
||||||
writeln!(f, $($arg)*)?;
|
writeln!(f, $($arg)*)?;
|
||||||
@ -149,17 +170,17 @@ impl PageTable {
|
|||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
w!(
|
print_one!(
|
||||||
"[{:>3}]: {:?} -> {:?} : {:?}",
|
"[{:>3}]: {:?} -> {:?} : {:?}",
|
||||||
i,
|
i,
|
||||||
base.merge_vpn(i, size),
|
base.merge_vpn(i, level),
|
||||||
entry.addr(),
|
entry.addr(),
|
||||||
entry
|
entry
|
||||||
);
|
);
|
||||||
|
|
||||||
if !entry.is_leaf() && size.next().is_some() {
|
if !entry.is_leaf() && level.next().is_some() {
|
||||||
let table = unsafe { Self::from_va(entry.addr().as_usize().into()) };
|
let table = unsafe { Self::new(entry.addr().as_usize().into()) };
|
||||||
table.debug_walk(f, base.merge_vpn(i, size), size.next().unwrap())?;
|
table.debug_walk(f, base.merge_vpn(i, level), level.next().unwrap())?;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -167,7 +188,7 @@ impl PageTable {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl core::fmt::Debug for PageTable {
|
impl core::fmt::Debug for Table {
|
||||||
fn fmt(&self, f: &mut core::fmt::Formatter) -> core::fmt::Result {
|
fn fmt(&self, f: &mut core::fmt::Formatter) -> core::fmt::Result {
|
||||||
writeln!(f, "PageTable({:p}):", self)?;
|
writeln!(f, "PageTable({:p}):", self)?;
|
||||||
self.debug_walk(f, VirtAddr(0), Self::MAX_PAGE_SIZE)
|
self.debug_walk(f, VirtAddr(0), Self::MAX_PAGE_SIZE)
|
1
kernel/src/arch/riscv/vspace/utils.rs
Normal file
1
kernel/src/arch/riscv/vspace/utils.rs
Normal file
@ -0,0 +1 @@
|
|||||||
|
|
@ -14,8 +14,12 @@
|
|||||||
#![reexport_test_harness_main = "test_main"]
|
#![reexport_test_harness_main = "test_main"]
|
||||||
#![cfg_attr(test, allow(dead_code))]
|
#![cfg_attr(test, allow(dead_code))]
|
||||||
|
|
||||||
|
#[macro_use]
|
||||||
extern crate static_assertions;
|
extern crate static_assertions;
|
||||||
|
|
||||||
|
#[macro_use]
|
||||||
|
extern crate num_derive;
|
||||||
|
|
||||||
mod arch;
|
mod arch;
|
||||||
mod drivers;
|
mod drivers;
|
||||||
mod entry;
|
mod entry;
|
||||||
@ -24,6 +28,7 @@ mod logging;
|
|||||||
mod objects;
|
mod objects;
|
||||||
mod plat;
|
mod plat;
|
||||||
mod utils;
|
mod utils;
|
||||||
|
mod vspace;
|
||||||
|
|
||||||
// test infrastructure
|
// test infrastructure
|
||||||
#[cfg(test)]
|
#[cfg(test)]
|
||||||
|
@ -1,4 +1,4 @@
|
|||||||
use vspace::addr::PhysAddr;
|
use crate::vspace::addr::PhysAddr;
|
||||||
|
|
||||||
extern "C" {
|
extern "C" {
|
||||||
pub type ExternSymbol;
|
pub type ExternSymbol;
|
||||||
|
@ -1,2 +1,3 @@
|
|||||||
pub mod extern_addr;
|
pub mod extern_addr;
|
||||||
pub mod function_name;
|
pub mod function_name;
|
||||||
|
pub mod size;
|
||||||
|
12
kernel/src/utils/size.rs
Normal file
12
kernel/src/utils/size.rs
Normal file
@ -0,0 +1,12 @@
|
|||||||
|
pub const B: usize = 1;
|
||||||
|
pub const KB: usize = B * 1000;
|
||||||
|
pub const MB: usize = KB * 1000;
|
||||||
|
pub const GB: usize = MB * 1000;
|
||||||
|
pub const TB: usize = GB * 1000;
|
||||||
|
pub const PB: usize = TB * 1000;
|
||||||
|
|
||||||
|
pub const KIB: usize = B * 1024;
|
||||||
|
pub const MIB: usize = KIB * 1024;
|
||||||
|
pub const GIB: usize = MIB * 1024;
|
||||||
|
pub const TIB: usize = GIB * 1024;
|
||||||
|
pub const PIB: usize = TIB * 1024;
|
@ -13,10 +13,10 @@ pub fn align_down(addr: usize, align: usize) -> usize {
|
|||||||
addr & !(align - 1)
|
addr & !(align - 1)
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Copy, Clone, PartialOrd, PartialEq)]
|
#[derive(Copy, Clone, Default, PartialOrd, PartialEq)]
|
||||||
pub struct PhysAddr(pub usize);
|
pub struct PhysAddr(pub usize);
|
||||||
|
|
||||||
#[derive(Copy, Clone, PartialOrd, PartialEq)]
|
#[derive(Copy, Clone, Default, PartialOrd, PartialEq)]
|
||||||
pub struct VirtAddr(pub usize);
|
pub struct VirtAddr(pub usize);
|
||||||
|
|
||||||
pub trait AddressOps {
|
pub trait AddressOps {
|
2
kernel/src/vspace/mod.rs
Normal file
2
kernel/src/vspace/mod.rs
Normal file
@ -0,0 +1,2 @@
|
|||||||
|
pub mod addr;
|
||||||
|
pub mod paging;
|
@ -1,4 +1,4 @@
|
|||||||
use crate::addr::PhysAddr;
|
use crate::vspace::addr::PhysAddr;
|
||||||
use bitflags::bitflags;
|
use bitflags::bitflags;
|
||||||
use core::fmt::Debug;
|
use core::fmt::Debug;
|
||||||
|
|
||||||
@ -13,9 +13,9 @@ bitflags! {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub trait PageTableEntryOps: Clone + Copy + Debug {
|
pub trait EntryOps: Clone + Copy + Debug {
|
||||||
fn new_page(paddr: PhysAddr, attr: MapAttr) -> Self;
|
fn new_page(phys_addr: PhysAddr, attr: MapAttr) -> Self;
|
||||||
fn new_table(paddr: PhysAddr) -> Self;
|
fn new_table(phys_addr: PhysAddr) -> Self;
|
||||||
|
|
||||||
fn addr(&self) -> PhysAddr;
|
fn addr(&self) -> PhysAddr;
|
||||||
fn attr(&self) -> MapAttr;
|
fn attr(&self) -> MapAttr;
|
9
kernel/src/vspace/paging/mod.rs
Normal file
9
kernel/src/vspace/paging/mod.rs
Normal file
@ -0,0 +1,9 @@
|
|||||||
|
mod entry;
|
||||||
|
mod table;
|
||||||
|
|
||||||
|
pub use crate::arch::vspace::*;
|
||||||
|
pub use entry::*;
|
||||||
|
pub use table::*;
|
||||||
|
|
||||||
|
assert_impl_all!(Entry: EntryOps);
|
||||||
|
assert_impl_all!(Table: TableOps);
|
48
kernel/src/vspace/paging/table.rs
Normal file
48
kernel/src/vspace/paging/table.rs
Normal file
@ -0,0 +1,48 @@
|
|||||||
|
use super::{EntryOps, MapAttr};
|
||||||
|
use crate::vspace::addr::{PhysAddr, VirtAddr};
|
||||||
|
use core::fmt::Debug;
|
||||||
|
|
||||||
|
#[derive(Debug, Clone, Copy, PartialEq, PartialOrd, Eq, FromPrimitive, ToPrimitive)]
|
||||||
|
pub enum TableLevel {
|
||||||
|
Level0 = 0,
|
||||||
|
Level1 = 1,
|
||||||
|
Level2 = 2,
|
||||||
|
Level3 = 3,
|
||||||
|
Level4 = 4,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl TableLevel {
|
||||||
|
pub fn next(&self) -> Option<Self> {
|
||||||
|
match self {
|
||||||
|
Self::Level0 => None,
|
||||||
|
Self::Level1 => Some(Self::Level0),
|
||||||
|
Self::Level2 => Some(Self::Level1),
|
||||||
|
Self::Level3 => Some(Self::Level2),
|
||||||
|
Self::Level4 => Some(Self::Level3),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Debug)]
|
||||||
|
pub enum PageError {
|
||||||
|
AlreadyMapped(TableLevel),
|
||||||
|
MissingEntry(TableLevel),
|
||||||
|
}
|
||||||
|
|
||||||
|
pub type PageResult<T = ()> = Result<T, PageError>;
|
||||||
|
|
||||||
|
pub trait TableOps: Debug {
|
||||||
|
type Entry: EntryOps;
|
||||||
|
const MAX_PAGE_SIZE: TableLevel;
|
||||||
|
|
||||||
|
unsafe fn new(location: PhysAddr) -> &'static mut Self;
|
||||||
|
|
||||||
|
fn map(&mut self, from: VirtAddr, to: PhysAddr, attr: MapAttr, level: TableLevel)
|
||||||
|
-> PageResult;
|
||||||
|
fn unmap(&mut self, vaddr: VirtAddr) -> PageResult;
|
||||||
|
|
||||||
|
fn lookup(&mut self, vaddr: VirtAddr) -> Option<&Self::Entry>;
|
||||||
|
fn lookup_mut(&mut self, vaddr: VirtAddr) -> Option<&mut Self::Entry>;
|
||||||
|
|
||||||
|
fn translate(&mut self, vaddr: VirtAddr) -> Option<PhysAddr>;
|
||||||
|
}
|
@ -1,7 +1,8 @@
|
|||||||
#![cfg_attr(not(test), no_std)]
|
#![cfg_attr(not(test), no_std)]
|
||||||
|
|
||||||
// reference: https://man.archlinux.org/man/cpio.5.en#New_ASCII_Format
|
// Reference:
|
||||||
// Reference: https://github.com/jcreekmore/cpio-rs/blob/master/src/newc.rs
|
// - https://man.archlinux.org/man/cpio.5.en#New_ASCII_Format
|
||||||
|
// - https://github.com/jcreekmore/cpio-rs/blob/master/src/newc.rs
|
||||||
|
|
||||||
const HEADER_LEN: usize = 110;
|
const HEADER_LEN: usize = 110;
|
||||||
const MAGIC_NEW_ASCII: [u8; 6] = *b"070701";
|
const MAGIC_NEW_ASCII: [u8; 6] = *b"070701";
|
||||||
|
16
lib/vspace/Cargo.lock
generated
16
lib/vspace/Cargo.lock
generated
@ -1,16 +0,0 @@
|
|||||||
# This file is automatically @generated by Cargo.
|
|
||||||
# It is not intended for manual editing.
|
|
||||||
version = 3
|
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "bitflags"
|
|
||||||
version = "2.5.0"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
checksum = "cf4b9d6a944f767f8e5e0db018570623c85f3d925ac718db4e06d0187adb21c1"
|
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "vspace"
|
|
||||||
version = "0.1.0"
|
|
||||||
dependencies = [
|
|
||||||
"bitflags",
|
|
||||||
]
|
|
@ -1,13 +0,0 @@
|
|||||||
[package]
|
|
||||||
name = "vspace"
|
|
||||||
version = "0.1.0"
|
|
||||||
edition = "2021"
|
|
||||||
|
|
||||||
[features]
|
|
||||||
default = ["arch_riscv", "riscv_sv39"]
|
|
||||||
|
|
||||||
arch_riscv = []
|
|
||||||
riscv_sv39 = ["arch_riscv"]
|
|
||||||
|
|
||||||
[dependencies]
|
|
||||||
bitflags = "2.4"
|
|
@ -1,3 +0,0 @@
|
|||||||
#![no_std]
|
|
||||||
|
|
||||||
pub mod addr;
|
|
@ -1,7 +0,0 @@
|
|||||||
pub use arch::*;
|
|
||||||
|
|
||||||
// Arch Level
|
|
||||||
#[cfg(feature = "arch_riscv")]
|
|
||||||
#[path = "riscv/mod.rs"]
|
|
||||||
#[allow(clippy::module_inception)]
|
|
||||||
mod arch;
|
|
@ -1,5 +0,0 @@
|
|||||||
mod entry;
|
|
||||||
mod table;
|
|
||||||
|
|
||||||
pub use entry::PageTableEntry;
|
|
||||||
pub use table::PageTable;
|
|
@ -1,7 +0,0 @@
|
|||||||
mod arch;
|
|
||||||
mod entry;
|
|
||||||
mod table;
|
|
||||||
|
|
||||||
pub use arch::*;
|
|
||||||
pub use entry::*;
|
|
||||||
pub use table::*;
|
|
@ -1,63 +0,0 @@
|
|||||||
use super::{MapAttr, PageTableEntryOps};
|
|
||||||
use crate::addr::{PhysAddr, VirtAddr};
|
|
||||||
use core::fmt::Debug;
|
|
||||||
|
|
||||||
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
|
|
||||||
pub enum PageSize {
|
|
||||||
Kilo,
|
|
||||||
Mega,
|
|
||||||
Giga,
|
|
||||||
Tera,
|
|
||||||
}
|
|
||||||
|
|
||||||
impl PageSize {
|
|
||||||
pub fn is_aligned(&self, addr: usize) -> bool {
|
|
||||||
match self {
|
|
||||||
Self::Kilo => addr % (4 * 1024) == 0,
|
|
||||||
Self::Mega => addr % (2 * 1024 * 1024) == 0,
|
|
||||||
Self::Giga => addr % (1 * 1024 * 1024 * 1024) == 0,
|
|
||||||
Self::Tera => addr % (512 * 1024 * 1024 * 1024 * 1024) == 0,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn to_level(&self) -> usize {
|
|
||||||
match self {
|
|
||||||
Self::Kilo => 0,
|
|
||||||
Self::Mega => 1,
|
|
||||||
Self::Giga => 2,
|
|
||||||
Self::Tera => 3,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn next(&self) -> Option<Self> {
|
|
||||||
match self {
|
|
||||||
Self::Kilo => None,
|
|
||||||
Self::Mega => Some(Self::Kilo),
|
|
||||||
Self::Giga => Some(Self::Mega),
|
|
||||||
Self::Tera => Some(Self::Giga),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
#[derive(Debug)]
|
|
||||||
pub enum PageError {
|
|
||||||
AlreadyMapped,
|
|
||||||
MissingEntry,
|
|
||||||
}
|
|
||||||
|
|
||||||
pub type PageResult<T = ()> = Result<T, PageError>;
|
|
||||||
|
|
||||||
pub trait PageTableOps: Debug {
|
|
||||||
type Entry: PageTableEntryOps;
|
|
||||||
const MAX_PAGE_SIZE: PageSize;
|
|
||||||
|
|
||||||
unsafe fn from_va(from: VirtAddr) -> &'static mut Self;
|
|
||||||
|
|
||||||
fn map(&mut self, from: VirtAddr, to: PhysAddr, attr: MapAttr, size: PageSize) -> PageResult;
|
|
||||||
fn unmap(&mut self, vaddr: VirtAddr) -> PageResult;
|
|
||||||
|
|
||||||
fn lookup(&mut self, vaddr: VirtAddr) -> Option<Self::Entry>;
|
|
||||||
fn lookup_mut(&mut self, vaddr: VirtAddr) -> Option<&mut Self::Entry>;
|
|
||||||
|
|
||||||
fn translate(&mut self, vaddr: VirtAddr) -> Option<PhysAddr>;
|
|
||||||
}
|
|
Loading…
Reference in New Issue
Block a user