diff --git a/src/arch/x86_64/paging/entry.rs b/src/arch/x86_64/paging/entry.rs index 167381947ea001488ecad5b4077412d18172e711..f031f62c022d79270846f72f4a247de692a673ce 100644 --- a/src/arch/x86_64/paging/entry.rs +++ b/src/arch/x86_64/paging/entry.rs @@ -24,16 +24,22 @@ bitflags! { } pub const ADDRESS_MASK: usize = 0x000f_ffff_ffff_f000; +pub const COUNTER_MASK: u64 = 0x3ff0_0000_0000_0000; impl Entry { + /// Clear entry + pub fn set_zero(&mut self) { + self.0 = 0; + } + /// Is the entry unused? pub fn is_unused(&self) -> bool { - self.0 == 0 + self.0 == (self.0 & COUNTER_MASK) } /// Make the entry unused pub fn set_unused(&mut self) { - self.0 = 0; + self.0 = self.0 & COUNTER_MASK; } /// Get the address this page references @@ -57,6 +63,16 @@ impl Entry { pub fn set(&mut self, frame: Frame, flags: EntryFlags) { debug_assert!(frame.start_address().get() & !ADDRESS_MASK == 0); - self.0 = (frame.start_address().get() as u64) | flags.bits(); + self.0 = (frame.start_address().get() as u64) | flags.bits() | (self.0 & COUNTER_MASK); + } + + /// Get bits 52-61 in entry, used as counter for page table + pub fn counter_bits(&self) -> u64 { + (self.0 & COUNTER_MASK) >> 52 + } + + /// Set bits 52-61 in entry, used as counter for page table + pub fn set_counter_bits(&mut self, count: u64) { + self.0 = (self.0 & !COUNTER_MASK) | (count << 52); } } diff --git a/src/arch/x86_64/paging/mapper.rs b/src/arch/x86_64/paging/mapper.rs index 79b9f3609b22119e2e508c67f6373a8482264c6b..c2cc5923fd413dc5f8648105426ab8449d29c314 100644 --- a/src/arch/x86_64/paging/mapper.rs +++ b/src/arch/x86_64/paging/mapper.rs @@ -107,6 +107,7 @@ impl Mapper { page.start_address().get(), p1[page.p1_index()].address().get(), p1[page.p1_index()].flags(), frame.start_address().get(), flags); + p1.increment_entry_count(); p1[page.p1_index()].set(frame, flags | EntryFlags::PRESENT); MapperFlush::new(page) } @@ -146,6 +147,7 @@ impl Mapper { panic!("unmap_inner({:X}): frame not found", page.start_address().get()) }; + p1.decrement_entry_count(); p1[page.p1_index()].set_unused(); if keep_parents || ! p1.is_unused() { @@ -157,13 +159,14 @@ impl Mapper { if let Some(p1_frame) = p2[page.p2_index()].pointed_frame() { //println!("Free p1 {:?}", p1_frame); + p2.decrement_entry_count(); p2[page.p2_index()].set_unused(); deallocate_frames(p1_frame, 1); } else { panic!("unmap_inner({:X}): p1_frame not found", page.start_address().get()); } - if keep_parents || ! p2.is_unused() { + if ! p2.is_unused() { return frame; } } else { @@ -172,13 +175,14 @@ impl Mapper { if let Some(p2_frame) = p3[page.p3_index()].pointed_frame() { //println!("Free p2 {:?}", p2_frame); + p3.decrement_entry_count(); p3[page.p3_index()].set_unused(); deallocate_frames(p2_frame, 1); } else { panic!("unmap_inner({:X}): p2_frame not found", page.start_address().get()); } - if keep_parents || ! p3.is_unused() { + if ! p3.is_unused() { return frame; } } else { @@ -187,6 +191,7 @@ impl Mapper { if let Some(p3_frame) = p4[page.p4_index()].pointed_frame() { //println!("Free p3 {:?}", p3_frame); + p4.decrement_entry_count(); p4[page.p4_index()].set_unused(); deallocate_frames(p3_frame, 1); } else { diff --git a/src/arch/x86_64/paging/table.rs b/src/arch/x86_64/paging/table.rs index 4e9ae6ddcf1ef3600585ab1a35b8f18697d6658c..67845607386d0b0074456c273de55ece1537e0dc 100644 --- a/src/arch/x86_64/paging/table.rs +++ b/src/arch/x86_64/paging/table.rs @@ -46,10 +46,8 @@ pub struct Table<L: TableLevel> { impl<L> Table<L> where L: TableLevel { pub fn is_unused(&self) -> bool { - for entry in self.entries.iter() { - if ! entry.is_unused() { - return false; - } + if self.entry_count() > 0 { + return false; } true @@ -57,9 +55,30 @@ impl<L> Table<L> where L: TableLevel { pub fn zero(&mut self) { for entry in self.entries.iter_mut() { - entry.set_unused(); + entry.set_zero(); } } + + /// Set number of entries in first table entry + fn set_entry_count(&mut self, count: u64) { + debug_assert!(count <= ENTRY_COUNT as u64, "count can't be greater than ENTRY_COUNT"); + self.entries[0].set_counter_bits(count); + } + + /// Get number of entries in first table entry + fn entry_count(&self) -> u64 { + self.entries[0].counter_bits() + } + + pub fn increment_entry_count(&mut self) { + let current_count = self.entry_count(); + self.set_entry_count(current_count + 1); + } + + pub fn decrement_entry_count(&mut self) { + let current_count = self.entry_count(); + self.set_entry_count(current_count - 1); + } } impl<L> Table<L> where L: HierarchicalLevel { @@ -76,6 +95,7 @@ impl<L> Table<L> where L: HierarchicalLevel { assert!(!self[index].flags().contains(EntryFlags::HUGE_PAGE), "next_table_create does not support huge pages"); let frame = allocate_frames(1).expect("no frames available"); + self.increment_entry_count(); self[index].set(frame, EntryFlags::PRESENT | EntryFlags::WRITABLE | EntryFlags::USER_ACCESSIBLE /* Allow users to go down the page table, implement permissions at the page level */); self.next_table_mut(index).unwrap().zero(); }