Skip to main content

regio/x86/
msr.rs

1// Copyright 2026 The Fuchsia Authors. All rights reserved.
2// Use of this source code is governed by a BSD-style license that can be
3// found in the LICENSE file.
4
5use crate::{Accessible, IoHandle, LayoutOver, Register};
6
7/// Example usage:
8/// ```
9/// use regio::{Register, Rw};
10/// use regio::x64::MsrIo;
11///
12/// const IA32_TIME_STAMP_COUNTER: Msr<0x10, u64, Rw> = unsafe { Msr::new() };
13/// ```
14pub type Msr<const ID: u32, Layout, Access> = Register<Layout, Access, MsrIo<ID>>;
15
16impl<const ID: u32, Layout, Access> Msr<ID, Layout, Access>
17where
18    Layout: LayoutOver<u64>,
19    Access: Accessible,
20{
21    /// Constructs an x86-64 MSR instance.
22    pub const fn new() -> Self {
23        // Safety: There is nothing unsafe about MsrIo construction.
24        unsafe { Self::from_io(MsrIo {}) }
25    }
26}
27
28impl<const ID: u32, Layout, Access> Default for Msr<ID, Layout, Access>
29where
30    Layout: LayoutOver<u64>,
31    Access: Accessible,
32{
33    fn default() -> Self {
34        Self::new()
35    }
36}
37
38/// A simple I/O backend for reading from and writing to MSRs.
39pub struct MsrIo<const ID: u32> {}
40
41impl<const ID: u32> IoHandle for MsrIo<ID> {
42    type Base = u64;
43}
44
45#[cfg(target_arch = "x86_64")]
46mod x86_64_only {
47    use super::*;
48    use crate::{ReadHandle, WriteHandle};
49
50    use core::arch::asm;
51
52    impl<const ID: u32> ReadHandle for MsrIo<ID> {
53        #[inline]
54        unsafe fn read_raw(&self) -> u64 {
55            let hi: u32;
56            let lo: u32;
57            unsafe {
58                asm!(
59                    "rdmsr",
60                    in("ecx") ID,
61                    out("eax") lo,
62                    out("edx") hi,
63                    options(nomem, nostack, preserves_flags),
64                )
65            };
66            u64::from(hi) << 32 | u64::from(lo)
67        }
68    }
69
70    impl<const ID: u32> WriteHandle for MsrIo<ID> {
71        #[inline]
72        unsafe fn write_raw(&self, value: u64) {
73            let hi = (value >> 32) as u32;
74            let lo = value as u32;
75            unsafe {
76                asm!(
77                    "wrmsr",
78                    in("ecx") ID,
79                    in("eax") lo,
80                    in("edx") hi,
81                    options(nomem, nostack, preserves_flags),
82                )
83            }
84        }
85    }
86}
87
88#[cfg(all(test, target_arch = "x86_64"))]
89mod tests {
90    use super::*;
91    use crate::RwSafe;
92
93    // MSRs are privileged instructions, but these abstractions are fine to
94    // compile in under any x86-64 environment so long as we don't actually
95    // perform the MSR access at runtime.
96    #[test]
97    fn test_msr_compilation() {
98        #[allow(unused)]
99        const IA32_TIME_STAMP_COUNTER: Msr<0x10, u64, RwSafe> = Msr::new();
100    }
101}