From b67656a3ace7ebf6569f90a4792d0c1b6a7b6aa3 Mon Sep 17 00:00:00 2001 From: Pavel Mores Date: Tue, 4 Mar 2025 14:05:52 +0100 Subject: [PATCH 1/2] runtime-rs: get SEV params using CPUID and store them in SevSnpDetails An implementation of cbitpos acquisition is supplied that was missing so far. We also get the physical address reduction value from the same source (CPUID Fn8000_001f function). This has been hardcoded at 1 so far, following the Go runtime example, but it's better to get it from the processor. Signed-off-by: Pavel Mores --- src/libs/kata-sys-util/src/protection.rs | 37 ++++++++++++++++--- .../hypervisor/ch-config/src/convert.rs | 10 ++++- .../crates/hypervisor/ch-config/src/lib.rs | 10 ++++- .../hypervisor/src/ch/inner_hypervisor.rs | 10 ++++- 4 files changed, 58 insertions(+), 9 deletions(-) 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 { From 0cb1535ad198ba856b983c45370aafa86c25a5d0 Mon Sep 17 00:00:00 2001 From: Pavel Mores Date: Tue, 4 Mar 2025 14:21:50 +0100 Subject: [PATCH 2/2] runtime-rs: remove hardcoding of SEV physical address reduction Previous commit enabled getting the physical address reduction from processor but just stored it for later use. This commit adds handling of the value to ProtectionDevice and enables the QEMU driver to use it. Signed-off-by: Pavel Mores --- .../src/device/driver/protection_device.rs | 1 + .../hypervisor/src/qemu/cmdline_generator.rs | 17 ++++++++++++----- .../crates/hypervisor/src/qemu/inner.rs | 2 ++ .../runtimes/virt_container/src/sandbox.rs | 2 ++ 4 files changed, 17 insertions(+), 5 deletions(-) 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, })))