From 486c61da5e21da7e35b41c0cc104226944ea2f61 Mon Sep 17 00:00:00 2001 From: Tom Dohrmann Date: Wed, 28 Aug 2024 09:07:41 +0200 Subject: [PATCH] hypervisor: mshv: add helpers for reading and writing guest memory Signed-off-by: Tom Dohrmann --- hypervisor/src/mshv/mod.rs | 195 +++++++++++++++---------------------- 1 file changed, 79 insertions(+), 116 deletions(-) diff --git a/hypervisor/src/mshv/mod.rs b/hypervisor/src/mshv/mod.rs index f93bef039..0d8ce8aed 100644 --- a/hypervisor/src/mshv/mod.rs +++ b/hypervisor/src/mshv/mod.rs @@ -908,17 +908,9 @@ impl cpu::Vcpu for MshvVcpu { 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( + self.gpa_write( + ghcb_gpa + GHCB_SW_EXITINFO2_OFFSET, &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 => { @@ -946,16 +938,9 @@ impl cpu::Vcpu for MshvVcpu { 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()), + self.gpa_write( + ghcb_gpa + GHCB_SW_EXITINFO2_OFFSET, + &exit_info2.to_le_bytes(), )?; // Clear the SW_EXIT_INFO1 register to indicate no error @@ -969,31 +954,19 @@ impl cpu::Vcpu for MshvVcpu { 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()), + + self.gpa_write( + ghcb_gpa + GHCB_SW_EXITINFO2_OFFSET, + &doorbell_gpa.to_le_bytes(), )?; // Clear the SW_EXIT_INFO1 register to indicate no error self.clear_swexit_info1(ghcb_gpa)?; } 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()), + self.gpa_write( + ghcb_gpa + GHCB_SW_EXITINFO2_OFFSET, + &[0; 8], )?; } _ => { @@ -1011,16 +984,10 @@ impl cpu::Vcpu for MshvVcpu { // 0x6 means `The NAE event was not valid` // Reference: GHCB Spec, page 42 let value: u64 = 0x6; - 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(&value.to_le_bytes()); - self.fd - .gpa_write(&mut swei2_rw_gpa_arg) - .map_err(|e| cpu::HypervisorCpuError::GpaWrite(e.into()))?; + self.gpa_write( + ghcb_gpa + GHCB_SW_EXITINFO2_OFFSET, + &value.to_le_bytes(), + )?; } SVM_EXITCODE_IOIO_PROT => { let exit_info1 = @@ -1046,42 +1013,26 @@ impl cpu::Vcpu for MshvVcpu { 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()))?; + + let mut data = [0; 8]; + self.gpa_read(ghcb_gpa + GHCB_RAX_OFFSET, &mut data)?; 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()) - })?; + vm_ops.pio_write(port.into(), &data[..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], - ) + .pio_read(port.into(), &mut data[..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()) - })?; + self.gpa_write(ghcb_gpa + GHCB_RAX_OFFSET, &data)?; } // Clear the SW_EXIT_INFO1 register to indicate no error @@ -1099,21 +1050,12 @@ impl cpu::Vcpu for MshvVcpu { let mut data: Vec = vec![0; data_len]; if let Some(vm_ops) = &self.vm_ops { - vm_ops.mmio_read(src_gpa, &mut data[0..data_len]).map_err( - |e| cpu::HypervisorCpuError::RunVcpu(e.into()), - )?; + vm_ops.mmio_read(src_gpa, &mut data).map_err(|e| { + cpu::HypervisorCpuError::RunVcpu(e.into()) + })?; } - let mut arg: mshv_read_write_gpa = - mshv_bindings::mshv_read_write_gpa { - base_gpa: dst_gpa, - byte_count: data_len as u32, - ..Default::default() - }; - arg.data[0..data_len].copy_from_slice(&data); - self.fd - .gpa_write(&mut arg) - .map_err(|e| cpu::HypervisorCpuError::GpaWrite(e.into()))?; + self.gpa_write(dst_gpa, &data)?; // Clear the SW_EXIT_INFO1 register to indicate no error self.clear_swexit_info1(ghcb_gpa)?; @@ -1127,23 +1069,14 @@ impl cpu::Vcpu for MshvVcpu { as usize; // Sanity check to make sure data len is within supported range. assert!(data_len <= 0x8); - let mut arg: mshv_read_write_gpa = - mshv_bindings::mshv_read_write_gpa { - base_gpa: src_gpa, - byte_count: data_len as u32, - ..Default::default() - }; - self.fd - .gpa_read(&mut arg) - .map_err(|e| cpu::HypervisorCpuError::GpaRead(e.into()))?; + let mut data = vec![0; data_len]; + self.gpa_read(src_gpa, &mut data)?; if let Some(vm_ops) = &self.vm_ops { - vm_ops - .mmio_write(dst_gpa, &arg.data[0..data_len]) - .map_err(|e| { - cpu::HypervisorCpuError::RunVcpu(e.into()) - })?; + vm_ops.mmio_write(dst_gpa, &data).map_err(|e| { + cpu::HypervisorCpuError::RunVcpu(e.into()) + })?; } // Clear the SW_EXIT_INFO1 register to indicate no error @@ -1166,14 +1099,7 @@ impl cpu::Vcpu for MshvVcpu { req_gpa, rsp_gpa ); - 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()))?; + self.gpa_write(ghcb_gpa + GHCB_SW_EXITINFO2_OFFSET, &[0; 8])?; } SVM_EXITCODE_SNP_AP_CREATION => { let vmsa_gpa = @@ -1577,17 +1503,54 @@ impl MshvVcpu { ghcb_gpa: u64, ) -> std::result::Result { // 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()))?; + self.gpa_write(ghcb_gpa + GHCB_SW_EXITINFO1_OFFSET, &[0; 4])?; Ok(cpu::VmExit::Ignore) } + + #[cfg(feature = "sev_snp")] + fn gpa_read(&self, gpa: u64, data: &mut [u8]) -> cpu::Result<()> { + for (gpa, chunk) in (gpa..) + .step_by(HV_READ_WRITE_GPA_MAX_SIZE as usize) + .zip(data.chunks_mut(HV_READ_WRITE_GPA_MAX_SIZE as usize)) + { + let mut rw_gpa_arg = mshv_bindings::mshv_read_write_gpa { + base_gpa: gpa, + byte_count: chunk.len() as u32, + ..Default::default() + }; + self.fd + .gpa_read(&mut rw_gpa_arg) + .map_err(|e| cpu::HypervisorCpuError::GpaRead(e.into()))?; + + chunk.copy_from_slice(&rw_gpa_arg.data[..chunk.len()]); + } + + Ok(()) + } + + #[cfg(feature = "sev_snp")] + fn gpa_write(&self, gpa: u64, data: &[u8]) -> cpu::Result<()> { + for (gpa, chunk) in (gpa..) + .step_by(HV_READ_WRITE_GPA_MAX_SIZE as usize) + .zip(data.chunks(HV_READ_WRITE_GPA_MAX_SIZE as usize)) + { + let mut data = [0; HV_READ_WRITE_GPA_MAX_SIZE as usize]; + data[..chunk.len()].copy_from_slice(chunk); + + let mut rw_gpa_arg = mshv_bindings::mshv_read_write_gpa { + base_gpa: gpa, + byte_count: chunk.len() as u32, + data, + ..Default::default() + }; + self.fd + .gpa_write(&mut rw_gpa_arg) + .map_err(|e| cpu::HypervisorCpuError::GpaWrite(e.into()))?; + } + + Ok(()) + } } /// Wrapper over Mshv VM ioctls.