Skip to content

Commit 0bb7ce7

Browse files
committed
don't let scratch base overlap with kvm apic page
Signed-off-by: Ludvig Liljenberg <4257730+ludfjig@users.noreply.github.com>
1 parent b45b363 commit 0bb7ce7

1 file changed

Lines changed: 66 additions & 1 deletion

File tree

src/hyperlight_common/src/layout.rs

Lines changed: 66 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -48,12 +48,77 @@ pub const SCRATCH_TOP_EXN_STACK_OFFSET: u64 = 0x20;
4848
#[cfg(feature = "nanvix-unstable")]
4949
pub const SCRATCH_TOP_GUEST_COUNTER_OFFSET: u64 = 0x1008;
5050

51+
/// GPA of the LAPIC access page that KVM reserves when hw-interrupts
52+
/// are enabled. Only relevant for i686 guests in practice,
53+
/// as amd64/aarch64 MAX_GPA is large enough that scratch
54+
/// never reaches this address.
55+
const KVM_APIC_PAGE_GPA: u64 = 0xFEE0_0000;
56+
5157
pub fn scratch_base_gpa(size: usize) -> u64 {
52-
(MAX_GPA - size + 1) as u64
58+
let base = (MAX_GPA - size + 1) as u64;
59+
if base <= KVM_APIC_PAGE_GPA {
60+
// Scratch would overlap the LAPIC access page at 0xFEE00000.
61+
// Place the entire region just below the APIC page.
62+
KVM_APIC_PAGE_GPA - size as u64
63+
} else {
64+
base
65+
}
5366
}
5467
pub fn scratch_base_gva(size: usize) -> u64 {
5568
(MAX_GVA - size + 1) as u64
5669
}
5770

5871
/// Compute the minimum scratch region size needed for a sandbox.
5972
pub use arch::min_scratch_size;
73+
74+
#[cfg(test)]
75+
mod tests {
76+
use super::*;
77+
78+
#[test]
79+
fn small_scratch_not_relocated() {
80+
// Default scratch (288KB) should not be relocated on any arch.
81+
let size = 0x48000;
82+
let base = scratch_base_gpa(size);
83+
assert_eq!(base, (MAX_GPA - size + 1) as u64);
84+
}
85+
86+
#[test]
87+
fn scratch_avoids_apic_page() {
88+
// For any scratch size, the region [base, base+size) must not
89+
// contain the APIC page at 0xFEE00000.
90+
for &size in &[0x48000, 0x100000, 0x2000000, 0x6000000] {
91+
let base = scratch_base_gpa(size);
92+
let end = base + size as u64;
93+
let apic_start = KVM_APIC_PAGE_GPA;
94+
let apic_end = KVM_APIC_PAGE_GPA + 0x1000;
95+
let overlaps = base < apic_end && end > apic_start;
96+
assert!(
97+
!overlaps,
98+
"scratch [base={:#x}, end={:#x}) overlaps APIC [{:#x}, {:#x}) for size={:#x}",
99+
base, end, apic_start, apic_end, size,
100+
);
101+
}
102+
}
103+
104+
/// On i686, MAX_GPA is 0xFFFFFFFF, so large scratch regions would
105+
/// normally overlap the APIC page. Verify relocation works.
106+
#[cfg(feature = "nanvix-unstable")]
107+
#[test]
108+
fn i686_large_scratch_relocated() {
109+
let size = 0x2000000; // 32MB
110+
let base = scratch_base_gpa(size);
111+
assert_eq!(base, KVM_APIC_PAGE_GPA - size as u64);
112+
assert!(base + size as u64 <= KVM_APIC_PAGE_GPA);
113+
}
114+
115+
#[cfg(feature = "nanvix-unstable")]
116+
#[test]
117+
fn i686_scratch_just_fitting_not_relocated() {
118+
// Scratch of ~18MB starts at 0xFEE00001, just above the APIC page.
119+
let size = 0x11FFFFF;
120+
let base = scratch_base_gpa(size);
121+
assert_eq!(base, (MAX_GPA - size + 1) as u64);
122+
assert!(base > KVM_APIC_PAGE_GPA);
123+
}
124+
}

0 commit comments

Comments
 (0)