Skip to content

Commit

Permalink
riscv: add fallible functions to pmpcfgx
Browse files Browse the repository at this point in the history
Adds fallible conversion functions for `Pmpcfgx` permission and range
fields.
  • Loading branch information
rmsyn committed Jul 4, 2024
1 parent 54bdc4e commit 77b692f
Showing 1 changed file with 80 additions and 30 deletions.
110 changes: 80 additions & 30 deletions riscv/src/register/pmpcfgx.rs
Original file line number Diff line number Diff line change
@@ -1,5 +1,7 @@
//! Physical memory protection configuration

use crate::result::{Error, Result};

/// Permission enum contains all possible permission modes for pmp registers
#[derive(Clone, Copy, Debug, Eq, PartialEq)]
pub enum Permission {
Expand All @@ -13,6 +15,28 @@ pub enum Permission {
RWX = 0b111,
}

impl TryFrom<u8> for Permission {
type Error = Error;

fn try_from(val: u8) -> Result<Self> {
match val {
0b000 => Ok(Self::NONE),
0b001 => Ok(Self::R),
0b010 => Ok(Self::W),
0b011 => Ok(Self::RW),
0b100 => Ok(Self::X),
0b101 => Ok(Self::RX),
0b110 => Ok(Self::WX),
0b111 => Ok(Self::RWX),
_ => Err(Error::InvalidValue {
field: "permission",
value: val as usize,
bitmask: 0b111,
}),
}
}
}

/// Range enum contains all possible addressing modes for pmp registers
#[derive(Clone, Copy, Debug, Eq, PartialEq)]
pub enum Range {
Expand All @@ -22,6 +46,24 @@ pub enum Range {
NAPOT = 0b11,
}

impl TryFrom<u8> for Range {
type Error = Error;

fn try_from(val: u8) -> Result<Self> {
match val {
0b00 => Ok(Self::OFF),
0b01 => Ok(Self::TOR),
0b10 => Ok(Self::NA4),
0b11 => Ok(Self::NAPOT),
_ => Err(Error::InvalidValue {
field: "range",
value: val as usize,
bitmask: 0b11,
}),
}
}
}

/// Pmp struct holds a high-level representation of a single pmp configuration
#[derive(Clone, Copy, Debug)]
pub struct Pmp {
Expand All @@ -42,38 +84,46 @@ pub struct Pmpcsr {

impl Pmpcsr {
/// Take the register contents and translate into a Pmp configuration struct
///
/// **WARNING**: panics on:
///
/// - non-`riscv` targets
/// - `index` is out of bounds
/// - register fields contain invalid values
#[inline]
pub fn into_config(&self, index: usize) -> Pmp {
#[cfg(riscv32)]
assert!(index < 4);

#[cfg(riscv64)]
assert!(index < 8);

let byte = (self.bits >> (8 * index)) as u8; // move config to LSB and drop the rest
let permission = byte & 0x7; // bits 0-2
let range = (byte >> 3) & 0x3; // bits 3-4
Pmp {
byte,
permission: match permission {
0 => Permission::NONE,
1 => Permission::R,
2 => Permission::W,
3 => Permission::RW,
4 => Permission::X,
5 => Permission::RX,
6 => Permission::WX,
7 => Permission::RWX,
_ => unreachable!(),
},
range: match range {
0 => Range::OFF,
1 => Range::TOR,
2 => Range::NA4,
3 => Range::NAPOT,
_ => unreachable!(),
},
locked: (byte & (1 << 7)) != 0,
self.try_into_config(index).unwrap()
}

/// Attempts to take the register contents, and translate into a Pmp configuration struct.
#[inline]
pub fn try_into_config(&self, index: usize) -> Result<Pmp> {
let max = match () {
#[cfg(riscv32)]
() => Ok(4usize),
#[cfg(riscv64)]
() => Ok(8usize),
#[cfg(not(any(riscv32, riscv64)))]
() => Err(Error::Unimplemented),
}?;

if index < max {
let byte = (self.bits >> (8 * index)) as u8; // move config to LSB and drop the rest
let permission = byte & 0x7; // bits 0-2
let range = (byte >> 3) & 0x3; // bits 3-4

Ok(Pmp {
byte,
permission: permission.try_into()?,
range: range.try_into()?,
locked: (byte & (1 << 7)) != 0,
})
} else {
Err(Error::IndexOutOfBounds {
index,
min: 0,
max: max - 1,
})
}
}
}
Expand Down

0 comments on commit 77b692f

Please sign in to comment.