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");
10	@MACRO_NAME: is_x86_feature_detected;
11	@MACRO_ATTRS: #[unstable(feature = "kernel_feature_detect", issue = "none")]
12	@FEATURE: tsc: "tsc";
13	@FEATURE: msr: "msr";
14	@FEATURE: apic: "apic";
15	@FEATURE: cx16: "cx16";
16	@FEATURE: pcid: "pcid";
17	@FEATURE: x2apic: "x2apic";
18	@FEATURE: tsc_deadline: "tsc_deadline";
19	@FEATURE: xsave: "xsave";
20	@FEATURE: hypervisor: "hypervisor";
21	@FEATURE: arat: "arat";
22	@FEATURE: intel_thread_director: "intel_thread_director";
23	@FEATURE: fsgsbase: "fsgsbase";
24	@FEATURE: tsc_adjust: "tsc_adjust";
25	@FEATURE: smep: "smep";
26	@FEATURE: invpcid: "invpcid";
27	@FEATURE: smap: "smap";
28	@FEATURE: la57: "la57";
29	@FEATURE: rdpid: "rdpid";
30	@FEATURE: hybrid: "hybrid";
31	@FEATURE: lass: "lass";
32	@FEATURE: nmi_src: "nmi_src";
33	@FEATURE: sipi64: "sipi64";
34	@FEATURE: xsave_x87: "xsave_x87";
35	@FEATURE: xsave_sse: "xsave_sse";
36	@FEATURE: xsave_avx: "xsave_avx";
37	@FEATURE: xsave_mpx_bounds: "xsave_mpx_bounds";
38	@FEATURE: xsave_mpx_cfg_status: "xsave_mpx_cfg_status";
39	@FEATURE: xsave_avx512_opmask: "xsave_avx512_opmask";
40	@FEATURE: xsave_avx512_zmm_hi256: "xsave_avx512_zmm_hi256";
41	@FEATURE: xsave_avx512_zmm_hi16: "xsave_avx512_zmm_hi16";
42	@FEATURE: xsave_pkru: "xsave_pkru";
43	@FEATURE: xsave_amx_cfg: "xsave_amx_cfg";
44	@FEATURE: xsave_amx_tile_data: "xsave_amx_tile_data";
45	@FEATURE: xsave_apx_gpr: "xsave_apx_gpr";
46	@FEATURE: nx: "nx";
47	@FEATURE: pdpe1gb: "pdpe1gb";
48	@FEATURE: rdtscp: "rdtscp";
49	@FEATURE: extapic: "extapic";
50	@FEATURE: invlpgb: "invlpgb";
51}
52
53pub fn detect() -> Initializer {
54	let mut initializer = Initializer::new();
55
56	let (max_basic_leaf, vendor_id) = unsafe {
57		let CpuidResult {
58			eax: max_basic_leaf,
59			ebx,
60			ecx,
61			edx,
62		} = __cpuid(0);
63		let vendor_id: [[u8; 4]; 3] = [
64			mem::transmute(ebx),
65			mem::transmute(edx),
66			mem::transmute(ecx),
67		];
68		let vendor_id: [u8; 12] = mem::transmute(vendor_id);
69		(max_basic_leaf, vendor_id)
70	};
71
72	if max_basic_leaf < 1 { return initializer; }
73
74	let CpuidResult {
75		ecx: proc_info_ecx,
76		edx: proc_info_edx,
77		..
78	} = unsafe { __cpuid(0x0000_0001_u32) };
79
80	let thermal_power_eax = if max_basic_leaf >= 6 {
81		let CpuidResult { eax, .. } = unsafe { __cpuid(0x0000_0006_u32) };
82		eax
83	} else {
84		0 // CPUID does not support "Thermal/power Management Features"
85	};
86
87	let (extended_features_eax, extended_features_ebx, extended_features_ecx, extended_features_edx) = if max_basic_leaf >= 7 {
88		let CpuidResult { eax, ebx, ecx, edx } = unsafe { __cpuid(0x0000_0007_u32) };
89		(eax, ebx, ecx, edx)
90	} else {
91		(0, 0, 0, 0) // CPUID does not support "Extended Features"
92	};
93
94	let (extended_features_1_eax, extended_features_1_ecx) = if extended_features_eax >= 1 {
95		let CpuidResult { eax, ecx, .. } = unsafe { __cpuid_count(0x0000_0007_u32, 1) };
96		(eax, ecx)
97	} else {
98		(0, 0) // CPUID does not support "Extended Features"
99	};
100
101	let (_xsave_xcr0_high, xsave_xcr0_low) = if proc_info_ecx & (1 << 26) != 0 {
102		let CpuidResult { eax, edx, .. } = unsafe { __cpuid_count(0x0000_000d_u32, 0) };
103		(edx, eax)
104	} else {
105		(0, 0)
106	};
107
108	let CpuidResult {
109		eax: extended_max_basic_leaf,
110		..
111	} = unsafe { __cpuid(0x8000_0000_u32) };
112
113	let (extended_proc_info_ecx, extended_proc_info_edx) = if extended_max_basic_leaf >= 1 {
114		let CpuidResult { ecx, edx, .. } = unsafe { __cpuid(0x8000_0001_u32) };
115		(ecx, edx)
116	} else {
117		(0, 0)
118	};
119
120	let paging_features_ebx = if extended_max_basic_leaf >= 8 {
121		let CpuidResult { ebx, .. } = unsafe { __cpuid(0x8000_0008_u32) };
122		ebx
123	} else {
124		0
125	};
126
127	{
128		let mut enable = |value: u32, bit: u32, feature: Feature| {
129			if value & (1 << bit) != 0 {
130				initializer.set(feature);
131			}
132		};
133
134		enable(proc_info_edx, 4, Feature::tsc);
135		enable(proc_info_edx, 5, Feature::msr);
136		enable(proc_info_edx, 9, Feature::apic);
137		enable(proc_info_ecx, 13, Feature::cx16);
138		enable(proc_info_ecx, 17, Feature::pcid);
139		enable(proc_info_ecx, 21, Feature::x2apic);
140		enable(proc_info_ecx, 24, Feature::tsc_deadline);
141		enable(proc_info_ecx, 26, Feature::xsave);
142		enable(proc_info_ecx, 31, Feature::hypervisor);
143		enable(thermal_power_eax, 2, Feature::arat);
144		enable(thermal_power_eax, 23, Feature::intel_thread_director);
145		enable(extended_features_ebx, 0, Feature::fsgsbase);
146		enable(extended_features_ebx, 1, Feature::tsc_adjust);
147		enable(extended_features_ebx, 7, Feature::smep);
148		enable(extended_features_ebx, 10, Feature::invpcid);
149		enable(extended_features_ebx, 20, Feature::smap);
150		enable(extended_features_ecx, 16, Feature::la57);
151		enable(extended_features_ecx, 22, Feature::rdpid);
152		enable(extended_features_edx, 15, Feature::hybrid);
153		enable(extended_features_1_eax, 6, Feature::lass);
154		enable(extended_features_1_eax, 20, Feature::nmi_src);
155		enable(extended_features_1_ecx, 4, Feature::sipi64);
156		enable(xsave_xcr0_low, 0, Feature::xsave_x87);
157		enable(xsave_xcr0_low, 1, Feature::xsave_sse);
158		enable(xsave_xcr0_low, 2, Feature::xsave_avx);
159		enable(xsave_xcr0_low, 3, Feature::xsave_mpx_bounds);
160		enable(xsave_xcr0_low, 4, Feature::xsave_mpx_cfg_status);
161		enable(xsave_xcr0_low, 5, Feature::xsave_avx512_opmask);
162		enable(xsave_xcr0_low, 6, Feature::xsave_avx512_zmm_hi256);
163		enable(xsave_xcr0_low, 7, Feature::xsave_avx512_zmm_hi16);
164		enable(xsave_xcr0_low, 9, Feature::xsave_pkru);
165		enable(xsave_xcr0_low, 17, Feature::xsave_amx_cfg);
166		enable(xsave_xcr0_low, 18, Feature::xsave_amx_tile_data);
167		enable(xsave_xcr0_low, 19, Feature::xsave_apx_gpr);
168		enable(extended_proc_info_edx, 20, Feature::nx);
169		enable(extended_proc_info_edx, 26, Feature::pdpe1gb);
170		enable(extended_proc_info_edx, 27, Feature::rdtscp);
171		enable(extended_proc_info_ecx, 3, Feature::extapic);
172		enable(paging_features_ebx, 3, Feature::invlpgb);
173	}
174
175	initializer
176}