1use crate::{Accessible, IoHandle, LayoutOver, Register, Ro, RwSafe, RwUnsafe};
6
7pub trait ControlRegister {
9 type Access: Accessible;
10}
11
12impl ControlRegister for CrIo<0> {
13 type Access = RwUnsafe;
15}
16
17impl ControlRegister for CrIo<2> {
18 type Access = Ro;
19}
20
21impl ControlRegister for CrIo<3> {
22 type Access = RwUnsafe;
24}
25
26impl ControlRegister for CrIo<4> {
27 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
39pub 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 pub const fn new() -> Self {
54 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
69pub 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 pub const fn new() -> Self {
85 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
100pub struct CrIo<const N: u32> {}
102
103impl<const N: u32> IoHandle for CrIo<N> {
104 type Base = u64;
105}
106
107pub 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 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}