Skip to content

Commit 3c184cd

Browse files
committed
[hyperlight_host] aarch64: initial KVM implementation
There are a number of features not yet supported (e.g. debugging, trace collection etc); however, this should implement a minimal coherent subset of Hyperlight functionality. Signed-off-by: Lucy Menon <168595099+syntactically@users.noreply.github.com>
1 parent 1c1aef8 commit 3c184cd

3 files changed

Lines changed: 434 additions & 34 deletions

File tree

src/hyperlight_host/src/hypervisor/hyperlight_vm/aarch64.rs

Lines changed: 154 additions & 26 deletions
Original file line numberDiff line numberDiff line change
@@ -17,15 +17,24 @@ limitations under the License.
1717
// TODO(aarch64): implement arch-specific HyperlightVm methods
1818

1919
use std::sync::Arc;
20+
use std::sync::atomic::{AtomicBool, AtomicU8, AtomicU64};
2021

2122
use super::{
2223
AccessPageTableError, CreateHyperlightVmError, DispatchGuestCallError, HyperlightVm,
2324
InitializeError,
2425
};
2526
#[cfg(gdb)]
2627
use crate::hypervisor::gdb::{DebugCommChannel, DebugMsg, DebugResponse};
27-
use crate::hypervisor::regs::CommonSpecialRegisters;
28-
use crate::hypervisor::virtual_machine::RegisterError;
28+
use crate::hypervisor::hyperlight_vm::get_guest_log_filter;
29+
use crate::hypervisor::regs::{CommonFpu, CommonRegisters, CommonSpecialRegisters};
30+
#[cfg(kvm)]
31+
use crate::hypervisor::virtual_machine::kvm::KvmVm;
32+
#[cfg(kvm)]
33+
use crate::hypervisor::virtual_machine::{HypervisorType, VmError};
34+
use crate::hypervisor::virtual_machine::{
35+
ResetVcpuError, VirtualMachine, get_available_hypervisor,
36+
};
37+
use crate::hypervisor::{InterruptHandleImpl, LinuxInterruptHandle};
2938
use crate::mem::mgr::{SandboxMemoryManager, SnapshotSharedMemory};
3039
use crate::mem::shared_mem::{GuestSharedMemory, HostSharedMemory};
3140
use crate::sandbox::SandboxConfiguration;
@@ -39,61 +48,180 @@ use crate::sandbox::uninitialized::SandboxRuntimeConfig;
3948
impl HyperlightVm {
4049
#[allow(clippy::too_many_arguments)]
4150
pub(crate) fn new(
42-
_snapshot_mem: SnapshotSharedMemory<GuestSharedMemory>,
43-
_scratch_mem: GuestSharedMemory,
44-
_root_pt_addr: u64,
45-
_entrypoint: NextAction,
46-
_rsp_gva: u64,
47-
_page_size: usize,
48-
_config: &SandboxConfiguration,
51+
snapshot_mem: SnapshotSharedMemory<GuestSharedMemory>,
52+
scratch_mem: GuestSharedMemory,
53+
root_pt_addr: u64,
54+
entrypoint: NextAction,
55+
rsp_gva: u64,
56+
page_size: usize,
57+
config: &SandboxConfiguration,
4958
#[cfg(gdb)] _gdb_conn: Option<DebugCommChannel<DebugResponse, DebugMsg>>,
5059
#[cfg(crashdump)] _rt_cfg: SandboxRuntimeConfig,
5160
#[cfg(feature = "mem_profile")] _trace_info: MemTraceInfo,
5261
) -> std::result::Result<Self, CreateHyperlightVmError> {
53-
unimplemented!("new")
62+
// TODO: support gdb on aarch64
63+
type VmType = Box<dyn VirtualMachine>;
64+
let vm: VmType = match get_available_hypervisor() {
65+
#[cfg(kvm)]
66+
Some(HypervisorType::Kvm) => Box::new(KvmVm::new().map_err(VmError::CreateVm)?),
67+
// TODO: mshv support
68+
#[cfg(mshv3)]
69+
Some(HypervisorType::Mshv) => return Err(CreateHyperlightVmError::NoHypervisorFound),
70+
None => return Err(CreateHyperlightVmError::NoHypervisorFound),
71+
};
72+
vm.set_sregs(&CommonSpecialRegisters::defaults(root_pt_addr))
73+
.map_err(VmError::Register)?;
74+
let interrupt_handle: Arc<dyn InterruptHandleImpl> = Arc::new(LinuxInterruptHandle {
75+
state: AtomicU8::new(0),
76+
tid: AtomicU64::new(unsafe { libc::pthread_self() as u64 }),
77+
retry_delay: config.get_interrupt_retry_delay(),
78+
sig_rt_min_offset: config.get_interrupt_vcpu_sigrtmin_offset(),
79+
dropped: AtomicBool::new(false),
80+
});
81+
82+
let snapshot_slot = 0u32;
83+
let scratch_slot = 1u32;
84+
let vm_can_reset_vcpu = vm.can_reset_vcpu();
85+
let mut ret = Self {
86+
vm,
87+
entrypoint,
88+
rsp_gva,
89+
interrupt_handle,
90+
page_size,
91+
92+
next_slot: scratch_slot + 1,
93+
freed_slots: Vec::new(),
94+
95+
snapshot_slot,
96+
snapshot_memory: None,
97+
scratch_slot,
98+
scratch_memory: None,
99+
100+
mmap_regions: Vec::new(),
101+
102+
vm_can_reset_vcpu,
103+
pending_tlb_flush: false,
104+
};
105+
ret.update_snapshot_mapping(snapshot_mem)?;
106+
ret.update_scratch_mapping(scratch_mem)?;
107+
Ok(ret)
54108
}
55109

56110
#[allow(clippy::too_many_arguments)]
57111
pub(crate) fn initialise(
58112
&mut self,
59-
_peb_addr: crate::mem::ptr::RawPtr,
60-
_seed: u64,
61-
_mem_mgr: &mut SandboxMemoryManager<HostSharedMemory>,
62-
_host_funcs: &Arc<std::sync::Mutex<FunctionRegistry>>,
63-
_guest_max_log_level: Option<tracing_core::LevelFilter>,
64-
#[cfg(gdb)] _dbg_mem_access_fn: Arc<
113+
peb_addr: crate::mem::ptr::RawPtr,
114+
seed: u64,
115+
mem_mgr: &mut SandboxMemoryManager<HostSharedMemory>,
116+
host_funcs: &Arc<std::sync::Mutex<FunctionRegistry>>,
117+
guest_max_log_level: Option<tracing_core::LevelFilter>,
118+
#[cfg(gdb)] dbg_mem_access_fn: Arc<
65119
std::sync::Mutex<SandboxMemoryManager<HostSharedMemory>>,
66120
>,
67121
) -> Result<(), InitializeError> {
68-
unimplemented!("initialise")
122+
let NextAction::Initialise(initialise) = self.entrypoint else {
123+
return Ok(());
124+
};
125+
let mut x: [u64; 31] = [0; 31];
126+
x[0] = peb_addr.into();
127+
x[1] = seed;
128+
x[2] = self.page_size as u64;
129+
x[3] = get_guest_log_filter(guest_max_log_level);
130+
let regs = CommonRegisters {
131+
pc: initialise,
132+
sp: self.rsp_gva,
133+
x,
134+
// start up with interrupts disabled in EL1t
135+
pstate: 0b11 << 6 | 0b100,
136+
};
137+
self.vm.set_regs(&regs)?;
138+
139+
self.run(
140+
mem_mgr,
141+
host_funcs,
142+
#[cfg(gdb)]
143+
dbg_mem_access_fn,
144+
)
145+
.map_err(InitializeError::Run)?;
146+
147+
let regs = self.vm.regs()?;
148+
if !regs.sp.is_multiple_of(16) {
149+
return Err(InitializeError::InvalidStackPointer(regs.sp));
150+
}
151+
self.rsp_gva = regs.sp;
152+
self.entrypoint = NextAction::Call(regs.x[0]);
153+
154+
Ok(())
69155
}
70156

71157
pub(crate) fn dispatch_call_from_host(
72158
&mut self,
73-
_mem_mgr: &mut SandboxMemoryManager<HostSharedMemory>,
74-
_host_funcs: &Arc<std::sync::Mutex<FunctionRegistry>>,
159+
mem_mgr: &mut SandboxMemoryManager<HostSharedMemory>,
160+
host_funcs: &Arc<std::sync::Mutex<FunctionRegistry>>,
75161
#[cfg(gdb)] _dbg_mem_access_fn: Arc<
76162
std::sync::Mutex<SandboxMemoryManager<HostSharedMemory>>,
77163
>,
78164
) -> Result<(), DispatchGuestCallError> {
79-
unimplemented!("dispatch_call_from_host")
165+
let NextAction::Call(dispatch_func_addr) = self.entrypoint else {
166+
return Err(DispatchGuestCallError::Uninitialized);
167+
};
168+
let mut regs = CommonRegisters {
169+
pc: dispatch_func_addr,
170+
sp: self.rsp_gva,
171+
// start with interrupts disabled in EL1t
172+
pstate: 0b1 << 21 | 0b11 << 6 | 0b100,
173+
..Default::default()
174+
};
175+
if self.pending_tlb_flush {
176+
regs.pc += 4;
177+
}
178+
self.vm
179+
.set_regs(&regs)
180+
.map_err(DispatchGuestCallError::SetupRegs)?;
181+
self.vm
182+
.set_fpu(&CommonFpu::default())
183+
.map_err(DispatchGuestCallError::SetupRegs)?;
184+
let result = self
185+
.run(
186+
mem_mgr,
187+
host_funcs,
188+
#[cfg(gdb)]
189+
mem_access_fn,
190+
)
191+
.map_err(DispatchGuestCallError::Run);
192+
self.pending_tlb_flush = false;
193+
result
80194
}
81195

82196
pub(crate) fn get_root_pt(&self) -> Result<u64, AccessPageTableError> {
83-
unimplemented!("get_root_pt")
197+
let sregs = self.vm.sregs()?;
198+
Ok(sregs.ttbr0_el1 & ((1 << 48) - 2))
84199
}
85200

86201
pub(crate) fn get_snapshot_sregs(
87202
&mut self,
88203
) -> Result<CommonSpecialRegisters, AccessPageTableError> {
89-
unimplemented!("get_snapshot_sregs")
204+
let x = self.vm.sregs()?;
205+
Ok(x)
90206
}
91207

92208
pub(crate) fn reset_vcpu(
93209
&mut self,
94-
_cr3: u64,
95-
_sregs: &CommonSpecialRegisters,
96-
) -> std::result::Result<(), RegisterError> {
97-
unimplemented!("reset_vcpu")
210+
cr3: u64,
211+
sregs: &CommonSpecialRegisters,
212+
) -> std::result::Result<(), ResetVcpuError> {
213+
self.pending_tlb_flush = true;
214+
debug_assert!(
215+
self.vm_can_reset_vcpu,
216+
"No fallback path for vcpu reset on aarch64"
217+
);
218+
self.vm.reset_vcpu()?;
219+
let mut sregs = *sregs;
220+
sregs.ttbr0_el1 = cr3 & ((1 << 48) - 2);
221+
222+
self.vm
223+
.set_sregs(&sregs)
224+
.map_err(ResetVcpuError::Register)?;
225+
Ok(())
98226
}
99227
}

0 commit comments

Comments
 (0)