From 1b58d2a956b97b2d680c1fb338a4a548d52b0f4f Mon Sep 17 00:00:00 2001 From: Jeremy Soller Date: Tue, 8 Sep 2020 11:13:49 -0600 Subject: [PATCH] Add FrameCount struct, improve zeroing page performance --- src/allocator/frame/buddy.rs | 35 +++++++++++++++-------------------- src/allocator/frame/bump.rs | 7 ++++--- src/allocator/frame/mod.rs | 29 ++++++++++++++++++++++++++--- src/arch/emulate.rs | 33 +++++++++++++++++++++++++++++++++ src/arch/mod.rs | 5 +++++ src/main.rs | 7 ++++--- src/page/mapper.rs | 4 ++-- 7 files changed, 89 insertions(+), 31 deletions(-) diff --git a/src/allocator/frame/buddy.rs b/src/allocator/frame/buddy.rs index 2d9b5ce489..947c61d512 100644 --- a/src/allocator/frame/buddy.rs +++ b/src/allocator/frame/buddy.rs @@ -7,6 +7,7 @@ use crate::{ Arch, BumpAllocator, FrameAllocator, + FrameCount, PhysicalAddress, VirtualAddress, }; @@ -49,7 +50,7 @@ impl BuddyAllocator { pub unsafe fn new(mut bump_allocator: BumpAllocator, clear_frees: bool) -> Option { // Allocate buddy table - let table_phys = bump_allocator.allocate(1)?; + let table_phys = bump_allocator.allocate_one()?; let table_virt = A::phys_to_virt(table_phys); for i in 0 .. (A::PAGE_SIZE / mem::size_of::()) { let virt = table_virt.add(i * mem::size_of::()); @@ -106,7 +107,7 @@ impl BuddyAllocator { println!(" map pages: {}", map_pages); for _ in 0 .. map_pages { - let map_phys = bump_allocator.allocate(1)?; + let map_phys = bump_allocator.allocate_one()?; let map_virt = A::phys_to_virt(map_phys); for i in 0..Self::MAP_PAGE_BYTES { A::write(map_virt.add(i), 0); @@ -127,7 +128,7 @@ impl BuddyAllocator { if area_offset < area.size { let area_base = area.base.add(area_offset); let area_size = area.size - area_offset; - allocator.free(area_base, area_size); + allocator.free(area_base, FrameCount::new(area_size / A::PAGE_SIZE)); area_offset = 0; } else { area_offset -= area.size; @@ -139,9 +140,9 @@ impl BuddyAllocator { } impl FrameAllocator for BuddyAllocator { - unsafe fn allocate(&mut self, size: usize) -> Option { + unsafe fn allocate(&mut self, count: FrameCount) -> Option { //TODO: support other sizes - if size != A::PAGE_SIZE { + if count.data() != 1 { return None; } @@ -177,27 +178,21 @@ impl FrameAllocator for BuddyAllocator { None } - unsafe fn free(&mut self, base: PhysicalAddress, size: usize) { - if self.clear_frees { - // Zero freed pages for security, also ensures all allocs are zerod - //TODO: improve performance - //TODO: assumes linear physical mapping - let mut zero_virt = A::phys_to_virt(base); - let zero_end = zero_virt.add(size); - while zero_virt < zero_end { - A::write(zero_virt, 0usize); - zero_virt = zero_virt.add(mem::size_of::()); - } - } - + unsafe fn free(&mut self, base: PhysicalAddress, count: FrameCount) { + let size = count.data() * A::PAGE_SIZE; for i in 0 .. Self::BUDDY_ENTRIES { let virt = self.table_virt.add(i * mem::size_of::()); let entry = A::read::(virt); if base >= entry.base && base.add(size) <= entry.base.add(entry.size) { //TODO: Correct logic - let pages = size / A::PAGE_SIZE; - for page in 0 .. pages { + for page in 0 .. count.data() { let page_base = base.add(page * A::PAGE_SIZE); + + if self.clear_frees { + let page_virt = A::phys_to_virt(page_base); + A::write_bytes(page_virt, 0, A::PAGE_SIZE); + } + let index = (page_base.data() - entry.base.data()) / A::PAGE_SIZE; let mut map_page = index / Self::MAP_PAGE_BITS; let map_bit = index % Self::MAP_PAGE_BITS; diff --git a/src/allocator/frame/bump.rs b/src/allocator/frame/bump.rs index aece627dea..af9822104f 100644 --- a/src/allocator/frame/bump.rs +++ b/src/allocator/frame/bump.rs @@ -3,6 +3,7 @@ use core::marker::PhantomData; use crate::{ Arch, FrameAllocator, + FrameCount, MemoryArea, PhysicalAddress, }; @@ -32,9 +33,9 @@ impl BumpAllocator { } impl FrameAllocator for BumpAllocator { - unsafe fn allocate(&mut self, count: usize) -> Option { + unsafe fn allocate(&mut self, count: FrameCount) -> Option { //TODO: support allocation of multiple pages - if count != 1 { + if count.data() != 1 { return None; } @@ -49,7 +50,7 @@ impl FrameAllocator for BumpAllocator { None } - unsafe fn free(&mut self, _address: PhysicalAddress, _count: usize) { + unsafe fn free(&mut self, _address: PhysicalAddress, _count: FrameCount) { unimplemented!(); } } diff --git a/src/allocator/frame/mod.rs b/src/allocator/frame/mod.rs index 7dc20163a3..33d07943bf 100644 --- a/src/allocator/frame/mod.rs +++ b/src/allocator/frame/mod.rs @@ -6,7 +6,30 @@ pub use self::bump::*; mod buddy; mod bump; -pub trait FrameAllocator { - unsafe fn allocate(&mut self, count: usize) -> Option; - unsafe fn free(&mut self, address: PhysicalAddress, count: usize); +#[derive(Clone, Copy, Debug)] +#[repr(transparent)] +pub struct FrameCount(usize); + +impl FrameCount { + pub fn new(count: usize) -> Self { + Self(count) + } + + pub fn data(&self) -> usize { + self.0 + } +} + +pub trait FrameAllocator { + unsafe fn allocate(&mut self, count: FrameCount) -> Option; + + unsafe fn free(&mut self, address: PhysicalAddress, count: FrameCount); + + unsafe fn allocate_one(&mut self) -> Option { + self.allocate(FrameCount::new(1)) + } + + unsafe fn free_one(&mut self, address: PhysicalAddress) { + self.free(address, FrameCount::new(1)); + } } diff --git a/src/arch/emulate.rs b/src/arch/emulate.rs index e4ed0ce220..f8d3f019a3 100644 --- a/src/arch/emulate.rs +++ b/src/arch/emulate.rs @@ -74,6 +74,11 @@ impl Arch for EmulateArch { MACHINE.as_mut().unwrap().write(address, value) } + #[inline(always)] + unsafe fn write_bytes(address: VirtualAddress, value: u8, count: usize) { + MACHINE.as_mut().unwrap().write_bytes(address, value, count) + } + #[inline(always)] unsafe fn invalidate(address: VirtualAddress) { MACHINE.as_mut().unwrap().invalidate(address); @@ -149,6 +154,16 @@ impl Machine { } } + fn write_phys_bytes(&mut self, phys: PhysicalAddress, value: u8, count: usize) { + if phys.add(count).data() <= self.memory.len() { + unsafe { + ptr::write_bytes(self.memory.as_mut_ptr().add(phys.data()) as *mut u8, value, count); + } + } else { + panic!("write_phys_bytes: 0x{:X} count 0x{:X} outside of memory", phys.data(), count); + } + } + fn translate(&self, virt: VirtualAddress) -> Option<(PhysicalAddress, usize)> { let virt_data = virt.data(); let page = virt_data & A::PAGE_ADDRESS_MASK; @@ -194,6 +209,24 @@ impl Machine { } } + fn write_bytes(&mut self, virt: VirtualAddress, value: u8, count: usize) { + //TODO: allow writing past page boundaries + let virt_data = virt.data(); + if (virt_data & A::PAGE_ADDRESS_MASK) != ((virt_data + (count - 1)) & A::PAGE_ADDRESS_MASK) { + panic!("write_bytes: 0x{:X} count 0x{:X} passes page boundary", virt_data, count); + } + + if let Some((phys, flags)) = self.translate(virt) { + if flags & A::ENTRY_FLAG_WRITABLE != 0 { + self.write_phys_bytes(phys, value, count); + } else { + panic!("write_bytes: 0x{:X} count 0x{:X} not writable", virt_data, count); + } + } else { + panic!("write_bytes: 0x{:X} count 0x{:X} not present", virt_data, count); + } + } + fn invalidate(&mut self, _address: VirtualAddress) { unimplemented!(); } diff --git a/src/arch/mod.rs b/src/arch/mod.rs index e0559713d8..53efdd3628 100644 --- a/src/arch/mod.rs +++ b/src/arch/mod.rs @@ -55,6 +55,11 @@ pub trait Arch { ptr::write(address.data() as *mut T, value) } + #[inline(always)] + unsafe fn write_bytes(address: VirtualAddress, value: u8, count: usize) { + ptr::write_bytes(address.data() as *mut u8, value, count) + } + unsafe fn invalidate(address: VirtualAddress); #[inline(always)] diff --git a/src/main.rs b/src/main.rs index b3ab505f40..9d7f3f2f18 100644 --- a/src/main.rs +++ b/src/main.rs @@ -202,11 +202,12 @@ unsafe fn new_tables(areas: &'static [MemoryArea]) { let mut allocator = BuddyAllocator::::new(bump_allocator, true).unwrap(); for i in 0..16 { - let phys_opt = allocator.allocate(4 * KILOBYTE); - println!("4 KB page {}: {:X?}", i, phys_opt); + let phys_opt = allocator.allocate_one(); + println!("page {}: {:X?}", i, phys_opt); if i % 2 == 0 { if let Some(phys) = phys_opt { - allocator.free(phys, 4 * KILOBYTE); + println!("free {}: {:X?}", i, phys_opt); + allocator.free_one(phys); } } } diff --git a/src/page/mapper.rs b/src/page/mapper.rs index cb1b57f44f..c2cc225843 100644 --- a/src/page/mapper.rs +++ b/src/page/mapper.rs @@ -17,7 +17,7 @@ pub struct PageMapper<'f, A, F> { impl<'f, A: Arch, F: FrameAllocator> PageMapper<'f, A, F> { pub unsafe fn new(allocator: &'f mut F) -> Option { - let table_addr = allocator.allocate(1)?; + let table_addr = allocator.allocate_one()?; Some(Self { table_addr, allocator, @@ -46,7 +46,7 @@ impl<'f, A: Arch, F: FrameAllocator> PageMapper<'f, A, F> { let next = match next_opt { Some(some) => some, None => { - let phys = self.allocator.allocate(1)?; + let phys = self.allocator.allocate_one()?; //TODO: correct flags? table.set_entry(i, PageEntry::new(phys.data() | A::ENTRY_FLAG_WRITABLE | A::ENTRY_FLAG_PRESENT)); table.next(i)?