1use inspect::Inspect;
7
8#[derive(Debug, Copy, Clone)]
14pub struct CpuidLeaf {
15 pub function: u32,
17 pub index: Option<u32>,
20 pub result: [u32; 4],
22 pub mask: [u32; 4],
24}
25
26impl CpuidLeaf {
27 pub fn new(function: u32, result: [u32; 4]) -> Self {
29 Self {
30 function,
31 index: None,
32 result,
33 mask: [!0; 4],
34 }
35 }
36
37 pub fn indexed(self, index: u32) -> Self {
39 Self {
40 index: Some(index),
41 ..self
42 }
43 }
44
45 pub fn masked(self, mask: [u32; 4]) -> Self {
47 Self { mask, ..self }
48 }
49
50 fn cmp_key(&self, other: &Self) -> std::cmp::Ordering {
51 (self.function, self.index).cmp(&(other.function, other.index))
52 }
53
54 pub fn matches(&self, eax: u32, ecx: u32) -> bool {
57 self.function == eax && (self.index.is_none() || self.index == Some(ecx))
58 }
59
60 pub fn apply(&self, result: &mut [u32; 4]) {
63 for ((x, y), m) in result.iter_mut().zip(self.result).zip(self.mask) {
64 *x &= !m;
65 *x |= y & m;
66 }
67 }
68
69 fn inspect_kv(&self) -> (String, impl '_ + Inspect) {
70 let key = if let Some(index) = self.index {
71 format!("{:#x}/{:#x}", self.function, index)
72 } else {
73 format!("{:#x}", self.function)
74 };
75 (
76 key,
77 inspect::adhoc(|req| {
78 let mut resp = req.respond();
79 resp.hex("eax", self.result[0])
80 .hex("ebx", self.result[1])
81 .hex("ecx", self.result[2])
82 .hex("edx", self.result[3]);
83 if self.mask != [!0, !0, !0, !0] {
84 resp.hex("eax_mask", self.mask[0])
85 .hex("ebx_mask", self.mask[1])
86 .hex("ecx_mask", self.mask[2])
87 .hex("edx_mask", self.mask[3]);
88 }
89 }),
90 )
91 }
92}
93
94#[derive(Debug, Inspect, Default)]
96pub struct CpuidLeafSet {
97 #[inspect(
98 flatten,
99 with = "|x| inspect::iter_by_key(x.iter().map(|y| y.inspect_kv()))"
100 )]
101 leaves: Vec<CpuidLeaf>,
102}
103
104impl CpuidLeafSet {
105 pub fn new(mut leaves: Vec<CpuidLeaf>) -> Self {
111 leaves.sort_by(|x, y| x.cmp_key(y));
114 leaves.dedup_by(|right, left| {
115 if left.cmp_key(right).is_ne() {
116 return false;
117 }
118 right.apply(&mut left.result);
119 for (x, y) in left.mask.iter_mut().zip(right.mask) {
120 *x |= y;
121 }
122 true
123 });
124 Self { leaves }
125 }
126
127 pub fn into_leaves(self) -> Vec<CpuidLeaf> {
129 self.leaves
130 }
131
132 pub fn leaves(&self) -> &[CpuidLeaf] {
134 &self.leaves
135 }
136
137 pub fn result(&self, eax: u32, ecx: u32, default: &[u32; 4]) -> [u32; 4] {
142 let mut result = *default;
143 if let Some(x) = self.leaves.iter().find(|x| x.matches(eax, ecx)) {
144 x.apply(&mut result);
145 }
146 result
147 }
148}