strat9_kernel/arch/x86_64/
mod.rs1pub mod apic;
6pub mod boot_timestamp;
7pub mod cpuid;
8pub mod gdt;
9pub mod idt;
10pub mod io;
11pub mod ioapic;
12pub mod keyboard;
13pub mod keyboard_layout;
14pub mod keyboard_us;
15pub mod mouse;
16pub mod msi;
17pub mod pci;
18pub mod percpu;
19pub mod pic;
20pub mod ring3_diag;
21pub mod serial;
22pub mod smp;
23pub mod speaker;
24pub mod syscall;
25pub mod timer;
26pub mod tlb;
27pub mod tss;
28pub mod vga;
29pub mod vgabuf;
30pub mod x2apic;
31
32use core::arch::asm;
33
34pub fn init_cpu_extensions() {
36 unsafe {
37 let mut cr4: u64;
38 asm!("mov {}, cr4", out(reg) cr4, options(nomem, nostack));
39 cr4 |= (1 << 9) | (1 << 10);
41
42 if cpuid::host_uses_xsave() {
43 cr4 |= 1 << 18;
45 }
46
47 if crate::arch::x86_64::cpuid::host()
51 .features
52 .contains(cpuid::CpuFeatures::SMEP)
53 {
54 cr4 |= 1 << 20;
55 log::info!("[init] SMEP enabled (CR4 bit 20)");
56 }
57
58 if crate::arch::x86_64::cpuid::host()
63 .features
64 .contains(cpuid::CpuFeatures::SMAP)
65 {
66 cr4 |= 1 << 21;
67 log::info!("[init] SMAP enabled (CR4 bit 21)");
68 }
69
70 asm!("mov cr4, {}", in(reg) cr4, options(nomem, nostack));
71
72 let mut cr0: u64;
73 asm!("mov {}, cr0", out(reg) cr0, options(nomem, nostack));
74 cr0 &= !(1 << 2); cr0 |= (1 << 1) | (1 << 5); asm!("mov cr0, {}", in(reg) cr0, options(nomem, nostack));
77
78 asm!("fninit", options(nomem, nostack));
79
80 if cpuid::host_uses_xsave() {
81 let xcr0 = cpuid::host_default_xcr0();
82 let supported = cpuid::host().supported_xcr0;
85 debug_assert_eq!(
86 xcr0 & !supported,
87 0,
88 "XCR0 {:#x} has bits outside hardware support {:#x}",
89 xcr0,
90 supported
91 );
92 xsetbv(0, xcr0 & supported);
93 }
94 }
95}
96
97pub fn cpuid_osxsave_enabled() -> bool {
102 let cr4: u64;
103 unsafe { asm!("mov {}, cr4", out(reg) cr4, options(nomem, nostack)) };
104 cr4 & (1 << 18) != 0
105}
106
107#[inline]
108pub fn xgetbv(xcr: u32) -> u64 {
110 let eax: u32;
111 let edx: u32;
112 unsafe {
113 asm!(
114 "xgetbv",
115 in("ecx") xcr,
116 out("eax") eax,
117 out("edx") edx,
118 options(nomem, nostack),
119 );
120 }
121 ((edx as u64) << 32) | eax as u64
122}
123
124#[inline]
129pub unsafe fn xsetbv(xcr: u32, value: u64) {
130 asm!(
131 "xsetbv",
132 in("ecx") xcr,
133 in("eax") value as u32,
134 in("edx") (value >> 32) as u32,
135 options(nomem, nostack),
136 );
137}
138
139#[inline]
141pub fn hlt() {
142 unsafe {
143 asm!("hlt", options(nomem, nostack, preserves_flags));
144 }
145}
146
147#[inline]
149pub fn cli() {
150 unsafe {
151 asm!("cli", options(nomem, nostack));
152 }
153}
154
155#[inline]
157pub fn sti() {
158 unsafe {
159 asm!("sti", options(nomem, nostack));
160 }
161}
162
163#[inline]
174pub fn stac() {
175 if !cpu_has_smap() {
176 return;
177 }
178 unsafe {
179 asm!("stac", options(nomem, nostack, preserves_flags));
180 }
181}
182
183#[inline]
187pub fn clac() {
188 if !cpu_has_smap() {
189 return;
190 }
191 unsafe {
192 asm!("clac", options(nomem, nostack, preserves_flags));
193 }
194}
195
196#[inline]
199fn cpu_has_smap() -> bool {
200 crate::arch::x86_64::cpuid::host()
201 .features
202 .contains(crate::arch::x86_64::cpuid::CpuFeatures::SMAP)
203}
204
205#[inline]
207pub fn interrupts_enabled() -> bool {
208 let rflags: u64;
209 unsafe {
210 asm!("pushfq; pop {}", out(reg) rflags, options(nomem));
211 }
212 rflags & 0x200 != 0
213}
214
215#[inline]
221pub fn save_flags_and_cli() -> u64 {
222 let flags: u64;
223 unsafe {
226 asm!("pushfq; pop {0}; cli", out(reg) flags);
227 }
228 flags
229}
230
231#[inline]
235pub fn restore_flags(flags: u64) {
236 unsafe {
238 asm!("push {0}; popfq", in(reg) flags);
239 }
240}
241
242#[inline]
244pub fn rdmsr(msr: u32) -> u64 {
245 let edx: u32;
246 let eax: u32;
247 unsafe {
248 asm!(
249 "rdmsr",
250 in("ecx") msr,
251 out("edx") edx,
252 out("eax") eax,
253 options(nostack)
254 );
255 }
256 ((edx as u64) << 32) | eax as u64
257}
258
259#[inline]
261pub fn wrmsr(msr: u32, val: u64) {
262 let edx = (val >> 32) as u32;
263 let eax = val as u32;
264 unsafe {
265 asm!(
266 "wrmsr",
267 in("ecx") msr,
268 in("edx") edx,
269 in("eax") eax,
270 options(nostack)
271 );
272 }
273}
274
275#[inline(never)]
279pub fn cpuid(leaf: u32, sub_leaf: u32) -> (u32, u32, u32, u32) {
280 let eax: u32;
281 let ebx: u32;
282 let ecx: u32;
283 let edx: u32;
284 unsafe {
285 asm!(
286 "push rbx",
287 "cpuid",
288 "mov r11d, ebx",
289 "pop rbx",
290 inout("eax") leaf => eax,
291 inout("ecx") sub_leaf => ecx,
292 out("r11") ebx,
293 out("edx") edx,
294 options(nostack, preserves_flags),
295 );
296 }
297 (eax, ebx, ecx, edx)
298}
299
300#[inline]
309pub fn rdtsc() -> u64 {
310 let eax: u32;
311 let edx: u32;
312 unsafe {
313 asm!(
314 "lfence",
315 "rdtsc",
316 out("eax") eax,
317 out("edx") edx,
318 options(nomem, nostack),
319 );
320 }
321 ((edx as u64) << 32) | eax as u64
322}