x86_64/registers/model_specific.rs
1//! Functions to read and write model specific registers.
2
3use bitflags::bitflags;
4// imports for intra doc links
5#[cfg(doc)]
6use crate::registers::segmentation::{FS, GS};
7
8/// A model specific register.
9#[cfg_attr(
10 not(all(feature = "instructions", target_arch = "x86_64")),
11 allow(dead_code)
12)] // FIXME
13#[derive(Debug)]
14pub struct Msr(u32);
15
16impl Msr {
17 /// Create an instance from a register.
18 #[inline]
19 pub const fn new(reg: u32) -> Msr {
20 Msr(reg)
21 }
22}
23
24/// The Extended Feature Enable Register.
25#[derive(Debug)]
26pub struct Efer;
27
28/// [FS].Base Model Specific Register.
29#[derive(Debug)]
30pub struct FsBase;
31
32/// [GS].Base Model Specific Register.
33///
34#[cfg_attr(
35 all(feature = "instructions", target_arch = "x86_64"),
36 doc = "[`GS::swap`] swaps this register with [`KernelGsBase`]."
37)]
38#[derive(Debug)]
39pub struct GsBase;
40
41/// KernelGsBase Model Specific Register.
42///
43#[cfg_attr(
44 all(feature = "instructions", target_arch = "x86_64"),
45 doc = "[`GS::swap`] swaps this register with [`GsBase`]."
46)]
47#[derive(Debug)]
48pub struct KernelGsBase;
49
50/// Syscall Register: STAR
51#[derive(Debug)]
52pub struct Star;
53
54/// Syscall Register: LSTAR
55#[derive(Debug)]
56pub struct LStar;
57
58/// Syscall Register: SFMASK
59#[derive(Debug)]
60pub struct SFMask;
61
62/// IA32_U_CET: user mode CET configuration
63#[derive(Debug)]
64pub struct UCet;
65
66/// IA32_S_CET: supervisor mode CET configuration
67#[derive(Debug)]
68pub struct SCet;
69
70impl Efer {
71 /// The underlying model specific register.
72 pub const MSR: Msr = Msr(0xC000_0080);
73}
74
75impl FsBase {
76 /// The underlying model specific register.
77 pub const MSR: Msr = Msr(0xC000_0100);
78}
79
80impl GsBase {
81 /// The underlying model specific register.
82 pub const MSR: Msr = Msr(0xC000_0101);
83}
84
85impl KernelGsBase {
86 /// The underlying model specific register.
87 pub const MSR: Msr = Msr(0xC000_0102);
88}
89
90impl Star {
91 /// The underlying model specific register.
92 pub const MSR: Msr = Msr(0xC000_0081);
93}
94
95impl LStar {
96 /// The underlying model specific register.
97 pub const MSR: Msr = Msr(0xC000_0082);
98}
99
100impl SFMask {
101 /// The underlying model specific register.
102 pub const MSR: Msr = Msr(0xC000_0084);
103}
104
105impl UCet {
106 /// The underlying model specific register.
107 pub const MSR: Msr = Msr(0x6A0);
108}
109
110impl SCet {
111 /// The underlying model specific register.
112 pub const MSR: Msr = Msr(0x6A2);
113}
114
115bitflags! {
116 /// Flags of the Extended Feature Enable Register.
117 #[repr(transparent)]
118 #[derive(PartialEq, Eq, PartialOrd, Ord, Hash, Debug, Clone, Copy)]
119 pub struct EferFlags: u64 {
120 /// Enables the `syscall` and `sysret` instructions.
121 const SYSTEM_CALL_EXTENSIONS = 1;
122 /// Activates long mode, requires activating paging.
123 const LONG_MODE_ENABLE = 1 << 8;
124 /// Indicates that long mode is active.
125 const LONG_MODE_ACTIVE = 1 << 10;
126 /// Enables the no-execute page-protection feature.
127 const NO_EXECUTE_ENABLE = 1 << 11;
128 /// Enables SVM extensions.
129 const SECURE_VIRTUAL_MACHINE_ENABLE = 1 << 12;
130 /// Enable certain limit checks in 64-bit mode.
131 const LONG_MODE_SEGMENT_LIMIT_ENABLE = 1 << 13;
132 /// Enable the `fxsave` and `fxrstor` instructions to execute faster in 64-bit mode.
133 const FAST_FXSAVE_FXRSTOR = 1 << 14;
134 /// Changes how the `invlpg` instruction operates on TLB entries of upper-level entries.
135 const TRANSLATION_CACHE_EXTENSION = 1 << 15;
136 }
137}
138
139bitflags! {
140 /// Flags stored in IA32_U_CET and IA32_S_CET (Table-2-2 in Intel SDM Volume
141 /// 4). The Intel SDM-equivalent names are described in parentheses.
142 #[repr(transparent)]
143 #[derive(PartialEq, Eq, PartialOrd, Ord, Hash, Debug, Clone, Copy)]
144 pub struct CetFlags: u64 {
145 /// Enable shadow stack (SH_STK_EN)
146 const SS_ENABLE = 1 << 0;
147 /// Enable WRSS{D,Q}W instructions (WR_SHTK_EN)
148 const SS_WRITE_ENABLE = 1 << 1;
149 /// Enable indirect branch tracking (ENDBR_EN)
150 const IBT_ENABLE = 1 << 2;
151 /// Enable legacy treatment for indirect branch tracking (LEG_IW_EN)
152 const IBT_LEGACY_ENABLE = 1 << 3;
153 /// Enable no-track opcode prefix for indirect branch tracking (NO_TRACK_EN)
154 const IBT_NO_TRACK_ENABLE = 1 << 4;
155 /// Disable suppression of CET on legacy compatibility (SUPPRESS_DIS)
156 const IBT_LEGACY_SUPPRESS_ENABLE = 1 << 5;
157 /// Enable suppression of indirect branch tracking (SUPPRESS)
158 const IBT_SUPPRESS_ENABLE = 1 << 10;
159 /// Is IBT waiting for a branch to return? (read-only, TRACKER)
160 const IBT_TRACKED = 1 << 11;
161 }
162}
163
164#[cfg(all(feature = "instructions", target_arch = "x86_64"))]
165mod x86_64 {
166 use super::*;
167 use crate::addr::VirtAddr;
168 use crate::registers::rflags::RFlags;
169 use crate::structures::gdt::SegmentSelector;
170 use crate::structures::paging::Page;
171 use crate::structures::paging::Size4KiB;
172 use crate::PrivilegeLevel;
173 use bit_field::BitField;
174 use core::convert::TryInto;
175 use core::fmt;
176 // imports for intra doc links
177 #[cfg(doc)]
178 use crate::registers::{
179 control::Cr4Flags,
180 segmentation::{Segment, Segment64, CS, SS},
181 };
182 use core::arch::asm;
183
184 impl Msr {
185 /// Read 64 bits msr register.
186 ///
187 /// ## Safety
188 ///
189 /// The caller must ensure that this read operation has no unsafe side
190 /// effects.
191 #[inline]
192 pub unsafe fn read(&self) -> u64 {
193 let (high, low): (u32, u32);
194 unsafe {
195 asm!(
196 "rdmsr",
197 in("ecx") self.0,
198 out("eax") low, out("edx") high,
199 options(nomem, nostack, preserves_flags),
200 );
201 }
202 ((high as u64) << 32) | (low as u64)
203 }
204
205 /// Write 64 bits to msr register.
206 ///
207 /// ## Safety
208 ///
209 /// The caller must ensure that this write operation has no unsafe side
210 /// effects.
211 #[inline]
212 pub unsafe fn write(&mut self, value: u64) {
213 let low = value as u32;
214 let high = (value >> 32) as u32;
215
216 unsafe {
217 asm!(
218 "wrmsr",
219 in("ecx") self.0,
220 in("eax") low, in("edx") high,
221 options(nostack, preserves_flags),
222 );
223 }
224 }
225 }
226
227 impl Efer {
228 /// Read the current EFER flags.
229 #[inline]
230 pub fn read() -> EferFlags {
231 EferFlags::from_bits_truncate(Self::read_raw())
232 }
233
234 /// Read the current raw EFER flags.
235 #[inline]
236 pub fn read_raw() -> u64 {
237 unsafe { Self::MSR.read() }
238 }
239
240 /// Write the EFER flags, preserving reserved values.
241 ///
242 /// Preserves the value of reserved fields.
243 ///
244 /// ## Safety
245 ///
246 /// Unsafe because it's possible to break memory
247 /// safety with wrong flags, e.g. by disabling long mode.
248 #[inline]
249 pub unsafe fn write(flags: EferFlags) {
250 let old_value = Self::read_raw();
251 let reserved = old_value & !(EferFlags::all().bits());
252 let new_value = reserved | flags.bits();
253
254 unsafe {
255 Self::write_raw(new_value);
256 }
257 }
258
259 /// Write the EFER flags.
260 ///
261 /// Does not preserve any bits, including reserved fields.
262 ///
263 /// ## Safety
264 ///
265 /// Unsafe because it's possible to
266 /// break memory safety with wrong flags, e.g. by disabling long mode.
267 #[inline]
268 pub unsafe fn write_raw(flags: u64) {
269 let mut msr = Self::MSR;
270 unsafe {
271 msr.write(flags);
272 }
273 }
274
275 /// Update EFER flags.
276 ///
277 /// Preserves the value of reserved fields.
278 ///
279 /// ## Safety
280 ///
281 /// Unsafe because it's possible to break memory
282 /// safety with wrong flags, e.g. by disabling long mode.
283 #[inline]
284 pub unsafe fn update<F>(f: F)
285 where
286 F: FnOnce(&mut EferFlags),
287 {
288 let mut flags = Self::read();
289 f(&mut flags);
290 unsafe {
291 Self::write(flags);
292 }
293 }
294 }
295
296 impl FsBase {
297 /// Read the current FsBase register.
298 ///
299 /// If [`CR4.FSGSBASE`][Cr4Flags::FSGSBASE] is set, the more efficient
300 /// [`FS::read_base`] can be used instead.
301 #[inline]
302 pub fn read() -> VirtAddr {
303 VirtAddr::new(unsafe { Self::MSR.read() })
304 }
305
306 /// Write a given virtual address to the FS.Base register.
307 ///
308 /// If [`CR4.FSGSBASE`][Cr4Flags::FSGSBASE] is set, the more efficient
309 /// [`FS::write_base`] can be used instead.
310 #[inline]
311 pub fn write(address: VirtAddr) {
312 let mut msr = Self::MSR;
313 unsafe { msr.write(address.as_u64()) };
314 }
315 }
316
317 impl GsBase {
318 /// Read the current GsBase register.
319 ///
320 /// If [`CR4.FSGSBASE`][Cr4Flags::FSGSBASE] is set, the more efficient
321 /// [`GS::read_base`] can be used instead.
322 #[inline]
323 pub fn read() -> VirtAddr {
324 VirtAddr::new(unsafe { Self::MSR.read() })
325 }
326
327 /// Write a given virtual address to the GS.Base register.
328 ///
329 /// If [`CR4.FSGSBASE`][Cr4Flags::FSGSBASE] is set, the more efficient
330 /// [`GS::write_base`] can be used instead.
331 #[inline]
332 pub fn write(address: VirtAddr) {
333 let mut msr = Self::MSR;
334 unsafe { msr.write(address.as_u64()) };
335 }
336 }
337
338 impl KernelGsBase {
339 /// Read the current KernelGsBase register.
340 #[inline]
341 pub fn read() -> VirtAddr {
342 VirtAddr::new(unsafe { Self::MSR.read() })
343 }
344
345 /// Write a given virtual address to the KernelGsBase register.
346 #[inline]
347 pub fn write(address: VirtAddr) {
348 let mut msr = Self::MSR;
349 unsafe { msr.write(address.as_u64()) };
350 }
351 }
352
353 impl Star {
354 /// Read the Ring 0 and Ring 3 segment bases.
355 /// The remaining fields are ignored because they are
356 /// not valid for long mode.
357 ///
358 /// # Returns
359 /// - Field 1 (SYSRET): The CS selector is set to this field + 16. SS.Sel is set to
360 /// this field + 8. Because SYSRET always returns to CPL 3, the
361 /// RPL bits 1:0 should be initialized to 11b.
362 /// - Field 2 (SYSCALL): This field is copied directly into CS.Sel. SS.Sel is set to
363 /// this field + 8. Because SYSCALL always switches to CPL 0, the RPL bits
364 /// 33:32 should be initialized to 00b.
365 #[inline]
366 pub fn read_raw() -> (u16, u16) {
367 let msr_value = unsafe { Self::MSR.read() };
368 let sysret = msr_value.get_bits(48..64);
369 let syscall = msr_value.get_bits(32..48);
370 (sysret.try_into().unwrap(), syscall.try_into().unwrap())
371 }
372
373 /// Read the Ring 0 and Ring 3 segment bases.
374 /// Returns
375 /// - CS Selector SYSRET
376 /// - SS Selector SYSRET
377 /// - CS Selector SYSCALL
378 /// - SS Selector SYSCALL
379 #[inline]
380 pub fn read() -> (
381 SegmentSelector,
382 SegmentSelector,
383 SegmentSelector,
384 SegmentSelector,
385 ) {
386 let raw = Self::read_raw();
387 (
388 SegmentSelector(raw.0 + 16),
389 SegmentSelector(raw.0 + 8),
390 SegmentSelector(raw.1),
391 SegmentSelector(raw.1 + 8),
392 )
393 }
394
395 /// Write the Ring 0 and Ring 3 segment bases.
396 /// The remaining fields are ignored because they are
397 /// not valid for long mode.
398 ///
399 /// # Parameters
400 /// - sysret: The CS selector is set to this field + 16. SS.Sel is set to
401 /// this field + 8. Because SYSRET always returns to CPL 3, the
402 /// RPL bits 1:0 should be initialized to 11b.
403 /// - syscall: This field is copied directly into CS.Sel. SS.Sel is set to
404 /// this field + 8. Because SYSCALL always switches to CPL 0, the RPL bits
405 /// 33:32 should be initialized to 00b.
406 ///
407 /// # Safety
408 ///
409 /// Unsafe because this can cause system instability if passed in the
410 /// wrong values for the fields.
411 #[inline]
412 pub unsafe fn write_raw(sysret: u16, syscall: u16) {
413 let mut msr_value = 0u64;
414 msr_value.set_bits(48..64, sysret.into());
415 msr_value.set_bits(32..48, syscall.into());
416 let mut msr = Self::MSR;
417 unsafe {
418 msr.write(msr_value);
419 }
420 }
421
422 /// Write the Ring 0 and Ring 3 segment bases.
423 /// The remaining fields are ignored because they are
424 /// not valid for long mode.
425 /// This function will fail if the segment selectors are
426 /// not in the correct offset of each other or if the
427 /// segment selectors do not have correct privileges.
428 #[inline]
429 pub fn write(
430 cs_sysret: SegmentSelector,
431 ss_sysret: SegmentSelector,
432 cs_syscall: SegmentSelector,
433 ss_syscall: SegmentSelector,
434 ) -> Result<(), InvalidStarSegmentSelectors> {
435 // Convert to i32 to prevent underflows.
436 let cs_sysret_cmp = i32::from(cs_sysret.0) - 16;
437 let ss_sysret_cmp = i32::from(ss_sysret.0) - 8;
438 let cs_syscall_cmp = i32::from(cs_syscall.0);
439 let ss_syscall_cmp = i32::from(ss_syscall.0) - 8;
440
441 if cs_sysret_cmp != ss_sysret_cmp {
442 return Err(InvalidStarSegmentSelectors::SysretOffset);
443 }
444
445 if cs_syscall_cmp != ss_syscall_cmp {
446 return Err(InvalidStarSegmentSelectors::SyscallOffset);
447 }
448
449 if ss_sysret.rpl() != PrivilegeLevel::Ring3 {
450 return Err(InvalidStarSegmentSelectors::SysretPrivilegeLevel);
451 }
452
453 if ss_syscall.rpl() != PrivilegeLevel::Ring0 {
454 return Err(InvalidStarSegmentSelectors::SyscallPrivilegeLevel);
455 }
456
457 unsafe { Self::write_raw(ss_sysret.0 - 8, cs_syscall.0) };
458
459 Ok(())
460 }
461 }
462
463 #[derive(Debug)]
464 pub enum InvalidStarSegmentSelectors {
465 SysretOffset,
466 SyscallOffset,
467 SysretPrivilegeLevel,
468 SyscallPrivilegeLevel,
469 }
470
471 impl fmt::Display for InvalidStarSegmentSelectors {
472 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
473 match self {
474 Self::SysretOffset => write!(f, "Sysret CS and SS are not offset by 8."),
475 Self::SyscallOffset => write!(f, "Syscall CS and SS are not offset by 8."),
476 Self::SysretPrivilegeLevel => {
477 write!(f, "Sysret's segment must be a Ring3 segment.")
478 }
479 Self::SyscallPrivilegeLevel => {
480 write!(f, "Syscall's segment must be a Ring0 segment.")
481 }
482 }
483 }
484 }
485
486 impl LStar {
487 /// Read the current LStar register.
488 /// This holds the target RIP of a syscall.
489 #[inline]
490 pub fn read() -> VirtAddr {
491 VirtAddr::new(unsafe { Self::MSR.read() })
492 }
493
494 /// Write a given virtual address to the LStar register.
495 /// This holds the target RIP of a syscall.
496 #[inline]
497 pub fn write(address: VirtAddr) {
498 let mut msr = Self::MSR;
499 unsafe { msr.write(address.as_u64()) };
500 }
501 }
502
503 impl SFMask {
504 /// Read to the SFMask register.
505 /// The SFMASK register is used to specify which RFLAGS bits
506 /// are cleared during a SYSCALL. In long mode, SFMASK is used
507 /// to specify which RFLAGS bits are cleared when SYSCALL is
508 /// executed. If a bit in SFMASK is set to 1, the corresponding
509 /// bit in RFLAGS is cleared to 0. If a bit in SFMASK is cleared
510 /// to 0, the corresponding rFLAGS bit is not modified.
511 #[inline]
512 pub fn read() -> RFlags {
513 RFlags::from_bits(unsafe { Self::MSR.read() }).unwrap()
514 }
515
516 /// Write to the SFMask register.
517 /// The SFMASK register is used to specify which RFLAGS bits
518 /// are cleared during a SYSCALL. In long mode, SFMASK is used
519 /// to specify which RFLAGS bits are cleared when SYSCALL is
520 /// executed. If a bit in SFMASK is set to 1, the corresponding
521 /// bit in RFLAGS is cleared to 0. If a bit in SFMASK is cleared
522 /// to 0, the corresponding rFLAGS bit is not modified.
523 #[inline]
524 pub fn write(value: RFlags) {
525 let mut msr = Self::MSR;
526 unsafe { msr.write(value.bits()) };
527 }
528 }
529
530 impl UCet {
531 /// Read the raw IA32_U_CET.
532 #[inline]
533 fn read_raw() -> u64 {
534 unsafe { Self::MSR.read() }
535 }
536
537 /// Write the raw IA32_U_CET.
538 #[inline]
539 fn write_raw(value: u64) {
540 let mut msr = Self::MSR;
541 unsafe {
542 msr.write(value);
543 }
544 }
545
546 /// Read IA32_U_CET. Returns a tuple of the flags and the address to the legacy code page bitmap.
547 #[inline]
548 pub fn read() -> (CetFlags, Page) {
549 let value = Self::read_raw();
550 let cet_flags = CetFlags::from_bits_truncate(value);
551 let legacy_bitmap =
552 Page::from_start_address(VirtAddr::new(value & !(Page::<Size4KiB>::SIZE - 1)))
553 .unwrap();
554
555 (cet_flags, legacy_bitmap)
556 }
557
558 /// Write IA32_U_CET.
559 #[inline]
560 pub fn write(flags: CetFlags, legacy_bitmap: Page) {
561 Self::write_raw(flags.bits() | legacy_bitmap.start_address().as_u64());
562 }
563 }
564
565 impl SCet {
566 /// Read the raw IA32_S_CET.
567 #[inline]
568 fn read_raw() -> u64 {
569 unsafe { Self::MSR.read() }
570 }
571
572 /// Write the raw IA32_S_CET.
573 #[inline]
574 fn write_raw(value: u64) {
575 let mut msr = Self::MSR;
576 unsafe {
577 msr.write(value);
578 }
579 }
580
581 /// Read IA32_S_CET. Returns a tuple of the flags and the address to the legacy code page bitmap.
582 #[inline]
583 pub fn read() -> (CetFlags, Page) {
584 let value = Self::read_raw();
585 let cet_flags = CetFlags::from_bits_truncate(value);
586 let legacy_bitmap =
587 Page::from_start_address(VirtAddr::new(value & !(Page::<Size4KiB>::SIZE - 1)))
588 .unwrap();
589
590 (cet_flags, legacy_bitmap)
591 }
592
593 /// Write IA32_S_CET.
594 #[inline]
595 pub fn write(flags: CetFlags, legacy_bitmap: Page) {
596 Self::write_raw(flags.bits() | legacy_bitmap.start_address().as_u64());
597 }
598 }
599}