From e7d3fb9fcb2828d2bde3a8dee8e89ad650f6327b Mon Sep 17 00:00:00 2001 From: Jon Lange Date: Fri, 21 Jun 2024 14:53:30 -0700 Subject: [PATCH] sev/ghcb: reorder #HV and guest APIC handling during guest entry Handling #HV events prior to guest entry must be before after the guest APIC state is evaluated. Otherwise, the host can deliver a guest interrupt which will be observed by the #HV handler but not scheduled for guest delivery, which will block further notification of guest interrupts. Signed-off-by: Jon Lange --- kernel/src/requests.rs | 9 +++++++++ kernel/src/sev/ghcb.rs | 8 +------- 2 files changed, 10 insertions(+), 7 deletions(-) diff --git a/kernel/src/requests.rs b/kernel/src/requests.rs index 9b797e7eb..e3c382c79 100644 --- a/kernel/src/requests.rs +++ b/kernel/src/requests.rs @@ -134,6 +134,15 @@ pub fn request_loop() { // the guest to execute. When halting, assume that the hypervisor // will schedule the guest VMPL on its own. if update_mappings().is_ok() { + // Process any pending #HV events before leaving the SVSM. This + // must be done before updating guest APIC state so that any + // additional guest APIC updates generated by the host will block + // the VMPL transition and permit reevaluation of guest APIC + // state. + if let Some(hv_doorbell) = this_cpu().hv_doorbell() { + hv_doorbell.process_pending_events(); + } + // Make VMSA runnable again by setting EFER.SVME. This requires a // separate scope so the CPU reference does not outlive the use of // the VMSA reference. diff --git a/kernel/src/sev/ghcb.rs b/kernel/src/sev/ghcb.rs index a838e0513..58bde7eba 100644 --- a/kernel/src/sev/ghcb.rs +++ b/kernel/src/sev/ghcb.rs @@ -693,13 +693,7 @@ pub fn switch_to_vmpl(vmpl: u32) { // correctly block the VMPL switch so that events can be processed. let hv_doorbell = this_cpu().hv_doorbell(); let ptr = match hv_doorbell { - Some(doorbell) => { - // Process any pending #HV events before leaving the SVSM. No event - // can cancel the request to enter the guest VMPL, so proceed with - // guest entry once events have been handled. - doorbell.process_pending_events(); - ptr::from_ref(doorbell) - } + Some(doorbell) => ptr::from_ref(doorbell), None => ptr::null(), }; unsafe {