Skip to content

Commit

Permalink
Handle 34-bit PMP address overflow
Browse files Browse the repository at this point in the history
The existing PMP code could not handle physical addresses above 32 bits on RV32, which are possible since Sv32 has 34-bit physical addresses, and the PMP registers are in units of 4 bytes, so they can encode 34-bit addresses.

This fixes that by delaying the *4 until the comparison where it can be done using `nat` instead of `xlenbits` which it would overflow.
  • Loading branch information
Timmmm committed May 14, 2024
1 parent e1242d8 commit 6b68172
Showing 1 changed file with 25 additions and 18 deletions.
43 changes: 25 additions & 18 deletions model/riscv_pmp_control.sail
Original file line number Diff line number Diff line change
Expand Up @@ -8,19 +8,17 @@

/* address ranges */

// TODO: handle the 34-bit paddr32 on RV32
// [min, max) of the matching range, in units of 4 bytes.
type pmp_addr_range_in_words = option((xlenbits, xlenbits))

/* [min, max) of the matching range. */
type pmp_addr_range = option((xlenbits, xlenbits))

function pmpAddrRange(cfg: Pmpcfg_ent, pmpaddr: xlenbits, prev_pmpaddr: xlenbits) -> pmp_addr_range = {
function pmpAddrRange(cfg: Pmpcfg_ent, pmpaddr: xlenbits, prev_pmpaddr: xlenbits) -> pmp_addr_range_in_words = {
match pmpAddrMatchType_of_bits(cfg[A]) {
OFF => None(),
TOR => { Some ((prev_pmpaddr << 2, pmpaddr << 2)) },
TOR => { Some ((prev_pmpaddr, pmpaddr)) },
NA4 => {
// NA4 is not selectable when the PMP grain G >= 1. See pmpWriteCfg().
assert(sys_pmp_grain() < 1, "NA4 cannot be selected when PMP grain G >= 1.");
let lo = pmpaddr << 2;
let lo = pmpaddr;
Some((lo, lo + 4))
},
NAPOT => {
Expand All @@ -33,7 +31,7 @@ function pmpAddrRange(cfg: Pmpcfg_ent, pmpaddr: xlenbits, prev_pmpaddr: xlenbits
let lo = pmpaddr & (~ (mask));
// mask + 1: 0b00000100000
let len = mask + 1;
Some((lo << 2, (lo + len) << 2))
Some((lo, (lo + len)))
}
}
}
Expand Down Expand Up @@ -65,18 +63,27 @@ function pmpCheckPerms(ent, acc, priv) = {

enum pmpAddrMatch = {PMP_NoMatch, PMP_PartialMatch, PMP_Match}

function pmpMatchAddr(addr: xlenbits, width: xlenbits, rng: pmp_addr_range) -> pmpAddrMatch = {
function pmpMatchAddr(addr: xlenbits, width: xlenbits, rng: pmp_addr_range_in_words) -> pmpAddrMatch = {
match rng {
None() => PMP_NoMatch,
Some((lo, hi)) => if hi <=_u lo /* to handle mis-configuration */
then PMP_NoMatch
else {
if (addr + width <=_u lo) | (hi <=_u addr)
then PMP_NoMatch
else if (lo <=_u addr) & (addr + width <=_u hi)
then PMP_Match
else PMP_PartialMatch
}
Some((lo, hi)) => {
// Convert to integers.
let addr = unsigned(addr);
let width = unsigned(width);
// These are in units of 4 bytes.
let lo = unsigned(lo) * 4;
let hi = unsigned(hi) * 4;

if hi <= lo /* to handle mis-configuration */
then PMP_NoMatch
else {
if (addr + width <= lo) | (hi <= addr)
then PMP_NoMatch
else if (lo <= addr) & (addr + width <= hi)
then PMP_Match
else PMP_PartialMatch
}
},
}
}

Expand Down

0 comments on commit 6b68172

Please sign in to comment.