diff --git a/.idea/rust.xml b/.idea/rust.xml new file mode 100644 index 0000000..7bc91ea --- /dev/null +++ b/.idea/rust.xml @@ -0,0 +1,6 @@ + + + + + \ No newline at end of file diff --git a/Cargo.lock b/Cargo.lock index e8fc13c..d2079da 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -14,6 +14,12 @@ version = "1.3.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "bef38d45163c2f1dde094a7dfd33ccf595c92905c8f8f4fdc18d06fb1037718a" +[[package]] +name = "bitflags" +version = "2.4.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "327762f6e5a765692301e5bb513e0d9fef63be86bbc14528052b1cd3e6f03e07" + [[package]] name = "lazy_static" version = "1.4.0" @@ -35,7 +41,7 @@ version = "10.7.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "6c297679cb867470fa8c9f67dbba74a78d78e3e98d7cf2b08d6d71540f797332" dependencies = [ - "bitflags", + "bitflags 1.3.2", ] [[package]] @@ -78,6 +84,7 @@ checksum = "a2eb9349b6444b326872e140eb1cf5e7c522154d69e7a0ffb0fb81c06b37543f" name = "tiny_os" version = "0.1.0" dependencies = [ + "bitflags 2.4.1", "lazy_static", "log", "sbi-rt", @@ -91,7 +98,7 @@ version = "0.3.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "6dc00444796f6c71f47c85397a35e9c4dbf9901902ac02386940d178e2b78687" dependencies = [ - "bitflags", + "bitflags 1.3.2", "rustversion", "x86", ] @@ -103,6 +110,6 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "2781db97787217ad2a2845c396a5efe286f87467a5810836db6d74926e94a385" dependencies = [ "bit_field", - "bitflags", + "bitflags 1.3.2", "raw-cpuid", ] diff --git a/Cargo.toml b/Cargo.toml index 1943da3..fa81c4f 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -23,6 +23,7 @@ panic = "abort" panic = "abort" [dependencies] +bitflags = "2.4.1" lazy_static = { version = "1.4.0", features = ["spin_no_std"] } log = "0.4" sbi-rt = { version = "0.0.2", features = ["legacy"] } diff --git a/src/arch/mod.rs b/src/arch/mod.rs index 2ad9760..fe4f540 100644 --- a/src/arch/mod.rs +++ b/src/arch/mod.rs @@ -5,6 +5,6 @@ pub mod io; pub mod lowlevel; // Arch Level -#[cfg(feature = "arch_riscv64")] +#[cfg(any(feature = "arch_riscv64", feature = "arch_riscv32"))] #[path = "riscv/mod.rs"] mod riscv; diff --git a/src/arch/riscv/mm/mod.rs b/src/arch/riscv/mm/mod.rs new file mode 100644 index 0000000..79d2861 --- /dev/null +++ b/src/arch/riscv/mm/mod.rs @@ -0,0 +1 @@ +pub mod page; diff --git a/src/arch/riscv/mm/page.rs b/src/arch/riscv/mm/page.rs new file mode 100644 index 0000000..5e51762 --- /dev/null +++ b/src/arch/riscv/mm/page.rs @@ -0,0 +1,135 @@ +use crate::mm::addr::{AddressOps, PhysAddr, VirtAddr}; +use crate::mm::page; + +use bitflags::bitflags; +use static_assertions::assert_eq_size; + +const PAGE_SIZE: usize = 4096; +const PAGE_TABLE_ENTRIES: usize = 512; + +const PG_OFFSET: u64 = 12; +const PPN_OFFSET: u64 = 10; +const PPN_BITS: u64 = 44; +const PTE_PPN_MASK: u64 = ((1 << PPN_BITS) - 1) << PPN_OFFSET; +const PA_PPN_MASK: u64 = ((1 << PPN_BITS) - 1) << PG_OFFSET; + +bitflags! { + pub struct PTEFlags : u64 { + const VALID = 1 << 0; + const READABLE = 1 << 1; + const WRITABLE = 1 << 2; + const EXECUTABLE = 1 << 3; + const USER_ACCESSIBLE = 1 << 4; + const GLOBAL = 1 << 5; + const ACCESSED = 1 << 6; + const DIRTY = 1 << 7; + const RSW = 1 << 8 | 1 << 9; + } +} + +impl From for page::MapAttr { + fn from(flags: PTEFlags) -> Self { + let mut attr = Self::empty(); + + if flags.contains(PTEFlags::READABLE) { + attr.insert(Self::READABLE); + } + if flags.contains(PTEFlags::WRITABLE) { + attr.insert(Self::WRITABLE); + } + if flags.contains(PTEFlags::EXECUTABLE) { + attr.insert(Self::EXECUTABLE); + } + if flags.contains(PTEFlags::USER_ACCESSIBLE) { + attr.insert(Self::USER_ACCESSIBLE); + } + + attr + } +} + +impl From for PTEFlags { + fn from(attr: page::MapAttr) -> Self { + if attr.is_empty() { + return Self::empty(); + } + + let mut flags = Self::VALID; + + if attr.contains(page::MapAttr::READABLE) { + flags.insert(Self::READABLE); + } + if attr.contains(page::MapAttr::WRITABLE) { + flags.insert(Self::WRITABLE); + } + if attr.contains(page::MapAttr::EXECUTABLE) { + flags.insert(Self::EXECUTABLE); + } + if attr.contains(page::MapAttr::USER_ACCESSIBLE) { + flags.insert(Self::USER_ACCESSIBLE); + } + + flags + } +} + +#[derive(Clone, Copy)] +struct PTE(u64); + +impl page::PageTableEntry for PTE { + fn new_page(paddr: PhysAddr, attr: page::MapAttr) -> Self { + let flags = PTEFlags::from(attr); + let ppn = ((paddr.as_u64() & PA_PPN_MASK) >> PG_OFFSET) << PPN_OFFSET; + + Self(ppn | flags.bits()) + } + + fn new_table(paddr: PhysAddr) -> Self { + let flags = PTEFlags::VALID; + let ppn = ((paddr.as_u64() & PA_PPN_MASK) >> PG_OFFSET) << PPN_OFFSET; + + Self(ppn | flags.bits()) + } + + fn addr(&self) -> PhysAddr { + let ppn = (self.0 & PTE_PPN_MASK) >> PPN_OFFSET; + let paddr = ppn << PG_OFFSET; + PhysAddr::from(paddr as usize) + } + + fn attr(&self) -> page::MapAttr { + let flags = PTEFlags::from_bits_truncate(self.0); + flags.into() + } + + fn set_addr(&mut self, addr: PhysAddr) { + let ppn = ((addr.as_u64() & PA_PPN_MASK) >> PG_OFFSET) << PPN_OFFSET; + self.0 = (self.0 & !PTE_PPN_MASK) | ppn; + } + + fn set_attr(&mut self, attr: page::MapAttr) { + let flags = PTEFlags::from(attr); + self.0 = (self.0 & !PTEFlags::all().bits()) | flags.bits(); + } + + fn is_valid(&self) -> bool { + self.0 & PTEFlags::VALID.bits() != 0 + } +} + +// we'll implement sv39 paging scheme + +pub struct Size4KiB; +impl page::PageSize for Size4KiB { + const SIZE: usize = 1 << 12; // 4KiB +} + +pub struct Size2MiB; +impl page::PageSize for Size2MiB { + const SIZE: usize = 1 << 21; // 2MiB +} + +pub struct Size1GiB; +impl page::PageSize for Size1GiB { + const SIZE: usize = 1 << 30; // 1GiB +} diff --git a/src/arch/riscv/mod.rs b/src/arch/riscv/mod.rs index a2b9f71..660c3fc 100644 --- a/src/arch/riscv/mod.rs +++ b/src/arch/riscv/mod.rs @@ -7,4 +7,5 @@ mod layout; pub mod entry; pub mod io; pub mod lowlevel; +pub mod mm; pub mod trap; diff --git a/src/arch/trap.rs b/src/arch/trap.rs new file mode 100644 index 0000000..13ccd74 --- /dev/null +++ b/src/arch/trap.rs @@ -0,0 +1,5 @@ +pub struct Trap; + +pub trait Trampoline { + fn init(); +} diff --git a/src/lib.rs b/src/lib.rs index cccc1ca..0420921 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -2,7 +2,6 @@ #![feature(asm_const)] #![feature(naked_functions)] #![feature(panic_info_message)] -#![feature(fmt_internals)] #![feature(stmt_expr_attributes)] extern crate static_assertions; diff --git a/src/mm/mod.rs b/src/mm/mod.rs index 9f3b826..6511c31 100644 --- a/src/mm/mod.rs +++ b/src/mm/mod.rs @@ -1 +1,2 @@ pub mod addr; +pub mod page; diff --git a/src/mm/page.rs b/src/mm/page.rs new file mode 100644 index 0000000..13d7df3 --- /dev/null +++ b/src/mm/page.rs @@ -0,0 +1,53 @@ +use crate::mm::addr::{AddressOps, PhysAddr, VirtAddr}; +use bitflags::bitflags; +use core::marker::PhantomData; + +#[derive(Debug)] +pub enum PagingError { + AddressNotAligned, +} + +bitflags! { + pub struct MapAttr: usize { + const READABLE = 1 << 1; + const WRITABLE = 1 << 2; + const EXECUTABLE = 1 << 3; + const USER_ACCESSIBLE = 1 << 4; + } +} + +pub trait PageTableEntry { + fn new_page(paddr: PhysAddr, attr: MapAttr) -> Self; + fn new_table(paddr: PhysAddr) -> Self; + + fn addr(&self) -> PhysAddr; + fn attr(&self) -> MapAttr; + + fn set_addr(&mut self, addr: PhysAddr); + fn set_attr(&mut self, attr: MapAttr); + + fn is_valid(&self) -> bool; +} + +pub trait PageSize { + // Arch should implement this + // For example, 4KiB / 2MiB / 1GiB in sv39 + + const SIZE: usize; +} + +pub struct Page { + start_address: VirtAddr, + size: PhantomData, +} + +impl Page { + pub const SIZE: usize = S::SIZE; + + pub fn new(addr: VirtAddr) -> Self { + Self { + start_address: addr.align_down(Self::SIZE), + size: PhantomData, + } + } +}