11//! Physical memory protection configuration
22
3+ use crate :: result:: { Error , Result } ;
4+
35/// Permission enum contains all possible permission modes for pmp registers
46#[ derive( Clone , Copy , Debug , Eq , PartialEq ) ]
57pub enum Permission {
@@ -13,6 +15,28 @@ pub enum Permission {
1315 RWX = 0b111 ,
1416}
1517
18+ impl TryFrom < u8 > for Permission {
19+ type Error = Error ;
20+
21+ fn try_from ( val : u8 ) -> Result < Self > {
22+ match val {
23+ 0b000 => Ok ( Self :: NONE ) ,
24+ 0b001 => Ok ( Self :: R ) ,
25+ 0b010 => Ok ( Self :: W ) ,
26+ 0b011 => Ok ( Self :: RW ) ,
27+ 0b100 => Ok ( Self :: X ) ,
28+ 0b101 => Ok ( Self :: RX ) ,
29+ 0b110 => Ok ( Self :: WX ) ,
30+ 0b111 => Ok ( Self :: RWX ) ,
31+ _ => Err ( Error :: InvalidValue {
32+ field : "permission" ,
33+ value : val as usize ,
34+ bitmask : 0b111 ,
35+ } ) ,
36+ }
37+ }
38+ }
39+
1640/// Range enum contains all possible addressing modes for pmp registers
1741#[ derive( Clone , Copy , Debug , Eq , PartialEq ) ]
1842pub enum Range {
@@ -22,6 +46,24 @@ pub enum Range {
2246 NAPOT = 0b11 ,
2347}
2448
49+ impl TryFrom < u8 > for Range {
50+ type Error = Error ;
51+
52+ fn try_from ( val : u8 ) -> Result < Self > {
53+ match val {
54+ 0b00 => Ok ( Self :: OFF ) ,
55+ 0b01 => Ok ( Self :: TOR ) ,
56+ 0b10 => Ok ( Self :: NA4 ) ,
57+ 0b11 => Ok ( Self :: NAPOT ) ,
58+ _ => Err ( Error :: InvalidValue {
59+ field : "range" ,
60+ value : val as usize ,
61+ bitmask : 0b11 ,
62+ } ) ,
63+ }
64+ }
65+ }
66+
2567/// Pmp struct holds a high-level representation of a single pmp configuration
2668#[ derive( Clone , Copy , Debug ) ]
2769pub struct Pmp {
@@ -42,38 +84,46 @@ pub struct Pmpcsr {
4284
4385impl Pmpcsr {
4486 /// Take the register contents and translate into a Pmp configuration struct
87+ ///
88+ /// **WARNING**: panics on:
89+ ///
90+ /// - non-`riscv` targets
91+ /// - `index` is out of bounds
92+ /// - register fields contain invalid values
4593 #[ inline]
4694 pub fn into_config ( & self , index : usize ) -> Pmp {
47- #[ cfg( riscv32) ]
48- assert ! ( index < 4 ) ;
49-
50- #[ cfg( riscv64) ]
51- assert ! ( index < 8 ) ;
52-
53- let byte = ( self . bits >> ( 8 * index) ) as u8 ; // move config to LSB and drop the rest
54- let permission = byte & 0x7 ; // bits 0-2
55- let range = ( byte >> 3 ) & 0x3 ; // bits 3-4
56- Pmp {
57- byte,
58- permission : match permission {
59- 0 => Permission :: NONE ,
60- 1 => Permission :: R ,
61- 2 => Permission :: W ,
62- 3 => Permission :: RW ,
63- 4 => Permission :: X ,
64- 5 => Permission :: RX ,
65- 6 => Permission :: WX ,
66- 7 => Permission :: RWX ,
67- _ => unreachable ! ( ) ,
68- } ,
69- range : match range {
70- 0 => Range :: OFF ,
71- 1 => Range :: TOR ,
72- 2 => Range :: NA4 ,
73- 3 => Range :: NAPOT ,
74- _ => unreachable ! ( ) ,
75- } ,
76- locked : ( byte & ( 1 << 7 ) ) != 0 ,
95+ self . try_into_config ( index) . unwrap ( )
96+ }
97+
98+ /// Attempts to take the register contents, and translate into a Pmp configuration struct.
99+ #[ inline]
100+ pub fn try_into_config ( & self , index : usize ) -> Result < Pmp > {
101+ let max = match ( ) {
102+ #[ cfg( riscv32) ]
103+ ( ) => Ok ( 4usize ) ,
104+ #[ cfg( riscv64) ]
105+ ( ) => Ok ( 8usize ) ,
106+ #[ cfg( not( any( riscv32, riscv64) ) ) ]
107+ ( ) => Err ( Error :: Unimplemented ) ,
108+ } ?;
109+
110+ if index < max {
111+ let byte = ( self . bits >> ( 8 * index) ) as u8 ; // move config to LSB and drop the rest
112+ let permission = byte & 0x7 ; // bits 0-2
113+ let range = ( byte >> 3 ) & 0x3 ; // bits 3-4
114+
115+ Ok ( Pmp {
116+ byte,
117+ permission : permission. try_into ( ) ?,
118+ range : range. try_into ( ) ?,
119+ locked : ( byte & ( 1 << 7 ) ) != 0 ,
120+ } )
121+ } else {
122+ Err ( Error :: IndexOutOfBounds {
123+ index,
124+ min : 0 ,
125+ max : max - 1 ,
126+ } )
77127 }
78128 }
79129}
0 commit comments