[wip] directory levels traversal

This commit is contained in:
Berkus Decker 2021-02-26 00:21:52 +02:00
parent 3c6fcfcf10
commit 55e1761492
1 changed files with 79 additions and 8 deletions

View File

@ -46,6 +46,17 @@ use {
* 48-bit virtual address space; different mappings in VBAR0 (EL0) and VBAR1 (EL1+).
*/
register_bitfields! {
u64,
VA_INDEX [
LEVEL0 OFFSET(39) NUMBITS(9) [],
LEVEL1 OFFSET(30) NUMBITS(9) [],
LEVEL2 OFFSET(21) NUMBITS(9) [],
LEVEL3 OFFSET(12) NUMBITS(9) [],
OFFSET OFFSET(0) NUMBITS(12) [],
]
}
register_bitfields! {
u64,
// AArch64 Reference Manual page 2150, D5-2445
@ -150,6 +161,7 @@ register_bitfields! {
]
}
type VaIndex = register::FieldValue<u64, VA_INDEX::Register>;
type EntryFlags = register::FieldValue<u64, TABLE_DESCRIPTOR::Register>;
// type EntryRegister = register::LocalRegisterCopy<u64, TABLE_DESCRIPTOR::Register>;
@ -218,17 +230,23 @@ type EntryFlags = register::FieldValue<u64, TABLE_DESCRIPTOR::Register>;
// return enum PageTableEntry constructed from table bits in u64
enum L0Entries {
UpperDirectoryEntry,
UpperDirectoryEntry(VirtAddr),
}
enum L1Entries {
PageDirectoryEntry,
GiantPageFrame,
PageDirectoryEntry(VirtAddr),
GiantPageFrame(PhysFrame<Size1GiB>),
}
enum L2Entries {
PageTableEntry,
LargePageFrame,
PageTableEntry(VirtAddr),
LargePageFrame(PhysFrame<Size2MiB>),
}
enum L3Entries {
PageFrame(PhysFrame<Size4KiB>),
}
enum Frames {
GiantPageFrame,
LargePageFrame,
PageFrame,
}
@ -326,6 +344,57 @@ struct Directory<Level: TableLevel> {
level: PhantomData<Level>,
}
impl Directory<L0PageGlobalDirectory> {
fn next(&self, address: VirtAddr) -> Option<L0Entries> {
let va = VaIndex::new(address.to_u64());
let index = va.read(VA_INDEX::LEVEL0);
match self.next_table_address(index.into()) {
Some(phys_addr) => {
Some(L0Entries::UpperDirectoryEntry(phys_addr.user_to_kernel()))
}
None => None,
}
}
}
impl Directory<L1PageUpperDirectory> {
fn next(&self, address: VirtAddr) -> Option<L1Entries> {
let va = VaIndex::new(address.to_u64());
let index = va.read(VA_INDEX::LEVEL1);
match self.next_table_address(index.into()) {
Some(phys_addr) => {
Some(L1Entries::PageDirectoryEntry(phys_addr.user_to_kernel()))
}
None => None, // @todo could be 1GiB frame
}
}
}
impl Directory<L2PageDirectory> {
fn next(&self, address: VirtAddr) -> Option<L2Entries> {
let va = VaIndex::new(address.to_u64());
let index = va.read(VA_INDEX::LEVEL2);
match self.next_table_address(index.into()) {
Some(phys_addr) => {
Some(L2Entries::PageTableEntry(phys_addr.user_to_kernel()))
}
None => None, // @todo could be 2MiB frame
}
}
}
impl Directory<L3PageTable> {
fn next(&self, address: VirtAddr) -> Option<L3Entries> {
let va = VaIndex::new(address.to_u64());
let index = va.read(VA_INDEX::LEVEL3);
match self.next_table_address(index.into()) { // @fixme wrong function
Some(phys_addr) => {
Some(L3Entries::PageFrame(phys_addr.user_to_kernel()))
}
None => None, // Nothing there
}
}
// Implementation code shared for all levels of page tables
impl<Level> Directory<Level>
where
@ -374,7 +443,7 @@ impl<Level> Directory<Level>
where
Level: HierarchicalLevel,
{
fn next_table_address(&self, index: usize) -> Option<usize> {
fn next_table_address(&self, index: usize) -> Option<PhysAddr> {
let entry_flags = EntryRegister::new(self[index]);
// If table entry has 0b11 mask set, it is a valid table entry.
// Address of the following table may be extracted from bits 47:12
@ -387,13 +456,15 @@ where
pub fn next_table(&self, index: usize) -> Option<&Table<Level::NextLevel>> {
self.next_table_address(index)
.map(|address| unsafe { &*(address as *const _) })
.map(|address| unsafe { &*(address.user_to_kernel() as *const _) })
}
pub fn next_table_mut(&mut self, index: usize) -> Option<&mut Table<Level::NextLevel>> {
self.next_table_address(index)
.map(|address| unsafe { &mut *(address as *mut _) })
.map(|address| unsafe { &mut *(address.user_to_kernel() as *mut _) })
}
pub fn translate_levels(&self, address: VirtAddr) -> Option<Frames> {}
}
// ----