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
28/// A simple I/O backend for reading from and writing to MSRs.
29pub struct MsrIo<const ID: u32> {}
30
31impl<const ID: u32> IoHandle for MsrIo<ID> {
32    type Base = u64;
33}
34
35#[cfg(target_arch = "x86_64")]
36mod x86_64_only {
37    use super::*;
38    use crate::{ReadHandle, WriteHandle};
39
40    use core::arch::asm;
41
42    impl<const ID: u32> ReadHandle for MsrIo<ID> {
43        #[inline]
44        unsafe fn read_raw(&self) -> u64 {
45            let hi: u32;
46            let lo: u32;
47            unsafe {
48                asm!(
49                    "rdmsr",
50                    in("ecx") ID,
51                    out("eax") lo,
52                    out("edx") hi,
53                    options(nomem, nostack, preserves_flags),
54                )
55            };
56            u64::from(hi) << 32 | u64::from(lo)
57        }
58    }
59
60    impl<const ID: u32> WriteHandle for MsrIo<ID> {
61        #[inline]
62        unsafe fn write_raw(&self, value: u64) {
63            let hi = (value >> 32) as u32;
64            let lo = value as u32;
65            unsafe {
66                asm!(
67                    "wrmsr",
68                    in("ecx") ID,
69                    in("eax") lo,
70                    in("edx") hi,
71                    options(nomem, nostack, preserves_flags),
72                )
73            }
74        }
75    }
76}
77
78#[cfg(all(test, target_arch = "x86_64"))]
79mod tests {
80    use super::*;
81    use crate::RwSafe;
82
83    // MSRs are privileged instructions, but these abstractions are fine to
84    // compile in under any x86-64 environment so long as we don't actually
85    // perform the MSR access at runtime.
86    #[test]
87    fn test_msr_compilation() {
88        #[allow(unused)]
89        const IA32_TIME_STAMP_COUNTER: Msr<0x10, u64, RwSafe> = Msr::new();
90    }
91}