diff --git a/doc/Status.md b/doc/Status.md index 539020a0a..a4d0db0ea 100644 --- a/doc/Status.md +++ b/doc/Status.md @@ -19,6 +19,8 @@ The Sail specification currently captures the following ISA features: - Physical Memory Protection (PMP) +- PMP Enhancements for memory accesses and execution prevention on Machine mode (Smepmp) + For the RVWMO memory consistency model, this Sail ISA semantics is integrated with the RVWMO operational model in [the RMEM tool](https://github.com/rems-project/rmem). diff --git a/model/riscv_csr_map.sail b/model/riscv_csr_map.sail index 31872d3f1..d47ce8d12 100644 --- a/model/riscv_csr_map.sail +++ b/model/riscv_csr_map.sail @@ -132,6 +132,8 @@ mapping clause csr_name_map = 0x342 <-> "mcause" mapping clause csr_name_map = 0x343 <-> "mtval" mapping clause csr_name_map = 0x344 <-> "mip" /* machine protection and translation */ +mapping clause csr_name_map = 0x747 <-> "mseccfg" +mapping clause csr_name_map = 0x757 <-> "mseccfgh" mapping clause csr_name_map = 0x3A0 <-> "pmpcfg0" mapping clause csr_name_map = 0x3A1 <-> "pmpcfg1" mapping clause csr_name_map = 0x3A2 <-> "pmpcfg2" diff --git a/model/riscv_insts_zicsr.sail b/model/riscv_insts_zicsr.sail index 518396f91..fe88eec70 100644 --- a/model/riscv_insts_zicsr.sail +++ b/model/riscv_insts_zicsr.sail @@ -105,6 +105,9 @@ function readCSR csr : csreg -> xlenbits = { (0x343, _) => mtval, (0x344, _) => mip.bits(), + (0x747, _) => mseccfg.bits(), // mseccfg + (0x757, 32) => mseccfgh, // mseccfgh + (0x3A0, _) => pmpReadCfgReg(0), // pmpcfg0 (0x3A1, 32) => pmpReadCfgReg(1), // pmpcfg1 (0x3A2, _) => pmpReadCfgReg(2), // pmpcfg2 @@ -193,6 +196,8 @@ function writeCSR (csr : csreg, value : xlenbits) -> unit = { (0x344, _) => { mip = legalize_mip(mip, value); Some(mip.bits()) }, // Note: Some(value) returned below is not the legalized value due to locked entries + (0x747, _) => { mseccfg = mseccfgWrite(mseccfg, value); Some(mseccfg.bits()) }, + (0x757, 32) => { Some(mseccfgh) }, // ignore writes for now (0x3A0, _) => { pmpWriteCfgReg(0, value); Some(pmpReadCfgReg(0)) }, // pmpcfg0 (0x3A1, 32) => { pmpWriteCfgReg(1, value); Some(pmpReadCfgReg(1)) }, // pmpcfg1 (0x3A2, _) => { pmpWriteCfgReg(2, value); Some(pmpReadCfgReg(2)) }, // pmpcfg2 diff --git a/model/riscv_pmp_control.sail b/model/riscv_pmp_control.sail index 669725b5b..5cc37cad2 100644 --- a/model/riscv_pmp_control.sail +++ b/model/riscv_pmp_control.sail @@ -104,15 +104,41 @@ function pmpCheckRWX(ent, acc) = { } } -// this needs to be called with the effective current privilege. -val pmpCheckPerms: (Pmpcfg_ent, AccessType(ext_access_type), Privilege) -> bool +/* this needs to be called with the effective current privilege */ +val pmpCheckPerms: (Pmpcfg_ent, AccessType(ext_access_type), Privilege) -> bool effect {rreg} function pmpCheckPerms(ent, acc, priv) = { + if mseccfg.MML() == 0b1 then { + if ent.R() == 0b0 & ent.W() == 0b1 then { + if pmpLockBit(ent) then { + match acc { + Execute(_) => true, + Read(_) => priv == Machine & ent.X() == 0b1, + _ => false + } + } else { + match acc { + Read(_) => true, + Write(_) => priv == Machine | ent.X() == 0b1, + _ => false + }} + } else { + if ent.R() == 0b1 & ent.W() == 0b1 & ent.X() == 0b1 & pmpLockBit(ent) then { + match acc { + Read(_) => true, + _ => false + } + } else { + if (priv == Machine) == pmpLockBit(ent) + then pmpCheckRWX(ent, acc) + else false + }} + } else { match priv { - Machine => if pmpLocked(ent) + Machine => if pmpLockBit(ent) then pmpCheckRWX(ent, acc) else true, _ => pmpCheckRWX(ent, acc) - } + }} } /* matching logic */ @@ -218,9 +244,17 @@ function pmpCheck forall 'n, 'n > 0. (addr: xlenbits, width: atom('n), acc: Acce PMP_Success => true, PMP_Fail => false, PMP_Continue => match priv { - Machine => true, - _ => false + Machine => if mseccfg.MMWP() == 0b1 /* Make Read, Write and execute denied by default, if condition meets for M mode */ + then false + else if mseccfg.MML() == 0b1 + then { /* Make execute denied, if condition meets for M mode */ + match acc { + Execute(_) => false, + _ => true } + } else true, + _ => false /* Make Read, Write and execute denied by default for S/U mode */ + } }}}}}}}}}}}}}}}}; if check @@ -234,6 +268,10 @@ function pmpCheck forall 'n, 'n > 0. (addr: xlenbits, width: atom('n), acc: Acce } function init_pmp() -> unit = { + mseccfg->RLB() = 0b0; + mseccfg->MML() = 0b0; + mseccfg->MMWP() = 0b0; + mseccfgh = EXTZ(0b0); pmp0cfg = update_A(pmp0cfg, pmpAddrMatchType_to_bits(OFF)); pmp1cfg = update_A(pmp1cfg, pmpAddrMatchType_to_bits(OFF)); pmp2cfg = update_A(pmp2cfg, pmpAddrMatchType_to_bits(OFF)); diff --git a/model/riscv_pmp_regs.sail b/model/riscv_pmp_regs.sail index a5e21edf5..967953c5d 100644 --- a/model/riscv_pmp_regs.sail +++ b/model/riscv_pmp_regs.sail @@ -100,6 +100,15 @@ bitfield Pmpcfg_ent : bits(8) = { R : 0 /* read */ } +bitfield Mseccfg_ent : xlenbits = { + RLB : 2, /* Rule Locking Bypass */ + MMWP : 1, /* Machine Mode Whitelist Policy */ + MML : 0 /* Machine Mode Lockdown */ +} + +register mseccfg : Mseccfg_ent +register mseccfgh : bits(32) + register pmp0cfg : Pmpcfg_ent register pmp1cfg : Pmpcfg_ent register pmp2cfg : Pmpcfg_ent @@ -154,15 +163,30 @@ function pmpReadCfgReg(n) = { } /* Helpers to handle locked entries */ -function pmpLocked(cfg: Pmpcfg_ent) -> bool = - cfg.L() == 0b1 - -function pmpTORLocked(cfg: Pmpcfg_ent) -> bool = - (cfg.L() == 0b1) & (pmpAddrMatchType_of_bits(cfg.A()) == TOR) +function pmpLockBit(cfg: Pmpcfg_ent) -> bool = cfg.L() == 0b1 + +function pmpLocked(cfg: Pmpcfg_ent) -> bool = (cfg.L() == 0b1) & (mseccfg.RLB() == 0b0) -function pmpWriteCfg(cfg: Pmpcfg_ent, v: bits(8)) -> Pmpcfg_ent = - if pmpLocked(cfg) then cfg - else Mk_Pmpcfg_ent(v & 0x9f) // Bits 5 and 6 are zero. +function pmpTORLocked(cfg: Pmpcfg_ent) -> bool = (cfg.L() == 0b1) & (mseccfg.RLB() == 0b0) & (pmpAddrMatchType_of_bits(cfg.A()) == TOR) + +function pmpWriteCfg(cfg: Pmpcfg_ent, v: bits(8)) -> Pmpcfg_ent = { + let legal_v : Pmpcfg_ent = Mk_Pmpcfg_ent(v & 0x9f); /* Constructing legal Pmpcfg_ent by making bit 5 and 6 zero */ + let legal_v = + if ((mseccfg.MML() == 0b0) & (legal_v.R() == 0b0) & (legal_v.W() == 0b1)) + then update_W(legal_v, 0b0) + else legal_v; + if pmpLocked(cfg) then cfg /* If locked then configuration is unchanged */ + else { + if (mseccfg.MML() == 0b1 & mseccfg.RLB() == 0b0 & legal_v.L() == 0b1) then { + if ((legal_v.R() == 0b0 & legal_v.W() == 0b0 & legal_v.X() == 0b1) | + (legal_v.R() == 0b0 & legal_v.W() == 0b1 & legal_v.X() == 0b0) | + (legal_v.R() == 0b0 & legal_v.W() == 0b1 & legal_v.X() == 0b1) | + (legal_v.R() == 0b1 & legal_v.W() == 0b0 & legal_v.X() == 0b1)) + then cfg /* If condition meets configuration remains same which means pmpcfg writes are ignored */ + else legal_v + } else legal_v + } +} val pmpWriteCfgReg : forall 'n, 0 <= 'n < 4 . (atom('n), xlenbits) -> unit effect {rreg, wreg} function pmpWriteCfgReg(n, v) = { @@ -216,3 +240,23 @@ function pmpWriteAddr(locked: bool, tor_locked: bool, reg: xlenbits, v: xlenbits if sizeof(xlen) == 32 then { if (locked | tor_locked) then reg else v } else { if (locked | tor_locked) then reg else EXTZ(v[53..0]) } + +function mseccfgWrite(reg: Mseccfg_ent, v: xlenbits) -> Mseccfg_ent = { + let legal_v : Mseccfg_ent = Mk_Mseccfg_ent(EXTZ(v[2 .. 0])); + let reg = + if reg.RLB() == 0b0 & legal_v.RLB() == 0b1 then { /* to set RLB, need to check PMPCFG_L */ + if (pmp0cfg.L() == 0b1 | pmp1cfg.L() == 0b1 | pmp2cfg.L() == 0b1 | pmp3cfg.L() == 0b1 + | pmp4cfg.L() == 0b1 | pmp5cfg.L() == 0b1 | pmp6cfg.L() == 0b1 | pmp7cfg.L() == 0b1 + | pmp8cfg.L() == 0b1 | pmp9cfg.L() == 0b1 | pmp10cfg.L() == 0b1 | pmp11cfg.L() == 0b1 + | pmp12cfg.L() == 0b1 | pmp13cfg.L() == 0b1 | pmp14cfg.L() == 0b1 | pmp15cfg.L() == 0b1) + then reg + else update_RLB(reg, legal_v.RLB()) + } else reg; + let reg = + if reg.MML() == 0b0 + then update_MML(reg, legal_v.MML()) + else reg; /* Implements stickiness of MML bit, if once set remains set */ + if reg.MMWP() == 0b0 + then update_MMWP(reg, legal_v.MMWP()) + else reg /* Implements stickiness of MMWP bit, if once set remains set */ +} diff --git a/model/riscv_sys_control.sail b/model/riscv_sys_control.sail index 6204ae59e..5e118ef4b 100644 --- a/model/riscv_sys_control.sail +++ b/model/riscv_sys_control.sail @@ -98,6 +98,9 @@ function is_CSR_defined (csr : csreg, p : Privilege) -> bool = 0x343 => p == Machine, // mtval 0x344 => p == Machine, // mip + 0x747 => p == Machine, // mseccfg + 0x757 => p == Machine & (sizeof(xlen) == 32), // mseccfgh + 0x3A0 => p == Machine, // pmpcfg0 0x3A1 => p == Machine & (sizeof(xlen) == 32), // pmpcfg1 0x3A2 => p == Machine, // pmpcfg2