vmm/cpu_config/x86_64/cpuid/
common.rs1#![allow(clippy::restriction)]
4
5use crate::arch::x86_64::generated::msr_index::{
6 MSR_IA32_BNDCFGS, MSR_IA32_CR_PAT, MSR_MTRRdefType, MSR_MTRRfix4K_C0000, MSR_MTRRfix4K_C8000,
7 MSR_MTRRfix4K_D0000, MSR_MTRRfix4K_D8000, MSR_MTRRfix4K_E0000, MSR_MTRRfix4K_E8000,
8 MSR_MTRRfix4K_F0000, MSR_MTRRfix4K_F8000, MSR_MTRRfix16K_80000, MSR_MTRRfix16K_A0000,
9 MSR_MTRRfix64K_00000,
10};
11
12#[derive(Debug, thiserror::Error, displaydoc::Display, PartialEq, Eq)]
14pub enum GetCpuidError {
15 UnsupportedLeaf(u32),
17 InvalidSubleaf(u32),
19}
20
21pub fn get_cpuid(leaf: u32, subleaf: u32) -> Result<std::arch::x86_64::CpuidResult, GetCpuidError> {
28 let max_leaf =
29 unsafe { std::arch::x86_64::__get_cpuid_max(leaf & 0x8000_0000).0 };
32 if leaf > max_leaf {
33 return Err(GetCpuidError::UnsupportedLeaf(leaf));
34 }
35
36 let entry = crate::cpu_config::x86_64::cpuid::cpuid_count(leaf, subleaf);
37 if entry.eax == 0 && entry.ebx == 0 && entry.ecx == 0 && entry.edx == 0 {
38 return Err(GetCpuidError::InvalidSubleaf(subleaf));
39 }
40
41 Ok(entry)
42}
43
44pub fn get_vendor_id_from_host() -> Result<[u8; 12], GetCpuidError> {
50 get_cpuid(0, 0).map(|vendor_entry| unsafe {
53 std::mem::transmute::<[u32; 3], [u8; 12]>([
55 vendor_entry.ebx,
56 vendor_entry.edx,
57 vendor_entry.ecx,
58 ])
59 })
60}
61
62pub(crate) fn msrs_to_save_by_cpuid(cpuid: &kvm_bindings::CpuId) -> Vec<u32> {
64 const MPX_BITINDEX: u32 = 14;
66
67 const MTRR_BITINDEX: u32 = 12;
69
70 const MCE_BITINDEX: u32 = 7;
72
73 macro_rules! cpuid_is_feature_set {
77 ($cpuid:ident, $leaf:expr, $index:expr, $reg:tt, $feature_bit:expr) => {{
78 let mut res = false;
79 for entry in $cpuid.as_slice().iter() {
80 if entry.function == $leaf && entry.index == $index {
81 if entry.$reg & (1 << $feature_bit) != 0 {
82 res = true;
83 break;
84 }
85 }
86 }
87 res
88 }};
89 }
90
91 let mut msrs = Vec::new();
92
93 macro_rules! cpuid_msr_dep {
95 ($leaf:expr, $index:expr, $reg:tt, $feature_bit:expr, $msr:expr) => {
96 if cpuid_is_feature_set!(cpuid, $leaf, $index, $reg, $feature_bit) {
97 msrs.extend($msr)
98 }
99 };
100 }
101
102 cpuid_msr_dep!(0x7, 0, ebx, MPX_BITINDEX, [MSR_IA32_BNDCFGS]);
104
105 cpuid_msr_dep!(0x1, 0, edx, MTRR_BITINDEX, 0x200..0x210);
107
108 cpuid_msr_dep!(
110 0x1,
111 0,
112 edx,
113 MTRR_BITINDEX,
114 [
115 MSR_MTRRfix64K_00000,
116 MSR_MTRRfix16K_80000,
117 MSR_MTRRfix16K_A0000,
118 MSR_MTRRfix4K_C0000,
119 MSR_MTRRfix4K_C8000,
120 MSR_MTRRfix4K_D0000,
121 MSR_MTRRfix4K_D8000,
122 MSR_MTRRfix4K_E0000,
123 MSR_MTRRfix4K_E8000,
124 MSR_MTRRfix4K_F0000,
125 MSR_MTRRfix4K_F8000,
126 MSR_IA32_CR_PAT,
127 MSR_MTRRdefType,
128 ]
129 );
130
131 cpuid_msr_dep!(0x1, 0, edx, MCE_BITINDEX, 0x400..0x480);
137
138 msrs
139}
140
141#[cfg(test)]
142mod tests {
143 use super::*;
144
145 #[test]
146 fn get_cpuid_unsupported_leaf() {
147 let max_leaf =
148 unsafe { std::arch::x86_64::__get_cpuid_max(0).0 };
151 let max_leaf_plus_one = max_leaf + 1;
152
153 assert_eq!(
154 get_cpuid(max_leaf_plus_one, 0),
155 Err(GetCpuidError::UnsupportedLeaf(max_leaf_plus_one))
156 );
157 }
158}