From f408d9463afbcc8901dfd55468f6f8b61841d5ad Mon Sep 17 00:00:00 2001 From: Roman Penyaev Date: Fri, 8 May 2026 13:24:10 +0200 Subject: [PATCH 1/2] measurement: add EPYC-Turin vCPU type support Adds EpycTurin, EpycTurinV1, EpycTurinV2 variants to CpuType so callers:(notably snpguest's "generate measurement --vcpu-type EPYC-Turin") can compute launch digests for guests booted with QEMU's EPYC-Turin CPU model. Without this, snpguest fails with: ERROR: Invalid VCPU type value provided: EPYC-Turin The CPUID family / model / stepping values used by sig() were taken verbatim from QEMU's CPU definition at target/i386/cpu.c (entry .name = "EPYC-Turin"): .family = 26, .model = 0, .stepping = 0 Two version variants exist in the same QEMU table: .versions = (X86CPUVersionDefinition[]) { { .version = 1 }, { .version = 2, ... }, } so EpycTurinV1 and EpycTurinV2 are added alongside the base EpycTurin; all three share the same CPU signature cpu_sig(26, 0, 0), matching how the existing Milan / Genoa entries are structured. Tested end-to-end on a real EPYC-Turin host: snpguest generate measurement, fetch ca / vcek, and verify attestation (TCB+FMC, signature, measurement match) all succeed against a V5 attestation report. Signed-off-by: Roman Penyaev --- src/measurement/vcpu_types.rs | 19 +++++++++++++++++++ 1 file changed, 19 insertions(+) diff --git a/src/measurement/vcpu_types.rs b/src/measurement/vcpu_types.rs index 4864080b..56d8f0e8 100644 --- a/src/measurement/vcpu_types.rs +++ b/src/measurement/vcpu_types.rs @@ -38,6 +38,12 @@ pub enum CpuType { EpycGenoa, /// EPYC GENOA V1 EpycGenoaV1, + /// EPYC TURIN + EpycTurin, + /// EPYC TURIN V1 + EpycTurinV1, + /// EPYC TURIN V2 + EpycTurinV2, } impl TryFrom for CpuType { @@ -59,6 +65,9 @@ impl TryFrom for CpuType { 12 => Ok(CpuType::EpycMilanV2), 13 => Ok(CpuType::EpycGenoa), 14 => Ok(CpuType::EpycGenoaV1), + 15 => Ok(CpuType::EpycTurin), + 16 => Ok(CpuType::EpycTurinV1), + 17 => Ok(CpuType::EpycTurinV2), _ => Err(MeasurementError::InvalidVcpuTypeError(value.to_string())), } } @@ -73,6 +82,7 @@ impl TryFrom for CpuType { sig if sig == cpu_sig(23, 49, 0) => Ok(CpuType::EpycRome), sig if sig == cpu_sig(25, 1, 1) => Ok(CpuType::EpycMilan), sig if sig == cpu_sig(25, 17, 0) => Ok(CpuType::EpycGenoa), + sig if sig == cpu_sig(26, 0, 0) => Ok(CpuType::EpycTurin), _ => Err(MeasurementError::InvalidVcpuSignatureError( value.to_string(), )), @@ -99,6 +109,9 @@ impl CpuType { CpuType::EpycMilanV2 => cpu_sig(25, 1, 1), CpuType::EpycGenoa => cpu_sig(25, 17, 0), CpuType::EpycGenoaV1 => cpu_sig(25, 17, 0), + CpuType::EpycTurin => cpu_sig(26, 0, 0), + CpuType::EpycTurinV1 => cpu_sig(26, 0, 0), + CpuType::EpycTurinV2 => cpu_sig(26, 0, 0), } } } @@ -121,6 +134,9 @@ impl fmt::Display for CpuType { CpuType::EpycMilanV2 => write!(f, "EPYC-Milan-v2"), CpuType::EpycGenoa => write!(f, "EPYC-Genoa"), CpuType::EpycGenoaV1 => write!(f, "EPYC-Genoa-v1"), + CpuType::EpycTurin => write!(f, "EPYC-Turin"), + CpuType::EpycTurinV1 => write!(f, "EPYC-Turin-v1"), + CpuType::EpycTurinV2 => write!(f, "EPYC-Turin-v2"), } } } @@ -145,6 +161,9 @@ impl TryFrom<&str> for CpuType { "epyc-milan-v2" => Ok(CpuType::EpycMilanV2), "epyc-genoa" => Ok(CpuType::EpycGenoa), "epyc-genoa-v1" => Ok(CpuType::EpycGenoaV1), + "epyc-turin" => Ok(CpuType::EpycTurin), + "epyc-turin-v1" => Ok(CpuType::EpycTurinV1), + "epyc-turin-v2" => Ok(CpuType::EpycTurinV2), _ => Err(MeasurementError::InvalidVcpuTypeError(value.to_string())), } } From b28fcb71ed4d89edfb84da561ac54181d2df9313 Mon Sep 17 00:00:00 2001 From: Roman Penyaev Date: Fri, 8 May 2026 13:27:08 +0200 Subject: [PATCH 2/2] sev: silence warnings under snp-only feature build Building with default-features=false, features=["openssl","snp"] (no "sev" feature) triggers five warnings. Fix each at the source. error.rs: "use openssl::error::ErrorStack" on cfg(all(openssl, sev)). firmware/host/types/snp.rs: replace unreachable "_" arms in TcbVersion's Encoder/Decoder. launch/linux/snp.rs: tag legacy "pub struct Init" (KVM_SEV_INIT payload, only consumed via the "sev" feature path) with #[allow(dead_code)] so it compiles cleanly under snp-only. Signed-off-by: Roman Penyaev --- src/error.rs | 2 +- src/firmware/host/types/snp.rs | 6 ++++-- src/launch/linux/sev.rs | 2 ++ src/launch/linux/snp.rs | 1 + src/lib.rs | 1 + src/util/parser_helper/mod.rs | 2 ++ src/util/parser_helper/read_ext.rs | 1 + src/util/parser_helper/write_ext.rs | 1 + 8 files changed, 13 insertions(+), 3 deletions(-) diff --git a/src/error.rs b/src/error.rs index 072b097f..b365397c 100644 --- a/src/error.rs +++ b/src/error.rs @@ -1,6 +1,6 @@ // SPDX-License-Identifier: Apache-2.0 -#[cfg(feature = "openssl")] +#[cfg(all(feature = "openssl", feature = "sev"))] use openssl::error::ErrorStack; use std::{ array::TryFromSliceError, diff --git a/src/firmware/host/types/snp.rs b/src/firmware/host/types/snp.rs index 1f442c9f..13b17fb1 100644 --- a/src/firmware/host/types/snp.rs +++ b/src/firmware/host/types/snp.rs @@ -527,7 +527,8 @@ impl Encoder for TcbVersion { let buffer = match generation { Generation::Milan | Generation::Genoa => self.to_legacy_bytes(), Generation::Turin | Generation::Venice => self.to_turin_bytes(), - _ => { + #[cfg(feature = "sev")] + Generation::Naples | Generation::Rome => { return Err(std::io::Error::new( std::io::ErrorKind::Unsupported, "Unsupported Processor Generation for TCB writing", @@ -548,7 +549,8 @@ impl Decoder for TcbVersion { Generation::Turin | Generation::Venice => { Ok(TcbVersion::from_turin_bytes(&reader.read_bytes()?)) } - _ => Err(std::io::Error::new( + #[cfg(feature = "sev")] + Generation::Naples | Generation::Rome => Err(std::io::Error::new( std::io::ErrorKind::Unsupported, "Unsupported Processor Generation for TCB parsing", )), diff --git a/src/launch/linux/sev.rs b/src/launch/linux/sev.rs index 283405c7..7ed288ed 100644 --- a/src/launch/linux/sev.rs +++ b/src/launch/linux/sev.rs @@ -11,10 +11,12 @@ use std::{ /// Initialize the SEV platform context. #[repr(C)] +#[allow(dead_code)] pub struct Init; /// Initialize the SEV-ES platform context. #[repr(C)] +#[allow(dead_code)] pub struct EsInit; #[derive(Clone, Copy)] diff --git a/src/launch/linux/snp.rs b/src/launch/linux/snp.rs index 492d7358..61d552a3 100644 --- a/src/launch/linux/snp.rs +++ b/src/launch/linux/snp.rs @@ -9,6 +9,7 @@ use std::marker::PhantomData; /// Initialize the SEV-SNP platform in KVM. #[derive(Default)] #[repr(C, packed)] +#[allow(dead_code)] pub struct Init { /// Reserved space, must be always set to 0 when issuing the ioctl. flags: u64, diff --git a/src/lib.rs b/src/lib.rs index cfe2a18f..a5c8fb2a 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -111,6 +111,7 @@ pub mod error; /// Module for Encoding and Decoding types. pub mod parser; +#[cfg(feature = "sev")] use crate::parser::Decoder; #[cfg(all(feature = "sev", feature = "dangerous_hw_tests"))] diff --git a/src/util/parser_helper/mod.rs b/src/util/parser_helper/mod.rs index 11fe04b9..acac1dea 100644 --- a/src/util/parser_helper/mod.rs +++ b/src/util/parser_helper/mod.rs @@ -4,6 +4,8 @@ mod read_ext; mod write_ext; +#[allow(unused_imports)] pub(crate) use read_ext::ReadExt; +#[allow(unused_imports)] pub(crate) use write_ext::WriteExt; diff --git a/src/util/parser_helper/read_ext.rs b/src/util/parser_helper/read_ext.rs index dc7e4fcb..72a94131 100644 --- a/src/util/parser_helper/read_ext.rs +++ b/src/util/parser_helper/read_ext.rs @@ -3,6 +3,7 @@ use crate::parser::Decoder; use std::io::Read; +#[allow(dead_code)] pub trait ReadExt: Read { /// Convenience: read a value with unit params. fn read_bytes(&mut self) -> Result diff --git a/src/util/parser_helper/write_ext.rs b/src/util/parser_helper/write_ext.rs index de6a1ffc..f249bbec 100644 --- a/src/util/parser_helper/write_ext.rs +++ b/src/util/parser_helper/write_ext.rs @@ -2,6 +2,7 @@ use crate::parser::Encoder; use std::io::Write; +#[allow(dead_code)] pub trait WriteExt: Write { /// Write a value using its Encoder implementation and the provided params fn write_bytes(&mut self, value: T, params: P) -> Result<(), std::io::Error>