Skip to content

Commit c4ac95e

Browse files
Unify page table manipulation code between the guest and the host (#1093)
* Unify page table manipulation code between the guest and the host Currently, the guest and the host both have code that manipulates architecture-specific page table structures: the guest has a general map operation, and the host has a much more specific routine that builds an identity map. As we move to more complex virtual memory configurations in the guest, the host will need the ability to build more complex mappings in the guest, so this commit removes the simple implementation in the host, and replaces it with calls to the implementation originally written for the guest (now moved to `hyperlight_common` and factored into an architecture-independent interface and architecture-specific code parts). Signed-off-by: Simon Davies <simongdavies@users.noreply.github.com> * Only include vm mod when init-paging is enabled Signed-off-by: Simon Davies <simongdavies@users.noreply.github.com> * Review changes Signed-off-by: Simon Davies <simongdavies@users.noreply.github.com> * last ever fix Signed-off-by: Simon Davies <simongdavies@users.noreply.github.com> --------- Signed-off-by: Simon Davies <simongdavies@users.noreply.github.com> Co-authored-by: Lucy Menon <168595099+syntactically@users.noreply.github.com>
1 parent 89ce6eb commit c4ac95e

File tree

11 files changed

+1124
-428
lines changed

11 files changed

+1124
-428
lines changed

src/hyperlight_common/Cargo.toml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -30,6 +30,7 @@ fuzzing = ["dep:arbitrary"]
3030
trace_guest = []
3131
mem_profile = []
3232
std = ["thiserror/std", "log/std", "tracing/std"]
33+
init-paging = []
3334

3435
[lib]
3536
bench = false # see https://bheisler.github.io/criterion.rs/book/faq.html#cargo-bench-gives-unrecognized-option-errors-for-valid-command-line-options

src/hyperlight_common/src/arch/amd64/vmem.rs

Lines changed: 756 additions & 0 deletions
Large diffs are not rendered by default.

src/hyperlight_common/src/lib.rs

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -38,3 +38,6 @@ pub mod resource;
3838

3939
/// cbindgen:ignore
4040
pub mod func;
41+
// cbindgen:ignore
42+
#[cfg(feature = "init-paging")]
43+
pub mod vmem;

src/hyperlight_common/src/vmem.rs

Lines changed: 140 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,140 @@
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;

src/hyperlight_guest_bin/Cargo.toml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -23,7 +23,7 @@ macros = ["dep:hyperlight-guest-macro", "dep:linkme"]
2323

2424
[dependencies]
2525
hyperlight-guest = { workspace = true, default-features = false }
26-
hyperlight-common = { workspace = true, default-features = false }
26+
hyperlight-common = { workspace = true, default-features = false, features = [ "init-paging" ] }
2727
hyperlight-guest-tracing = { workspace = true, default-features = false }
2828
hyperlight-guest-macro = { workspace = true, default-features = false, optional = true }
2929
buddy_system_allocator = "0.11.0"

0 commit comments

Comments
 (0)