Skip to content

Commit fcc1a79

Browse files
arch: Improve CPUID incompatibility logging
We use the Intel CPUID definitions to provide more information when CPUID compatibility checks fail (when both the source and destination VM run on Intel CPUs). Signed-off-by: Oliver Anderson <[email protected]> On-behalf-of: SAP [email protected]
1 parent 5280f09 commit fcc1a79

File tree

1 file changed

+57
-3
lines changed

1 file changed

+57
-3
lines changed

arch/src/x86_64/mod.rs

Lines changed: 57 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -536,8 +536,60 @@ impl CpuidFeatureEntry {
536536
let src_vm_features = Self::get_features_from_cpuid(src_vm_cpuid, feature_entry_list);
537537
let dest_vm_features = Self::get_features_from_cpuid(dest_vm_cpuid, feature_entry_list);
538538

539-
// Loop on feature bit and check if the 'source vm' feature is a subset
540-
// of those of the 'destination vm' feature
539+
// If both processors are Intel then we can use the existing Intel CPUID definitions to log more
540+
// precise information about potential errors
541+
let both_intel = {
542+
// Check if the vendor string is "GenuineIntel". This assumes that `leaf_0` is the entry
543+
// corresponding to CPUID leaf 0.
544+
let is_intel = |leaf_0: &CpuIdEntry| {
545+
leaf_0.ebx == 0x756e_6547 && leaf_0.ecx == 0x6c65_746e && leaf_0.edx == 0x4965_6e69
546+
};
547+
let src_0 = src_vm_cpuid
548+
.iter()
549+
.find(|entry| (entry.function == 0x0) & (entry.index == 0x0));
550+
let dest_0 = dest_vm_cpuid
551+
.iter()
552+
.find(|entry| (entry.function == 0x0) & (entry.index == 0x0));
553+
src_0
554+
.zip(dest_0)
555+
.is_some_and(|(src, dest)| is_intel(src) & is_intel(dest))
556+
};
557+
let extra_reporting = |entry: &CpuidFeatureEntry, src_reg: u32, dest_reg: u32| {
558+
if let Some((_, defs)) = cpuid_definitions::intel::INTEL_CPUID_DEFINITIONS
559+
.as_slice()
560+
.iter()
561+
.find(|(param, _)| {
562+
(param.leaf == entry.function) && (param.sub_leaf.contains(&entry.index))
563+
})
564+
{
565+
for def in defs.as_slice() {
566+
let mask = (def.bits_range.0..=def.bits_range.1)
567+
.fold(0, |acc, next| acc | (1 << next));
568+
569+
let src_val = src_reg & mask;
570+
let dest_val = dest_reg & mask;
571+
572+
let is_compatible = match entry.compatible_check {
573+
CpuidCompatibleCheck::BitwiseSubset => (src_val & (!dest_val)) == 0,
574+
CpuidCompatibleCheck::NumNotGreater => src_val <= dest_val,
575+
CpuidCompatibleCheck::Equal => src_val == dest_val,
576+
};
577+
if !is_compatible {
578+
info!(
579+
"CPUID incompatibility for value definition='{:?}' detected in leaf={:#02x}, sub-leaf={:#02x}, register={:?}, compatibility_check={:?}, source VM value='{:#04x}' destination VM value='{:#04x}'",
580+
def,
581+
entry.function,
582+
entry.index,
583+
entry.feature_reg,
584+
entry.compatible_check,
585+
src_val,
586+
dest_val
587+
);
588+
}
589+
}
590+
}
591+
};
592+
541593
let mut compatible = true;
542594
for (i, (src_vm_feature, dest_vm_feature)) in src_vm_features
543595
.iter()
@@ -565,7 +617,9 @@ impl CpuidFeatureEntry {
565617
src_vm_feature,
566618
dest_vm_feature
567619
);
568-
620+
if both_intel {
621+
extra_reporting(entry, *src_vm_feature, *dest_vm_feature);
622+
}
569623
compatible = false;
570624
}
571625
}

0 commit comments

Comments
 (0)