Skip to content

Commit 54bdc4e

Browse files
committed
riscv: add fallible functions to satp
Adds fallible access functions for `Satp` ASID and PPN fields.
1 parent 56f30bb commit 54bdc4e

File tree

1 file changed

+113
-20
lines changed

1 file changed

+113
-20
lines changed

riscv/src/register/satp.rs

+113-20
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,7 @@
11
//! satp register
22
3+
use crate::result::{Error, Result};
4+
35
/// satp register
46
#[derive(Clone, Copy, Debug)]
57
pub struct Satp {
@@ -14,27 +16,35 @@ impl Satp {
1416
}
1517

1618
/// Current address-translation scheme
19+
///
20+
/// **WARNING**: panics if the field has an invalid variant.
1721
#[inline]
1822
#[cfg(target_pointer_width = "32")]
1923
pub fn mode(&self) -> Mode {
20-
match self.bits & (1 << 31) != 0 {
21-
false => Mode::Bare,
22-
true => Mode::Sv32,
23-
}
24+
self.try_mode().unwrap()
25+
}
26+
27+
/// Attempts to get the current address-translation scheme.
28+
#[inline]
29+
#[cfg(target_pointer_width = "32")]
30+
pub fn try_mode(&self) -> Result<Mode> {
31+
((self.bits >> 31) as u8).try_into()
2432
}
2533

2634
/// Current address-translation scheme
35+
///
36+
/// **WARNING**: panics if the field has an invalid variant.
2737
#[inline]
2838
#[cfg(target_pointer_width = "64")]
2939
pub fn mode(&self) -> Mode {
30-
match self.bits >> 60 {
31-
0 => Mode::Bare,
32-
8 => Mode::Sv39,
33-
9 => Mode::Sv48,
34-
10 => Mode::Sv57,
35-
11 => Mode::Sv64,
36-
_ => unreachable!(),
37-
}
40+
self.try_mode().unwrap()
41+
}
42+
43+
/// Attempts to get the current address-translation scheme.
44+
#[inline]
45+
#[cfg(target_pointer_width = "64")]
46+
pub fn try_mode(&self) -> Result<Mode> {
47+
((self.bits >> 60) as u8).try_into()
3848
}
3949

4050
/// Address space identifier
@@ -92,25 +102,108 @@ pub enum Mode {
92102
Sv64 = 11,
93103
}
94104

105+
#[cfg(target_pointer_width = "32")]
106+
impl TryFrom<u8> for Mode {
107+
type Error = Error;
108+
109+
fn try_from(val: u8) -> Result<Self> {
110+
match val {
111+
0 => Ok(Mode::Bare),
112+
1 => Ok(Mode::Sv32),
113+
_ => Err(Error::InvalidVariant {
114+
field: "mode",
115+
value: val as usize,
116+
}),
117+
}
118+
}
119+
}
120+
121+
#[cfg(target_pointer_width = "64")]
122+
impl TryFrom<u8> for Mode {
123+
type Error = Error;
124+
125+
fn try_from(val: u8) -> Result<Self> {
126+
match val {
127+
0 => Ok(Mode::Bare),
128+
8 => Ok(Mode::Sv39),
129+
9 => Ok(Mode::Sv48),
130+
10 => Ok(Mode::Sv57),
131+
11 => Ok(Mode::Sv64),
132+
_ => Err(Error::InvalidVariant {
133+
field: "mode",
134+
value: val as usize,
135+
}),
136+
}
137+
}
138+
}
139+
95140
read_csr_as!(Satp, 0x180);
96141
write_csr_as_usize!(0x180);
97142

98143
/// Sets the register to corresponding page table mode, physical page number and address space id.
144+
///
145+
/// **WARNING**: panics on:
146+
///
147+
/// - non-`riscv` targets
148+
/// - invalid field values
99149
#[inline]
100150
#[cfg(target_pointer_width = "32")]
101151
pub unsafe fn set(mode: Mode, asid: usize, ppn: usize) {
102-
assert_eq!(asid, asid & 0x1FF, "invalid value for asid");
103-
assert_eq!(ppn, ppn & 0x3F_FFFF, "invalid value for ppn");
104-
let bits = (mode as usize) << 31 | (asid << 22) | ppn;
105-
_write(bits);
152+
try_set(mode, asid, ppn).unwrap();
153+
}
154+
155+
/// Attempts to set the register to corresponding page table mode, physical page number and address space id.
156+
#[inline]
157+
#[cfg(target_pointer_width = "32")]
158+
pub unsafe fn try_set(mode: Mode, asid: usize, ppn: usize) -> Result<()> {
159+
if asid != asid & 0x1FF {
160+
Err(Error::InvalidValue {
161+
field: "asid",
162+
value: asid,
163+
bitmask: 0x1FF,
164+
})
165+
} else if ppn != ppn & 0x3F_FFFF {
166+
Err(Error::InvalidValue {
167+
field: "ppn",
168+
value: ppn,
169+
bitmask: 0x3F_FFFF,
170+
})
171+
} else {
172+
let bits = (mode as usize) << 31 | (asid << 22) | ppn;
173+
_try_write(bits)
174+
}
106175
}
107176

108177
/// Sets the register to corresponding page table mode, physical page number and address space id.
178+
///
179+
/// **WARNING**: panics on:
180+
///
181+
/// - non-`riscv` targets
182+
/// - invalid field values
109183
#[inline]
110184
#[cfg(target_pointer_width = "64")]
111185
pub unsafe fn set(mode: Mode, asid: usize, ppn: usize) {
112-
assert_eq!(asid, asid & 0xFFFF, "invalid value for asid");
113-
assert_eq!(ppn, ppn & 0xFFF_FFFF_FFFF, "invalid value for ppn");
114-
let bits = (mode as usize) << 60 | (asid << 44) | ppn;
115-
_write(bits);
186+
try_set(mode, asid, ppn).unwrap()
187+
}
188+
189+
/// Attempts to set the register to corresponding page table mode, physical page number and address space id.
190+
#[inline]
191+
#[cfg(target_pointer_width = "64")]
192+
pub unsafe fn try_set(mode: Mode, asid: usize, ppn: usize) -> Result<()> {
193+
if asid != asid & 0xFFFF {
194+
Err(Error::InvalidValue {
195+
field: "asid",
196+
value: asid,
197+
bitmask: 0xFFFF,
198+
})
199+
} else if ppn != ppn & 0xFFF_FFFF_FFFF {
200+
Err(Error::InvalidValue {
201+
field: "ppn",
202+
value: ppn,
203+
bitmask: 0xFFF_FFFF_FFFF,
204+
})
205+
} else {
206+
let bits = (mode as usize) << 60 | (asid << 44) | ppn;
207+
_try_write(bits)
208+
}
116209
}

0 commit comments

Comments
 (0)