|
| 1 | +/* |
| 2 | +Copyright 2025 The Hyperlight Authors. |
| 3 | +
|
| 4 | +Licensed under the Apache License, Version 2.0 (the "License"); |
| 5 | +you may not use this file except in compliance with the License. |
| 6 | +You may obtain a copy of the License at |
| 7 | +
|
| 8 | + http://www.apache.org/licenses/LICENSE-2.0 |
| 9 | +
|
| 10 | +Unless required by applicable law or agreed to in writing, software |
| 11 | +distributed under the License is distributed on an "AS IS" BASIS, |
| 12 | +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
| 13 | +See the License for the specific language governing permissions and |
| 14 | +limitations under the License. |
| 15 | + */ |
| 16 | + |
| 17 | +#[cfg_attr(target_arch = "x86_64", path = "arch/amd64/vmem.rs")] |
| 18 | +pub mod arch; |
| 19 | + |
| 20 | +pub use arch::{PAGE_SIZE, PAGE_TABLE_SIZE, PageTableEntry, PhysAddr, VirtAddr}; |
| 21 | +pub const PAGE_TABLE_ENTRIES_PER_TABLE: usize = |
| 22 | + PAGE_TABLE_SIZE / core::mem::size_of::<PageTableEntry>(); |
| 23 | + |
| 24 | +/// The operations used to actually access the page table structures, |
| 25 | +/// used to allow the same code to be used in the host and the guest |
| 26 | +/// for page table setup |
| 27 | +pub trait TableOps { |
| 28 | + /// The type of table addresses |
| 29 | + type TableAddr: Copy; |
| 30 | + |
| 31 | + /// Allocate a zeroed table |
| 32 | + /// |
| 33 | + /// # Safety |
| 34 | + /// The current implementations of this function are not |
| 35 | + /// inherently unsafe, but the guest implementation will likely |
| 36 | + /// become so in the future when a real physical page allocator is |
| 37 | + /// implemented. |
| 38 | + /// |
| 39 | + /// Currently, callers should take care not to call this on |
| 40 | + /// multiple threads at the same time. |
| 41 | + /// |
| 42 | + /// # Panics |
| 43 | + /// This function may panic if: |
| 44 | + /// - The Layout creation fails |
| 45 | + /// - Memory allocation fails |
| 46 | + unsafe fn alloc_table(&self) -> Self::TableAddr; |
| 47 | + |
| 48 | + /// Offset the table address by the given offset in bytes. |
| 49 | + /// |
| 50 | + /// # Parameters |
| 51 | + /// - `addr`: The base address of the table. |
| 52 | + /// - `entry_offset`: The offset in **bytes** within the page table. This is |
| 53 | + /// not an entry index; callers must multiply the entry index by the size |
| 54 | + /// of a page table entry (typically 8 bytes) to obtain the correct byte offset. |
| 55 | + /// |
| 56 | + /// # Returns |
| 57 | + /// The address of the entry at the given byte offset from the base address. |
| 58 | + fn entry_addr(addr: Self::TableAddr, entry_offset: u64) -> Self::TableAddr; |
| 59 | + |
| 60 | + /// Read a u64 from the given address, used to read existing page |
| 61 | + /// table entries |
| 62 | + /// |
| 63 | + /// # Safety |
| 64 | + /// This reads from the given memory address, and so all the usual |
| 65 | + /// Rust things about raw pointers apply. This will also be used |
| 66 | + /// to update guest page tables, so especially in the guest, it is |
| 67 | + /// important to ensure that the page tables updates do not break |
| 68 | + /// invariants. The implementor of the trait should ensure that |
| 69 | + /// nothing else will be reading/writing the address at the same |
| 70 | + /// time as mapping code using the trait. |
| 71 | + unsafe fn read_entry(&self, addr: Self::TableAddr) -> PageTableEntry; |
| 72 | + |
| 73 | + /// Write a u64 to the given address, used to write updated page |
| 74 | + /// table entries |
| 75 | + /// |
| 76 | + /// # Safety |
| 77 | + /// This writes to the given memory address, and so all the usual |
| 78 | + /// Rust things about raw pointers apply. This will also be used |
| 79 | + /// to update guest page tables, so especially in the guest, it is |
| 80 | + /// important to ensure that the page tables updates do not break |
| 81 | + /// invariants. The implementor of the trait should ensure that |
| 82 | + /// nothing else will be reading/writing the address at the same |
| 83 | + /// time as mapping code using the trait. |
| 84 | + unsafe fn write_entry(&self, addr: Self::TableAddr, entry: PageTableEntry); |
| 85 | + |
| 86 | + /// Convert an abstract table address to a concrete physical address (u64) |
| 87 | + /// which can be e.g. written into a page table entry |
| 88 | + fn to_phys(addr: Self::TableAddr) -> PhysAddr; |
| 89 | + |
| 90 | + /// Convert a concrete physical address (u64) which may have been e.g. read |
| 91 | + /// from a page table entry back into an abstract table address |
| 92 | + fn from_phys(addr: PhysAddr) -> Self::TableAddr; |
| 93 | + |
| 94 | + /// Return the address of the root page table |
| 95 | + fn root_table(&self) -> Self::TableAddr; |
| 96 | +} |
| 97 | + |
| 98 | +#[derive(Debug)] |
| 99 | +pub struct BasicMapping { |
| 100 | + pub readable: bool, |
| 101 | + pub writable: bool, |
| 102 | + pub executable: bool, |
| 103 | +} |
| 104 | + |
| 105 | +#[derive(Debug)] |
| 106 | +pub enum MappingKind { |
| 107 | + BasicMapping(BasicMapping), |
| 108 | + /* TODO: What useful things other than basic mappings actually |
| 109 | + * require touching the tables? */ |
| 110 | +} |
| 111 | + |
| 112 | +#[derive(Debug)] |
| 113 | +pub struct Mapping { |
| 114 | + pub phys_base: u64, |
| 115 | + pub virt_base: u64, |
| 116 | + pub len: u64, |
| 117 | + pub kind: MappingKind, |
| 118 | +} |
| 119 | + |
| 120 | +/// Assumption: all are page-aligned |
| 121 | +/// |
| 122 | +/// # Safety |
| 123 | +/// This function modifies pages backing a virtual memory range which |
| 124 | +/// is inherently unsafe w.r.t. the Rust memory model. |
| 125 | +/// |
| 126 | +/// When using this function, please note: |
| 127 | +/// - No locking is performed before touching page table data structures, |
| 128 | +/// as such do not use concurrently with any other page table operations |
| 129 | +/// - TLB invalidation is not performed, if previously-mapped ranges |
| 130 | +/// are being remapped, TLB invalidation may need to be performed |
| 131 | +/// afterwards. |
| 132 | +pub use arch::map; |
| 133 | +/// This function is not presently used for anything, but is useful |
| 134 | +/// for debugging |
| 135 | +/// |
| 136 | +/// # Safety |
| 137 | +/// This function traverses page table data structures, and should not |
| 138 | +/// be called concurrently with any other operations that modify the |
| 139 | +/// page table. |
| 140 | +pub use arch::virt_to_phys; |
0 commit comments