Skip to main content

regio/x86/
cr.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, Ro, RwSafe, RwUnsafe};
6
7/// Trait implemented by supported control registers, fixing their access permissions.
8pub trait ControlRegister {
9    type Access: Accessible;
10}
11
12impl ControlRegister for CrIo<0> {
13    // Can enable/disable paging (PG) and caching (CD, NW).
14    type Access = RwUnsafe;
15}
16
17impl ControlRegister for CrIo<2> {
18    type Access = Ro;
19}
20
21impl ControlRegister for CrIo<3> {
22    // Can switch the active page table root and PCID.
23    type Access = RwUnsafe;
24}
25
26impl ControlRegister for CrIo<4> {
27    // Can alter virtual memory mode (PAE, LA57, PCIDE) and execution protection (SMEP, SMAP, PKE).
28    type Access = RwUnsafe;
29}
30
31impl ControlRegister for CrIo<8> {
32    type Access = RwSafe;
33}
34
35impl ControlRegister for XcrIo<0> {
36    type Access = RwSafe;
37}
38
39/// Example usage:
40/// ```
41/// use regio::x86::Cr;
42///
43/// const CR0: Cr<0, u64> = Cr::new();
44/// ```
45pub type Cr<const N: u32, Layout> = Register<Layout, <CrIo<N> as ControlRegister>::Access, CrIo<N>>;
46
47impl<const N: u32, Layout> Cr<N, Layout>
48where
49    CrIo<N>: ControlRegister,
50    Layout: LayoutOver<u64>,
51{
52    /// Constructs an x86-64 control register instance.
53    pub const fn new() -> Self {
54        // Safety: There is nothing unsafe about CrIo construction.
55        unsafe { Self::from_io(CrIo {}) }
56    }
57}
58
59impl<const N: u32, Layout> Default for Cr<N, Layout>
60where
61    CrIo<N>: ControlRegister,
62    Layout: LayoutOver<u64>,
63{
64    fn default() -> Self {
65        Self::new()
66    }
67}
68
69/// Example usage:
70/// ```
71/// use regio::x86::Xcr;
72///
73/// const XCR0: Xcr<0, u64> = Xcr::new();
74/// ```
75pub type Xcr<const N: u32, Layout> =
76    Register<Layout, <XcrIo<N> as ControlRegister>::Access, XcrIo<N>>;
77
78impl<const N: u32, Layout> Xcr<N, Layout>
79where
80    XcrIo<N>: ControlRegister,
81    Layout: LayoutOver<u64>,
82{
83    /// Constructs an x86-64 control register instance.
84    pub const fn new() -> Self {
85        // Safety: There is nothing unsafe about XcrIo construction.
86        unsafe { Self::from_io(XcrIo {}) }
87    }
88}
89
90impl<const N: u32, Layout> Default for Xcr<N, Layout>
91where
92    XcrIo<N>: ControlRegister,
93    Layout: LayoutOver<u64>,
94{
95    fn default() -> Self {
96        Self::new()
97    }
98}
99
100/// A simple I/O backend for reading from and writing to control registers.
101pub struct CrIo<const N: u32> {}
102
103impl<const N: u32> IoHandle for CrIo<N> {
104    type Base = u64;
105}
106
107/// A simple I/O backend for reading from and writing to extended control registers.
108pub struct XcrIo<const N: u32> {}
109
110impl<const N: u32> IoHandle for XcrIo<N> {
111    type Base = u64;
112}
113
114#[cfg(target_arch = "x86_64")]
115mod x86_64_only {
116    use core::arch::asm;
117
118    use super::*;
119    use crate::{ReadHandle, WriteHandle};
120
121    macro_rules! impl_cr_io {
122        ($n:literal, $cr_str:literal) => {
123            impl ReadHandle for CrIo<$n> {
124                #[inline]
125                unsafe fn read_raw(&self) -> u64 {
126                    let value: u64;
127                    unsafe {
128                        asm!(
129                            concat!("mov {value}, ", $cr_str),
130                            value = out(reg) value,
131                            options(nomem, nostack, preserves_flags),
132                        );
133                    }
134                    value
135                }
136            }
137
138            impl WriteHandle for CrIo<$n> {
139                #[inline]
140                unsafe fn write_raw(&self, value: u64) {
141                    unsafe {
142                        asm!(
143                            concat!("mov ", $cr_str, ", {value}"),
144                            value = in(reg) value,
145                            // TODO(https://fxbug.dev/525077555): Revisit using nomem here.
146                            options(nostack, preserves_flags),
147                        );
148                    }
149                }
150            }
151        };
152    }
153
154    impl_cr_io!(0, "cr0");
155    impl_cr_io!(2, "cr2");
156    impl_cr_io!(3, "cr3");
157    impl_cr_io!(4, "cr4");
158    impl_cr_io!(8, "cr8");
159}
160
161#[cfg(all(target_arch = "x86_64", feature = "xsave"))]
162mod x86_64_xsave_only {
163    use core::arch::x86::{_xgetbv, _xsetbv};
164
165    use super::*;
166    use crate::{ReadHandle, WriteHandle};
167
168    macro_rules! impl_xcr_io {
169        ($n:literal) => {
170            impl ReadHandle for XcrIo<$n> {
171                #[inline]
172                unsafe fn read_raw(&self) -> u64 {
173                    unsafe { _xgetbv($n) }
174                }
175            }
176
177            impl WriteHandle for XcrIo<$n> {
178                #[inline]
179                unsafe fn write_raw(&self, value: u64) {
180                    unsafe { _xsetbv($n, value) }
181                }
182            }
183        };
184    }
185    impl_xcr_io!(0);
186}
187
188#[cfg(all(test, target_arch = "x86_64"))]
189mod tests {
190    use super::*;
191
192    #[test]
193    fn test_cr_compilation() {
194        #[allow(unused)]
195        {
196            const CR0: Cr<0, u64> = Cr::new();
197            const CR2: Cr<2, u64> = Cr::new();
198            const CR3: Cr<3, u64> = Cr::new();
199            const CR4: Cr<4, u64> = Cr::new();
200            const CR8: Cr<8, u64> = Cr::new();
201        }
202    }
203}