11//! satp register
22
3+ use crate :: result:: { Error , Result } ;
4+
35/// satp register
46#[ derive( Clone , Copy , Debug ) ]
57pub 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+
95140read_csr_as ! ( Satp , 0x180 ) ;
96141write_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" ) ]
101151pub 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" ) ]
111185pub 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