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
59/// Example usage:
60/// ```
61/// use regio::x86::Xcr;
62///
63/// const XCR0: Xcr<0, u64> = Xcr::new();
64/// ```
65pub type Xcr<const N: u32, Layout> =
66    Register<Layout, <XcrIo<N> as ControlRegister>::Access, XcrIo<N>>;
67
68impl<const N: u32, Layout> Xcr<N, Layout>
69where
70    XcrIo<N>: ControlRegister,
71    Layout: LayoutOver<u64>,
72{
73    /// Constructs an x86-64 control register instance.
74    pub const fn new() -> Self {
75        // Safety: There is nothing unsafe about XcrIo construction.
76        unsafe { Self::from_io(XcrIo {}) }
77    }
78}
79
80/// A simple I/O backend for reading from and writing to control registers.
81pub struct CrIo<const N: u32> {}
82
83impl<const N: u32> IoHandle for CrIo<N> {
84    type Base = u64;
85}
86
87/// A simple I/O backend for reading from and writing to extended control registers.
88pub struct XcrIo<const N: u32> {}
89
90impl<const N: u32> IoHandle for XcrIo<N> {
91    type Base = u64;
92}
93
94#[cfg(target_arch = "x86_64")]
95mod x86_64_only {
96    use core::arch::asm;
97
98    use super::*;
99    use crate::{ReadHandle, WriteHandle};
100
101    macro_rules! impl_cr_io {
102        ($n:literal, $cr_str:literal) => {
103            impl ReadHandle for CrIo<$n> {
104                #[inline]
105                unsafe fn read_raw(&self) -> u64 {
106                    let value: u64;
107                    unsafe {
108                        asm!(
109                            concat!("mov {value}, ", $cr_str),
110                            value = out(reg) value,
111                            options(nomem, nostack, preserves_flags),
112                        );
113                    }
114                    value
115                }
116            }
117
118            impl WriteHandle for CrIo<$n> {
119                #[inline]
120                unsafe fn write_raw(&self, value: u64) {
121                    unsafe {
122                        asm!(
123                            concat!("mov ", $cr_str, ", {value}"),
124                            value = in(reg) value,
125                            // TODO(https://fxbug.dev/525077555): Revisit using nomem here.
126                            options(nostack, preserves_flags),
127                        );
128                    }
129                }
130            }
131        };
132    }
133
134    impl_cr_io!(0, "cr0");
135    impl_cr_io!(2, "cr2");
136    impl_cr_io!(3, "cr3");
137    impl_cr_io!(4, "cr4");
138    impl_cr_io!(8, "cr8");
139}
140
141#[cfg(all(target_arch = "x86_64", feature = "xsave"))]
142mod x86_64_xsave_only {
143    use core::arch::x86::{_xgetbv, _xsetbv};
144
145    use super::*;
146    use crate::{ReadHandle, WriteHandle};
147
148    macro_rules! impl_xcr_io {
149        ($n:literal) => {
150            impl ReadHandle for XcrIo<$n> {
151                #[inline]
152                unsafe fn read_raw(&self) -> u64 {
153                    unsafe { _xgetbv($n) }
154                }
155            }
156
157            impl WriteHandle for XcrIo<$n> {
158                #[inline]
159                unsafe fn write_raw(&self, value: u64) {
160                    unsafe { _xsetbv($n, value) }
161                }
162            }
163        };
164    }
165    impl_xcr_io!(0);
166}
167
168#[cfg(all(test, target_arch = "x86_64"))]
169mod tests {
170    use super::*;
171
172    #[test]
173    fn test_cr_compilation() {
174        #[allow(unused)]
175        {
176            const CR0: Cr<0, u64> = Cr::new();
177            const CR2: Cr<2, u64> = Cr::new();
178            const CR3: Cr<3, u64> = Cr::new();
179            const CR4: Cr<4, u64> = Cr::new();
180            const CR8: Cr<8, u64> = Cr::new();
181        }
182    }
183}