diff --git a/src/libs/kata-sys-util/src/protection.rs b/src/libs/kata-sys-util/src/protection.rs index 223a971e84..15d8dff986 100644 --- a/src/libs/kata-sys-util/src/protection.rs +++ b/src/libs/kata-sys-util/src/protection.rs @@ -6,6 +6,8 @@ #[cfg(any(target_arch = "s390x", target_arch = "x86_64", target_arch = "aarch64"))] use anyhow::Result; use serde::{Deserialize, Serialize}; +#[cfg(target_arch = "x86_64")] +use std::arch::x86_64; use std::fmt; #[cfg(all(target_arch = "powerpc64", target_endian = "little"))] use std::fs; @@ -26,6 +28,7 @@ use std::fs; #[derive(Debug, Clone, PartialEq, Serialize, Deserialize)] pub struct SevSnpDetails { pub cbitpos: u32, + pub phys_addr_reduction: u32, } #[allow(dead_code)] @@ -117,17 +120,39 @@ pub fn arch_guest_protection( Ok(false) }; - let retrieve_sev_cbitpos = || -> Result { - Err(ProtectionError::CheckFailed( - "cbitpos retrieval NOT IMPLEMENTED YET".to_owned(), - )) + let retrieve_sev_params = || -> Result<(u32, u32), ProtectionError> { + // The initial checks for AMD and SEV shouldn't be necessary due to + // the context this function is currently called from, however it + // shouldn't hurt to double-check and have better logging if anything + // goes wrong. + + let fn0 = unsafe { x86_64::__cpuid(0) }; + // The values in [ ebx, edx, ecx ] spell out "AuthenticAMD" when + // interpreted byte-wise as ASCII. No need to bother here with an + // actual conversion to string though. + // See also AMD64 Architecture Programmer's Manual pg. 600 + // https://www.amd.com/content/dam/amd/en/documents/processor-tech-docs/programmer-references/24594.pdf + if fn0.ebx != 0x68747541 || fn0.edx != 0x69746e65 || fn0.ecx != 0x444d4163 { + return Err(ProtectionError::CheckFailed("Not an AMD processor".to_owned())); + } + + // AMD64 Architecture Prgrammer's Manual Fn8000_001f docs on pg. 640 + let fn8000_001f = unsafe { x86_64::__cpuid(0x8000_001f) }; + if fn8000_001f.eax & 0x10 == 0 { + return Err(ProtectionError::CheckFailed("SEV not supported".to_owned())); + } + + let cbitpos = fn8000_001f.ebx & 0b11_1111; + let phys_addr_reduction = (fn8000_001f.ebx & 0b1111_1100_0000) >> 6; + + Ok((cbitpos, phys_addr_reduction)) }; let is_snp_available = check_contents(snp_path)?; let is_sev_available = is_snp_available || check_contents(sev_path)?; if is_snp_available || is_sev_available { - let cbitpos = retrieve_sev_cbitpos()?; - let sev_snp_details = SevSnpDetails { cbitpos }; + let (cbitpos, phys_addr_reduction) = retrieve_sev_params()?; + let sev_snp_details = SevSnpDetails { cbitpos, phys_addr_reduction }; return Ok(if is_snp_available { GuestProtection::Snp(sev_snp_details) } else { diff --git a/src/runtime-rs/crates/hypervisor/ch-config/src/convert.rs b/src/runtime-rs/crates/hypervisor/ch-config/src/convert.rs index 49cdcf4b59..3552e169fe 100644 --- a/src/runtime-rs/crates/hypervisor/ch-config/src/convert.rs +++ b/src/runtime-rs/crates/hypervisor/ch-config/src/convert.rs @@ -2144,7 +2144,15 @@ mod tests { #[test] fn test_check_tdx_rootfs_settings() { - let sev_snp_details = SevSnpDetails { cbitpos: 42 }; + let tdx_details = TDXDetails { + major_version: 1, + minor_version: 0, + }; + + let sev_snp_details = SevSnpDetails { + cbitpos: 42, + phys_addr_reduction: 42, + }; #[derive(Debug)] struct TestData<'a> { diff --git a/src/runtime-rs/crates/hypervisor/ch-config/src/lib.rs b/src/runtime-rs/crates/hypervisor/ch-config/src/lib.rs index 54f74648f1..742aafa7e1 100644 --- a/src/runtime-rs/crates/hypervisor/ch-config/src/lib.rs +++ b/src/runtime-rs/crates/hypervisor/ch-config/src/lib.rs @@ -539,7 +539,15 @@ mod tests { #[test] fn test_guest_protection_is_tdx() { - let sev_snp_details = SevSnpDetails { cbitpos: 42 }; + let tdx_details = TDXDetails { + major_version: 1, + minor_version: 0, + }; + + let sev_snp_details = SevSnpDetails { + cbitpos: 42, + phys_addr_reduction: 42, + }; #[derive(Debug)] struct TestData { diff --git a/src/runtime-rs/crates/hypervisor/src/ch/inner_hypervisor.rs b/src/runtime-rs/crates/hypervisor/src/ch/inner_hypervisor.rs index 768029608d..fb02ce9c42 100644 --- a/src/runtime-rs/crates/hypervisor/src/ch/inner_hypervisor.rs +++ b/src/runtime-rs/crates/hypervisor/src/ch/inner_hypervisor.rs @@ -1110,7 +1110,15 @@ mod tests { // available_guest_protection() requires super user privs. skip_if_not_root!(); - let sev_snp_details = SevSnpDetails { cbitpos: 42 }; + let tdx_details = TDXDetails { + major_version: 1, + minor_version: 0, + }; + + let sev_snp_details = SevSnpDetails { + cbitpos: 42, + phys_addr_reduction: 42, + }; #[derive(Debug)] struct TestData { diff --git a/src/runtime-rs/crates/hypervisor/src/device/driver/protection_device.rs b/src/runtime-rs/crates/hypervisor/src/device/driver/protection_device.rs index e990cc873c..2d13d0020e 100644 --- a/src/runtime-rs/crates/hypervisor/src/device/driver/protection_device.rs +++ b/src/runtime-rs/crates/hypervisor/src/device/driver/protection_device.rs @@ -21,6 +21,7 @@ pub enum ProtectionDeviceConfig { pub struct SevSnpConfig { pub is_snp: bool, pub cbitpos: u32, + pub phys_addr_reduction: u32, pub firmware: String, pub host_data: Option, } diff --git a/src/runtime-rs/crates/hypervisor/src/qemu/cmdline_generator.rs b/src/runtime-rs/crates/hypervisor/src/qemu/cmdline_generator.rs index 87dcbea4f3..24d7005f37 100644 --- a/src/runtime-rs/crates/hypervisor/src/qemu/cmdline_generator.rs +++ b/src/runtime-rs/crates/hypervisor/src/qemu/cmdline_generator.rs @@ -1803,11 +1803,11 @@ struct ObjectSevSnpGuest { } impl ObjectSevSnpGuest { - fn new(is_snp: bool, cbitpos: u32, host_data: Option) -> Self { + fn new(is_snp: bool, cbitpos: u32, reduced_phys_bits: u32, host_data: Option) -> Self { ObjectSevSnpGuest { id: (if is_snp { "snp" } else { "sev" }).to_owned(), cbitpos, - reduced_phys_bits: 1, + reduced_phys_bits, kernel_hashes: true, host_data, is_snp, @@ -2433,8 +2433,13 @@ impl<'a> QemuCmdLine<'a> { .remove_all_by_key("rootfstype".to_string()); } - pub fn add_sev_protection_device(&mut self, cbitpos: u32, firmware: &str) { - let sev_object = ObjectSevSnpGuest::new(true, cbitpos, None); + pub fn add_sev_protection_device( + &mut self, + cbitpos: u32, + phys_addr_reduction: u32, + firmware: &str, + ) { + let sev_object = ObjectSevSnpGuest::new(false, cbitpos, phys_addr_reduction, None); self.devices.push(Box::new(sev_object)); self.devices.push(Box::new(Bios::new(firmware.to_owned()))); @@ -2447,10 +2452,12 @@ impl<'a> QemuCmdLine<'a> { pub fn add_sev_snp_protection_device( &mut self, cbitpos: u32, + phys_addr_reduction: u32, firmware: &str, host_data: &Option, ) { - let sev_snp_object = ObjectSevSnpGuest::new(true, cbitpos, host_data.clone()); + let sev_snp_object = + ObjectSevSnpGuest::new(true, cbitpos, phys_addr_reduction, host_data.clone()); self.devices.push(Box::new(sev_snp_object)); self.devices.push(Box::new(Bios::new(firmware.to_owned()))); diff --git a/src/runtime-rs/crates/hypervisor/src/qemu/inner.rs b/src/runtime-rs/crates/hypervisor/src/qemu/inner.rs index 7e4cc50cab..a6f9799eb3 100644 --- a/src/runtime-rs/crates/hypervisor/src/qemu/inner.rs +++ b/src/runtime-rs/crates/hypervisor/src/qemu/inner.rs @@ -136,12 +136,14 @@ impl QemuInner { if sev_snp_cfg.is_snp { cmdline.add_sev_snp_protection_device( sev_snp_cfg.cbitpos, + sev_snp_cfg.phys_addr_reduction, &sev_snp_cfg.firmware, &sev_snp_cfg.host_data, ) } else { cmdline.add_sev_protection_device( sev_snp_cfg.cbitpos, + sev_snp_cfg.phys_addr_reduction, &sev_snp_cfg.firmware, ) } diff --git a/src/runtime-rs/crates/runtimes/virt_container/src/sandbox.rs b/src/runtime-rs/crates/runtimes/virt_container/src/sandbox.rs index 801718e734..870d21f4c5 100644 --- a/src/runtime-rs/crates/runtimes/virt_container/src/sandbox.rs +++ b/src/runtime-rs/crates/runtimes/virt_container/src/sandbox.rs @@ -393,6 +393,7 @@ impl VirtSandbox { Ok(Some(ProtectionDeviceConfig::SevSnp(SevSnpConfig { is_snp: false, cbitpos: details.cbitpos, + phys_addr_reduction: details.phys_addr_reduction, firmware: hypervisor_config.boot_info.firmware.clone(), host_data: None, }))) @@ -413,6 +414,7 @@ impl VirtSandbox { Ok(Some(ProtectionDeviceConfig::SevSnp(SevSnpConfig { is_snp, cbitpos: details.cbitpos, + phys_addr_reduction: details.phys_addr_reduction, firmware: hypervisor_config.boot_info.firmware.clone(), host_data: init_data, })))