Skip to content

Commit 1fa2105

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 <oliver.anderson@cyberus-technology.de> On-behalf-of: SAP oliver.anderson@sap.com
1 parent bb2127e commit 1fa2105

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
@@ -513,8 +513,60 @@ impl CpuidFeatureEntry {
513513
let src_vm_features = Self::get_features_from_cpuid(src_vm_cpuid, feature_entry_list);
514514
let dest_vm_features = Self::get_features_from_cpuid(dest_vm_cpuid, feature_entry_list);
515515

516-
// Loop on feature bit and check if the 'source vm' feature is a subset
517-
// of those of the 'destination vm' feature
516+
// If both processors are Intel then we can use the existing Intel CPUID definitions to log more
517+
// precise information about potential errors
518+
let both_intel = {
519+
// Check if the vendor string is "GenuineIntel". This assumes that `leaf_0` is the entry
520+
// corresponding to CPUID leaf 0.
521+
let is_intel = |leaf_0: &CpuIdEntry| {
522+
leaf_0.ebx == 0x756e_6547 && leaf_0.ecx == 0x6c65_746e && leaf_0.edx == 0x4965_6e69
523+
};
524+
let src_0 = src_vm_cpuid
525+
.iter()
526+
.find(|entry| (entry.function == 0x0) & (entry.index == 0x0));
527+
let dest_0 = dest_vm_cpuid
528+
.iter()
529+
.find(|entry| (entry.function == 0x0) & (entry.index == 0x0));
530+
src_0
531+
.zip(dest_0)
532+
.is_some_and(|(src, dest)| is_intel(src) & is_intel(dest))
533+
};
534+
let extra_reporting = |entry: &CpuidFeatureEntry, src_reg: u32, dest_reg: u32| {
535+
if let Some((_, defs)) = cpuid_definitions::intel::INTEL_CPUID_DEFINITIONS
536+
.as_slice()
537+
.iter()
538+
.find(|(param, _)| {
539+
(param.leaf == entry.function) && (param.sub_leaf.contains(&entry.index))
540+
})
541+
{
542+
for def in defs.as_slice() {
543+
let mask = (def.bits_range.0..=def.bits_range.1)
544+
.fold(0, |acc, next| acc | (1 << next));
545+
546+
let src_val = src_reg & mask;
547+
let dest_val = dest_reg & mask;
548+
549+
let is_compatible = match entry.compatible_check {
550+
CpuidCompatibleCheck::BitwiseSubset => (src_val & (!dest_val)) == 0,
551+
CpuidCompatibleCheck::NumNotGreater => src_val <= dest_val,
552+
CpuidCompatibleCheck::Equal => src_val == dest_val,
553+
};
554+
if !is_compatible {
555+
info!(
556+
"CPUID incompatibility for value definition='{:?}' detected in leaf={:#02x}, sub-leaf={:#02x}, register={:?}, compatibility_check={:?}, source VM value='{:#04x}' destination VM value='{:#04x}'",
557+
def,
558+
entry.function,
559+
entry.index,
560+
entry.feature_reg,
561+
entry.compatible_check,
562+
src_val,
563+
dest_val
564+
);
565+
}
566+
}
567+
}
568+
};
569+
518570
let mut compatible = true;
519571
for (i, (src_vm_feature, dest_vm_feature)) in src_vm_features
520572
.iter()
@@ -542,7 +594,9 @@ impl CpuidFeatureEntry {
542594
src_vm_feature,
543595
dest_vm_feature
544596
);
545-
597+
if both_intel {
598+
extra_reporting(entry, *src_vm_feature, *dest_vm_feature);
599+
}
546600
compatible = false;
547601
}
548602
}

0 commit comments

Comments
 (0)