Skip to main content

kernel_api/detect/
x86.rs

1use super::cache::Initializer;
2use super::features_macro;
3
4use core::arch::x86_64::{__cpuid, __cpuid_count, CpuidResult};
5use core::mem;
6
7features_macro! {
8	@TARGET: x86;
9	@CFG: any(target_arch = "x86", target_arch = "x86_64", doc);
10	@MACRO_NAME: is_x86_feature_detected;
11	@MACRO_ATTRS: #[doc(cfg(any(target_arch = "x86", target_arch = "x86_64")))]
12	@FEATURE: tsc: "tsc": "system has a timestamp counter accessible through `rdtsc`";
13	@FEATURE: msr: "msr": "system supports reading and writing model specific registers through `rdmsr` and `wrmsr`";
14	@FEATURE: apic: "apic": "system has an APIC";
15	@FEATURE: cx16: "cx16": "system support 16-byte atomics";
16	@FEATURE: pcid: "pcid": "system supports PCIDs in page tables";
17	@FEATURE: x2apic: "x2apic": "APIC supports x2APIC features";
18	@FEATURE: tsc_deadline: "tsc_deadline": "local APIC timer supports TSC deadline mode";
19	@FEATURE: xsave: "xsave": "system supports the `xsave` instruction";
20	@FEATURE: hypervisor: "hypervisor": "system is running in a hypervisor";
21	@FEATURE: arat: "arat": "local APIC timer continues counting while sleeping";
22	@FEATURE: intel_thread_director: "intel_thread_director": "system supports Intel Thread Director";
23	@FEATURE: fsgsbase: "fsgsbase": "system supports writing to the `fs` and `gs` registers from userspace";
24	@FEATURE: tsc_adjust: "tsc_adjust": "system supports adjusting TSC value per-core";
25	@FEATURE: smep: "smep": "system supports Supervisor Mode Execution Prevention";
26	@FEATURE: invpcid: "invpcid": "system supports invalidating an entire PCID from the TLB";
27	@FEATURE: smap: "smap": "system supports Supervisor Mode Access Prevention";
28	@FEATURE: la57: "la57": "system supports 57-bit virtual addresses";
29	@FEATURE: rdpid: "rdpid": "system supports reading OS core ID from `IA32_TSC_AUX`";
30	@FEATURE: hybrid: "hybrid": "system has AMP";
31	@FEATURE: lass: "lass": "system supports trapping access based on MSB of address";
32	@FEATURE: nmi_src: "nmi_src": "system supports reporting source of NMI exceptions";
33	@FEATURE: xsave_x87: "xsave_x87": "system supports saving x87 registers with `xsave`";
34	@FEATURE: xsave_sse: "xsave_sse": "system supports saving SSE registers with `xsave`";
35	@FEATURE: xsave_avx: "xsave_avx": "system supports saving AVX registers with `xsave`";
36	@FEATURE: xsave_avx512_opmask: "xsave_avx512_opmask": "system supports saving AVX512 opmask registers with `xsave`";
37	@FEATURE: xsave_avx512_zmm_hi256: "xsave_avx512_zmm_hi256": "system supports saving upper 256 bits of `zmm0` through `zmm15` with `xsave`";
38	@FEATURE: xsave_avx512_zmm_hi16: "xsave_avx512_zmm_hi16": "system supports saving `zmm16` through `zmm31` with `xsave`";
39	@FEATURE: xsave_pkru: "xsave_pkru": "system supports saving PKRU register with `xsave`";
40	@FEATURE: xsave_amx_cfg: "xsave_amx_cfg": "system supports saving AMX `tilecfg` register with `xsave`";
41	@FEATURE: xsave_amx_tile_data: "xsave_amx_tile_data": "system supports saving AMX `tmm0` through `tmm7` registers with `xsave`";
42	@FEATURE: xsave_apx_gpr: "xsave_apx_gpr": "system supports saving `r16` through `r31` GPRs with `save`";
43	@FEATURE: nx: "nx": "page tables support no-execute bit";
44	@FEATURE: pdpe1gb: "pdpe1gb": "page tables support 1 GiB huge pages";
45	@FEATURE: rdtscp: "rdtscp": "system supports `rdtscp` instruction to read TSC and `IA32_TSC_AUX`";
46	@FEATURE: extapic: "extapic": "APIC support Extended APIC Space";
47	@FEATURE: invlpgb: "invlpgb": "system supports `invlpgb` instruction";
48}
49
50pub(super) fn detect() -> Initializer {
51	let mut initializer = Initializer::new();
52
53	let (max_basic_leaf, _vendor_id) = {
54		let CpuidResult {
55			eax: max_basic_leaf,
56			ebx,
57			ecx,
58			edx,
59		} = __cpuid(0);
60		let vendor_id: [[u8; 4]; 3] = [
61			u32::to_ne_bytes(ebx),
62			u32::to_ne_bytes(edx),
63			u32::to_ne_bytes(ecx),
64		];
65		let vendor_id: [u8; 12] = unsafe { mem::transmute(vendor_id) };
66		(max_basic_leaf, vendor_id)
67	};
68
69	if max_basic_leaf < 1 { return initializer; }
70
71	let CpuidResult {
72		ecx: proc_info_ecx,
73		edx: proc_info_edx,
74		..
75	} = __cpuid(0x0000_0001_u32);
76
77	let thermal_power_eax = if max_basic_leaf >= 6 {
78		let CpuidResult { eax, .. } = __cpuid(0x0000_0006_u32);
79		eax
80	} else {
81		0 // CPUID does not support "Thermal/power Management Features"
82	};
83
84	let (extended_features_eax, extended_features_ebx, extended_features_ecx, extended_features_edx) = if max_basic_leaf >= 7 {
85		let CpuidResult { eax, ebx, ecx, edx } = __cpuid(0x0000_0007_u32);
86		(eax, ebx, ecx, edx)
87	} else {
88		(0, 0, 0, 0) // CPUID does not support "Extended Features"
89	};
90
91	let (extended_features_1_eax, extended_features_1_ecx) = if extended_features_eax >= 1 {
92		let CpuidResult { eax, ecx, .. } = __cpuid_count(0x0000_0007_u32, 1);
93		(eax, ecx)
94	} else {
95		(0, 0) // CPUID does not support "Extended Features"
96	};
97
98	let (_xsave_xcr0_high, xsave_xcr0_low) = if proc_info_ecx & (1 << 26) != 0 {
99		let CpuidResult { eax, edx, .. } = __cpuid_count(0x0000_000d_u32, 0);
100		(edx, eax)
101	} else {
102		(0, 0)
103	};
104
105	let CpuidResult {
106		eax: extended_max_basic_leaf,
107		..
108	} = __cpuid(0x8000_0000_u32);
109
110	let (extended_proc_info_ecx, extended_proc_info_edx) = if extended_max_basic_leaf >= 1 {
111		let CpuidResult { ecx, edx, .. } = __cpuid(0x8000_0001_u32);
112		(ecx, edx)
113	} else {
114		(0, 0)
115	};
116
117	let paging_features_ebx = if extended_max_basic_leaf >= 8 {
118		let CpuidResult { ebx, .. } = __cpuid(0x8000_0008_u32);
119		ebx
120	} else {
121		0
122	};
123
124	{
125		let mut enable = |value: u32, bit: u32, feature: Feature| {
126			if value & (1 << bit) != 0 {
127				initializer.set(feature);
128			}
129		};
130
131		enable(proc_info_edx, 4, Feature::tsc);
132		enable(proc_info_edx, 5, Feature::msr);
133		enable(proc_info_edx, 9, Feature::apic);
134		enable(proc_info_ecx, 13, Feature::cx16);
135		enable(proc_info_ecx, 17, Feature::pcid);
136		enable(proc_info_ecx, 21, Feature::x2apic);
137		enable(proc_info_ecx, 24, Feature::tsc_deadline);
138		enable(proc_info_ecx, 26, Feature::xsave);
139		enable(proc_info_ecx, 31, Feature::hypervisor);
140		enable(thermal_power_eax, 2, Feature::arat);
141		enable(thermal_power_eax, 23, Feature::intel_thread_director);
142		enable(extended_features_ebx, 0, Feature::fsgsbase);
143		enable(extended_features_ebx, 1, Feature::tsc_adjust);
144		enable(extended_features_ebx, 7, Feature::smep);
145		enable(extended_features_ebx, 10, Feature::invpcid);
146		enable(extended_features_ebx, 20, Feature::smap);
147		enable(extended_features_ecx, 16, Feature::la57);
148		enable(extended_features_ecx, 22, Feature::rdpid);
149		enable(extended_features_edx, 15, Feature::hybrid);
150		enable(extended_features_1_eax, 6, Feature::lass);
151		enable(extended_features_1_eax, 20, Feature::nmi_src);
152		enable(xsave_xcr0_low, 0, Feature::xsave_x87);
153		enable(xsave_xcr0_low, 1, Feature::xsave_sse);
154		enable(xsave_xcr0_low, 2, Feature::xsave_avx);
155		enable(xsave_xcr0_low, 5, Feature::xsave_avx512_opmask);
156		enable(xsave_xcr0_low, 6, Feature::xsave_avx512_zmm_hi256);
157		enable(xsave_xcr0_low, 7, Feature::xsave_avx512_zmm_hi16);
158		enable(xsave_xcr0_low, 9, Feature::xsave_pkru);
159		enable(xsave_xcr0_low, 17, Feature::xsave_amx_cfg);
160		enable(xsave_xcr0_low, 18, Feature::xsave_amx_tile_data);
161		enable(xsave_xcr0_low, 19, Feature::xsave_apx_gpr);
162		enable(extended_proc_info_edx, 20, Feature::nx);
163		enable(extended_proc_info_edx, 26, Feature::pdpe1gb);
164		enable(extended_proc_info_edx, 27, Feature::rdtscp);
165		enable(extended_proc_info_ecx, 3, Feature::extapic);
166		enable(paging_features_ebx, 3, Feature::invlpgb);
167	}
168
169	initializer
170}