diff --git a/src/cpu-template-helper/src/template/dump/x86_64.rs b/src/cpu-template-helper/src/template/dump/x86_64.rs index eaa2553a658..02e06a0a69a 100644 --- a/src/cpu-template-helper/src/template/dump/x86_64.rs +++ b/src/cpu-template-helper/src/template/dump/x86_64.rs @@ -8,7 +8,7 @@ use vmm::arch::x86_64::generated::msr_index::*; use vmm::arch::x86_64::msr::MsrRange; use vmm::cpu_config::templates::{CpuConfiguration, CustomCpuTemplate, RegisterValueFilter}; use vmm::cpu_config::x86_64::cpuid::common::get_vendor_id_from_host; -use vmm::cpu_config::x86_64::cpuid::{Cpuid, VENDOR_ID_AMD}; +use vmm::cpu_config::x86_64::cpuid::{Cpuid, VENDOR_ID_AMD, VENDOR_ID_HYGON}; use vmm::cpu_config::x86_64::custom_cpu_template::{ CpuidLeafModifier, CpuidRegister, CpuidRegisterModifier, RegisterModifier, }; @@ -49,9 +49,11 @@ fn msrs_to_modifier(msrs: &BTreeMap) -> Vec { .iter() .map(|(index, value)| msr_modifier!(*index, *value)) .collect(); + let vendor = get_vendor_id_from_host().unwrap(); msrs.retain(|modifier| !should_exclude_msr(modifier.addr)); - if &get_vendor_id_from_host().unwrap() == VENDOR_ID_AMD { + + if matches!(&vendor, VENDOR_ID_AMD | VENDOR_ID_HYGON) { msrs.retain(|modifier| !should_exclude_msr_amd(modifier.addr)); } @@ -216,7 +218,9 @@ mod tests { msr_modifier!(0x3, 0x0000_0000_ffff_ffff), msr_modifier!(0x5, 0xffff_ffff_0000_0000), ]; - if &get_vendor_id_from_host().unwrap() != VENDOR_ID_AMD { + let vendor = get_vendor_id_from_host().unwrap(); + + if !matches!(&vendor, VENDOR_ID_AMD | VENDOR_ID_HYGON) { MSR_EXCLUSION_LIST_AMD.iter().for_each(|range| { (range.base..(range.base + range.nmsrs)).for_each(|id| { v.push(msr_modifier!(id, 0)); diff --git a/src/vmm/src/arch/x86_64/vcpu.rs b/src/vmm/src/arch/x86_64/vcpu.rs index 98563aab2e3..61db3f6e723 100644 --- a/src/vmm/src/arch/x86_64/vcpu.rs +++ b/src/vmm/src/arch/x86_64/vcpu.rs @@ -947,7 +947,7 @@ mod tests { ); assert!(!t2a_res); } - cpuid::VENDOR_ID_AMD => { + cpuid::VENDOR_ID_AMD | cpuid::VENDOR_ID_HYGON => { assert!(!t2_res); assert!(!c3_res); assert!(!t2s_res); diff --git a/src/vmm/src/cpu_config/x86_64/cpuid/amd/normalize.rs b/src/vmm/src/cpu_config/x86_64/cpuid/amd/normalize.rs index f3a938e9a62..0eef6f4b314 100644 --- a/src/vmm/src/cpu_config/x86_64/cpuid/amd/normalize.rs +++ b/src/vmm/src/cpu_config/x86_64/cpuid/amd/normalize.rs @@ -7,7 +7,7 @@ use crate::cpu_config::x86_64::cpuid::normalize::{ }; use crate::cpu_config::x86_64::cpuid::{ BRAND_STRING_LENGTH, CpuidEntry, CpuidKey, CpuidRegisters, CpuidTrait, KvmCpuidFlags, - MissingBrandStringLeaves, VENDOR_ID_AMD, cpuid, cpuid_count, + MissingBrandStringLeaves, VENDOR_ID_AMD, VENDOR_ID_HYGON, cpuid, cpuid_count, }; /// Error type for [`super::AmdCpuid::normalize`]. @@ -121,11 +121,12 @@ impl super::AmdCpuid { /// /// This function passes through leaves from the host CPUID, if this does not match the AMD /// specification it is possible to enter an indefinite loop. To avoid this, this will return an - /// error when the host CPUID vendor id does not match the AMD CPUID vendor id. + /// error when the host CPUID vendor id does not match the AMD or Hygon CPUID vendor id. fn passthrough_cache_topology(&mut self) -> Result<(), PassthroughCacheTopologyError> { - if get_vendor_id_from_host().map_err(PassthroughCacheTopologyError::NoVendorId)? - != *VENDOR_ID_AMD - { + let vendor = + get_vendor_id_from_host().map_err(PassthroughCacheTopologyError::NoVendorId)?; + + if !matches!(&vendor, VENDOR_ID_AMD | VENDOR_ID_HYGON) { return Err(PassthroughCacheTopologyError::BadVendorId); } diff --git a/src/vmm/src/cpu_config/x86_64/cpuid/mod.rs b/src/vmm/src/cpu_config/x86_64/cpuid/mod.rs index ce249cf1a76..337e96f79e3 100644 --- a/src/vmm/src/cpu_config/x86_64/cpuid/mod.rs +++ b/src/vmm/src/cpu_config/x86_64/cpuid/mod.rs @@ -57,6 +57,9 @@ pub const VENDOR_ID_INTEL: &[u8; 12] = b"GenuineIntel"; /// AMD brand string. pub const VENDOR_ID_AMD: &[u8; 12] = b"AuthenticAMD"; +/// Hygon brand string. +pub const VENDOR_ID_HYGON: &[u8; 12] = b"HygonGenuine"; + /// Intel brand string. #[allow(clippy::undocumented_unsafe_blocks)] pub const VENDOR_ID_INTEL_STR: &str = unsafe { std::str::from_utf8_unchecked(VENDOR_ID_INTEL) }; @@ -65,6 +68,10 @@ pub const VENDOR_ID_INTEL_STR: &str = unsafe { std::str::from_utf8_unchecked(VEN #[allow(clippy::undocumented_unsafe_blocks)] pub const VENDOR_ID_AMD_STR: &str = unsafe { std::str::from_utf8_unchecked(VENDOR_ID_AMD) }; +/// Hygon brand string. +#[allow(clippy::undocumented_unsafe_blocks)] +pub const VENDOR_ID_HYGON_STR: &str = unsafe { std::str::from_utf8_unchecked(VENDOR_ID_HYGON) }; + /// To store the brand string we have 3 leaves, each with 4 registers, each with 4 bytes. pub const BRAND_STRING_LENGTH: usize = 3 * 4 * 4; @@ -407,7 +414,9 @@ impl TryFrom for Cpuid { match std::str::from_utf8(&vendor_id) { Ok(VENDOR_ID_INTEL_STR) => Ok(Cpuid::Intel(IntelCpuid::from(kvm_cpuid))), - Ok(VENDOR_ID_AMD_STR) => Ok(Cpuid::Amd(AmdCpuid::from(kvm_cpuid))), + Ok(VENDOR_ID_AMD_STR | VENDOR_ID_HYGON_STR) => { + Ok(Cpuid::Amd(AmdCpuid::from(kvm_cpuid))) + } _ => Err(CpuidTryFromKvmCpuid::UnsupportedVendor(vendor_id)), } } @@ -653,6 +662,39 @@ mod tests { } } + fn build_hygon_leaf0_for_cpuid() -> (CpuidKey, CpuidEntry) { + ( + CpuidKey { + leaf: 0x0, + subleaf: 0x0, + }, + CpuidEntry { + flags: KvmCpuidFlags::EMPTY, + result: CpuidRegisters { + eax: 0x1, + // HygonGenuine + ebx: 0x6f677948, + ecx: 0x656e6975, + edx: 0x6e65476e, + }, + }, + ) + } + + fn build_hygon_leaf0_for_kvmcpuid() -> kvm_bindings::kvm_cpuid_entry2 { + kvm_bindings::kvm_cpuid_entry2 { + function: 0x0, + index: 0x0, + flags: 0x0, + eax: 0x1, + // HygonGenuine + ebx: 0x6f677948, + ecx: 0x656e6975, + edx: 0x6e65476e, + ..Default::default() + } + } + fn build_sample_leaf_for_cpuid() -> (CpuidKey, CpuidEntry) { ( CpuidKey { @@ -714,6 +756,21 @@ mod tests { .unwrap() } + fn build_sample_hygon_cpuid() -> Cpuid { + Cpuid::Amd(AmdCpuid(BTreeMap::from([ + build_hygon_leaf0_for_cpuid(), + build_sample_leaf_for_cpuid(), + ]))) + } + + fn build_sample_hygon_kvmcpuid() -> kvm_bindings::CpuId { + kvm_bindings::CpuId::from_entries(&[ + build_hygon_leaf0_for_kvmcpuid(), + build_sample_leaf_for_kvmcpuid(), + ]) + .unwrap() + } + #[test] fn get() { let cpuid = build_sample_intel_cpuid(); @@ -763,6 +820,10 @@ mod tests { let kvm_cpuid = build_sample_amd_kvmcpuid(); let cpuid = Cpuid::try_from(kvm_cpuid).unwrap(); assert_eq!(cpuid, build_sample_amd_cpuid()); + + let kvm_cpuid = build_sample_hygon_kvmcpuid(); + let cpuid = Cpuid::try_from(kvm_cpuid).unwrap(); + assert_eq!(cpuid, build_sample_hygon_cpuid()); } #[test] @@ -774,6 +835,10 @@ mod tests { let cpuid = build_sample_amd_cpuid(); let kvm_cpuid = kvm_bindings::CpuId::try_from(cpuid).unwrap(); assert_eq!(kvm_cpuid, build_sample_amd_kvmcpuid()); + + let cpuid = build_sample_hygon_cpuid(); + let kvm_cpuid = kvm_bindings::CpuId::try_from(cpuid).unwrap(); + assert_eq!(kvm_cpuid, build_sample_hygon_kvmcpuid()); } #[test] diff --git a/tests/framework/utils_cpuid.py b/tests/framework/utils_cpuid.py index 52976d5964a..2e42a4b979b 100644 --- a/tests/framework/utils_cpuid.py +++ b/tests/framework/utils_cpuid.py @@ -69,7 +69,7 @@ def get_cpu_model_name(): _, stdout, _ = check_output("cat /proc/cpuinfo | grep 'CPU part' | uniq") else: _, stdout, _ = check_output("cat /proc/cpuinfo | grep 'model name' | uniq") - info = stdout.strip().split(sep=":") + info = stdout.strip().split(sep=":", maxsplit=1) assert len(info) == 2 raw_cpu_model = info[1].strip() if platform.machine() == "x86_64":