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