[wip] directory levels traversal
This commit is contained in:
		
							parent
							
								
									3c6fcfcf10
								
							
						
					
					
						commit
						55e1761492
					
				|  | @ -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> {} | ||||
| } | ||||
| 
 | ||||
| // ----
 | ||||
|  |  | |||
		Loading…
	
		Reference in New Issue