1
1
//! satp register
2
2
3
+ use crate :: result:: { Error , Result } ;
4
+
3
5
/// satp register
4
6
#[ derive( Clone , Copy , Debug ) ]
5
7
pub struct Satp {
@@ -14,27 +16,35 @@ impl Satp {
14
16
}
15
17
16
18
/// Current address-translation scheme
19
+ ///
20
+ /// **WARNING**: panics if the field has an invalid variant.
17
21
#[ inline]
18
22
#[ cfg( target_pointer_width = "32" ) ]
19
23
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 ( )
24
32
}
25
33
26
34
/// Current address-translation scheme
35
+ ///
36
+ /// **WARNING**: panics if the field has an invalid variant.
27
37
#[ inline]
28
38
#[ cfg( target_pointer_width = "64" ) ]
29
39
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 ( )
38
48
}
39
49
40
50
/// Address space identifier
@@ -92,25 +102,108 @@ pub enum Mode {
92
102
Sv64 = 11 ,
93
103
}
94
104
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
+
95
140
read_csr_as ! ( Satp , 0x180 ) ;
96
141
write_csr_as_usize ! ( 0x180 ) ;
97
142
98
143
/// 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
99
149
#[ inline]
100
150
#[ cfg( target_pointer_width = "32" ) ]
101
151
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
+ }
106
175
}
107
176
108
177
/// 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
109
183
#[ inline]
110
184
#[ cfg( target_pointer_width = "64" ) ]
111
185
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
+ }
116
209
}
0 commit comments