Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
10 changes: 7 additions & 3 deletions src/cpu-template-helper/src/template/dump/x86_64.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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,
};
Expand Down Expand Up @@ -49,9 +49,11 @@ fn msrs_to_modifier(msrs: &BTreeMap<u32, u64>) -> Vec<RegisterModifier> {
.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));
}

Expand Down Expand Up @@ -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));
Expand Down
2 changes: 1 addition & 1 deletion src/vmm/src/arch/x86_64/vcpu.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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);
Expand Down
11 changes: 6 additions & 5 deletions src/vmm/src/cpu_config/x86_64/cpuid/amd/normalize.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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`].
Expand Down Expand Up @@ -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);
}

Expand Down
67 changes: 66 additions & 1 deletion src/vmm/src/cpu_config/x86_64/cpuid/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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) };
Expand All @@ -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;

Expand Down Expand Up @@ -407,7 +414,9 @@ impl TryFrom<kvm_bindings::CpuId> 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)),
}
}
Expand Down Expand Up @@ -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 {
Expand Down Expand Up @@ -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();
Expand Down Expand Up @@ -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]
Expand All @@ -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]
Expand Down
2 changes: 1 addition & 1 deletion tests/framework/utils_cpuid.py
Original file line number Diff line number Diff line change
Expand Up @@ -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":
Expand Down