Skip to content

Commit 9ea85d5

Browse files
committed
feat(vmm): Normalize CPUID leaf 0x1F
Intel Sapphire Rapids has CPUID leaf 0x1F that is a preferred superset to leaf 0xB. Intel recommends using leaf 0x1F when available rather than leaf 0xB. We don't use any other domains than ones supported leaf 0xB, so just copy leaf 0xB to leaf 0x1F. Signed-off-by: Takahiro Itazuri <[email protected]>
1 parent 2ad0570 commit 9ea85d5

File tree

2 files changed

+130
-0
lines changed

2 files changed

+130
-0
lines changed

docs/cpu_templates/cpuid-normalization.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -36,6 +36,7 @@ See also: [boot protocol settings](boot-protocol.md)
3636
| Set FDP_EXCPTN_ONLY bit | 0x7 | 0x0 | EBX | 6 |
3737
| Set "Deprecates FPU CS and FPU DS values" bit | 0x7 | 0x0 | EBX | 13 |
3838
| Disable performance monitoring | 0xa | - | all | all |
39+
| Fill v2 extended topology enumeration leaf | 0x1f | all | all | all |
3940
| Update brand string to use a default format and real frequency | 0x80000002, 0x80000003, 0x80000004 | - | all | all |
4041

4142
## AMD-specifc CPUID normalization

src/vmm/src/cpu_config/x86_64/cpuid/intel/normalize.rs

Lines changed: 129 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -73,6 +73,7 @@ impl super::IntelCpuid {
7373
self.update_power_management_entry()?;
7474
self.update_extended_feature_flags_entry()?;
7575
self.update_performance_monitoring_entry()?;
76+
self.update_extended_topology_v2_entry();
7677
self.update_brand_string_entry()?;
7778

7879
Ok(())
@@ -210,6 +211,29 @@ impl super::IntelCpuid {
210211
Ok(())
211212
}
212213

214+
/// Update extended topology v2 entry
215+
///
216+
/// CPUID leaf 1FH is a preferred superset to leaf 0xB. Intel recommends using leaf 0x1F when
217+
/// available rather than leaf 0xB.
218+
///
219+
/// Since we don't use any domains than ones supported in leaf 0xB, we just copy contents of
220+
/// leaf 0xB to leaf 0x1F.
221+
fn update_extended_topology_v2_entry(&mut self) {
222+
// Skip if leaf 0x1F does not exist.
223+
if self.get(&CpuidKey::leaf(0x1F)).is_none() {
224+
return;
225+
}
226+
227+
for index in 0.. {
228+
if let Some(subleaf) = self.get(&CpuidKey::subleaf(0xB, index)) {
229+
self.0
230+
.insert(CpuidKey::subleaf(0x1F, index), subleaf.clone());
231+
} else {
232+
break;
233+
}
234+
}
235+
}
236+
213237
fn update_brand_string_entry(&mut self) -> Result<(), NormalizeCpuidError> {
214238
// Get host brand string.
215239
let host_brand_string: [u8; BRAND_STRING_LENGTH] = host_brand_string();
@@ -331,9 +355,12 @@ mod tests {
331355
clippy::as_conversions
332356
)]
333357

358+
use std::collections::BTreeMap;
334359
use std::ffi::CStr;
335360

336361
use super::*;
362+
use crate::cpu_config::x86_64::cpuid::{CpuidEntry, IntelCpuid, KvmCpuidFlags};
363+
337364
#[test]
338365
fn default_brand_string_test() {
339366
let brand_string = b"Intel(R) Xeon(R) Platinum 8275CL CPU @ 3.00GHz\0\0";
@@ -394,4 +421,106 @@ mod tests {
394421
assert!((leaf_7_0.result.ebx & (1 << 6)) > 0);
395422
assert!((leaf_7_0.result.ebx & (1 << 13)) > 0);
396423
}
424+
425+
#[test]
426+
fn test_update_extended_topology_v2_entry_no_leaf_0x1f() {
427+
let mut cpuid = IntelCpuid(BTreeMap::from([(
428+
CpuidKey {
429+
leaf: 0xB,
430+
subleaf: 0,
431+
},
432+
CpuidEntry {
433+
flags: KvmCpuidFlags::SIGNIFICANT_INDEX,
434+
..Default::default()
435+
},
436+
)]));
437+
438+
cpuid.update_extended_topology_v2_entry();
439+
440+
assert!(
441+
cpuid
442+
.get(&CpuidKey {
443+
leaf: 0x1F,
444+
subleaf: 0,
445+
})
446+
.is_none()
447+
);
448+
}
449+
450+
#[test]
451+
fn test_update_extended_topology_v2_entry() {
452+
let mut cpuid = IntelCpuid(BTreeMap::from([
453+
(
454+
CpuidKey {
455+
leaf: 0xB,
456+
subleaf: 0,
457+
},
458+
CpuidEntry {
459+
flags: KvmCpuidFlags::SIGNIFICANT_INDEX,
460+
result: CpuidRegisters {
461+
eax: 0x1,
462+
ebx: 0x2,
463+
ecx: 0x3,
464+
edx: 0x4,
465+
},
466+
},
467+
),
468+
(
469+
CpuidKey {
470+
leaf: 0xB,
471+
subleaf: 1,
472+
},
473+
CpuidEntry {
474+
flags: KvmCpuidFlags::SIGNIFICANT_INDEX,
475+
result: CpuidRegisters {
476+
eax: 0xa,
477+
ebx: 0xb,
478+
ecx: 0xc,
479+
edx: 0xd,
480+
},
481+
},
482+
),
483+
(
484+
CpuidKey {
485+
leaf: 0x1F,
486+
subleaf: 0,
487+
},
488+
CpuidEntry {
489+
flags: KvmCpuidFlags::SIGNIFICANT_INDEX,
490+
result: CpuidRegisters {
491+
eax: 0xFFFFFFFF,
492+
ebx: 0xFFFFFFFF,
493+
ecx: 0xFFFFFFFF,
494+
edx: 0xFFFFFFFF,
495+
},
496+
},
497+
),
498+
]));
499+
500+
cpuid.update_extended_topology_v2_entry();
501+
502+
// Check leaf 0x1F, subleaf 0 is updated.
503+
let leaf_1f_0 = cpuid
504+
.get(&CpuidKey {
505+
leaf: 0x1F,
506+
subleaf: 0,
507+
})
508+
.unwrap();
509+
assert_eq!(leaf_1f_0.result.eax, 0x1);
510+
assert_eq!(leaf_1f_0.result.ebx, 0x2);
511+
assert_eq!(leaf_1f_0.result.ecx, 0x3);
512+
assert_eq!(leaf_1f_0.result.edx, 0x4);
513+
514+
// Check lefa 0x1F, subleaf 1 is inserted.
515+
let leaf_1f_1 = cpuid
516+
.get(&CpuidKey {
517+
leaf: 0x1F,
518+
subleaf: 1,
519+
})
520+
.unwrap();
521+
assert_eq!(leaf_1f_1.result.eax, 0xa);
522+
assert_eq!(leaf_1f_1.result.ebx, 0xb);
523+
assert_eq!(leaf_1f_1.result.ecx, 0xc);
524+
assert_eq!(leaf_1f_1.result.edx, 0xd);
525+
}
397526
}

0 commit comments

Comments
 (0)