1use super::cpuid::{
31 EXTENDED_AMD_FEATURES_B, EXTENDED_FEATURES_D, FEATURE_FLAGS_C, Microarchitecture, VERSION_INFO,
32 VendorString,
33};
34use super::{
35 ArchCapabilitiesMsr, SpeculationControlMsr, Vendor, VirtualSpeculationControlMsr, has_ibrs,
36 has_stibp, tsx_is_supported,
37};
38use bitrs::layout;
39use regio::traits::{ReadReg, RwSafeReg, SafeWriteReg};
40use regio::x86::{Cpuid, Msr};
41use regio::{LayoutOver, RwSafe};
42
43pub fn has_x86_swapgs_bug(cpuid: &impl Cpuid) -> bool {
48 let vendor = VendorString::from_cpuid(cpuid).vendor();
49 match vendor {
50 Vendor::Unknown | Vendor::Intel => true,
53 Vendor::Amd => false,
54 }
55}
56
57pub fn has_x86_mds_bugs(cpuid: &impl Cpuid, msr: &impl ReadReg<ArchCapabilitiesMsr>) -> bool {
62 if ArchCapabilitiesMsr::is_supported(cpuid) && msr.read().mds_no() {
64 return false;
65 }
66 let version_info = cpuid.read(VERSION_INFO);
67 let vendor = VendorString::from_cpuid(cpuid).vendor();
68 let march = version_info.microarchitecture(vendor);
69 match march {
70 Microarchitecture::Unknown
71 | Microarchitecture::IntelCore2
72 | Microarchitecture::IntelNehalem
73 | Microarchitecture::IntelWestmere
74 | Microarchitecture::IntelSandyBridge
75 | Microarchitecture::IntelIvyBridge
76 | Microarchitecture::IntelHaswell
77 | Microarchitecture::IntelBroadwell
78 | Microarchitecture::IntelSkylake
79 | Microarchitecture::IntelSkylakeServer
80 | Microarchitecture::IntelCannonLake
81 | Microarchitecture::IntelIceLake
82 | Microarchitecture::IntelSilvermont
83 | Microarchitecture::IntelAirmont => true,
84
85 Microarchitecture::IntelTigerLake
86 | Microarchitecture::IntelAlderLake
87 | Microarchitecture::IntelRaptorLake
88 | Microarchitecture::IntelBonnell
89 | Microarchitecture::IntelSaltwell
90 | Microarchitecture::IntelGoldmont
91 | Microarchitecture::IntelGoldmontPlus
92 | Microarchitecture::IntelTremont
93 | Microarchitecture::AmdFamilyBulldozer
94 | Microarchitecture::AmdFamilyJaguar
95 | Microarchitecture::AmdFamilyZen
96 | Microarchitecture::AmdFamilyZen3 => false,
97 }
98}
99
100pub fn has_x86_taa_bug(cpuid: &impl Cpuid, msr: &impl ReadReg<ArchCapabilitiesMsr>) -> bool {
104 let taa_no = ArchCapabilitiesMsr::is_supported(cpuid) && msr.read().taa_no();
110 if !tsx_is_supported(cpuid) || taa_no {
111 return false;
112 }
113 let version_info = cpuid.read(VERSION_INFO);
114 let vendor = VendorString::from_cpuid(cpuid).vendor();
115 match version_info.microarchitecture(vendor) {
116 Microarchitecture::Unknown
117 | Microarchitecture::IntelHaswell
118 | Microarchitecture::IntelBroadwell
119 | Microarchitecture::IntelSkylake
120 | Microarchitecture::IntelSkylakeServer
121 | Microarchitecture::IntelCannonLake
122 | Microarchitecture::IntelIceLake => true,
123
124 Microarchitecture::IntelCore2
126 | Microarchitecture::IntelNehalem
128 | Microarchitecture::IntelWestmere
130 | Microarchitecture::IntelSandyBridge
131 | Microarchitecture::IntelIvyBridge
132 | Microarchitecture::IntelTigerLake
133 | Microarchitecture::IntelAlderLake
134 | Microarchitecture::IntelRaptorLake
135 | Microarchitecture::IntelBonnell
136 | Microarchitecture::IntelSaltwell
137 | Microarchitecture::IntelSilvermont
138 | Microarchitecture::IntelAirmont
139 | Microarchitecture::IntelGoldmont
140 | Microarchitecture::IntelGoldmontPlus
141 | Microarchitecture::IntelTremont
142 | Microarchitecture::AmdFamilyBulldozer
143 | Microarchitecture::AmdFamilyJaguar
144 | Microarchitecture::AmdFamilyZen
145 | Microarchitecture::AmdFamilyZen3 => false,
146 }
147}
148
149pub fn has_x86_mds_taa_bugs(cpuid: &impl Cpuid, msr: &impl ReadReg<ArchCapabilitiesMsr>) -> bool {
152 has_x86_mds_bugs(cpuid, msr) || has_x86_taa_bug(cpuid, msr)
153}
154
155pub fn can_mitigate_x86_mds_taa_bugs(cpuid: &impl Cpuid) -> bool {
159 cpuid.read(EXTENDED_FEATURES_D).md_clear()
160}
161
162pub fn has_x86_ssb_bug(cpuid: &impl Cpuid, msr: &impl ReadReg<ArchCapabilitiesMsr>) -> bool {
167 if ArchCapabilitiesMsr::is_supported(cpuid) && msr.read().ssb_no() {
170 return false;
171 }
172 if cpuid.supports(EXTENDED_AMD_FEATURES_B) && cpuid.read(EXTENDED_AMD_FEATURES_B).ssb_no() {
173 return false;
174 }
175 let version_info = cpuid.read(VERSION_INFO);
176 let vendor = VendorString::from_cpuid(cpuid).vendor();
177 match version_info.microarchitecture(vendor) {
178 Microarchitecture::Unknown
179 | Microarchitecture::IntelCore2
180 | Microarchitecture::IntelNehalem
181 | Microarchitecture::IntelWestmere
182 | Microarchitecture::IntelSandyBridge
183 | Microarchitecture::IntelIvyBridge
184 | Microarchitecture::IntelHaswell
185 | Microarchitecture::IntelBroadwell
186 | Microarchitecture::IntelSkylake
187 | Microarchitecture::IntelSkylakeServer
188 | Microarchitecture::IntelCannonLake
189 | Microarchitecture::IntelIceLake
190 | Microarchitecture::IntelTigerLake
191 | Microarchitecture::IntelAlderLake
192 | Microarchitecture::IntelRaptorLake
193 | Microarchitecture::IntelGoldmont
194 | Microarchitecture::IntelGoldmontPlus
195 | Microarchitecture::IntelTremont
196 | Microarchitecture::AmdFamilyBulldozer
197 | Microarchitecture::AmdFamilyJaguar
198 | Microarchitecture::AmdFamilyZen
199 | Microarchitecture::AmdFamilyZen3 => true,
200 Microarchitecture::IntelBonnell
201 | Microarchitecture::IntelSaltwell
202 | Microarchitecture::IntelSilvermont
203 | Microarchitecture::IntelAirmont => false,
204 }
205}
206
207pub fn has_x86_meltdown_bug(cpuid: &impl Cpuid, msr: &impl ReadReg<ArchCapabilitiesMsr>) -> bool {
212 if ArchCapabilitiesMsr::is_supported(cpuid) && msr.read().rdcl_no() {
214 return false;
215 }
216 let version_info = cpuid.read(VERSION_INFO);
217 let vendor = VendorString::from_cpuid(cpuid).vendor();
218 let march = version_info.microarchitecture(vendor);
219 match march {
220 Microarchitecture::Unknown
221 | Microarchitecture::IntelCore2
222 | Microarchitecture::IntelNehalem
223 | Microarchitecture::IntelWestmere
224 | Microarchitecture::IntelSandyBridge
225 | Microarchitecture::IntelIvyBridge
226 | Microarchitecture::IntelHaswell
227 | Microarchitecture::IntelBroadwell
228 | Microarchitecture::IntelSkylake
229 | Microarchitecture::IntelCannonLake => true,
230 Microarchitecture::IntelIceLake
231 | Microarchitecture::IntelTigerLake
232 | Microarchitecture::IntelAlderLake
233 | Microarchitecture::IntelRaptorLake
234 | Microarchitecture::IntelBonnell
235 | Microarchitecture::IntelSaltwell
236 | Microarchitecture::IntelSilvermont
237 | Microarchitecture::IntelAirmont
238 | Microarchitecture::IntelGoldmont
239 | Microarchitecture::IntelTremont
240 | Microarchitecture::AmdFamilyBulldozer
241 | Microarchitecture::AmdFamilyJaguar
242 | Microarchitecture::AmdFamilyZen
243 | Microarchitecture::AmdFamilyZen3 => false,
244 Microarchitecture::IntelSkylakeServer => {
246 let info = cpuid.read(VERSION_INFO);
247 if info.stepping() >= 0x6 {
248 return false;
250 }
251 true }
253 Microarchitecture::IntelGoldmontPlus => {
254 let info = cpuid.read(VERSION_INFO);
255 if info.stepping() == 0x1 {
256 return true;
258 }
259 false
260 }
261 }
262}
263
264#[derive(Clone, Copy, Debug, Eq, PartialEq)]
266pub enum SpectreV2Mitigation {
267 Ibrs,
270 IbpbRetpoline,
272 IbpbRetpolineStibp,
275}
276
277pub fn get_preferred_spectre_v2_mitigation(
279 cpuid: &impl Cpuid,
280 msr: &impl ReadReg<ArchCapabilitiesMsr>,
281) -> SpectreV2Mitigation {
282 let vendor = VendorString::from_cpuid(cpuid).vendor();
283 match vendor {
284 Vendor::Unknown => {}
285 Vendor::Intel => {
286 if has_ibrs(cpuid, msr, true) {
291 return SpectreV2Mitigation::Ibrs;
292 }
293 }
294 Vendor::Amd => {
295 if has_ibrs(cpuid, msr, true)
299 && cpuid.supports(EXTENDED_AMD_FEATURES_B)
300 && cpuid.read(EXTENDED_AMD_FEATURES_B).prefers_ibrs()
301 {
302 return SpectreV2Mitigation::Ibrs;
303 }
304 if has_stibp(cpuid, true) {
307 return SpectreV2Mitigation::IbpbRetpolineStibp;
308 }
309 }
310 }
311 SpectreV2Mitigation::IbpbRetpoline
314}
315
316pub const AMD_LOAD_STORE_CONFIGURATION: Msr<0xc001_1020, AmdLoadStoreConfigurationMsr, RwSafe> =
319 Msr::new();
320
321layout!({
322 pub struct AmdLoadStoreConfigurationMsr(u64);
324 {
325 let __ @ 63..58;
326 let erratum_1095_workaround @ 57;
327 let __ @ 56..55;
328 let ssbd_15h @ 54;
329 let __ @ 53..34;
330 let ssbd_16h @ 33;
331 let __ @ 32..11;
332 let ssbd_17h @ 10;
333 let __ @ 9..5;
334 let erratum_1033_workaround @ 4;
335 let __ @ 3..0;
336 }
337});
338
339pub const AMD_C0011028: Msr<0xc001_1028, AmdC0011028Msr, RwSafe> = Msr::new();
341
342layout!({
343 pub struct AmdC0011028Msr(u64);
345 {
346 let __ @ 63..5;
347 let erratum_1049_workaround @ 4;
348 let __ @ 3..0;
349 }
350});
351
352pub const AMD_C0011029: Msr<0xc001_1029, AmdC0011029Msr, RwSafe> = Msr::new();
354
355layout!({
356 pub struct AmdC0011029Msr(u64);
358 {
359 let __ @ 63..14;
360 let erratum_1021_workaround @ 13;
361 let __ @ 12..0;
362 }
363});
364
365pub const AMD_C001102D: Msr<0xc001_102d, AmdC001102dMsr, RwSafe> = Msr::new();
367
368layout!({
369 pub struct AmdC001102dMsr(u64);
371 {
372 let __ @ 63..35;
373 let erratum_1091_workaround @ 34;
374 let __ @ 33..0;
375 }
376});
377
378pub fn mitigate_x86_ssb_bug(
381 cpuid: &impl Cpuid,
382 speculation: &impl RwSafeReg<SpeculationControlMsr>,
383 virtual_speculation: &impl RwSafeReg<VirtualSpeculationControlMsr>,
384 load_store_configuration: &impl RwSafeReg<AmdLoadStoreConfigurationMsr>,
385) -> bool {
386 if cpuid.read(EXTENDED_FEATURES_D).ssbd() {
387 debug_assert!(SpeculationControlMsr::is_supported(cpuid));
388 speculation.modify(|value| *value.set_ssbd(true));
389 return true;
390 }
391 if cpuid.supports(EXTENDED_AMD_FEATURES_B) {
392 let amd_features = cpuid.read(EXTENDED_AMD_FEATURES_B);
393 if amd_features.ssbd() {
394 debug_assert!(SpeculationControlMsr::is_supported(cpuid));
395 speculation.modify(|value| *value.set_ssbd(true));
396 return true;
397 }
398
399 if amd_features.virt_ssbd() {
400 debug_assert!(VirtualSpeculationControlMsr::is_supported(cpuid));
401 virtual_speculation.modify(|value| *value.set_ssbd(true));
402 return true;
403 }
404 }
405
406 let version_info = cpuid.read(VERSION_INFO);
411 let vendor = VendorString::from_cpuid(cpuid).vendor();
412 match version_info.microarchitecture(vendor) {
413 Microarchitecture::AmdFamilyBulldozer => {
414 load_store_configuration.modify(|value| *value.set_ssbd_15h(true));
415 true
416 }
417 Microarchitecture::AmdFamilyJaguar => {
418 load_store_configuration.modify(|value| *value.set_ssbd_16h(true));
419 true
420 }
421 Microarchitecture::AmdFamilyZen => {
422 load_store_configuration.modify(|value| *value.set_ssbd_17h(true));
423 true
424 }
425 _ => false,
426 }
427}
428
429pub fn can_mitigate_x86_ssb_bug(cpuid: &impl Cpuid) -> bool {
430 struct NullMsr;
434
435 impl<Layout: LayoutOver<u64>> ReadReg<Layout> for NullMsr {
436 fn read(&self) -> Layout {
437 Layout::from(0u64)
438 }
439 }
440
441 impl<Layout> SafeWriteReg<Layout> for NullMsr {
442 fn write(&self, _value: Layout) {}
443 }
444
445 mitigate_x86_ssb_bug(cpuid, &NullMsr, &NullMsr, &NullMsr)
446}
447
448pub fn apply_x86_errata_workarounds(
450 cpuid: &impl Cpuid,
451 c0011028: &impl RwSafeReg<AmdC0011028Msr>,
452 c0011029: &impl RwSafeReg<AmdC0011029Msr>,
453 c001102d: &impl RwSafeReg<AmdC001102dMsr>,
454 load_store: &impl RwSafeReg<AmdLoadStoreConfigurationMsr>,
455) {
456 if cpuid.read(FEATURE_FLAGS_C).hypervisor() {
457 return;
458 }
459
460 let vendor = VendorString::from_cpuid(cpuid).vendor();
461 match vendor {
462 Vendor::Unknown => {}
463 Vendor::Intel => {}
464 Vendor::Amd => {
465 let info = cpuid.read(VERSION_INFO);
466 #[expect(clippy::single_match)]
467 match info.family() {
468 0x17 => {
469 #[expect(clippy::single_match)]
470 match info.model() {
471 0x00..=0x0f => {
473 let zp_b1 = info.model() == 1 && info.stepping() == 1;
476 c0011029.modify(|value| *value.set_erratum_1021_workaround(true));
479
480 let mut lscfg = load_store.read();
481 if zp_b1 {
483 lscfg.set_erratum_1033_workaround(true);
484 }
485 if true {
488 lscfg.set_erratum_1095_workaround(true);
491 }
492 load_store.write(lscfg);
493
494 c0011028.modify(|value| *value.set_erratum_1049_workaround(true));
496
497 c001102d.modify(|value| *value.set_erratum_1091_workaround(true));
500 }
501 _ => {}
502 }
503 }
504 _ => {}
505 }
506 }
507 }
508}