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,
+ }
+ }
+}