mirror of
https://github.com/cloud-hypervisor/cloud-hypervisor.git
synced 2026-08-05 02:19:16 +00:00
hypervisor: handle VcpuExit::MemoryFault for AP boot page conversions
During SNP boot all guest RAM is initially marked KVM_MEMORY_ATTRIBUTE_PRIVATE. Pages imported via SNP_LAUNCH_UPDATE are properly accepted by the guest, but generic RAM pages (e.g. the AP trampoline at GPA 0xD000) are not. When stage0 on the BSP starts secondary vCPUs via x2APIC, the APs try to execute from the trampoline page through the shared mapping while KVM still has it marked private, causing a KVM_EXIT_MEMORY_FAULT (flags=KVM_MEMORY_EXIT_FLAG_PRIVATE) that previously fell through to the catch-all error, killing the VM. Handle VcpuExit::MemoryFault by toggling the page's memory attribute between private and shared based on the exit flags, allowing the vCPU to retry the access. Signed-off-by: Ruben Hakobyan <hruben@meta.com>
This commit is contained in:
committed by
Rob Bradford
parent
4a0cfa02de
commit
b5ddcdc74a
@@ -2354,6 +2354,38 @@ impl cpu::Vcpu for KvmVcpu {
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(feature = "sev_snp")]
|
||||
VcpuExit::MemoryFault { flags, gpa, size } => {
|
||||
debug!("VcpuExit::MemoryFault: flags={flags:#x}, gpa={gpa:#x}, size={size:#x}");
|
||||
|
||||
const KVM_MEMORY_EXIT_FLAG_PRIVATE: u64 =
|
||||
kvm_bindings::KVM_MEMORY_EXIT_FLAG_PRIVATE as u64;
|
||||
|
||||
if flags & !KVM_MEMORY_EXIT_FLAG_PRIVATE != 0 {
|
||||
return Err(cpu::HypervisorCpuError::RunVcpu(anyhow!(
|
||||
"VcpuExit::MemoryFault: unknown flags {flags:#x}"
|
||||
)));
|
||||
}
|
||||
|
||||
let attributes = if flags & KVM_MEMORY_EXIT_FLAG_PRIVATE != 0 {
|
||||
KVM_MEMORY_ATTRIBUTE_PRIVATE as u64
|
||||
} else {
|
||||
// the only attribute available is private, o/w 0
|
||||
// https://docs.kernel.org/virt/kvm/api.html#kvm-set-memory-attributes
|
||||
0u64
|
||||
};
|
||||
|
||||
self.vm_fd
|
||||
.set_memory_attributes(kvm_memory_attributes {
|
||||
address: gpa,
|
||||
size,
|
||||
attributes,
|
||||
flags: 0,
|
||||
})
|
||||
.map(|_| cpu::VmExit::Ignore)
|
||||
.map_err(|e| cpu::HypervisorCpuError::RunVcpu(e.into()))
|
||||
}
|
||||
|
||||
r => Err(cpu::HypervisorCpuError::RunVcpu(anyhow!(
|
||||
"Unexpected exit reason on vcpu run: {r:?}"
|
||||
))),
|
||||
|
||||
Reference in New Issue
Block a user