diff --git a/Cargo.lock b/Cargo.lock
index 4cc49f9..475ce24 100644
--- a/Cargo.lock
+++ b/Cargo.lock
@@ -2,6 +2,7 @@
name = "mahdi_os"
version = "0.1.0"
dependencies = [
+ "bitflags 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)",
"multiboot2 0.1.0 (git+https://github.com/phil-opp/multiboot2-elf64)",
"rlibc 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)",
"spin 0.3.5 (registry+https://github.com/rust-lang/crates.io-index)",
@@ -12,6 +13,11 @@ name = "bitflags"
version = "0.4.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
+[[package]]
+name = "bitflags"
+version = "0.7.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+
[[package]]
name = "multiboot2"
version = "0.1.0"
diff --git a/Cargo.toml b/Cargo.toml
index 53493bd..8377246 100644
--- a/Cargo.toml
+++ b/Cargo.toml
@@ -9,6 +9,7 @@ crate-type = ["staticlib"]
[dependencies]
rlibc = "0.1.4"
spin = "0.3.4"
+bitflags = "0.7.0"
[dependencies.multiboot2]
git = "https://github.com/phil-opp/multiboot2-elf64"
diff --git a/src/arch/x86_64/boot.asm b/src/arch/x86_64/boot.asm
index 38163f7..92e55b3 100644
--- a/src/arch/x86_64/boot.asm
+++ b/src/arch/x86_64/boot.asm
@@ -13,6 +13,9 @@ start:
call check_long_mode
call set_up_page_tables
+ mov eax, p4_table
+ or eax, 0b11 ; present + writable
+ mov [p4_table + 511 * 8], eax
call enable_paging
call set_up_SSE
diff --git a/src/lib.rs b/src/lib.rs
index 3ae5167..c7104e1 100644
--- a/src/lib.rs
+++ b/src/lib.rs
@@ -3,6 +3,8 @@
#![feature(unique)]
#![feature(const_fn)]
+#[macro_use]
+extern crate bitflags;
extern crate rlibc;
extern crate spin;
extern crate multiboot2;
diff --git a/src/memory/mod.rs b/src/memory/mod.rs
index 75e3a6a..0757a75 100644
--- a/src/memory/mod.rs
+++ b/src/memory/mod.rs
@@ -1,5 +1,8 @@
pub use self::area_frame_allocator::AreaFrameAllocator;
+use self::paging::PhysicalAddress;
+
mod area_frame_allocator;
+mod paging;
pub const PAGE_SIZE: usize = 4096;
@@ -12,6 +15,10 @@ impl Frame {
fn containing_address(address: usize) -> Frame {
Frame { number: address / PAGE_SIZE }
}
+
+ fn start_address(&self) -> PhysicalAddress {
+ self.number * PAGE_SIZE
+ }
}
pub trait FrameAllocator {
diff --git a/src/memory/paging/entry.rs b/src/memory/paging/entry.rs
new file mode 100644
index 0000000..e507540
--- /dev/null
+++ b/src/memory/paging/entry.rs
@@ -0,0 +1,49 @@
+use memory::PAGE_SIZE;
+
+pub struct Entry(u64);
+
+impl Entry {
+ pub fn is_unused(&self) -> bool {
+ self.0 == 0
+ }
+
+ pub fn set_unused(&mut self) {
+ self.0 = 0;
+ }
+
+ pub fn flags(&self) -> EntryFlags {
+ EntryFlags::from_bits_truncate(self.0)
+ }
+
+ pub fn pointed_frame(&self) -> Option {
+ if self.flags().contains(PRESENT) {
+ Some(Frame::containing_address(
+ self.0 as usize & 0x000fffff_fffff000
+ ))
+ } else {
+ None
+ }
+ }
+
+ pub fn set (&mut self, frame: Frame, flags: EntryFlags) {
+ assert!(frame.start_address() & !x000fffff_fffff000 == 0);
+ self.0 = (frame.start_address() as u64) | flags.bits();
+ }
+}
+
+bitflags! {
+ pub flags EntryFlags: u64 {
+ const PRESENT = 1 << 0,
+ const WRITABLE = 1 << 1,
+ const USER_ACCESSABLE = 1 << 2,
+ const WRITE_THROUGH = 1 << 3,
+ const NO_CACHE = 1 << 4,
+ const ACCESSED = 1 << 5,
+ const DIRTY = 1 << 6,
+ const HUGE_PAGE = 1 << 7,
+ const GLOBAL = 1 << 8,
+ const NO_EXECUTE = 1 << 63,
+ }
+}
+
+
diff --git a/src/memory/paging/mod.rs b/src/memory/paging/mod.rs
new file mode 100644
index 0000000..03c32a0
--- /dev/null
+++ b/src/memory/paging/mod.rs
@@ -0,0 +1,57 @@
+use memory::PAGE_SIZE;
+use memory::Frame;
+
+const ENTRY_COUNT: usize = 512;
+
+pub type PhysicalAddress = usize;
+pub type VirtualAddress = usize;
+
+pub struct Page {
+ number: usize,
+}
+
+pub struct Entry(u64);
+
+impl Entry {
+ pub fn is_unused(&self) -> bool {
+ self.0 == 0
+ }
+
+ pub fn set_unused(&mut self) {
+ self.0 = 0;
+ }
+
+ pub fn flags(&self) -> EntryFlags {
+ EntryFlags::from_bits_truncate(self.0)
+ }
+
+ pub fn pointed_frame(&self) -> Option {
+ if self.flags().contains(PRESENT) {
+ Some(Frame::containing_address(
+ self.0 as usize & 0x000fffff_fffff000
+ ))
+ } else {
+ None
+ }
+ }
+
+ pub fn set(&mut self, frame: Frame, flags: EntryFlags) {
+ assert!(frame.start_address() & !0x000fffff_fffff000 == 0);
+ self.0 = (frame.start_address() as u64) | flags.bits();
+ }
+}
+
+bitflags! {
+ pub flags EntryFlags: u64 {
+ const PRESENT = 1 << 0,
+ const WRITABLE = 1 << 1,
+ const USER_ACCESSABLE = 1 << 2,
+ const WRITE_THROUGH = 1 << 3,
+ const NO_CACHE = 1 << 4,
+ const ACCESSED = 1 << 5,
+ const DIRTY = 1 << 6,
+ const HUGE_PAGE = 1 << 7,
+ const GLOBAL = 1 << 8,
+ const NO_EXECUTE = 1 << 63,
+ }
+}
diff --git a/src/memory/paging/table.rs b/src/memory/paging/table.rs
new file mode 100644
index 0000000..d3e1cc2
--- /dev/null
+++ b/src/memory/paging/table.rs
@@ -0,0 +1,89 @@
+use memory::paging::entry::*;
+use memory::paging::ENTRY_COUNT;
+use core::ops::{Index, IndexMut};
+use core::marker::PhantomData;
+
+pub const P4: *mut Table = 0xffffffff_fffff000 as *mut _;
+
+pub trait TableLevel {}
+pub enum Level 4 {}
+pub enum Level 3 {}
+pub enum Level 2 {}
+pub enum Level 1 {}
+
+impl TableLevel for Level4 {}
+impl TableLevel for Level3 {}
+impl TableLevel for Level2 {}
+impl TableLevel for Level1 {}
+
+pub trait HierarchicalLevel: TableLevel {
+ type NextLevel: TableLevel;
+}
+
+impl HierarchicalLevel for Level4 {
+ type NextLevel: Level3
+}
+impl HierarchicalLevel for Level3 {
+ type NextLevel: Level2
+}
+impl HierarchicalLevel for Level2 {
+ type NextLevel: Level1
+}
+
+pub struct Table {
+ entries : [Entry; ENTRY_COUNT],
+ level: PhantomData
+}
+
+impl Table where L: TableLevel {
+ pub fn zero(&mut self) {
+ for entry in self.entries.iter_mut() {
+ entry.set_unused();
+ }
+ }
+}
+
+impl Table where L: HierarchicalLevel {
+ fn next_table_address(&self, index: usize) -> Option {
+ let entry_flags = self[index].flags();
+
+ if entry_flags.contains(PRESENT) && !entry_flags.contains(HUGE_PAGE) {
+ let table_address = self as *const _ as usize;
+ Some((table_address << 9) | (index << 12))
+ } else {
+ None
+ }
+ }
+
+ pub fn next_table(&self, index: usize) -> Option<&Table> {
+ self.next_table_address(index)
+ .map(|address| unsafe { &*(address as *const _) })
+ }
+
+ pub fn next_table_mut(&mut self, index: usize) -> Option<&mut Table> {
+ self.next_table_address(index)
+ .map(|address| unsafe { &mut *(address as *mut _) })
+ }
+}
+
+impl Index for Table where L: TableLevel {
+ type Output = Entry;
+
+ fn index(&self, index: usize) -> &Entry {
+ &self.entries[index]
+ }
+}
+
+impl IndexMut for Table where L: TableLevel {
+ fn index_mut(&mut self, index: usize) -> &mut Entry {
+ &mut self.entries[index]
+ }
+}
+
+fn test() {
+ let p4 = unsafe { &*P4 };
+ p4.next_table(4@)
+ .and_then(|p3| p3.next_table(1337))
+ .and_then(|p2| p2.next_table(0xdeadbeaf))
+ .and_then(|p1| p1.next_table(0xcafebabe))
+}