From cb5ea05945c8bb37c9a9d4c65b926ec02cbf1ca0 Mon Sep 17 00:00:00 2001 From: Jinank Jain Date: Thu, 19 Oct 2023 03:05:02 +0000 Subject: [PATCH] hypervisor: Add support for handling #HV Doorbell Page As part of this handling there are 4 different operations: 1. Getting the hypervisor preffered doorbell page GPA. 2. Informing hypervisor about the doorbell page chosen by the guest 3. Querying the GPA of the doorbell page 4. Clearing the GPA of the doorbell page from hypervisor Signed-off-by: Jinank Jain Signed-off-by: Muminul Islam --- hypervisor/src/cpu.rs | 10 +++ hypervisor/src/mshv/mod.rs | 121 +++++++++++++++++++++++++++ hypervisor/src/mshv/snp_constants.rs | 5 ++ 3 files changed, 136 insertions(+) diff --git a/hypervisor/src/cpu.rs b/hypervisor/src/cpu.rs index a240c17e2..a67e2cb50 100644 --- a/hypervisor/src/cpu.rs +++ b/hypervisor/src/cpu.rs @@ -257,6 +257,16 @@ pub enum HypervisorCpuError { /// #[error("Failed to set TSC frequency: {0}")] SetTscKhz(#[source] anyhow::Error), + /// + /// Error reading value at given GPA + /// + #[error("Failed to read from GPA: {0}")] + GpaRead(#[source] anyhow::Error), + /// + /// Error writing value at given GPA + /// + #[error("Failed to write to GPA: {0}")] + GpaWrite(#[source] anyhow::Error), } #[derive(Debug)] diff --git a/hypervisor/src/mshv/mod.rs b/hypervisor/src/mshv/mod.rs index da1c43837..f0a883ef1 100644 --- a/hypervisor/src/mshv/mod.rs +++ b/hypervisor/src/mshv/mod.rs @@ -716,6 +716,127 @@ impl cpu::Vcpu for MshvVcpu { set_registers_64!(self.fd, arr_reg_name_value) .map_err(|e| cpu::HypervisorCpuError::SetRegister(e.into()))?; } + GHCB_INFO_NORMAL => { + let exit_code = + info.__bindgen_anon_2.__bindgen_anon_1.sw_exit_code as u32; + // SAFETY: Accessing a union element from bindgen generated bindings. + let pfn = unsafe { ghcb_msr.__bindgen_anon_2.gpa_page_number() }; + let ghcb_gpa = pfn << GHCB_INFO_BIT_WIDTH; + match exit_code { + SVM_EXITCODE_HV_DOORBELL_PAGE => { + let exit_info1 = + info.__bindgen_anon_2.__bindgen_anon_1.sw_exit_info1 as u32; + match exit_info1 { + SVM_NAE_HV_DOORBELL_PAGE_GET_PREFERRED => { + // Hypervisor does not have any preference for doorbell GPA. + let preferred_doorbell_gpa: u64 = 0xFFFFFFFFFFFFFFFF; + let mut swei2_rw_gpa_arg = + mshv_bindings::mshv_read_write_gpa { + base_gpa: ghcb_gpa + GHCB_SW_EXITINFO2_OFFSET, + byte_count: std::mem::size_of::() as u32, + ..Default::default() + }; + swei2_rw_gpa_arg.data.copy_from_slice( + &preferred_doorbell_gpa.to_le_bytes(), + ); + self.fd.gpa_write(&mut swei2_rw_gpa_arg).map_err( + |e| cpu::HypervisorCpuError::GpaWrite(e.into()), + )?; + } + SVM_NAE_HV_DOORBELL_PAGE_SET => { + let exit_info2 = info + .__bindgen_anon_2 + .__bindgen_anon_1 + .sw_exit_info2; + let mut ghcb_doorbell_gpa = + hv_x64_register_sev_hv_doorbell::default(); + // SAFETY: Accessing a union element from bindgen generated bindings. + unsafe { + ghcb_doorbell_gpa.__bindgen_anon_1.set_enabled(1); + ghcb_doorbell_gpa + .__bindgen_anon_1 + .set_page_number(exit_info2 >> PAGE_SHIFT); + } + // SAFETY: Accessing a union element from bindgen generated bindings. + let reg_names = unsafe { + [( + hv_register_name_HV_X64_REGISTER_SEV_DOORBELL_GPA, + ghcb_doorbell_gpa.as_uint64, + )] + }; + set_registers_64!(self.fd, reg_names).map_err(|e| { + cpu::HypervisorCpuError::SetRegister(e.into()) + })?; + + let mut swei2_rw_gpa_arg = + mshv_bindings::mshv_read_write_gpa { + base_gpa: ghcb_gpa + GHCB_SW_EXITINFO2_OFFSET, + byte_count: std::mem::size_of::() as u32, + ..Default::default() + }; + swei2_rw_gpa_arg.data[0..8] + .copy_from_slice(&exit_info2.to_le_bytes()); + self.fd.gpa_write(&mut swei2_rw_gpa_arg).map_err( + |e| cpu::HypervisorCpuError::GpaWrite(e.into()), + )?; + + // Clear the SW_EXIT_INFO1 register to indicate no error + let mut swei1_rw_gpa_arg = + mshv_bindings::mshv_read_write_gpa { + base_gpa: ghcb_gpa + GHCB_SW_EXITINFO1_OFFSET, + byte_count: std::mem::size_of::() as u32, + ..Default::default() + }; + self.fd.gpa_write(&mut swei1_rw_gpa_arg).map_err( + |e| cpu::HypervisorCpuError::GpaWrite(e.into()), + )?; + } + SVM_NAE_HV_DOORBELL_PAGE_QUERY => { + let mut reg_assocs = [ hv_register_assoc { + name: hv_register_name_HV_X64_REGISTER_SEV_DOORBELL_GPA, + ..Default::default() + } ]; + self.fd.get_reg(&mut reg_assocs).unwrap(); + // SAFETY: Accessing a union element from bindgen generated bindings. + let doorbell_gpa = unsafe { reg_assocs[0].value.reg64 }; + let mut swei2_rw_gpa_arg = + mshv_bindings::mshv_read_write_gpa { + base_gpa: ghcb_gpa + GHCB_SW_EXITINFO2_OFFSET, + byte_count: std::mem::size_of::() as u32, + ..Default::default() + }; + swei2_rw_gpa_arg + .data + .copy_from_slice(&doorbell_gpa.to_le_bytes()); + self.fd.gpa_write(&mut swei2_rw_gpa_arg).map_err( + |e| cpu::HypervisorCpuError::GpaWrite(e.into()), + )?; + } + SVM_NAE_HV_DOORBELL_PAGE_CLEAR => { + let mut swei2_rw_gpa_arg = + mshv_bindings::mshv_read_write_gpa { + base_gpa: ghcb_gpa + GHCB_SW_EXITINFO2_OFFSET, + byte_count: std::mem::size_of::() as u32, + ..Default::default() + }; + self.fd.gpa_write(&mut swei2_rw_gpa_arg).map_err( + |e| cpu::HypervisorCpuError::GpaWrite(e.into()), + )?; + } + _ => { + panic!( + "SVM_EXITCODE_HV_DOORBELL_PAGE: Unhandled exit code: {:0x}", + exit_info1 + ); + } + } + } + _ => panic!( + "GHCB_INFO_NORMAL: Unhandled exit code: {:0x}", + exit_code + ), + } + } _ => panic!("Unsupported VMGEXIT operation: {:0x}", ghcb_op), } diff --git a/hypervisor/src/mshv/snp_constants.rs b/hypervisor/src/mshv/snp_constants.rs index 84e240c49..50e709393 100644 --- a/hypervisor/src/mshv/snp_constants.rs +++ b/hypervisor/src/mshv/snp_constants.rs @@ -16,3 +16,8 @@ pub const ECDSA_SIG_X_COMPONENT_END: usize = pub const ECDSA_SIG_Y_COMPONENT_START: usize = ECDSA_SIG_X_COMPONENT_END; pub const ECDSA_SIG_Y_COMPONENT_END: usize = ECDSA_SIG_X_COMPONENT_END + ECDSA_SIG_Y_COMPONENT_SIZE_IN_BYTES; + +// These constants are derived from GHCB spec Sect. 2.6 Table 3 GHCB Layout +// Link: https://www.amd.com/content/dam/amd/en/documents/epyc-technical-docs/specifications/56421.pdf +pub const GHCB_SW_EXITINFO1_OFFSET: u64 = 0x398; +pub const GHCB_SW_EXITINFO2_OFFSET: u64 = 0x3A0;