From 7975207e0f9fcfbb5a75f28b50a36ce03b666861 Mon Sep 17 00:00:00 2001 From: Jinank Jain Date: Thu, 19 Oct 2023 10:23:28 +0000 Subject: [PATCH] hypervisor: Add support for legacy I/O port emulation Legacy port emulation requires reading RAX register from GHCB page for SEV-SNP guest. This is the major difference between a regular guest and SEV-SNP enabled guest. Signed-off-by: Jinank Jain Signed-off-by: Muminul Islam --- hypervisor/src/mshv/mod.rs | 72 ++++++++++++++++++++++++++++ hypervisor/src/mshv/snp_constants.rs | 1 + 2 files changed, 73 insertions(+) diff --git a/hypervisor/src/mshv/mod.rs b/hypervisor/src/mshv/mod.rs index 92ac370a8..f6fb1d83e 100644 --- a/hypervisor/src/mshv/mod.rs +++ b/hypervisor/src/mshv/mod.rs @@ -848,6 +848,78 @@ impl cpu::Vcpu for MshvVcpu { .gpa_write(&mut swei2_rw_gpa_arg) .map_err(|e| cpu::HypervisorCpuError::GpaWrite(e.into()))?; } + SVM_EXITCODE_IOIO_PROT => { + let exit_info1 = + info.__bindgen_anon_2.__bindgen_anon_1.sw_exit_info1 as u32; + let port_info = hv_sev_vmgexit_port_info { + as_uint32: exit_info1, + }; + + let port = + // SAFETY: Accessing a union element from bindgen generated bindings. + unsafe { port_info.__bindgen_anon_1.intercepted_port() }; + let mut len = 4; + // SAFETY: Accessing a union element from bindgen generated bindings. + unsafe { + if port_info.__bindgen_anon_1.operand_size_16bit() == 1 { + len = 2; + } else if port_info.__bindgen_anon_1.operand_size_8bit() + == 1 + { + len = 1; + } + } + let is_write = + // SAFETY: Accessing a union element from bindgen generated bindings. + unsafe { port_info.__bindgen_anon_1.access_type() == 0 }; + let mut rax_rw_gpa_arg: mshv_read_write_gpa = + mshv_bindings::mshv_read_write_gpa { + base_gpa: ghcb_gpa + GHCB_RAX_OFFSET, + byte_count: std::mem::size_of::() as u32, + ..Default::default() + }; + self.fd + .gpa_read(&mut rax_rw_gpa_arg) + .map_err(|e| cpu::HypervisorCpuError::GpaRead(e.into()))?; + + if is_write { + if let Some(vm_ops) = &self.vm_ops { + vm_ops + .pio_write( + port.into(), + &rax_rw_gpa_arg.data[0..len], + ) + .map_err(|e| { + cpu::HypervisorCpuError::RunVcpu(e.into()) + })?; + } + } else { + if let Some(vm_ops) = &self.vm_ops { + vm_ops + .pio_read( + port.into(), + &mut rax_rw_gpa_arg.data[0..len], + ) + .map_err(|e| { + cpu::HypervisorCpuError::RunVcpu(e.into()) + })?; + } + + self.fd.gpa_write(&mut rax_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()))?; + } _ => panic!( "GHCB_INFO_NORMAL: Unhandled exit code: {:0x}", exit_code diff --git a/hypervisor/src/mshv/snp_constants.rs b/hypervisor/src/mshv/snp_constants.rs index 50e709393..307326ddd 100644 --- a/hypervisor/src/mshv/snp_constants.rs +++ b/hypervisor/src/mshv/snp_constants.rs @@ -19,5 +19,6 @@ pub const ECDSA_SIG_Y_COMPONENT_END: usize = // 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_RAX_OFFSET: u64 = 0x01F8; pub const GHCB_SW_EXITINFO1_OFFSET: u64 = 0x398; pub const GHCB_SW_EXITINFO2_OFFSET: u64 = 0x3A0;