|
2 | 2 |
|
3 | 3 | use super::{ |
4 | 4 | pg_descriptors::L3Descriptor, |
5 | | - pg_tables::{L0Table, L3Table}, |
| 5 | + pg_tables::{L0Table, L1Table, L3Table}, |
6 | 6 | }; |
7 | 7 | use crate::{ |
8 | 8 | error::{MapError, Result}, |
9 | 9 | memory::{ |
10 | 10 | PAGE_SIZE, |
11 | | - address::{TPA, VA}, |
| 11 | + address::{PA, TPA, VA}, |
12 | 12 | paging::{ |
13 | | - NullTlbInvalidator, PageTableEntry, PageTableMapper, PgTable, PgTableArray, |
14 | | - walk::{RecursiveWalker, WalkContext}, |
| 13 | + NullTlbInvalidator, PaMapper, PageTableEntry, PageTableMapper, PgTable, PgTableArray, |
| 14 | + TableMapper, |
| 15 | + permissions::PtePermissions, |
| 16 | + walk::{RecursiveWalker, Translator, WalkContext}, |
15 | 17 | }, |
16 | | - region::VirtMemoryRegion, |
| 18 | + region::{PhysMemoryRegion, VirtMemoryRegion}, |
17 | 19 | }, |
18 | 20 | }; |
19 | 21 |
|
@@ -111,6 +113,71 @@ pub fn get_pte<PM: PageTableMapper>( |
111 | 113 | Ok(descriptor) |
112 | 114 | } |
113 | 115 |
|
| 116 | +impl Translator for L0Table { |
| 117 | + fn translate<PM: PageTableMapper>( |
| 118 | + table_pa: TPA<PgTableArray<Self>>, |
| 119 | + va: VA, |
| 120 | + ctx: &mut WalkContext<PM>, |
| 121 | + ) -> Result<Option<(PA, usize, PtePermissions)>> { |
| 122 | + let desc = unsafe { |
| 123 | + ctx.mapper |
| 124 | + .with_page_table(table_pa, |pgtable| Self::from_ptr(pgtable).get_desc(va))? |
| 125 | + }; |
| 126 | + |
| 127 | + match desc.next_table_address() { |
| 128 | + Some(next_pa) => L1Table::translate(next_pa, va, ctx), |
| 129 | + None if desc.is_valid() => Err(MapError::InvalidDescriptor.into()), |
| 130 | + None => Ok(None), |
| 131 | + } |
| 132 | + } |
| 133 | +} |
| 134 | + |
| 135 | +impl Translator for L3Table { |
| 136 | + fn translate<PM: PageTableMapper>( |
| 137 | + table_pa: TPA<PgTableArray<Self>>, |
| 138 | + va: VA, |
| 139 | + ctx: &mut WalkContext<PM>, |
| 140 | + ) -> Result<Option<(PA, usize, PtePermissions)>> { |
| 141 | + let desc = unsafe { |
| 142 | + ctx.mapper |
| 143 | + .with_page_table(table_pa, |pgtable| Self::from_ptr(pgtable).get_desc(va))? |
| 144 | + }; |
| 145 | + |
| 146 | + match desc.mapped_address() { |
| 147 | + Some(pa) => Ok(Some(( |
| 148 | + pa, |
| 149 | + 1 << Self::Descriptor::MAP_SHIFT, |
| 150 | + desc.permissions().unwrap(), |
| 151 | + ))), |
| 152 | + None if desc.is_valid() => Err(MapError::InvalidDescriptor.into()), |
| 153 | + None => Ok(None), |
| 154 | + } |
| 155 | + } |
| 156 | +} |
| 157 | + |
| 158 | +/// Translates the VA into a physical region plus an offset and permissions. |
| 159 | +pub fn translate<PM: PageTableMapper>( |
| 160 | + l0_table: TPA<PgTableArray<L0Table>>, |
| 161 | + va: VA, |
| 162 | + mapper: &mut PM, |
| 163 | +) -> Result<Option<(PhysMemoryRegion, usize, PtePermissions)>> { |
| 164 | + let mut walk_ctx = WalkContext { |
| 165 | + mapper, |
| 166 | + // Safe to not invalidate the TLB, as we are not modifying any PTEs. |
| 167 | + invalidator: &NullTlbInvalidator {}, |
| 168 | + }; |
| 169 | + |
| 170 | + if let Some((pa, blk_sz, perms)) = L0Table::translate(l0_table, va, &mut walk_ctx)? { |
| 171 | + debug_assert!(blk_sz.is_power_of_two()); |
| 172 | + |
| 173 | + let offset = va.value() & (blk_sz - 1); |
| 174 | + |
| 175 | + Ok(Some((PhysMemoryRegion::new(pa, blk_sz), offset, perms))) |
| 176 | + } else { |
| 177 | + Ok(None) |
| 178 | + } |
| 179 | +} |
| 180 | + |
114 | 181 | #[cfg(test)] |
115 | 182 | mod tests { |
116 | 183 | use super::*; |
|
0 commit comments