nub_host_common/
layout.rs1#[cfg_attr(target_arch = "x86", path = "arch/i686/layout.rs")]
18#[cfg_attr(
19 all(target_arch = "x86_64", not(feature = "i686-guest")),
20 path = "arch/amd64/layout.rs"
21)]
22#[cfg_attr(
23 all(target_arch = "x86_64", feature = "i686-guest"),
24 path = "arch/i686/layout.rs"
25)]
26#[cfg_attr(target_arch = "aarch64", path = "arch/aarch64/layout.rs")]
27mod arch;
28
29pub use arch::{MAX_GPA, MAX_GVA};
30#[cfg(any(
31 all(target_arch = "x86_64", not(feature = "i686-guest")),
32 target_arch = "aarch64"
33))]
34pub use arch::{SNAPSHOT_PT_GVA_MAX, SNAPSHOT_PT_GVA_MIN};
35
36pub const GUEST_VA_BASE_DEFAULT: u64 = 0x5000_0000_0000;
43pub const GUEST_VA_SIZE: u64 = 0x4_4000_0000;
47pub const KERNEL_OFFSET: u64 = 0x1_4000_0000; #[cfg(all(feature = "std", target_os = "macos"))]
55static MACOS_RESERVED_BASE: std::sync::OnceLock<u64> = std::sync::OnceLock::new();
56
57#[cfg(feature = "std")]
58pub fn guest_va_base() -> u64 {
59 #[cfg(target_os = "macos")]
60 if let Some(&base) = MACOS_RESERVED_BASE.get() {
61 return base;
62 }
63 if let Ok(s) = std::env::var("JAR_GUEST_VA_BASE") {
64 let s = s.trim().trim_start_matches("0x");
65 u64::from_str_radix(s, 16).expect("JAR_GUEST_VA_BASE must be hex")
66 } else {
67 GUEST_VA_BASE_DEFAULT
68 }
69}
70
71#[cfg(feature = "std")]
87pub fn reserve_guest_va_range() -> Result<(), std::io::Error> {
88 use std::sync::OnceLock;
89 static RESERVED: OnceLock<Result<(), String>> = OnceLock::new();
90 let res = RESERVED.get_or_init(reserve_guest_va_range_inner);
91 res.clone().map_err(std::io::Error::other)
92}
93
94#[cfg(all(feature = "std", target_os = "linux"))]
95fn reserve_guest_va_range_inner() -> Result<(), String> {
96 let base = guest_va_base();
97 let size = GUEST_VA_SIZE as usize;
98 let ptr = unsafe {
100 libc::mmap(
101 base as *mut libc::c_void,
102 size,
103 libc::PROT_NONE,
104 libc::MAP_PRIVATE
105 | libc::MAP_ANONYMOUS
106 | libc::MAP_FIXED_NOREPLACE
107 | libc::MAP_NORESERVE,
108 -1,
109 0,
110 )
111 };
112 if ptr == libc::MAP_FAILED {
113 return Err(format!(
114 "JAR guest VA reservation failed: mmap({:#x}, {} bytes, MAP_FIXED_NOREPLACE): {}",
115 base,
116 size,
117 std::io::Error::last_os_error()
118 ));
119 }
120 if ptr as u64 != base {
121 unsafe {
126 libc::munmap(ptr, size);
127 }
128 return Err(format!(
129 "JAR guest VA reservation: requested {:#x}, kernel returned {:#x} — \
130 something is squatting on our range",
131 base, ptr as u64
132 ));
133 }
134 Ok(())
135}
136
137#[cfg(all(feature = "std", target_os = "macos"))]
138fn reserve_guest_va_range_inner() -> Result<(), String> {
139 const MIN_BASE: u64 = 0x1_4000_0000;
143 let size = GUEST_VA_SIZE as usize;
144 for _ in 0..10 {
145 let ptr = unsafe {
147 libc::mmap(
148 core::ptr::null_mut(),
149 size,
150 libc::PROT_NONE,
151 libc::MAP_PRIVATE | libc::MAP_ANON,
152 -1,
153 0,
154 )
155 };
156 if ptr == libc::MAP_FAILED {
157 return Err(format!(
158 "JAR guest VA reservation failed: mmap({} bytes): {}",
159 size,
160 std::io::Error::last_os_error()
161 ));
162 }
163 if (ptr as u64) >= MIN_BASE {
164 MACOS_RESERVED_BASE
165 .set(ptr as u64)
166 .expect("MACOS_RESERVED_BASE set once");
167 return Ok(());
168 }
169 unsafe {
171 libc::munmap(ptr, size);
172 }
173 }
174 Err("macOS: could not reserve guest VA range outside low 5 GiB after 10 retries".into())
175}
176
177#[cfg(all(feature = "std", not(any(target_os = "linux", target_os = "macos"))))]
178fn reserve_guest_va_range_inner() -> Result<(), String> {
179 Err("JAR guest VA reservation: unsupported host OS (only linux and macos are supported)".into())
180}
181
182pub const SCRATCH_TOP_SIZE_OFFSET: u64 = 0x08;
184pub const SCRATCH_TOP_ALLOCATOR_OFFSET: u64 = 0x10;
185pub const SCRATCH_TOP_SNAPSHOT_PT_GPA_BASE_OFFSET: u64 = 0x18;
186pub const SCRATCH_TOP_SNAPSHOT_GENERATION_OFFSET: u64 = 0x20;
187pub const SCRATCH_TOP_EXN_STACK_OFFSET: u64 = 0x30;
188
189#[cfg(feature = "guest-counter")]
196pub const SCRATCH_TOP_GUEST_COUNTER_OFFSET: u64 = 0x1008;
197
198pub fn scratch_base_gpa(size: usize) -> u64 {
199 (MAX_GPA - size + 1) as u64
200}
201pub fn scratch_base_gva(size: usize) -> u64 {
202 (MAX_GVA - size + 1) as u64
203}
204
205pub use arch::min_scratch_size;