1 // Copyright 2022 The aarch64-paging Authors.
2 // This project is dual-licensed under Apache 2.0 and MIT terms.
3 // See LICENSE-APACHE and LICENSE-MIT for details.
4 
5 //! Generic aarch64 page table manipulation functionality which doesn't assume anything about how
6 //! addresses are mapped.
7 
8 use crate::MapError;
9 #[cfg(feature = "alloc")]
10 use alloc::alloc::{alloc_zeroed, dealloc, handle_alloc_error, Layout};
11 use bitflags::bitflags;
12 use core::fmt::{self, Debug, Display, Formatter};
13 use core::marker::PhantomData;
14 use core::ops::{Add, Range, Sub};
15 use core::ptr::NonNull;
16 
17 const PAGE_SHIFT: usize = 12;
18 
19 /// The pagetable level at which all entries are page mappings.
20 const LEAF_LEVEL: usize = 3;
21 
22 /// The page size in bytes assumed by this library, 4 KiB.
23 pub const PAGE_SIZE: usize = 1 << PAGE_SHIFT;
24 
25 /// The number of address bits resolved in one level of page table lookup. This is a function of the
26 /// page size.
27 pub const BITS_PER_LEVEL: usize = PAGE_SHIFT - 3;
28 
29 /// Which virtual address range a page table is for, i.e. which TTBR register to use for it.
30 #[derive(Copy, Clone, Debug, Eq, PartialEq)]
31 pub enum VaRange {
32     /// The page table covers the bottom of the virtual address space (starting at address 0), so
33     /// will be used with `TTBR0`.
34     Lower,
35     /// The page table covers the top of the virtual address space (ending at address
36     /// 0xffff_ffff_ffff_ffff), so will be used with `TTBR1`.
37     Upper,
38 }
39 
40 /// Which translation regime a page table is for.
41 ///
42 /// This depends on the exception level, among other things.
43 #[derive(Copy, Clone, Debug, Eq, PartialEq)]
44 pub enum TranslationRegime {
45     /// Secure EL3.
46     El3,
47     /// Non-secure EL2.
48     El2,
49     /// Non-secure EL2&0, with VHE.
50     El2And0,
51     /// Non-secure EL1&0, stage 1.
52     El1And0,
53 }
54 
55 impl TranslationRegime {
56     /// Returns whether this translation regime supports use of an ASID.
57     ///
58     /// This also implies that it supports two VA ranges.
supports_asid(self) -> bool59     pub(crate) fn supports_asid(self) -> bool {
60         matches!(self, Self::El2And0 | Self::El1And0)
61     }
62 }
63 
64 /// An aarch64 virtual address, the input type of a stage 1 page table.
65 #[derive(Copy, Clone, Eq, Ord, PartialEq, PartialOrd)]
66 pub struct VirtualAddress(pub usize);
67 
68 impl Display for VirtualAddress {
fmt(&self, f: &mut Formatter) -> Result<(), fmt::Error>69     fn fmt(&self, f: &mut Formatter) -> Result<(), fmt::Error> {
70         write!(f, "{:#018x}", self.0)
71     }
72 }
73 
74 impl Debug for VirtualAddress {
fmt(&self, f: &mut Formatter) -> Result<(), fmt::Error>75     fn fmt(&self, f: &mut Formatter) -> Result<(), fmt::Error> {
76         write!(f, "VirtualAddress({})", self)
77     }
78 }
79 
80 impl Sub for VirtualAddress {
81     type Output = usize;
82 
sub(self, other: Self) -> Self::Output83     fn sub(self, other: Self) -> Self::Output {
84         self.0 - other.0
85     }
86 }
87 
88 impl Add<usize> for VirtualAddress {
89     type Output = Self;
90 
add(self, other: usize) -> Self91     fn add(self, other: usize) -> Self {
92         Self(self.0 + other)
93     }
94 }
95 
96 impl Sub<usize> for VirtualAddress {
97     type Output = Self;
98 
sub(self, other: usize) -> Self99     fn sub(self, other: usize) -> Self {
100         Self(self.0 - other)
101     }
102 }
103 
104 /// A range of virtual addresses which may be mapped in a page table.
105 #[derive(Clone, Eq, PartialEq)]
106 pub struct MemoryRegion(Range<VirtualAddress>);
107 
108 /// An aarch64 physical address or intermediate physical address, the output type of a stage 1 page
109 /// table.
110 #[derive(Copy, Clone, Eq, Ord, PartialEq, PartialOrd)]
111 pub struct PhysicalAddress(pub usize);
112 
113 impl Display for PhysicalAddress {
fmt(&self, f: &mut Formatter) -> Result<(), fmt::Error>114     fn fmt(&self, f: &mut Formatter) -> Result<(), fmt::Error> {
115         write!(f, "{:#018x}", self.0)
116     }
117 }
118 
119 impl Debug for PhysicalAddress {
fmt(&self, f: &mut Formatter) -> Result<(), fmt::Error>120     fn fmt(&self, f: &mut Formatter) -> Result<(), fmt::Error> {
121         write!(f, "PhysicalAddress({})", self)
122     }
123 }
124 
125 impl Sub for PhysicalAddress {
126     type Output = usize;
127 
sub(self, other: Self) -> Self::Output128     fn sub(self, other: Self) -> Self::Output {
129         self.0 - other.0
130     }
131 }
132 
133 impl Add<usize> for PhysicalAddress {
134     type Output = Self;
135 
add(self, other: usize) -> Self136     fn add(self, other: usize) -> Self {
137         Self(self.0 + other)
138     }
139 }
140 
141 impl Sub<usize> for PhysicalAddress {
142     type Output = Self;
143 
sub(self, other: usize) -> Self144     fn sub(self, other: usize) -> Self {
145         Self(self.0 - other)
146     }
147 }
148 
149 /// Returns the size in bytes of the address space covered by a single entry in the page table at
150 /// the given level.
granularity_at_level(level: usize) -> usize151 pub(crate) fn granularity_at_level(level: usize) -> usize {
152     PAGE_SIZE << ((LEAF_LEVEL - level) * BITS_PER_LEVEL)
153 }
154 
155 /// An implementation of this trait needs to be provided to the mapping routines, so that the
156 /// physical addresses used in the page tables can be converted into virtual addresses that can be
157 /// used to access their contents from the code.
158 pub trait Translation {
159     /// Allocates a zeroed page, which is already mapped, to be used for a new subtable of some
160     /// pagetable. Returns both a pointer to the page and its physical address.
allocate_table(&mut self) -> (NonNull<PageTable>, PhysicalAddress)161     fn allocate_table(&mut self) -> (NonNull<PageTable>, PhysicalAddress);
162 
163     /// Deallocates the page which was previous allocated by [`allocate_table`](Self::allocate_table).
164     ///
165     /// # Safety
166     ///
167     /// The memory must have been allocated by `allocate_table` on the same `Translation`, and not
168     /// yet deallocated.
deallocate_table(&mut self, page_table: NonNull<PageTable>)169     unsafe fn deallocate_table(&mut self, page_table: NonNull<PageTable>);
170 
171     /// Given the physical address of a subtable, returns the virtual address at which it is mapped.
physical_to_virtual(&self, pa: PhysicalAddress) -> NonNull<PageTable>172     fn physical_to_virtual(&self, pa: PhysicalAddress) -> NonNull<PageTable>;
173 }
174 
175 impl MemoryRegion {
176     /// Constructs a new `MemoryRegion` for the given range of virtual addresses.
177     ///
178     /// The start is inclusive and the end is exclusive. Both will be aligned to the [`PAGE_SIZE`],
179     /// with the start being rounded down and the end being rounded up.
new(start: usize, end: usize) -> MemoryRegion180     pub const fn new(start: usize, end: usize) -> MemoryRegion {
181         MemoryRegion(
182             VirtualAddress(align_down(start, PAGE_SIZE))..VirtualAddress(align_up(end, PAGE_SIZE)),
183         )
184     }
185 
186     /// Returns the first virtual address of the memory range.
start(&self) -> VirtualAddress187     pub const fn start(&self) -> VirtualAddress {
188         self.0.start
189     }
190 
191     /// Returns the first virtual address after the memory range.
end(&self) -> VirtualAddress192     pub const fn end(&self) -> VirtualAddress {
193         self.0.end
194     }
195 
196     /// Returns the length of the memory region in bytes.
len(&self) -> usize197     pub const fn len(&self) -> usize {
198         self.0.end.0 - self.0.start.0
199     }
200 
201     /// Returns whether the memory region contains exactly 0 bytes.
is_empty(&self) -> bool202     pub const fn is_empty(&self) -> bool {
203         self.0.start.0 == self.0.end.0
204     }
205 
split(&self, level: usize) -> ChunkedIterator206     fn split(&self, level: usize) -> ChunkedIterator {
207         ChunkedIterator {
208             range: self,
209             granularity: granularity_at_level(level),
210             start: self.0.start.0,
211         }
212     }
213 
214     /// Returns whether this region can be mapped at 'level' using block mappings only.
is_block(&self, level: usize) -> bool215     pub(crate) fn is_block(&self, level: usize) -> bool {
216         let gran = granularity_at_level(level);
217         (self.0.start.0 | self.0.end.0) & (gran - 1) == 0
218     }
219 }
220 
221 impl From<Range<VirtualAddress>> for MemoryRegion {
from(range: Range<VirtualAddress>) -> Self222     fn from(range: Range<VirtualAddress>) -> Self {
223         Self::new(range.start.0, range.end.0)
224     }
225 }
226 
227 impl Display for MemoryRegion {
fmt(&self, f: &mut Formatter) -> Result<(), fmt::Error>228     fn fmt(&self, f: &mut Formatter) -> Result<(), fmt::Error> {
229         write!(f, "{}..{}", self.0.start, self.0.end)
230     }
231 }
232 
233 impl Debug for MemoryRegion {
fmt(&self, f: &mut Formatter) -> Result<(), fmt::Error>234     fn fmt(&self, f: &mut Formatter) -> Result<(), fmt::Error> {
235         Display::fmt(self, f)
236     }
237 }
238 
239 bitflags! {
240     /// Constraints on page table mappings
241     #[derive(Copy, Clone, Debug, Eq, Hash, Ord, PartialEq, PartialOrd)]
242     pub struct Constraints: usize {
243         /// Block mappings are not permitted, only page mappings
244         const NO_BLOCK_MAPPINGS    = 1 << 0;
245         /// Use of the contiguous hint is not permitted
246         const NO_CONTIGUOUS_HINT   = 1 << 1;
247     }
248 }
249 
250 /// A complete hierarchy of page tables including all levels.
251 pub struct RootTable<T: Translation> {
252     table: PageTableWithLevel<T>,
253     translation: T,
254     pa: PhysicalAddress,
255     translation_regime: TranslationRegime,
256     va_range: VaRange,
257 }
258 
259 impl<T: Translation> RootTable<T> {
260     /// Creates a new page table starting at the given root level.
261     ///
262     /// The level must be between 0 and 3; level -1 (for 52-bit addresses with LPA2) is not
263     /// currently supported by this library. The value of `TCR_EL1.T0SZ` must be set appropriately
264     /// to match.
new( mut translation: T, level: usize, translation_regime: TranslationRegime, va_range: VaRange, ) -> Self265     pub fn new(
266         mut translation: T,
267         level: usize,
268         translation_regime: TranslationRegime,
269         va_range: VaRange,
270     ) -> Self {
271         if level > LEAF_LEVEL {
272             panic!("Invalid root table level {}.", level);
273         }
274         if !translation_regime.supports_asid() && va_range != VaRange::Lower {
275             panic!(
276                 "{:?} doesn't have an upper virtual address range.",
277                 translation_regime
278             );
279         }
280         let (table, pa) = PageTableWithLevel::new(&mut translation, level);
281         RootTable {
282             table,
283             translation,
284             pa,
285             translation_regime,
286             va_range,
287         }
288     }
289 
290     /// Returns the size in bytes of the virtual address space which can be mapped in this page
291     /// table.
292     ///
293     /// This is a function of the chosen root level.
size(&self) -> usize294     pub fn size(&self) -> usize {
295         granularity_at_level(self.table.level) << BITS_PER_LEVEL
296     }
297 
298     /// Recursively maps a range into the pagetable hierarchy starting at the root level, mapping
299     /// the pages to the corresponding physical address range starting at `pa`. Block and page
300     /// entries will be written to, but will only be mapped if `flags` contains `Attributes::VALID`.
301     ///
302     /// Returns an error if the virtual address range is out of the range covered by the pagetable,
303     /// or if the `flags` argument has unsupported attributes set.
map_range( &mut self, range: &MemoryRegion, pa: PhysicalAddress, flags: Attributes, constraints: Constraints, ) -> Result<(), MapError>304     pub fn map_range(
305         &mut self,
306         range: &MemoryRegion,
307         pa: PhysicalAddress,
308         flags: Attributes,
309         constraints: Constraints,
310     ) -> Result<(), MapError> {
311         if flags.contains(Attributes::TABLE_OR_PAGE) {
312             return Err(MapError::InvalidFlags(Attributes::TABLE_OR_PAGE));
313         }
314         self.verify_region(range)?;
315         self.table
316             .map_range(&mut self.translation, range, pa, flags, constraints);
317         Ok(())
318     }
319 
320     /// Returns the physical address of the root table in memory.
to_physical(&self) -> PhysicalAddress321     pub fn to_physical(&self) -> PhysicalAddress {
322         self.pa
323     }
324 
325     /// Returns the virtual address range for which this table is intended.
326     ///
327     /// This affects which TTBR register is used.
va_range(&self) -> VaRange328     pub fn va_range(&self) -> VaRange {
329         self.va_range
330     }
331 
332     /// Returns the translation regime for which this table is intended.
translation_regime(&self) -> TranslationRegime333     pub fn translation_regime(&self) -> TranslationRegime {
334         self.translation_regime
335     }
336 
337     /// Returns a reference to the translation used for this page table.
translation(&self) -> &T338     pub fn translation(&self) -> &T {
339         &self.translation
340     }
341 
342     /// Applies the provided updater function to the page table descriptors covering a given
343     /// memory range.
344     ///
345     /// This may involve splitting block entries if the provided range is not currently mapped
346     /// down to its precise boundaries. For visiting all the descriptors covering a memory range
347     /// without potential splitting (and no descriptor updates), use
348     /// [`walk_range`](Self::walk_range) instead.
349     ///
350     /// The updater function receives the following arguments:
351     ///
352     /// - The virtual address range mapped by each page table descriptor. A new descriptor will
353     ///   have been allocated before the invocation of the updater function if a page table split
354     ///   was needed.
355     /// - A mutable reference to the page table descriptor that permits modifications.
356     /// - The level of a translation table the descriptor belongs to.
357     ///
358     /// The updater function should return:
359     ///
360     /// - `Ok` to continue updating the remaining entries.
361     /// - `Err` to signal an error and stop updating the remaining entries.
362     ///
363     /// This should generally only be called while the page table is not active. In particular, any
364     /// change that may require break-before-make per the architecture must be made while the page
365     /// table is inactive. Mapping a previously unmapped memory range may be done while the page
366     /// table is active.
367     ///
368     /// # Errors
369     ///
370     /// Returns [`MapError::PteUpdateFault`] if the updater function returns an error.
371     ///
372     /// Returns [`MapError::RegionBackwards`] if the range is backwards.
373     ///
374     /// Returns [`MapError::AddressRange`] if the largest address in the `range` is greater than the
375     /// largest virtual address covered by the page table given its root level.
376     ///
377     /// Returns [`MapError::BreakBeforeMakeViolation'] if the range intersects with live mappings,
378     /// and modifying those would violate architectural break-before-make (BBM) requirements.
modify_range<F>(&mut self, range: &MemoryRegion, f: &F) -> Result<(), MapError> where F: Fn(&MemoryRegion, &mut Descriptor, usize) -> Result<(), ()> + ?Sized,379     pub fn modify_range<F>(&mut self, range: &MemoryRegion, f: &F) -> Result<(), MapError>
380     where
381         F: Fn(&MemoryRegion, &mut Descriptor, usize) -> Result<(), ()> + ?Sized,
382     {
383         self.verify_region(range)?;
384         self.table.modify_range(&mut self.translation, range, f)
385     }
386 
387     /// Applies the provided callback function to the page table descriptors covering a given
388     /// memory range.
389     ///
390     /// The callback function receives the following arguments:
391     ///
392     /// - The range covered by the current step in the walk. This is always a subrange of `range`
393     ///   even when the descriptor covers a region that exceeds it.
394     /// - The page table descriptor itself.
395     /// - The level of a translation table the descriptor belongs to.
396     ///
397     /// The callback function should return:
398     ///
399     /// - `Ok` to continue visiting the remaining entries.
400     /// - `Err` to signal an error and stop visiting the remaining entries.
401     ///
402     /// # Errors
403     ///
404     /// Returns [`MapError::PteUpdateFault`] if the callback function returns an error.
405     ///
406     /// Returns [`MapError::RegionBackwards`] if the range is backwards.
407     ///
408     /// Returns [`MapError::AddressRange`] if the largest address in the `range` is greater than the
409     /// largest virtual address covered by the page table given its root level.
walk_range<F>(&self, range: &MemoryRegion, f: &mut F) -> Result<(), MapError> where F: FnMut(&MemoryRegion, &Descriptor, usize) -> Result<(), ()>,410     pub fn walk_range<F>(&self, range: &MemoryRegion, f: &mut F) -> Result<(), MapError>
411     where
412         F: FnMut(&MemoryRegion, &Descriptor, usize) -> Result<(), ()>,
413     {
414         self.visit_range(range, &mut |mr, desc, level| {
415             f(mr, desc, level).map_err(|_| MapError::PteUpdateFault(*desc))
416         })
417     }
418 
419     // Private version of `walk_range` using a closure that returns MapError on error
visit_range<F>(&self, range: &MemoryRegion, f: &mut F) -> Result<(), MapError> where F: FnMut(&MemoryRegion, &Descriptor, usize) -> Result<(), MapError>,420     pub(crate) fn visit_range<F>(&self, range: &MemoryRegion, f: &mut F) -> Result<(), MapError>
421     where
422         F: FnMut(&MemoryRegion, &Descriptor, usize) -> Result<(), MapError>,
423     {
424         self.verify_region(range)?;
425         self.table.visit_range(&self.translation, range, f)
426     }
427 
428     /// Returns the level of mapping used for the given virtual address:
429     /// - `None` if it is unmapped
430     /// - `Some(LEAF_LEVEL)` if it is mapped as a single page
431     /// - `Some(level)` if it is mapped as a block at `level`
432     #[cfg(test)]
mapping_level(&self, va: VirtualAddress) -> Option<usize>433     pub(crate) fn mapping_level(&self, va: VirtualAddress) -> Option<usize> {
434         self.table.mapping_level(&self.translation, va)
435     }
436 
437     /// Checks whether the region is within range of the page table.
verify_region(&self, region: &MemoryRegion) -> Result<(), MapError>438     fn verify_region(&self, region: &MemoryRegion) -> Result<(), MapError> {
439         if region.end() < region.start() {
440             return Err(MapError::RegionBackwards(region.clone()));
441         }
442         match self.va_range {
443             VaRange::Lower => {
444                 if (region.start().0 as isize) < 0 {
445                     return Err(MapError::AddressRange(region.start()));
446                 } else if region.end().0 > self.size() {
447                     return Err(MapError::AddressRange(region.end()));
448                 }
449             }
450             VaRange::Upper => {
451                 if region.start().0 as isize >= 0
452                     || (region.start().0 as isize).unsigned_abs() > self.size()
453                 {
454                     return Err(MapError::AddressRange(region.start()));
455                 }
456             }
457         }
458         Ok(())
459     }
460 }
461 
462 impl<T: Translation> Debug for RootTable<T> {
fmt(&self, f: &mut Formatter) -> Result<(), fmt::Error>463     fn fmt(&self, f: &mut Formatter) -> Result<(), fmt::Error> {
464         writeln!(
465             f,
466             "RootTable {{ pa: {}, level: {}, table:",
467             self.pa, self.table.level
468         )?;
469         self.table.fmt_indented(f, &self.translation, 0)?;
470         write!(f, "}}")
471     }
472 }
473 
474 impl<T: Translation> Drop for RootTable<T> {
drop(&mut self)475     fn drop(&mut self) {
476         // SAFETY: We created the table in `RootTable::new` by calling `PageTableWithLevel::new`
477         // with `self.translation`. Subtables were similarly created by
478         // `PageTableWithLevel::split_entry` calling `PageTableWithLevel::new` with the same
479         // translation.
480         unsafe { self.table.free(&mut self.translation) }
481     }
482 }
483 
484 struct ChunkedIterator<'a> {
485     range: &'a MemoryRegion,
486     granularity: usize,
487     start: usize,
488 }
489 
490 impl Iterator for ChunkedIterator<'_> {
491     type Item = MemoryRegion;
492 
next(&mut self) -> Option<MemoryRegion>493     fn next(&mut self) -> Option<MemoryRegion> {
494         if !self.range.0.contains(&VirtualAddress(self.start)) {
495             return None;
496         }
497         let end = self
498             .range
499             .0
500             .end
501             .0
502             .min((self.start | (self.granularity - 1)) + 1);
503         let c = MemoryRegion::new(self.start, end);
504         self.start = end;
505         Some(c)
506     }
507 }
508 
509 bitflags! {
510     /// Attribute bits for a mapping in a page table.
511     #[derive(Copy, Clone, Debug, Eq, Hash, Ord, PartialEq, PartialOrd)]
512     pub struct Attributes: usize {
513         const VALID         = 1 << 0;
514         const TABLE_OR_PAGE = 1 << 1;
515 
516         const ATTRIBUTE_INDEX_0 = 0 << 2;
517         const ATTRIBUTE_INDEX_1 = 1 << 2;
518         const ATTRIBUTE_INDEX_2 = 2 << 2;
519         const ATTRIBUTE_INDEX_3 = 3 << 2;
520         const ATTRIBUTE_INDEX_4 = 4 << 2;
521         const ATTRIBUTE_INDEX_5 = 5 << 2;
522         const ATTRIBUTE_INDEX_6 = 6 << 2;
523         const ATTRIBUTE_INDEX_7 = 7 << 2;
524 
525         const OUTER_SHAREABLE = 2 << 8;
526         const INNER_SHAREABLE = 3 << 8;
527 
528         const NS            = 1 << 5;
529         const USER          = 1 << 6;
530         const READ_ONLY     = 1 << 7;
531         const ACCESSED      = 1 << 10;
532         const NON_GLOBAL    = 1 << 11;
533         const DBM           = 1 << 51;
534         /// Privileged Execute-never, if two privilege levels are supported.
535         const PXN           = 1 << 53;
536         /// Unprivileged Execute-never, or just Execute-never if only one privilege level is
537         /// supported.
538         const UXN           = 1 << 54;
539 
540         // Software flags in block and page descriptor entries.
541         const SWFLAG_0 = 1 << 55;
542         const SWFLAG_1 = 1 << 56;
543         const SWFLAG_2 = 1 << 57;
544         const SWFLAG_3 = 1 << 58;
545     }
546 }
547 
548 impl Attributes {
549     /// Mask for the bits determining the shareability of the mapping.
550     pub const SHAREABILITY_MASK: Self = Self::INNER_SHAREABLE;
551 
552     /// Mask for the bits determining the attribute index of the mapping.
553     pub const ATTRIBUTE_INDEX_MASK: Self = Self::ATTRIBUTE_INDEX_7;
554 }
555 
556 /// Smart pointer which owns a [`PageTable`] and knows what level it is at. This allows it to
557 /// implement `Debug` and `Drop`, as walking the page table hierachy requires knowing the starting
558 /// level.
559 #[derive(Debug)]
560 struct PageTableWithLevel<T: Translation> {
561     table: NonNull<PageTable>,
562     level: usize,
563     _translation: PhantomData<T>,
564 }
565 
566 // SAFETY: The underlying PageTable is process-wide and can be safely accessed from any thread
567 // with appropriate synchronization. This type manages ownership for the raw pointer.
568 unsafe impl<T: Translation + Send> Send for PageTableWithLevel<T> {}
569 
570 // SAFETY: &Self only allows reading from the page table, which is safe to do from any thread.
571 unsafe impl<T: Translation + Sync> Sync for PageTableWithLevel<T> {}
572 
573 impl<T: Translation> PageTableWithLevel<T> {
574     /// Allocates a new, zeroed, appropriately-aligned page table with the given translation,
575     /// returning both a pointer to it and its physical address.
new(translation: &mut T, level: usize) -> (Self, PhysicalAddress)576     fn new(translation: &mut T, level: usize) -> (Self, PhysicalAddress) {
577         assert!(level <= LEAF_LEVEL);
578         let (table, pa) = translation.allocate_table();
579         (
580             // Safe because the pointer has been allocated with the appropriate layout, and the
581             // memory is zeroed which is valid initialisation for a PageTable.
582             Self::from_pointer(table, level),
583             pa,
584         )
585     }
586 
from_pointer(table: NonNull<PageTable>, level: usize) -> Self587     fn from_pointer(table: NonNull<PageTable>, level: usize) -> Self {
588         Self {
589             table,
590             level,
591             _translation: PhantomData,
592         }
593     }
594 
595     /// Returns a reference to the descriptor corresponding to a given virtual address.
get_entry(&self, va: VirtualAddress) -> &Descriptor596     fn get_entry(&self, va: VirtualAddress) -> &Descriptor {
597         let shift = PAGE_SHIFT + (LEAF_LEVEL - self.level) * BITS_PER_LEVEL;
598         let index = (va.0 >> shift) % (1 << BITS_PER_LEVEL);
599         // SAFETY: Safe because we know that the pointer is properly aligned, dereferenced and
600         // initialised, and nothing else can access the page table while we hold a mutable reference
601         // to the PageTableWithLevel (assuming it is not currently active).
602         let table = unsafe { self.table.as_ref() };
603         &table.entries[index]
604     }
605 
606     /// Returns a mutable reference to the descriptor corresponding to a given virtual address.
get_entry_mut(&mut self, va: VirtualAddress) -> &mut Descriptor607     fn get_entry_mut(&mut self, va: VirtualAddress) -> &mut Descriptor {
608         let shift = PAGE_SHIFT + (LEAF_LEVEL - self.level) * BITS_PER_LEVEL;
609         let index = (va.0 >> shift) % (1 << BITS_PER_LEVEL);
610         // SAFETY: Safe because we know that the pointer is properly aligned, dereferenced and
611         // initialised, and nothing else can access the page table while we hold a mutable reference
612         // to the PageTableWithLevel (assuming it is not currently active).
613         let table = unsafe { self.table.as_mut() };
614         &mut table.entries[index]
615     }
616 
617     /// Convert the descriptor in `entry` from a block mapping to a table mapping of
618     /// the same range with the same attributes
split_entry( translation: &mut T, chunk: &MemoryRegion, entry: &mut Descriptor, level: usize, ) -> Self619     fn split_entry(
620         translation: &mut T,
621         chunk: &MemoryRegion,
622         entry: &mut Descriptor,
623         level: usize,
624     ) -> Self {
625         let granularity = granularity_at_level(level);
626         let old = *entry;
627         let (mut subtable, subtable_pa) = Self::new(translation, level + 1);
628         if let Some(old_flags) = old.flags() {
629             let old_pa = old.output_address();
630             if !old_flags.contains(Attributes::TABLE_OR_PAGE)
631                 && (!old_flags.is_empty() || old_pa.0 != 0)
632             {
633                 // `old` was a block entry, so we need to split it.
634                 // Recreate the entire block in the newly added table.
635                 let a = align_down(chunk.0.start.0, granularity);
636                 let b = align_up(chunk.0.end.0, granularity);
637                 subtable.map_range(
638                     translation,
639                     &MemoryRegion::new(a, b),
640                     old_pa,
641                     old_flags,
642                     Constraints::empty(),
643                 );
644             }
645         }
646         entry.set(subtable_pa, Attributes::TABLE_OR_PAGE | Attributes::VALID);
647         subtable
648     }
649 
650     /// Maps the the given virtual address range in this pagetable to the corresponding physical
651     /// address range starting at the given `pa`, recursing into any subtables as necessary. To map
652     /// block and page entries, `Attributes::VALID` must be set in `flags`.
653     ///
654     /// Assumes that the entire range is within the range covered by this pagetable.
655     ///
656     /// Panics if the `translation` doesn't provide a corresponding physical address for some
657     /// virtual address within the range, as there is no way to roll back to a safe state so this
658     /// should be checked by the caller beforehand.
map_range( &mut self, translation: &mut T, range: &MemoryRegion, mut pa: PhysicalAddress, flags: Attributes, constraints: Constraints, )659     fn map_range(
660         &mut self,
661         translation: &mut T,
662         range: &MemoryRegion,
663         mut pa: PhysicalAddress,
664         flags: Attributes,
665         constraints: Constraints,
666     ) {
667         let level = self.level;
668         let granularity = granularity_at_level(level);
669 
670         for chunk in range.split(level) {
671             let entry = self.get_entry_mut(chunk.0.start);
672 
673             if level == LEAF_LEVEL {
674                 // Put down a page mapping.
675                 entry.set(pa, flags | Attributes::TABLE_OR_PAGE);
676             } else if chunk.is_block(level)
677                 && !entry.is_table_or_page()
678                 && is_aligned(pa.0, granularity)
679                 && !constraints.contains(Constraints::NO_BLOCK_MAPPINGS)
680             {
681                 // Rather than leak the entire subhierarchy, only put down
682                 // a block mapping if the region is not already covered by
683                 // a table mapping.
684                 entry.set(pa, flags);
685             } else {
686                 let mut subtable = entry
687                     .subtable(translation, level)
688                     .unwrap_or_else(|| Self::split_entry(translation, &chunk, entry, level));
689                 subtable.map_range(translation, &chunk, pa, flags, constraints);
690             }
691             pa.0 += chunk.len();
692         }
693     }
694 
fmt_indented( &self, f: &mut Formatter, translation: &T, indentation: usize, ) -> Result<(), fmt::Error>695     fn fmt_indented(
696         &self,
697         f: &mut Formatter,
698         translation: &T,
699         indentation: usize,
700     ) -> Result<(), fmt::Error> {
701         const WIDTH: usize = 3;
702         // SAFETY: Safe because we know that the pointer is aligned, initialised and dereferencable,
703         // and the PageTable won't be mutated while we are using it.
704         let table = unsafe { self.table.as_ref() };
705 
706         let mut i = 0;
707         while i < table.entries.len() {
708             if table.entries[i].0 == 0 {
709                 let first_zero = i;
710                 while i < table.entries.len() && table.entries[i].0 == 0 {
711                     i += 1;
712                 }
713                 if i - 1 == first_zero {
714                     writeln!(f, "{:indentation$}{: <WIDTH$}: 0", "", first_zero)?;
715                 } else {
716                     writeln!(f, "{:indentation$}{: <WIDTH$}-{}: 0", "", first_zero, i - 1)?;
717                 }
718             } else {
719                 writeln!(
720                     f,
721                     "{:indentation$}{: <WIDTH$}: {:?}",
722                     "", i, table.entries[i],
723                 )?;
724                 if let Some(subtable) = table.entries[i].subtable(translation, self.level) {
725                     subtable.fmt_indented(f, translation, indentation + 2)?;
726                 }
727                 i += 1;
728             }
729         }
730         Ok(())
731     }
732 
733     /// Frees the memory used by this pagetable and all subtables. It is not valid to access the
734     /// page table after this.
735     ///
736     /// # Safety
737     ///
738     /// The table and all its subtables must have been created by `PageTableWithLevel::new` with the
739     /// same `translation`.
free(&mut self, translation: &mut T)740     unsafe fn free(&mut self, translation: &mut T) {
741         // SAFETY: Safe because we know that the pointer is aligned, initialised and dereferencable,
742         // and the PageTable won't be mutated while we are freeing it.
743         let table = unsafe { self.table.as_ref() };
744         for entry in table.entries {
745             if let Some(mut subtable) = entry.subtable(translation, self.level) {
746                 // Safe because our caller promised that all our subtables were created by
747                 // `PageTableWithLevel::new` with the same `translation`.
748                 subtable.free(translation);
749             }
750         }
751         // SAFETY: Safe because our caller promised that the table was created by
752         // `PageTableWithLevel::new` with `translation`, which then allocated it by calling
753         // `allocate_table` on `translation`.
754         unsafe {
755             // Actually free the memory used by the `PageTable`.
756             translation.deallocate_table(self.table);
757         }
758     }
759 
760     /// Modifies a range of page table entries by applying a function to each page table entry.
761     /// If the range is not aligned to block boundaries, block descriptors will be split up.
modify_range<F>( &mut self, translation: &mut T, range: &MemoryRegion, f: &F, ) -> Result<(), MapError> where F: Fn(&MemoryRegion, &mut Descriptor, usize) -> Result<(), ()> + ?Sized,762     fn modify_range<F>(
763         &mut self,
764         translation: &mut T,
765         range: &MemoryRegion,
766         f: &F,
767     ) -> Result<(), MapError>
768     where
769         F: Fn(&MemoryRegion, &mut Descriptor, usize) -> Result<(), ()> + ?Sized,
770     {
771         let level = self.level;
772         for chunk in range.split(level) {
773             let entry = self.get_entry_mut(chunk.0.start);
774             if let Some(mut subtable) = entry.subtable(translation, level).or_else(|| {
775                 if !chunk.is_block(level) {
776                     // The current chunk is not aligned to the block size at this level
777                     // Split it before recursing to the next level
778                     Some(Self::split_entry(translation, &chunk, entry, level))
779                 } else {
780                     None
781                 }
782             }) {
783                 subtable.modify_range(translation, &chunk, f)?;
784             } else {
785                 f(&chunk, entry, level).map_err(|_| MapError::PteUpdateFault(*entry))?;
786             }
787         }
788         Ok(())
789     }
790 
791     /// Walks a range of page table entries and passes each one to a caller provided function.
792     /// If the function returns an error, the walk is terminated and the error value is passed on
visit_range<F, E>(&self, translation: &T, range: &MemoryRegion, f: &mut F) -> Result<(), E> where F: FnMut(&MemoryRegion, &Descriptor, usize) -> Result<(), E>,793     fn visit_range<F, E>(&self, translation: &T, range: &MemoryRegion, f: &mut F) -> Result<(), E>
794     where
795         F: FnMut(&MemoryRegion, &Descriptor, usize) -> Result<(), E>,
796     {
797         let level = self.level;
798         for chunk in range.split(level) {
799             let entry = self.get_entry(chunk.0.start);
800             if let Some(subtable) = entry.subtable(translation, level) {
801                 subtable.visit_range(translation, &chunk, f)?;
802             } else {
803                 f(&chunk, entry, level)?;
804             }
805         }
806         Ok(())
807     }
808 
809     /// Returns the level of mapping used for the given virtual address:
810     /// - `None` if it is unmapped
811     /// - `Some(LEAF_LEVEL)` if it is mapped as a single page
812     /// - `Some(level)` if it is mapped as a block at `level`
813     #[cfg(test)]
mapping_level(&self, translation: &T, va: VirtualAddress) -> Option<usize>814     fn mapping_level(&self, translation: &T, va: VirtualAddress) -> Option<usize> {
815         let entry = self.get_entry(va);
816         if let Some(subtable) = entry.subtable(translation, self.level) {
817             subtable.mapping_level(translation, va)
818         } else {
819             if entry.is_valid() {
820                 Some(self.level)
821             } else {
822                 None
823             }
824         }
825     }
826 }
827 
828 /// A single level of a page table.
829 #[repr(C, align(4096))]
830 pub struct PageTable {
831     entries: [Descriptor; 1 << BITS_PER_LEVEL],
832 }
833 
834 impl PageTable {
835     /// Allocates a new zeroed, appropriately-aligned pagetable on the heap using the global
836     /// allocator and returns a pointer to it.
837     #[cfg(feature = "alloc")]
new() -> NonNull<Self>838     pub fn new() -> NonNull<Self> {
839         // SAFETY: Safe because the pointer has been allocated with the appropriate layout by the
840         // global allocator, and the memory is zeroed which is valid initialisation for a PageTable.
841         unsafe { allocate_zeroed() }
842     }
843 }
844 
845 /// An entry in a page table.
846 ///
847 /// A descriptor may be:
848 ///   - Invalid, i.e. the virtual address range is unmapped
849 ///   - A page mapping, if it is in the lowest level page table.
850 ///   - A block mapping, if it is not in the lowest level page table.
851 ///   - A pointer to a lower level pagetable, if it is not in the lowest level page table.
852 #[derive(Clone, Copy, PartialEq, Eq)]
853 #[repr(C)]
854 pub struct Descriptor(usize);
855 
856 impl Descriptor {
857     const PHYSICAL_ADDRESS_BITMASK: usize = !(PAGE_SIZE - 1) & !(0xffff << 48);
858 
output_address(self) -> PhysicalAddress859     pub(crate) fn output_address(self) -> PhysicalAddress {
860         PhysicalAddress(self.0 & Self::PHYSICAL_ADDRESS_BITMASK)
861     }
862 
863     /// Returns the flags of this page table entry, or `None` if its state does not
864     /// contain a valid set of flags.
flags(self) -> Option<Attributes>865     pub fn flags(self) -> Option<Attributes> {
866         Attributes::from_bits(self.0 & !Self::PHYSICAL_ADDRESS_BITMASK)
867     }
868 
869     /// Modifies the page table entry by setting or clearing its flags.
870     /// Panics when attempting to convert a table descriptor into a block/page descriptor or vice
871     /// versa - this is not supported via this API.
modify_flags(&mut self, set: Attributes, clear: Attributes)872     pub fn modify_flags(&mut self, set: Attributes, clear: Attributes) {
873         let flags = (self.0 | set.bits()) & !clear.bits();
874 
875         if (self.0 ^ flags) & Attributes::TABLE_OR_PAGE.bits() != 0 {
876             panic!("Cannot convert between table and block/page descriptors\n");
877         }
878         self.0 = flags;
879     }
880 
881     /// Returns `true` if [`Attributes::VALID`] is set on this entry, e.g. if the entry is mapped.
is_valid(self) -> bool882     pub fn is_valid(self) -> bool {
883         (self.0 & Attributes::VALID.bits()) != 0
884     }
885 
886     /// Returns `true` if this is a valid entry pointing to a next level translation table or a page.
is_table_or_page(self) -> bool887     pub fn is_table_or_page(self) -> bool {
888         if let Some(flags) = self.flags() {
889             flags.contains(Attributes::TABLE_OR_PAGE | Attributes::VALID)
890         } else {
891             false
892         }
893     }
894 
set(&mut self, pa: PhysicalAddress, flags: Attributes)895     pub(crate) fn set(&mut self, pa: PhysicalAddress, flags: Attributes) {
896         self.0 = (pa.0 & Self::PHYSICAL_ADDRESS_BITMASK) | flags.bits();
897     }
898 
subtable<T: Translation>( self, translation: &T, level: usize, ) -> Option<PageTableWithLevel<T>>899     fn subtable<T: Translation>(
900         self,
901         translation: &T,
902         level: usize,
903     ) -> Option<PageTableWithLevel<T>> {
904         if level < LEAF_LEVEL && self.is_table_or_page() {
905             let output_address = self.output_address();
906             let table = translation.physical_to_virtual(output_address);
907             return Some(PageTableWithLevel::from_pointer(table, level + 1));
908         }
909         None
910     }
911 }
912 
913 impl Debug for Descriptor {
fmt(&self, f: &mut Formatter) -> Result<(), fmt::Error>914     fn fmt(&self, f: &mut Formatter) -> Result<(), fmt::Error> {
915         write!(f, "{:#016x}", self.0)?;
916         if self.is_valid() {
917             if let Some(flags) = self.flags() {
918                 write!(f, " ({}, {:?})", self.output_address(), flags)?;
919             }
920         }
921         Ok(())
922     }
923 }
924 
925 /// Allocates appropriately aligned heap space for a `T` and zeroes it.
926 ///
927 /// # Safety
928 ///
929 /// It must be valid to initialise the type `T` by simply zeroing its memory.
930 #[cfg(feature = "alloc")]
allocate_zeroed<T>() -> NonNull<T>931 unsafe fn allocate_zeroed<T>() -> NonNull<T> {
932     let layout = Layout::new::<T>();
933     // Safe because we know the layout has non-zero size.
934     let pointer = alloc_zeroed(layout);
935     if pointer.is_null() {
936         handle_alloc_error(layout);
937     }
938     // Safe because we just checked that the pointer is non-null.
939     NonNull::new_unchecked(pointer as *mut T)
940 }
941 
942 /// Deallocates the heap space for a `T` which was previously allocated by `allocate_zeroed`.
943 ///
944 /// # Safety
945 ///
946 /// The memory must have been allocated by the global allocator, with the layout for `T`, and not
947 /// yet deallocated.
948 #[cfg(feature = "alloc")]
deallocate<T>(ptr: NonNull<T>)949 pub(crate) unsafe fn deallocate<T>(ptr: NonNull<T>) {
950     let layout = Layout::new::<T>();
951     dealloc(ptr.as_ptr() as *mut u8, layout);
952 }
953 
align_down(value: usize, alignment: usize) -> usize954 const fn align_down(value: usize, alignment: usize) -> usize {
955     value & !(alignment - 1)
956 }
957 
align_up(value: usize, alignment: usize) -> usize958 const fn align_up(value: usize, alignment: usize) -> usize {
959     ((value - 1) | (alignment - 1)) + 1
960 }
961 
is_aligned(value: usize, alignment: usize) -> bool962 pub(crate) const fn is_aligned(value: usize, alignment: usize) -> bool {
963     value & (alignment - 1) == 0
964 }
965 
966 #[cfg(test)]
967 mod tests {
968     use super::*;
969     #[cfg(feature = "alloc")]
970     use crate::idmap::IdTranslation;
971     #[cfg(feature = "alloc")]
972     use alloc::{format, string::ToString, vec, vec::Vec};
973 
974     #[cfg(feature = "alloc")]
975     #[test]
display_memory_region()976     fn display_memory_region() {
977         let region = MemoryRegion::new(0x1234, 0x56789);
978         assert_eq!(
979             &region.to_string(),
980             "0x0000000000001000..0x0000000000057000"
981         );
982         assert_eq!(
983             &format!("{:?}", region),
984             "0x0000000000001000..0x0000000000057000"
985         );
986     }
987 
988     #[test]
subtract_virtual_address()989     fn subtract_virtual_address() {
990         let low = VirtualAddress(0x12);
991         let high = VirtualAddress(0x1234);
992         assert_eq!(high - low, 0x1222);
993     }
994 
995     #[cfg(debug_assertions)]
996     #[test]
997     #[should_panic]
subtract_virtual_address_overflow()998     fn subtract_virtual_address_overflow() {
999         let low = VirtualAddress(0x12);
1000         let high = VirtualAddress(0x1234);
1001 
1002         // This would overflow, so should panic.
1003         let _ = low - high;
1004     }
1005 
1006     #[test]
add_virtual_address()1007     fn add_virtual_address() {
1008         assert_eq!(VirtualAddress(0x1234) + 0x42, VirtualAddress(0x1276));
1009     }
1010 
1011     #[test]
subtract_physical_address()1012     fn subtract_physical_address() {
1013         let low = PhysicalAddress(0x12);
1014         let high = PhysicalAddress(0x1234);
1015         assert_eq!(high - low, 0x1222);
1016     }
1017 
1018     #[cfg(debug_assertions)]
1019     #[test]
1020     #[should_panic]
subtract_physical_address_overflow()1021     fn subtract_physical_address_overflow() {
1022         let low = PhysicalAddress(0x12);
1023         let high = PhysicalAddress(0x1234);
1024 
1025         // This would overflow, so should panic.
1026         let _ = low - high;
1027     }
1028 
1029     #[test]
add_physical_address()1030     fn add_physical_address() {
1031         assert_eq!(PhysicalAddress(0x1234) + 0x42, PhysicalAddress(0x1276));
1032     }
1033 
1034     #[test]
invalid_descriptor()1035     fn invalid_descriptor() {
1036         let desc = Descriptor(0usize);
1037         assert!(!desc.is_valid());
1038         assert!(!desc.flags().unwrap().contains(Attributes::VALID));
1039     }
1040 
1041     #[test]
set_descriptor()1042     fn set_descriptor() {
1043         const PHYSICAL_ADDRESS: usize = 0x12340000;
1044         let mut desc = Descriptor(0usize);
1045         assert!(!desc.is_valid());
1046         desc.set(
1047             PhysicalAddress(PHYSICAL_ADDRESS),
1048             Attributes::TABLE_OR_PAGE | Attributes::USER | Attributes::SWFLAG_1 | Attributes::VALID,
1049         );
1050         assert!(desc.is_valid());
1051         assert_eq!(
1052             desc.flags().unwrap(),
1053             Attributes::TABLE_OR_PAGE | Attributes::USER | Attributes::SWFLAG_1 | Attributes::VALID
1054         );
1055         assert_eq!(desc.output_address(), PhysicalAddress(PHYSICAL_ADDRESS));
1056     }
1057 
1058     #[test]
modify_descriptor_flags()1059     fn modify_descriptor_flags() {
1060         let mut desc = Descriptor(0usize);
1061         assert!(!desc.is_valid());
1062         desc.set(
1063             PhysicalAddress(0x12340000),
1064             Attributes::TABLE_OR_PAGE | Attributes::USER | Attributes::SWFLAG_1,
1065         );
1066         desc.modify_flags(
1067             Attributes::DBM | Attributes::SWFLAG_3,
1068             Attributes::VALID | Attributes::SWFLAG_1,
1069         );
1070         assert!(!desc.is_valid());
1071         assert_eq!(
1072             desc.flags().unwrap(),
1073             Attributes::TABLE_OR_PAGE | Attributes::USER | Attributes::SWFLAG_3 | Attributes::DBM
1074         );
1075     }
1076 
1077     #[test]
1078     #[should_panic]
modify_descriptor_table_or_page_flag()1079     fn modify_descriptor_table_or_page_flag() {
1080         let mut desc = Descriptor(0usize);
1081         assert!(!desc.is_valid());
1082         desc.set(
1083             PhysicalAddress(0x12340000),
1084             Attributes::TABLE_OR_PAGE | Attributes::USER | Attributes::SWFLAG_1,
1085         );
1086         desc.modify_flags(Attributes::VALID, Attributes::TABLE_OR_PAGE);
1087     }
1088 
1089     #[cfg(feature = "alloc")]
1090     #[test]
unaligned_chunks()1091     fn unaligned_chunks() {
1092         let region = MemoryRegion::new(0x0000_2000, 0x0020_5000);
1093         let chunks = region.split(LEAF_LEVEL - 1).collect::<Vec<_>>();
1094         assert_eq!(
1095             chunks,
1096             vec![
1097                 MemoryRegion::new(0x0000_2000, 0x0020_0000),
1098                 MemoryRegion::new(0x0020_0000, 0x0020_5000),
1099             ]
1100         );
1101     }
1102 
1103     #[cfg(feature = "alloc")]
1104     #[test]
1105     #[should_panic]
no_el2_ttbr1()1106     fn no_el2_ttbr1() {
1107         RootTable::<IdTranslation>::new(IdTranslation, 1, TranslationRegime::El2, VaRange::Upper);
1108     }
1109 
1110     #[cfg(feature = "alloc")]
1111     #[test]
1112     #[should_panic]
no_el3_ttbr1()1113     fn no_el3_ttbr1() {
1114         RootTable::<IdTranslation>::new(IdTranslation, 1, TranslationRegime::El3, VaRange::Upper);
1115     }
1116 }
1117