1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
/// Physical memory protection configuration
use bit_field::BitField;

/// Permission enum contains all possible permission modes for pmp registers
#[derive(Clone, Copy, Debug)]
pub enum Permission {
    NONE = 0b000,
    R = 0b001,
    W = 0b010,
    RW = 0b011,
    X = 0b100,
    RX = 0b101,
    WX = 0b110,
    RWX = 0b111,
}

/// Range enum contains all possible addressing modes for pmp registers
#[derive(Clone, Copy, Debug)]
pub enum Range {
    OFF = 0b00,
    TOR = 0b01,
    NA4 = 0b10,
    NAPOT = 0b11,
}

/// Pmp struct holds a high-level representation of a single pmp configuration
#[derive(Clone, Copy, Debug)]
pub struct Pmp {
    /// raw bits
    pub byte: u8,
    /// Current PMP Permission
    pub permission: Permission,
    /// Current PMP Range
    pub range: Range,
    /// Is PMP locked?
    pub locked: bool,
}

pub struct Pmpcsr {
    /// Holds the raw contents of a PMP CSR Register
    pub bits: usize,
}

impl Pmpcsr {
    /// Take the register contents and translate into a Pmp configuration struct
    #[inline]
    pub fn into_config(&self, index: usize) -> Pmp {
        #[cfg(riscv32)]
        assert!(index < 4);

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

        let byte = self.bits.get_bits(8 * index..=8 * index + 7) as u8;
        Pmp {
            byte,
            permission: match byte.get_bits(0..=2) {
                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 byte.get_bits(3..=4) {
                0 => Range::OFF,
                1 => Range::TOR,
                2 => Range::NA4,
                3 => Range::NAPOT,
                _ => unreachable!(),
            },
            locked: byte.get_bit(7) as bool,
        }
    }
}

/// Physical memory protection configuration
/// pmpcfg0 struct contains pmp0cfg - pmp3cfg for RV32, and pmp0cfg - pmp7cfg for RV64
pub mod pmpcfg0 {
    use super::{Permission, Pmpcsr, Range};
    use bit_field::BitField;

    read_csr_as!(Pmpcsr, 0x3A0, __read_pmpcfg0);
    write_csr_as_usize!(0x3A0, __write_pmpcfg0);

    set_pmp!();
    clear_pmp!();
}

/// Physical memory protection configuration
/// pmpcfg1 struct contains pmp4cfg - pmp7cfg for RV32 only
#[cfg(riscv32)]
pub mod pmpcfg1 {
    use super::{Permission, Pmpcsr, Range};
    use bit_field::BitField;

    read_csr_as!(Pmpcsr, 0x3A1, __read_pmpcfg1);
    write_csr_as_usize_rv32!(0x3A1, __write_pmpcfg1);

    set_pmp!();
    clear_pmp!();
}

/// Physical memory protection configuration
/// pmpcfg2 struct contains pmp8cfg - pmp11cfg for RV32, or pmp8cfg - pmp15cfg for RV64
pub mod pmpcfg2 {
    use super::{Permission, Pmpcsr, Range};
    use bit_field::BitField;

    read_csr_as!(Pmpcsr, 0x3A2, __read_pmpcfg2);
    write_csr_as_usize!(0x3A2, __write_pmpcfg2);

    set_pmp!();
    clear_pmp!();
}

/// Physical memory protection configuration
/// pmpcfg3 struct contains pmp12cfg - pmp15cfg for RV32 only
#[cfg(riscv32)]
pub mod pmpcfg3 {
    use super::{Permission, Pmpcsr, Range};
    use bit_field::BitField;

    read_csr_as!(Pmpcsr, 0x3A3, __read_pmpcfg3);
    write_csr_as_usize_rv32!(0x3A3, __write_pmpcfg3);

    set_pmp!();
    clear_pmp!();
}