Update to the 2024 edition

On newer rustc versions let_chain is only allowed with the 2024 edition.
This commit is contained in:
bjorn3
2025-09-10 15:37:17 +02:00
parent 63669069f4
commit 08c00a434d
13 changed files with 679 additions and 563 deletions
+1 -1
View File
@@ -2,7 +2,7 @@
name = "rmm"
version = "0.1.0"
authors = ["Jeremy Soller <jeremy@system76.com>"]
edition = "2018"
edition = "2024"
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
+186 -172
View File
@@ -54,22 +54,28 @@ impl<A: Arch> BuddyEntry<A> {
}
unsafe fn usage_addr(&self, page: usize) -> Option<VirtualAddress> {
if page < self.pages() {
let phys = self.base.add(page * mem::size_of::<BuddyUsage>());
Some(A::phys_to_virt(phys))
} else {
None
unsafe {
if page < self.pages() {
let phys = self.base.add(page * mem::size_of::<BuddyUsage>());
Some(A::phys_to_virt(phys))
} else {
None
}
}
}
unsafe fn usage(&self, page: usize) -> Option<BuddyUsage> {
let addr = self.usage_addr(page)?;
Some(A::read(addr))
unsafe {
let addr = self.usage_addr(page)?;
Some(A::read(addr))
}
}
unsafe fn set_usage(&self, page: usize, usage: BuddyUsage) -> Option<()> {
let addr = self.usage_addr(page)?;
Some(A::write(addr, usage))
unsafe {
let addr = self.usage_addr(page)?;
Some(A::write(addr, usage))
}
}
}
@@ -82,208 +88,216 @@ impl<A: Arch> BuddyAllocator<A> {
const BUDDY_ENTRIES: usize = A::PAGE_SIZE / mem::size_of::<BuddyEntry<A>>();
pub unsafe fn new(mut bump_allocator: BumpAllocator<A>) -> Option<Self> {
// Allocate buddy table
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::<BuddyEntry<A>>()) {
let virt = table_virt.add(i * mem::size_of::<BuddyEntry<A>>());
A::write(virt, BuddyEntry::<A>::empty());
}
let allocator = Self {
table_virt,
phantom: PhantomData,
};
// Add areas to buddy table, combining areas when possible, and skipping frames used
// by the bump allocator
let mut offset = bump_allocator.offset();
for old_area in bump_allocator.areas().iter() {
let mut area = old_area.clone();
if offset >= area.size {
offset -= area.size;
continue;
} else if offset > 0 {
area.base = area.base.add(offset);
area.size -= offset;
offset = 0;
}
unsafe {
// Allocate buddy table
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::<BuddyEntry<A>>()) {
let virt = table_virt.add(i * mem::size_of::<BuddyEntry<A>>());
A::write(virt, BuddyEntry::<A>::empty());
}
let allocator = Self {
table_virt,
phantom: PhantomData,
};
// Add areas to buddy table, combining areas when possible, and skipping frames used
// by the bump allocator
let mut offset = bump_allocator.offset();
for old_area in bump_allocator.areas().iter() {
let mut area = old_area.clone();
if offset >= area.size {
offset -= area.size;
continue;
} else if offset > 0 {
area.base = area.base.add(offset);
area.size -= offset;
offset = 0;
}
for i in 0..(A::PAGE_SIZE / mem::size_of::<BuddyEntry<A>>()) {
let virt = table_virt.add(i * mem::size_of::<BuddyEntry<A>>());
let mut entry = A::read::<BuddyEntry<A>>(virt);
let inserted = if area.base.add(area.size) == { entry.base } {
// Combine entry at start
entry.base = area.base;
entry.size += area.size;
true
} else if area.base == entry.base.add(entry.size) {
// Combine entry at end
entry.size += area.size;
true
} else if entry.size == 0 {
// Create new entry
entry.base = area.base;
entry.size = area.size;
true
} else {
false
};
if inserted {
A::write(virt, entry);
break;
}
}
}
//TODO: sort areas?
// Allocate buddy maps
for i in 0..Self::BUDDY_ENTRIES {
let virt = table_virt.add(i * mem::size_of::<BuddyEntry<A>>());
let mut entry = A::read::<BuddyEntry<A>>(virt);
let inserted = if area.base.add(area.size) == { entry.base } {
// Combine entry at start
entry.base = area.base;
entry.size += area.size;
true
} else if area.base == entry.base.add(entry.size) {
// Combine entry at end
entry.size += area.size;
true
} else if entry.size == 0 {
// Create new entry
entry.base = area.base;
entry.size = area.size;
true
} else {
false
};
if inserted {
A::write(virt, entry);
break;
}
}
}
//TODO: sort areas?
// Only set up entries that have enough space for their own usage map
let usage_pages = entry.usage_pages();
if entry.pages() > usage_pages {
// Mark all usage bytes as unused
let usage_start = entry.usage_addr(0)?;
for page in 0..usage_pages {
A::write_bytes(usage_start.add(page << A::PAGE_SHIFT), 0, A::PAGE_SIZE);
}
// Allocate buddy maps
for i in 0..Self::BUDDY_ENTRIES {
let virt = table_virt.add(i * mem::size_of::<BuddyEntry<A>>());
let mut entry = A::read::<BuddyEntry<A>>(virt);
// Only set up entries that have enough space for their own usage map
let usage_pages = entry.usage_pages();
if entry.pages() > usage_pages {
// Mark all usage bytes as unused
let usage_start = entry.usage_addr(0)?;
for page in 0..usage_pages {
A::write_bytes(usage_start.add(page << A::PAGE_SHIFT), 0, A::PAGE_SIZE);
// Mark bytes used for usage as used
for page in 0..usage_pages {
entry.set_usage(page, BuddyUsage(1))?;
}
}
// Mark bytes used for usage as used
for page in 0..usage_pages {
entry.set_usage(page, BuddyUsage(1))?;
}
// Skip the pages used for usage
entry.skip = usage_pages;
// Set used pages to pages used for usage
entry.used = usage_pages;
// Write updated entry
A::write(virt, entry);
}
// Skip the pages used for usage
entry.skip = usage_pages;
// Set used pages to pages used for usage
entry.used = usage_pages;
// Write updated entry
A::write(virt, entry);
Some(allocator)
}
Some(allocator)
}
}
impl<A: Arch> FrameAllocator for BuddyAllocator<A> {
unsafe fn allocate(&mut self, count: FrameCount) -> Option<PhysicalAddress> {
if self.table_virt.data() == 0 {
return None;
}
unsafe {
if self.table_virt.data() == 0 {
return None;
}
for entry_i in 0..Self::BUDDY_ENTRIES {
let virt = self
.table_virt
.add(entry_i * mem::size_of::<BuddyEntry<A>>());
let mut entry = A::read::<BuddyEntry<A>>(virt);
for entry_i in 0..Self::BUDDY_ENTRIES {
let virt = self
.table_virt
.add(entry_i * mem::size_of::<BuddyEntry<A>>());
let mut entry = A::read::<BuddyEntry<A>>(virt);
let mut free_page = entry.skip;
let mut free_count = 0;
for page in entry.skip..entry.pages() {
let usage = entry.usage(page)?;
if usage.0 == 0 {
free_count += 1;
let mut free_page = entry.skip;
let mut free_count = 0;
for page in entry.skip..entry.pages() {
let usage = entry.usage(page)?;
if usage.0 == 0 {
free_count += 1;
if free_count == count.data() {
break;
if free_count == count.data() {
break;
}
} else {
free_page = page + 1;
free_count = 0;
}
} else {
free_page = page + 1;
free_count = 0;
}
if free_count == count.data() {
for page in free_page..free_page + free_count {
// Update usage
let mut usage = entry.usage(page)?;
usage.0 += 1;
entry.set_usage(page, usage);
// Zero page
let page_phys = entry.base.add(page << A::PAGE_SHIFT);
let page_virt = A::phys_to_virt(page_phys);
A::write_bytes(page_virt, 0, A::PAGE_SIZE);
}
// Update skip if necessary
if entry.skip == free_page {
entry.skip = free_page + free_count;
}
// Update used page count
entry.used += free_count;
// Write updated entry
A::write(virt, entry);
return Some(entry.base.add(free_page << A::PAGE_SHIFT));
}
}
if free_count == count.data() {
for page in free_page..free_page + free_count {
// Update usage
let mut usage = entry.usage(page)?;
usage.0 += 1;
entry.set_usage(page, usage);
// Zero page
let page_phys = entry.base.add(page << A::PAGE_SHIFT);
let page_virt = A::phys_to_virt(page_phys);
A::write_bytes(page_virt, 0, A::PAGE_SIZE);
}
// Update skip if necessary
if entry.skip == free_page {
entry.skip = free_page + free_count;
}
// Update used page count
entry.used += free_count;
// Write updated entry
A::write(virt, entry);
return Some(entry.base.add(free_page << A::PAGE_SHIFT));
}
None
}
None
}
unsafe fn free(&mut self, base: PhysicalAddress, count: FrameCount) {
if self.table_virt.data() == 0 {
return;
}
unsafe {
if self.table_virt.data() == 0 {
return;
}
let size = count.data() * A::PAGE_SIZE;
for i in 0..Self::BUDDY_ENTRIES {
let virt = self.table_virt.add(i * mem::size_of::<BuddyEntry<A>>());
let mut entry = A::read::<BuddyEntry<A>>(virt);
let size = count.data() * A::PAGE_SIZE;
for i in 0..Self::BUDDY_ENTRIES {
let virt = self.table_virt.add(i * mem::size_of::<BuddyEntry<A>>());
let mut entry = A::read::<BuddyEntry<A>>(virt);
if base >= { entry.base } && base.add(size) <= entry.base.add(entry.size) {
let start_page = (base.data() - { entry.base }.data()) >> A::PAGE_SHIFT;
for page in start_page..start_page + count.data() {
let mut usage = entry.usage(page).expect("failed to get usage during free");
if base >= { entry.base } && base.add(size) <= entry.base.add(entry.size) {
let start_page = (base.data() - { entry.base }.data()) >> A::PAGE_SHIFT;
for page in start_page..start_page + count.data() {
let mut usage = entry.usage(page).expect("failed to get usage during free");
if usage.0 > 0 {
usage.0 -= 1;
} else {
panic!("tried to free already free frame");
}
// If page was freed
if usage.0 == 0 {
// Update skip if necessary
if page < entry.skip {
entry.skip = page;
if usage.0 > 0 {
usage.0 -= 1;
} else {
panic!("tried to free already free frame");
}
// Update used page count
entry.used -= 1;
// If page was freed
if usage.0 == 0 {
// Update skip if necessary
if page < entry.skip {
entry.skip = page;
}
// Update used page count
entry.used -= 1;
}
entry
.set_usage(page, usage)
.expect("failed to set usage during free");
}
entry
.set_usage(page, usage)
.expect("failed to set usage during free");
// Write updated entry
A::write(virt, entry);
return;
}
// Write updated entry
A::write(virt, entry);
return;
}
}
}
unsafe fn usage(&self) -> FrameUsage {
let mut total = 0;
let mut used = 0;
for i in 0..Self::BUDDY_ENTRIES {
let virt = self.table_virt.add(i * mem::size_of::<BuddyEntry<A>>());
let entry = A::read::<BuddyEntry<A>>(virt);
total += entry.size >> A::PAGE_SHIFT;
used += entry.used;
unsafe {
let mut total = 0;
let mut used = 0;
for i in 0..Self::BUDDY_ENTRIES {
let virt = self.table_virt.add(i * mem::size_of::<BuddyEntry<A>>());
let entry = A::read::<BuddyEntry<A>>(virt);
total += entry.size >> A::PAGE_SHIFT;
used += entry.used;
}
FrameUsage::new(FrameCount::new(used), FrameCount::new(total))
}
FrameUsage::new(FrameCount::new(used), FrameCount::new(total))
}
}
+25 -16
View File
@@ -11,7 +11,9 @@ pub struct BumpAllocator<A> {
impl<A: Arch> BumpAllocator<A> {
pub fn new(mut areas: &'static [MemoryArea], mut offset: usize) -> Self {
while let Some(first) = areas.first() && first.size <= offset {
while let Some(first) = areas.first()
&& first.size <= offset
{
offset -= first.size;
areas = &areas[1..];
}
@@ -32,7 +34,9 @@ impl<A: Arch> BumpAllocator<A> {
}
pub fn abs_offset(&self) -> PhysicalAddress {
let (areas, off) = self.cur_areas;
areas.first().map_or(PhysicalAddress::new(0), |a| a.base.add(off))
areas
.first()
.map_or(PhysicalAddress::new(0), |a| a.base.add(off))
}
pub fn offset(&self) -> usize {
(unsafe { self.usage().total().data() - self.usage().free().data() }) * A::PAGE_SIZE
@@ -41,21 +45,23 @@ impl<A: Arch> BumpAllocator<A> {
impl<A: Arch> FrameAllocator for BumpAllocator<A> {
unsafe fn allocate(&mut self, count: FrameCount) -> Option<PhysicalAddress> {
let req_size = count.data() * A::PAGE_SIZE;
unsafe {
let req_size = count.data() * A::PAGE_SIZE;
let block = loop {
let area = self.cur_areas.0.first()?;
let off = self.cur_areas.1;
if area.size - off < req_size {
self.cur_areas = (&self.cur_areas.0[1..], 0);
continue;
}
self.cur_areas.1 += req_size;
let block = loop {
let area = self.cur_areas.0.first()?;
let off = self.cur_areas.1;
if area.size - off < req_size {
self.cur_areas = (&self.cur_areas.0[1..], 0);
continue;
}
self.cur_areas.1 += req_size;
break area.base.add(off);
};
A::write_bytes(A::phys_to_virt(block), 0, req_size);
Some(block)
break area.base.add(off);
};
A::write_bytes(A::phys_to_virt(block), 0, req_size);
Some(block)
}
}
unsafe fn free(&mut self, _address: PhysicalAddress, _count: FrameCount) {
@@ -65,6 +71,9 @@ impl<A: Arch> FrameAllocator for BumpAllocator<A> {
unsafe fn usage(&self) -> FrameUsage {
let total = self.orig_areas.0.iter().map(|a| a.size).sum::<usize>() - self.orig_areas.1;
let free = self.cur_areas.0.iter().map(|a| a.size).sum::<usize>() - self.cur_areas.1;
FrameUsage::new(FrameCount::new((total - free) / A::PAGE_SIZE), FrameCount::new(total / A::PAGE_SIZE))
FrameUsage::new(
FrameCount::new((total - free) / A::PAGE_SIZE),
FrameCount::new(total / A::PAGE_SIZE),
)
}
}
+9 -7
View File
@@ -49,11 +49,13 @@ pub trait FrameAllocator {
unsafe fn free(&mut self, address: PhysicalAddress, count: FrameCount);
unsafe fn allocate_one(&mut self) -> Option<PhysicalAddress> {
self.allocate(FrameCount::new(1))
unsafe { self.allocate(FrameCount::new(1)) }
}
unsafe fn free_one(&mut self, address: PhysicalAddress) {
self.free(address, FrameCount::new(1));
unsafe {
self.free(address, FrameCount::new(1));
}
}
unsafe fn usage(&self) -> FrameUsage;
@@ -64,18 +66,18 @@ where
T: FrameAllocator,
{
unsafe fn allocate(&mut self, count: FrameCount) -> Option<PhysicalAddress> {
T::allocate(self, count)
unsafe { T::allocate(self, count) }
}
unsafe fn free(&mut self, address: PhysicalAddress, count: FrameCount) {
T::free(self, address, count)
unsafe { T::free(self, address, count) }
}
unsafe fn allocate_one(&mut self) -> Option<PhysicalAddress> {
T::allocate_one(self)
unsafe { T::allocate_one(self) }
}
unsafe fn free_one(&mut self, address: PhysicalAddress) {
T::free_one(self, address)
unsafe { T::free_one(self, address) }
}
unsafe fn usage(&self) -> FrameUsage {
T::usage(self)
unsafe { T::usage(self) }
}
}
+27 -19
View File
@@ -42,51 +42,59 @@ impl Arch for AArch64Arch {
#[inline(always)]
unsafe fn invalidate(address: VirtualAddress) {
asm!("
unsafe {
asm!("
dsb ishst
tlbi vaae1is, {}
dsb ish
isb
", in(reg) (address.data() >> Self::PAGE_SHIFT));
}
}
#[inline(always)]
unsafe fn invalidate_all() {
asm!(
"
unsafe {
asm!(
"
dsb ishst
tlbi vmalle1is
dsb ish
isb
"
);
);
}
}
#[inline(always)]
unsafe fn table(table_kind: TableKind) -> PhysicalAddress {
let address: usize;
match table_kind {
TableKind::User => {
asm!("mrs {0}, ttbr0_el1", out(reg) address);
}
TableKind::Kernel => {
asm!("mrs {0}, ttbr1_el1", out(reg) address);
unsafe {
let address: usize;
match table_kind {
TableKind::User => {
asm!("mrs {0}, ttbr0_el1", out(reg) address);
}
TableKind::Kernel => {
asm!("mrs {0}, ttbr1_el1", out(reg) address);
}
}
PhysicalAddress::new(address)
}
PhysicalAddress::new(address)
}
#[inline(always)]
unsafe fn set_table(table_kind: TableKind, address: PhysicalAddress) {
match table_kind {
TableKind::User => {
asm!("msr ttbr0_el1, {0}", in(reg) address.data());
}
TableKind::Kernel => {
asm!("msr ttbr1_el1, {0}", in(reg) address.data());
unsafe {
match table_kind {
TableKind::User => {
asm!("msr ttbr0_el1, {0}", in(reg) address.data());
}
TableKind::Kernel => {
asm!("msr ttbr1_el1, {0}", in(reg) address.data());
}
}
Self::invalidate_all();
}
Self::invalidate_all();
}
fn virt_is_valid(_address: VirtualAddress) -> bool {
+46 -38
View File
@@ -34,76 +34,84 @@ impl Arch for EmulateArch {
const ENTRY_FLAG_WRITE_COMBINING: usize = X8664Arch::ENTRY_FLAG_WRITE_COMBINING;
unsafe fn init() -> &'static [MemoryArea] {
// Create machine with PAGE_ENTRIES pages offset mapped (2 MiB on x86_64)
let mut machine = Machine::new(MEMORY_SIZE);
unsafe {
// Create machine with PAGE_ENTRIES pages offset mapped (2 MiB on x86_64)
let mut machine = Machine::new(MEMORY_SIZE);
// PML4 index 256 (PHYS_OFFSET) link to PDP
let pml4 = 0;
let pdp = pml4 + Self::PAGE_SIZE;
let flags = Self::ENTRY_FLAG_READWRITE | Self::ENTRY_FLAG_PRESENT;
machine.write_phys::<usize>(
PhysicalAddress::new(pml4 + 256 * Self::PAGE_ENTRY_SIZE),
pdp | flags,
);
// PDP link to PD
let pd = pdp + Self::PAGE_SIZE;
machine.write_phys::<usize>(PhysicalAddress::new(pdp), pd | flags);
// PD link to PT
let pt = pd + Self::PAGE_SIZE;
machine.write_phys::<usize>(PhysicalAddress::new(pd), pt | flags);
// PT links to frames
for i in 0..Self::PAGE_ENTRIES {
let page = i * Self::PAGE_SIZE;
// PML4 index 256 (PHYS_OFFSET) link to PDP
let pml4 = 0;
let pdp = pml4 + Self::PAGE_SIZE;
let flags = Self::ENTRY_FLAG_READWRITE | Self::ENTRY_FLAG_PRESENT;
machine.write_phys::<usize>(
PhysicalAddress::new(pt + i * Self::PAGE_ENTRY_SIZE),
page | flags,
PhysicalAddress::new(pml4 + 256 * Self::PAGE_ENTRY_SIZE),
pdp | flags,
);
// PDP link to PD
let pd = pdp + Self::PAGE_SIZE;
machine.write_phys::<usize>(PhysicalAddress::new(pdp), pd | flags);
// PD link to PT
let pt = pd + Self::PAGE_SIZE;
machine.write_phys::<usize>(PhysicalAddress::new(pd), pt | flags);
// PT links to frames
for i in 0..Self::PAGE_ENTRIES {
let page = i * Self::PAGE_SIZE;
machine.write_phys::<usize>(
PhysicalAddress::new(pt + i * Self::PAGE_ENTRY_SIZE),
page | flags,
);
}
MACHINE = Some(machine);
// Set table to pml4
EmulateArch::set_table(TableKind::Kernel, PhysicalAddress::new(pml4));
&MEMORY_AREAS
}
MACHINE = Some(machine);
// Set table to pml4
EmulateArch::set_table(TableKind::Kernel, PhysicalAddress::new(pml4));
&MEMORY_AREAS
}
#[inline(always)]
unsafe fn read<T>(address: VirtualAddress) -> T {
MACHINE.as_ref().unwrap().read(address)
unsafe { MACHINE.as_ref().unwrap().read(address) }
}
#[inline(always)]
unsafe fn write<T>(address: VirtualAddress, value: T) {
MACHINE.as_mut().unwrap().write(address, value)
unsafe { 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)
unsafe { MACHINE.as_mut().unwrap().write_bytes(address, value, count) }
}
#[inline(always)]
unsafe fn invalidate(address: VirtualAddress) {
MACHINE.as_mut().unwrap().invalidate(address);
unsafe {
MACHINE.as_mut().unwrap().invalidate(address);
}
}
#[inline(always)]
unsafe fn invalidate_all() {
MACHINE.as_mut().unwrap().invalidate_all();
unsafe {
MACHINE.as_mut().unwrap().invalidate_all();
}
}
#[inline(always)]
unsafe fn table(_table_kind: TableKind) -> PhysicalAddress {
MACHINE.as_mut().unwrap().get_table()
unsafe { MACHINE.as_mut().unwrap().get_table() }
}
#[inline(always)]
unsafe fn set_table(_table_kind: TableKind, address: PhysicalAddress) {
MACHINE.as_mut().unwrap().set_table(address);
unsafe {
MACHINE.as_mut().unwrap().set_table(address);
}
}
fn virt_is_valid(_address: VirtualAddress) -> bool {
// TODO: Don't see why an emulated arch would have any problems with canonicalness...
+7 -5
View File
@@ -65,25 +65,27 @@ pub trait Arch: Clone + Copy {
#[inline(always)]
unsafe fn read<T>(address: VirtualAddress) -> T {
ptr::read(address.data() as *const T)
unsafe { ptr::read(address.data() as *const T) }
}
#[inline(always)]
unsafe fn write<T>(address: VirtualAddress, value: T) {
ptr::write(address.data() as *mut T, value)
unsafe { 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 { ptr::write_bytes(address.data() as *mut u8, value, count) }
}
unsafe fn invalidate(address: VirtualAddress);
#[inline(always)]
unsafe fn invalidate_all() {
//TODO: this stub only works on x86_64, maybe make the arch implement this?
Self::set_table(TableKind::User, Self::table(TableKind::User));
unsafe {
//TODO: this stub only works on x86_64, maybe make the arch implement this?
Self::set_table(TableKind::User, Self::table(TableKind::User));
}
}
unsafe fn table(table_kind: TableKind) -> PhysicalAddress;
+18 -10
View File
@@ -34,29 +34,37 @@ impl Arch for RiscV64Sv39Arch {
#[inline(always)]
unsafe fn invalidate(address: VirtualAddress) {
asm!("sfence.vma {}", in(reg) address.data());
unsafe {
asm!("sfence.vma {}", in(reg) address.data());
}
}
#[inline(always)]
unsafe fn invalidate_all() {
asm!("sfence.vma");
unsafe {
asm!("sfence.vma");
}
}
#[inline(always)]
unsafe fn table(_table_kind: TableKind) -> PhysicalAddress {
let satp: usize;
asm!("csrr {0}, satp", out(reg) satp);
PhysicalAddress::new(
(satp & Self::ENTRY_ADDRESS_MASK) << Self::PAGE_SHIFT, // Convert from PPN
)
unsafe {
let satp: usize;
asm!("csrr {0}, satp", out(reg) satp);
PhysicalAddress::new(
(satp & Self::ENTRY_ADDRESS_MASK) << Self::PAGE_SHIFT, // Convert from PPN
)
}
}
#[inline(always)]
unsafe fn set_table(_table_kind: TableKind, address: PhysicalAddress) {
let satp = (8 << 60) | // Sv39 MODE
unsafe {
let satp = (8 << 60) | // Sv39 MODE
(address.data() >> Self::PAGE_SHIFT); // Convert to PPN (TODO: ensure alignment)
asm!("csrw satp, {0}", in(reg) satp);
Self::invalidate_all();
asm!("csrw satp, {0}", in(reg) satp);
Self::invalidate_all();
}
}
fn virt_is_valid(address: VirtualAddress) -> bool {
+18 -10
View File
@@ -34,29 +34,37 @@ impl Arch for RiscV64Sv48Arch {
#[inline(always)]
unsafe fn invalidate(address: VirtualAddress) {
asm!("sfence.vma {}", in(reg) address.data());
unsafe {
asm!("sfence.vma {}", in(reg) address.data());
}
}
#[inline(always)]
unsafe fn invalidate_all() {
asm!("sfence.vma");
unsafe {
asm!("sfence.vma");
}
}
#[inline(always)]
unsafe fn table(_table_kind: TableKind) -> PhysicalAddress {
let satp: usize;
asm!("csrr {0}, satp", out(reg) satp);
PhysicalAddress::new(
(satp & Self::ENTRY_ADDRESS_MASK) << Self::PAGE_SHIFT, // Convert from PPN
)
unsafe {
let satp: usize;
asm!("csrr {0}, satp", out(reg) satp);
PhysicalAddress::new(
(satp & Self::ENTRY_ADDRESS_MASK) << Self::PAGE_SHIFT, // Convert from PPN
)
}
}
#[inline(always)]
unsafe fn set_table(_table_kind: TableKind, address: PhysicalAddress) {
let satp = (9 << 60) | // Sv48 MODE
unsafe {
let satp = (9 << 60) | // Sv48 MODE
(address.data() >> Self::PAGE_SHIFT); // Convert to PPN (TODO: ensure alignment)
asm!("csrw satp, {0}", in(reg) satp);
Self::invalidate_all();
asm!("csrw satp, {0}", in(reg) satp);
Self::invalidate_all();
}
}
fn virt_is_valid(address: VirtualAddress) -> bool {
+11 -5
View File
@@ -32,19 +32,25 @@ impl Arch for X8664Arch {
#[inline(always)]
unsafe fn invalidate(address: VirtualAddress) {
asm!("invlpg [{0}]", in(reg) address.data());
unsafe {
asm!("invlpg [{0}]", in(reg) address.data());
}
}
#[inline(always)]
unsafe fn table(_table_kind: TableKind) -> PhysicalAddress {
let address: usize;
asm!("mov {0}, cr3", out(reg) address);
PhysicalAddress::new(address)
unsafe {
let address: usize;
asm!("mov {0}, cr3", out(reg) address);
PhysicalAddress::new(address)
}
}
#[inline(always)]
unsafe fn set_table(_table_kind: TableKind, address: PhysicalAddress) {
asm!("mov cr3, {0}", in(reg) address.data());
unsafe {
asm!("mov cr3, {0}", in(reg) address.data());
}
}
fn virt_is_valid(address: VirtualAddress) -> bool {
+183 -167
View File
@@ -23,22 +23,24 @@ pub fn format_size(size: usize) -> String {
#[allow(dead_code)]
unsafe fn dump_tables<A: Arch>(table: PageTable<A>) {
let level = table.level();
for i in 0..A::PAGE_ENTRIES {
if level == 0 {
if let Some(entry) = table.entry(i) {
if entry.present() {
let base = table.entry_base(i).unwrap();
println!(
"0x{:X}: 0x{:X}",
base.data(),
entry.address().unwrap().data()
);
unsafe {
let level = table.level();
for i in 0..A::PAGE_ENTRIES {
if level == 0 {
if let Some(entry) = table.entry(i) {
if entry.present() {
let base = table.entry_base(i).unwrap();
println!(
"0x{:X}: 0x{:X}",
base.data(),
entry.address().unwrap().data()
);
}
}
} else {
if let Some(next) = table.next(i) {
dump_tables(next);
}
}
} else {
if let Some(next) = table.next(i) {
dump_tables(next);
}
}
}
@@ -64,21 +66,25 @@ impl<A: Arch> SlabNode<A> {
}
pub unsafe fn insert(&mut self, phys: PhysicalAddress) {
let virt = A::phys_to_virt(phys);
A::write(virt, self.next);
self.next = phys;
self.count += 1;
unsafe {
let virt = A::phys_to_virt(phys);
A::write(virt, self.next);
self.next = phys;
self.count += 1;
}
}
pub unsafe fn remove(&mut self) -> Option<PhysicalAddress> {
if self.count > 0 {
let phys = self.next;
let virt = A::phys_to_virt(phys);
self.next = A::read(virt);
self.count -= 1;
Some(phys)
} else {
None
unsafe {
if self.count > 0 {
let phys = self.next;
let virt = A::phys_to_virt(phys);
self.next = A::read(virt);
self.count -= 1;
Some(phys)
} else {
None
}
}
}
}
@@ -91,57 +97,63 @@ pub struct SlabAllocator<A> {
impl<A: Arch> SlabAllocator<A> {
pub unsafe fn new(areas: &'static [MemoryArea], offset: usize) -> Self {
let mut allocator = Self {
nodes: [
SlabNode::empty(),
SlabNode::empty(),
SlabNode::empty(),
SlabNode::empty(),
],
phantom: PhantomData,
};
unsafe {
let mut allocator = Self {
nodes: [
SlabNode::empty(),
SlabNode::empty(),
SlabNode::empty(),
SlabNode::empty(),
],
phantom: PhantomData,
};
// Add unused areas to free lists
let mut area_offset = offset;
for area in areas.iter() {
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);
area_offset = 0;
} else {
area_offset -= area.size;
// Add unused areas to free lists
let mut area_offset = offset;
for area in areas.iter() {
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);
area_offset = 0;
} else {
area_offset -= area.size;
}
}
}
allocator
allocator
}
}
pub unsafe fn allocate(&mut self, size: usize) -> Option<PhysicalAddress> {
for level in 0..A::PAGE_LEVELS - 1 {
let level_shift = level * A::PAGE_ENTRY_SHIFT + A::PAGE_SHIFT;
let level_size = 1 << level_shift;
if size <= level_size {
if let Some(base) = self.nodes[level].remove() {
self.free(base.add(size), level_size - size);
return Some(base);
unsafe {
for level in 0..A::PAGE_LEVELS - 1 {
let level_shift = level * A::PAGE_ENTRY_SHIFT + A::PAGE_SHIFT;
let level_size = 1 << level_shift;
if size <= level_size {
if let Some(base) = self.nodes[level].remove() {
self.free(base.add(size), level_size - size);
return Some(base);
}
}
}
None
}
None
}
//TODO: This causes fragmentation, since neighbors are not identified
//TODO: remainders less than PAGE_SIZE will be lost
pub unsafe fn free(&mut self, mut base: PhysicalAddress, mut size: usize) {
for level in (0..A::PAGE_LEVELS - 1).rev() {
let level_shift = level * A::PAGE_ENTRY_SHIFT + A::PAGE_SHIFT;
let level_size = 1 << level_shift;
while size >= level_size {
println!("Add {:X} {}", base.data(), format_size(level_size));
self.nodes[level].insert(base);
base = base.add(level_size);
size -= level_size;
unsafe {
for level in (0..A::PAGE_LEVELS - 1).rev() {
let level_shift = level * A::PAGE_ENTRY_SHIFT + A::PAGE_SHIFT;
let level_size = 1 << level_shift;
while size >= level_size {
println!("Add {:X} {}", base.data(), format_size(level_size));
self.nodes[level].insert(base);
base = base.add(level_size);
size -= level_size;
}
}
}
}
@@ -158,133 +170,137 @@ impl<A: Arch> SlabAllocator<A> {
}
unsafe fn new_tables<A: Arch>(areas: &'static [MemoryArea]) {
// First, calculate how much memory we have
let mut size = 0;
for area in areas.iter() {
size += area.size;
}
println!("Memory: {}", format_size(size));
// Create a basic allocator for the first pages
let mut bump_allocator = BumpAllocator::<A>::new(areas, 0);
{
// Map all physical areas at PHYS_OFFSET
let mut mapper = PageMapper::<A, _>::create(TableKind::Kernel, &mut bump_allocator)
.expect("failed to create Mapper");
unsafe {
// First, calculate how much memory we have
let mut size = 0;
for area in areas.iter() {
for i in 0..area.size / A::PAGE_SIZE {
let phys = area.base.add(i * A::PAGE_SIZE);
let virt = A::phys_to_virt(phys);
let flush = mapper
.map_phys(virt, phys, PageFlags::<A>::new().write(true))
.expect("failed to map page to frame");
flush.ignore(); // Not the active table
}
size += area.size;
}
// Use the new table
mapper.make_current();
}
println!("Memory: {}", format_size(size));
// Create the physical memory map
let offset = bump_allocator.offset();
println!("Permanently used: {}", format_size(offset));
// Create a basic allocator for the first pages
let mut bump_allocator = BumpAllocator::<A>::new(areas, 0);
let mut allocator = BuddyAllocator::<A>::new(bump_allocator).unwrap();
for i in 0..16 {
{
let phys_opt = allocator.allocate_one();
println!("page {}: {:X?}", i, phys_opt);
if i % 3 == 0 {
if let Some(phys) = phys_opt {
println!("free {}: {:X?}", i, phys_opt);
allocator.free_one(phys);
// Map all physical areas at PHYS_OFFSET
let mut mapper = PageMapper::<A, _>::create(TableKind::Kernel, &mut bump_allocator)
.expect("failed to create Mapper");
for area in areas.iter() {
for i in 0..area.size / A::PAGE_SIZE {
let phys = area.base.add(i * A::PAGE_SIZE);
let virt = A::phys_to_virt(phys);
let flush = mapper
.map_phys(virt, phys, PageFlags::<A>::new().write(true))
.expect("failed to map page to frame");
flush.ignore(); // Not the active table
}
}
// Use the new table
mapper.make_current();
}
// Create the physical memory map
let offset = bump_allocator.offset();
println!("Permanently used: {}", format_size(offset));
let mut allocator = BuddyAllocator::<A>::new(bump_allocator).unwrap();
for i in 0..16 {
{
let phys_opt = allocator.allocate_one();
println!("page {}: {:X?}", i, phys_opt);
if i % 3 == 0 {
if let Some(phys) = phys_opt {
println!("free {}: {:X?}", i, phys_opt);
allocator.free_one(phys);
}
}
}
{
let phys_opt = allocator.allocate(FrameCount::new(16));
println!("page*16 {}: {:X?}", i, phys_opt);
if i % 2 == 0 {
if let Some(phys) = phys_opt {
println!("free*16 {}: {:X?}", i, phys_opt);
allocator.free(phys, FrameCount::new(16));
}
}
}
}
{
let phys_opt = allocator.allocate(FrameCount::new(16));
println!("page*16 {}: {:X?}", i, phys_opt);
if i % 2 == 0 {
if let Some(phys) = phys_opt {
println!("free*16 {}: {:X?}", i, phys_opt);
allocator.free(phys, FrameCount::new(16));
}
}
let mut mapper = PageMapper::<A, _>::current(TableKind::Kernel, &mut allocator);
let mut flush_all = PageFlushAll::new();
for i in 0..16 {
let virt = VirtualAddress::new(MEGABYTE + i * A::PAGE_SIZE);
let flush = mapper
.map(virt, PageFlags::<A>::new().user(true).write(true))
.expect("failed to map page");
flush_all.consume(flush);
}
}
flush_all.flush();
let mut mapper = PageMapper::<A, _>::current(TableKind::Kernel, &mut allocator);
let mut flush_all = PageFlushAll::new();
for i in 0..16 {
let virt = VirtualAddress::new(MEGABYTE + i * A::PAGE_SIZE);
let flush = mapper
.map(virt, PageFlags::<A>::new().user(true).write(true))
.expect("failed to map page");
flush_all.consume(flush);
}
flush_all.flush();
let mut flush_all = PageFlushAll::new();
for i in 0..16 {
let virt = VirtualAddress::new(MEGABYTE + i * A::PAGE_SIZE);
let flush = mapper.unmap(virt, false).expect("failed to unmap page");
flush_all.consume(flush);
}
flush_all.flush();
let mut flush_all = PageFlushAll::new();
for i in 0..16 {
let virt = VirtualAddress::new(MEGABYTE + i * A::PAGE_SIZE);
let flush = mapper.unmap(virt, false).expect("failed to unmap page");
flush_all.consume(flush);
let usage = allocator.usage();
println!("Allocator usage:");
println!(
" Used: {}",
format_size(usage.used().data() * A::PAGE_SIZE)
);
println!(
" Free: {}",
format_size(usage.free().data() * A::PAGE_SIZE)
);
println!(
" Total: {}",
format_size(usage.total().data() * A::PAGE_SIZE)
);
}
flush_all.flush();
let usage = allocator.usage();
println!("Allocator usage:");
println!(
" Used: {}",
format_size(usage.used().data() * A::PAGE_SIZE)
);
println!(
" Free: {}",
format_size(usage.free().data() * A::PAGE_SIZE)
);
println!(
" Total: {}",
format_size(usage.total().data() * A::PAGE_SIZE)
);
}
unsafe fn inner<A: Arch>() {
let areas = A::init();
unsafe {
let areas = A::init();
// Debug table
//dump_tables(PageTable::<A>::top());
// Debug table
//dump_tables(PageTable::<A>::top());
new_tables::<A>(areas);
new_tables::<A>(areas);
//dump_tables(PageTable::<A>::top());
//dump_tables(PageTable::<A>::top());
for i in &[1, 2, 4, 8, 16, 32] {
let phys = PhysicalAddress::new(i * MEGABYTE);
let virt = A::phys_to_virt(phys);
for i in &[1, 2, 4, 8, 16, 32] {
let phys = PhysicalAddress::new(i * MEGABYTE);
let virt = A::phys_to_virt(phys);
// Test read
println!(
"0x{:X} (0x{:X}) = 0x{:X}",
virt.data(),
phys.data(),
A::read::<u8>(virt)
);
// Test read
println!(
"0x{:X} (0x{:X}) = 0x{:X}",
virt.data(),
phys.data(),
A::read::<u8>(virt)
);
// Test write
A::write::<u8>(virt, 0x5A);
// Test write
A::write::<u8>(virt, 0x5A);
// Test read
println!(
"0x{:X} (0x{:X}) = 0x{:X}",
virt.data(),
phys.data(),
A::read::<u8>(virt)
);
// Test read
println!(
"0x{:X} (0x{:X}) = 0x{:X}",
virt.data(),
phys.data(),
A::read::<u8>(virt)
);
}
}
}
+105 -82
View File
@@ -23,13 +23,17 @@ impl<A: Arch, F: FrameAllocator> PageMapper<A, F> {
}
pub unsafe fn create(table_kind: TableKind, mut allocator: F) -> Option<Self> {
let table_addr = allocator.allocate_one()?;
Some(Self::new(table_kind, table_addr, allocator))
unsafe {
let table_addr = allocator.allocate_one()?;
Some(Self::new(table_kind, table_addr, allocator))
}
}
pub unsafe fn current(table_kind: TableKind, allocator: F) -> Self {
let table_addr = A::table(table_kind);
Self::new(table_kind, table_addr, allocator)
unsafe {
let table_addr = A::table(table_kind);
Self::new(table_kind, table_addr, allocator)
}
}
pub fn is_current(&self) -> bool {
@@ -37,7 +41,9 @@ impl<A: Arch, F: FrameAllocator> PageMapper<A, F> {
}
pub unsafe fn make_current(&self) {
A::set_table(self.table_kind, self.table_addr);
unsafe {
A::set_table(self.table_kind, self.table_addr);
}
}
pub fn table(&self) -> PageTable<A> {
@@ -59,33 +65,37 @@ impl<A: Arch, F: FrameAllocator> PageMapper<A, F> {
virt: VirtualAddress,
f: impl FnOnce(PhysicalAddress, PageFlags<A>) -> (PhysicalAddress, PageFlags<A>),
) -> Option<(PageFlags<A>, PhysicalAddress, PageFlush<A>)> {
self.visit(virt, |p1, i| {
let old_entry = p1.entry(i)?;
let old_phys = old_entry.address().ok()?;
let old_flags = old_entry.flags();
let (new_phys, new_flags) = f(old_phys, old_flags);
// TODO: Higher-level PageEntry::new interface?
let new_entry = PageEntry::new(new_phys.data(), new_flags.data());
p1.set_entry(i, new_entry);
Some((old_flags, old_phys, PageFlush::new(virt)))
})
.flatten()
unsafe {
self.visit(virt, |p1, i| {
let old_entry = p1.entry(i)?;
let old_phys = old_entry.address().ok()?;
let old_flags = old_entry.flags();
let (new_phys, new_flags) = f(old_phys, old_flags);
// TODO: Higher-level PageEntry::new interface?
let new_entry = PageEntry::new(new_phys.data(), new_flags.data());
p1.set_entry(i, new_entry);
Some((old_flags, old_phys, PageFlush::new(virt)))
})
.flatten()
}
}
pub unsafe fn remap_with(
&mut self,
virt: VirtualAddress,
map_flags: impl FnOnce(PageFlags<A>) -> PageFlags<A>,
) -> Option<(PageFlags<A>, PhysicalAddress, PageFlush<A>)> {
self.remap_with_full(virt, |same_phys, old_flags| {
(same_phys, map_flags(old_flags))
})
unsafe {
self.remap_with_full(virt, |same_phys, old_flags| {
(same_phys, map_flags(old_flags))
})
}
}
pub unsafe fn remap(
&mut self,
virt: VirtualAddress,
flags: PageFlags<A>,
) -> Option<PageFlush<A>> {
self.remap_with(virt, |_| flags).map(|(_, _, flush)| flush)
unsafe { self.remap_with(virt, |_| flags).map(|(_, _, flush)| flush) }
}
pub unsafe fn map(
@@ -93,8 +103,10 @@ impl<A: Arch, F: FrameAllocator> PageMapper<A, F> {
virt: VirtualAddress,
flags: PageFlags<A>,
) -> Option<PageFlush<A>> {
let phys = self.allocator.allocate_one()?;
self.map_phys(virt, phys, flags)
unsafe {
let phys = self.allocator.allocate_one()?;
self.map_phys(virt, phys, flags)
}
}
pub unsafe fn map_phys(
@@ -103,34 +115,36 @@ impl<A: Arch, F: FrameAllocator> PageMapper<A, F> {
phys: PhysicalAddress,
flags: PageFlags<A>,
) -> Option<PageFlush<A>> {
//TODO: verify virt and phys are aligned
//TODO: verify flags have correct bits
let entry = PageEntry::new(phys.data(), flags.data());
let mut table = self.table();
loop {
let i = table.index_of(virt)?;
if table.level() == 0 {
//TODO: check for overwriting entry
table.set_entry(i, entry);
return Some(PageFlush::new(virt));
} else {
let next_opt = table.next(i);
let next = match next_opt {
Some(some) => some,
None => {
let next_phys = self.allocator.allocate_one()?;
//TODO: correct flags?
let flags = A::ENTRY_FLAG_DEFAULT_TABLE
| if virt.kind() == TableKind::User {
A::ENTRY_FLAG_TABLE_USER
} else {
0
};
table.set_entry(i, PageEntry::new(next_phys.data(), flags));
table.next(i)?
}
};
table = next;
unsafe {
//TODO: verify virt and phys are aligned
//TODO: verify flags have correct bits
let entry = PageEntry::new(phys.data(), flags.data());
let mut table = self.table();
loop {
let i = table.index_of(virt)?;
if table.level() == 0 {
//TODO: check for overwriting entry
table.set_entry(i, entry);
return Some(PageFlush::new(virt));
} else {
let next_opt = table.next(i);
let next = match next_opt {
Some(some) => some,
None => {
let next_phys = self.allocator.allocate_one()?;
//TODO: correct flags?
let flags = A::ENTRY_FLAG_DEFAULT_TABLE
| if virt.kind() == TableKind::User {
A::ENTRY_FLAG_TABLE_USER
} else {
0
};
table.set_entry(i, PageEntry::new(next_phys.data(), flags));
table.next(i)?
}
};
table = next;
}
}
}
}
@@ -139,8 +153,10 @@ impl<A: Arch, F: FrameAllocator> PageMapper<A, F> {
phys: PhysicalAddress,
flags: PageFlags<A>,
) -> Option<(VirtualAddress, PageFlush<A>)> {
let virt = A::phys_to_virt(phys);
self.map_phys(virt, phys, flags).map(|flush| (virt, flush))
unsafe {
let virt = A::phys_to_virt(phys);
self.map_phys(virt, phys, flags).map(|flush| (virt, flush))
}
}
fn visit<T>(
&self,
@@ -169,9 +185,11 @@ impl<A: Arch, F: FrameAllocator> PageMapper<A, F> {
virt: VirtualAddress,
unmap_parents: bool,
) -> Option<PageFlush<A>> {
let (old, _, flush) = self.unmap_phys(virt, unmap_parents)?;
self.allocator.free_one(old);
Some(flush)
unsafe {
let (old, _, flush) = self.unmap_phys(virt, unmap_parents)?;
self.allocator.free_one(old);
Some(flush)
}
}
pub unsafe fn unmap_phys(
@@ -179,11 +197,13 @@ impl<A: Arch, F: FrameAllocator> PageMapper<A, F> {
virt: VirtualAddress,
unmap_parents: bool,
) -> Option<(PhysicalAddress, PageFlags<A>, PageFlush<A>)> {
//TODO: verify virt is aligned
let mut table = self.table();
let level = table.level();
unmap_phys_inner(virt, &mut table, level, unmap_parents, &mut self.allocator)
.map(|(pa, pf)| (pa, pf, PageFlush::new(virt)))
unsafe {
//TODO: verify virt is aligned
let mut table = self.table();
let level = table.level();
unmap_phys_inner(virt, &mut table, level, unmap_parents, &mut self.allocator)
.map(|(pa, pf)| (pa, pf, PageFlush::new(virt)))
}
}
}
unsafe fn unmap_phys_inner<A: Arch>(
@@ -193,35 +213,38 @@ unsafe fn unmap_phys_inner<A: Arch>(
unmap_parents: bool,
allocator: &mut impl FrameAllocator,
) -> Option<(PhysicalAddress, PageFlags<A>)> {
let i = table.index_of(virt)?;
unsafe {
let i = table.index_of(virt)?;
if table.level() == 0 {
let entry_opt = table.entry(i);
table.set_entry(i, PageEntry::new(0, 0));
let entry = entry_opt?;
if table.level() == 0 {
let entry_opt = table.entry(i);
table.set_entry(i, PageEntry::new(0, 0));
let entry = entry_opt?;
Some((entry.address().ok()?, entry.flags()))
} else {
let mut subtable = table.next(i)?;
Some((entry.address().ok()?, entry.flags()))
} else {
let mut subtable = table.next(i)?;
let res = unmap_phys_inner(virt, &mut subtable, initial_level, unmap_parents, allocator)?;
let res =
unmap_phys_inner(virt, &mut subtable, initial_level, unmap_parents, allocator)?;
//TODO: This is a bad idea for architectures where the kernel mappings are done in the process tables,
// as these mappings may become out of sync
if unmap_parents {
// TODO: Use a counter? This would reduce the remaining number of available bits, but could be
// faster (benchmark is needed).
let is_still_populated = (0..A::PAGE_ENTRIES)
.map(|j| subtable.entry(j).expect("must be within bounds"))
.any(|e| e.present());
//TODO: This is a bad idea for architectures where the kernel mappings are done in the process tables,
// as these mappings may become out of sync
if unmap_parents {
// TODO: Use a counter? This would reduce the remaining number of available bits, but could be
// faster (benchmark is needed).
let is_still_populated = (0..A::PAGE_ENTRIES)
.map(|j| subtable.entry(j).expect("must be within bounds"))
.any(|e| e.present());
if !is_still_populated {
allocator.free_one(subtable.phys());
table.set_entry(i, PageEntry::new(0, 0));
if !is_still_populated {
allocator.free_one(subtable.phys());
table.set_entry(i, PageEntry::new(0, 0));
}
}
}
Some(res)
Some(res)
}
}
}
impl<A, F: core::fmt::Debug> core::fmt::Debug for PageMapper<A, F> {
+43 -31
View File
@@ -21,11 +21,13 @@ impl<A: Arch> PageTable<A> {
}
pub unsafe fn top(table_kind: TableKind) -> Self {
Self::new(
VirtualAddress::new(0),
A::table(table_kind),
A::PAGE_LEVELS - 1,
)
unsafe {
Self::new(
VirtualAddress::new(0),
A::table(table_kind),
A::PAGE_LEVELS - 1,
)
}
}
pub fn base(&self) -> VirtualAddress {
@@ -41,16 +43,18 @@ impl<A: Arch> PageTable<A> {
}
pub unsafe fn virt(&self) -> VirtualAddress {
A::phys_to_virt(self.phys)
unsafe {
A::phys_to_virt(self.phys)
// Recursive mapping
// let mut addr = 0xFFFF_FFFF_FFFF_F000;
// for level in (self.level + 1 .. A::PAGE_LEVELS).rev() {
// let index = (self.base.0 >> (level * A::PAGE_ENTRY_SHIFT + A::PAGE_SHIFT)) & A::PAGE_ENTRY_MASK;
// addr <<= A::PAGE_ENTRY_SHIFT;
// addr |= index << A::PAGE_SHIFT;
// }
// VirtualAddress::new(addr)
// Recursive mapping
// let mut addr = 0xFFFF_FFFF_FFFF_F000;
// for level in (self.level + 1 .. A::PAGE_LEVELS).rev() {
// let index = (self.base.0 >> (level * A::PAGE_ENTRY_SHIFT + A::PAGE_SHIFT)) & A::PAGE_ENTRY_MASK;
// addr <<= A::PAGE_ENTRY_SHIFT;
// addr |= index << A::PAGE_SHIFT;
// }
// VirtualAddress::new(addr)
}
}
pub fn entry_base(&self, i: usize) -> Option<VirtualAddress> {
@@ -63,22 +67,28 @@ impl<A: Arch> PageTable<A> {
}
pub unsafe fn entry_virt(&self, i: usize) -> Option<VirtualAddress> {
if i < A::PAGE_ENTRIES {
Some(self.virt().add(i * A::PAGE_ENTRY_SIZE))
} else {
None
unsafe {
if i < A::PAGE_ENTRIES {
Some(self.virt().add(i * A::PAGE_ENTRY_SIZE))
} else {
None
}
}
}
pub unsafe fn entry(&self, i: usize) -> Option<PageEntry<A>> {
let addr = self.entry_virt(i)?;
Some(PageEntry::from_data(A::read::<usize>(addr)))
unsafe {
let addr = self.entry_virt(i)?;
Some(PageEntry::from_data(A::read::<usize>(addr)))
}
}
pub unsafe fn set_entry(&mut self, i: usize, entry: PageEntry<A>) -> Option<()> {
let addr = self.entry_virt(i)?;
A::write::<usize>(addr, entry.data());
Some(())
unsafe {
let addr = self.entry_virt(i)?;
A::write::<usize>(addr, entry.data());
Some(())
}
}
pub unsafe fn index_of(&self, address: VirtualAddress) -> Option<usize> {
@@ -98,14 +108,16 @@ impl<A: Arch> PageTable<A> {
}
pub unsafe fn next(&self, i: usize) -> Option<Self> {
if self.level == 0 {
return None;
}
unsafe {
if self.level == 0 {
return None;
}
Some(PageTable::new(
self.entry_base(i)?,
self.entry(i)?.address().ok()?,
self.level - 1,
))
Some(PageTable::new(
self.entry_base(i)?,
self.entry(i)?.address().ok()?,
self.level - 1,
))
}
}
}