gem5  v21.1.0.2
pmp.cc
Go to the documentation of this file.
1 /*
2  * Copyright (c) 2021 The Regents of the University of California
3  * All rights reserved.
4  *
5  * Redistribution and use in source and binary forms, with or without
6  * modification, are permitted provided that the following conditions are
7  * met: redistributions of source code must retain the above copyright
8  * notice, this list of conditions and the following disclaimer;
9  * redistributions in binary form must reproduce the above copyright
10  * notice, this list of conditions and the following disclaimer in the
11  * documentation and/or other materials provided with the distribution;
12  * neither the name of the copyright holders nor the names of its
13  * contributors may be used to endorse or promote products derived from
14  * this software without specific prior written permission.
15  *
16  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
17  * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
18  * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
19  * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
20  * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
21  * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
22  * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
23  * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
24  * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
25  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
26  * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
27  */
28 
29 #include "arch/riscv/pmp.hh"
30 
31 #include "arch/generic/tlb.hh"
32 #include "arch/riscv/faults.hh"
33 #include "arch/riscv/isa.hh"
34 #include "arch/riscv/regs/misc.hh"
35 #include "base/addr_range.hh"
36 #include "base/types.hh"
37 #include "cpu/thread_context.hh"
38 #include "debug/PMP.hh"
39 #include "math.h"
40 #include "mem/request.hh"
41 #include "params/PMP.hh"
42 #include "sim/sim_object.hh"
43 
44 namespace gem5
45 {
46 
47 PMP::PMP(const Params &params) :
48  SimObject(params),
49  pmpEntries(params.pmp_entries),
50  numRules(0)
51 {
52  pmpTable.resize(pmpEntries);
53 }
54 
55 Fault
58  Addr vaddr)
59 {
60  // First determine if pmp table should be consulted
61  if (!shouldCheckPMP(pmode, mode, tc))
62  return NoFault;
63 
64  if (req->hasVaddr()) {
65  DPRINTF(PMP, "Checking pmp permissions for va: %#x , pa: %#x\n",
66  req->getVaddr(), req->getPaddr());
67  }
68  else { // this access is corresponding to a page table walk
69  DPRINTF(PMP, "Checking pmp permissions for pa: %#x\n",
70  req->getPaddr());
71  }
72 
73  // An access should be successful if there are
74  // no rules defined yet or we are in M mode (based
75  // on specs v1.10)
76  if (numRules == 0 || (pmode == RiscvISA::PrivilegeMode::PRV_M))
77  return NoFault;
78 
79  // match_index will be used to identify the pmp entry
80  // which matched for the given address
81  int match_index = -1;
82 
83  // all pmp entries need to be looked from the lowest to
84  // the highest number
85  for (int i = 0; i < pmpTable.size(); i++) {
86  AddrRange pmp_range = pmpTable[i].pmpAddr;
87  if (pmp_range.contains(req->getPaddr()) &&
88  pmp_range.contains(req->getPaddr() + req->getSize())) {
89  // according to specs address is only matched,
90  // when (addr) and (addr + request_size) are both
91  // within the pmp range
92  match_index = i;
93  }
94 
95  if ((PMP_OFF != pmpGetAField(pmpTable[match_index].pmpCfg))
96  && (match_index > -1)) {
97  // check the RWX permissions from the pmp entry
98  uint8_t allowed_privs = PMP_READ | PMP_WRITE | PMP_EXEC;
99 
100  // i is the index of pmp table which matched
101  allowed_privs &= pmpTable[match_index].pmpCfg;
102 
103  if ((mode == BaseMMU::Mode::Read) &&
104  (PMP_READ & allowed_privs)) {
105  return NoFault;
106  } else if ((mode == BaseMMU::Mode::Write) &&
107  (PMP_WRITE & allowed_privs)) {
108  return NoFault;
109  } else if ((mode == BaseMMU::Mode::Execute) &&
110  (PMP_EXEC & allowed_privs)) {
111  return NoFault;
112  } else {
113  if (req->hasVaddr()) {
114  return createAddrfault(req->getVaddr(), mode);
115  } else {
116  return createAddrfault(vaddr, mode);
117  }
118  }
119  }
120  }
121  // if no entry matched and we are not in M mode return fault
122  if (req->hasVaddr()) {
123  return createAddrfault(req->getVaddr(), mode);
124  } else {
125  return createAddrfault(vaddr, mode);
126  }
127 }
128 
129 Fault
131 {
133  if (mode == BaseMMU::Read) {
135  } else if (mode == BaseMMU::Write) {
137  } else {
139  }
140  warn("pmp access fault.\n");
141  return std::make_shared<RiscvISA::AddressFault>(vaddr, code);
142 }
143 
144 inline uint8_t
145 PMP::pmpGetAField(uint8_t cfg)
146 {
147  // to get a field from pmpcfg register
148  uint8_t a = cfg >> 3;
149  return a & 0x03;
150 }
151 
152 
153 void
154 PMP::pmpUpdateCfg(uint32_t pmp_index, uint8_t this_cfg)
155 {
156  DPRINTF(PMP, "Update pmp config with %u for pmp entry: %u \n",
157  (unsigned)this_cfg, pmp_index);
158 
159  warn_if((PMP_LOCK & this_cfg), "pmp lock feature is not supported.\n");
160 
161  pmpTable[pmp_index].pmpCfg = this_cfg;
162  pmpUpdateRule(pmp_index);
163 
164 }
165 
166 void
167 PMP::pmpUpdateRule(uint32_t pmp_index)
168 {
169  // In qemu, the rule is updated whenever
170  // pmpaddr/pmpcfg is written
171 
172  numRules = 0;
173  Addr prevAddr = 0;
174 
175  if (pmp_index >= 1) {
176  prevAddr = pmpTable[pmp_index - 1].rawAddr;
177  }
178 
179  Addr this_addr = pmpTable[pmp_index].rawAddr;
180  uint8_t this_cfg = pmpTable[pmp_index].pmpCfg;
181  AddrRange this_range;
182 
183  switch (pmpGetAField(this_cfg)) {
184  // checking the address matching mode of pmp entry
185  case PMP_OFF:
186  // null region (pmp disabled)
187  this_range = AddrRange(0, 0);
188  break;
189  case PMP_TOR:
190  // top of range mode
191  this_range = AddrRange(prevAddr << 2, (this_addr << 2) - 1);
192  break;
193  case PMP_NA4:
194  // naturally aligned four byte region
195  this_range = AddrRange(this_addr << 2, (this_addr + 4) - 1);
196  break;
197  case PMP_NAPOT:
198  // naturally aligned power of two region, >= 8 bytes
199  this_range = AddrRange(pmpDecodeNapot(this_addr));
200  break;
201  default:
202  this_range = AddrRange(0,0);
203  }
204 
205  pmpTable[pmp_index].pmpAddr = this_range;
206 
207  for (int i = 0; i < pmpEntries; i++) {
208  const uint8_t a_field = pmpGetAField(pmpTable[i].pmpCfg);
209  if (PMP_OFF != a_field) {
210  numRules++;
211  }
212  }
213 }
214 
215 void
216 PMP::pmpUpdateAddr(uint32_t pmp_index, Addr this_addr)
217 {
218  DPRINTF(PMP, "Update pmp addr %#x for pmp entry %u \n",
219  this_addr, pmp_index);
220 
221  // just writing the raw addr in the pmp table
222  // will convert it into a range, once cfg
223  // reg is written
224  pmpTable[pmp_index].rawAddr = this_addr;
225  for (int index = 0; index < pmpEntries; index++) {
227  }
228 }
229 
230 bool
233 {
234  // instruction fetch in S and U mode
235  bool cond1 = (mode == BaseMMU::Execute &&
236  (pmode != RiscvISA::PrivilegeMode::PRV_M));
237 
238  // data access in S and U mode when MPRV in mstatus is clear
239  RiscvISA::STATUS status =
241  bool cond2 = (mode != BaseMMU::Execute &&
243  && (!status.mprv));
244 
245  // data access in any mode when MPRV bit in mstatus is set
246  // and the MPP field in mstatus is S or U
247  bool cond3 = (mode != BaseMMU::Execute && (status.mprv)
249 
250  return (cond1 || cond2 || cond3);
251 }
252 
253 AddrRange
255 {
256  if (pmpaddr == -1) {
257  AddrRange this_range(0, -1);
258  return this_range;
259  } else {
260  uint64_t t1 = ctz64(~pmpaddr);
261  uint64_t range = (std::pow(2,t1+3))-1;
262 
263  // pmpaddr reg encodes bits 55-2 of a
264  // 56 bit physical address for RV64
265  uint64_t base = mbits(pmpaddr, 63, t1) << 2;
266  AddrRange this_range(base, base+range);
267  return this_range;
268  }
269 }
270 
271 } // namespace gem5
gem5::PMP
This class helps to implement RISCV's physical memory protection (pmp) primitive.
Definition: pmp.hh:53
gem5::RiscvISA::MISCREG_STATUS
@ MISCREG_STATUS
Definition: misc.hh:71
gem5::BaseMMU::Read
@ Read
Definition: mmu.hh:53
gem5::NoFault
constexpr decltype(nullptr) NoFault
Definition: types.hh:260
gem5::RiscvISA::PRV_M
@ PRV_M
Definition: isa.hh:56
warn
#define warn(...)
Definition: logging.hh:245
gem5::PMP::PMP_OFF
@ PMP_OFF
Definition: pmp.hh:73
faults.hh
gem5::PMP::PMP
PMP(const Params &params)
Definition: pmp.cc:47
gem5::MipsISA::index
Bitfield< 30, 0 > index
Definition: pra_constants.hh:47
gem5::BaseMMU::Mode
Mode
Definition: mmu.hh:53
gem5::BaseMMU::Write
@ Write
Definition: mmu.hh:53
gem5::AddrRange::contains
bool contains(const Addr &a) const
Determine if the range contains an address.
Definition: addr_range.hh:438
tlb.hh
gem5::RiscvISA::PrivilegeMode
PrivilegeMode
Definition: isa.hh:52
gem5::ArmISA::a
Bitfield< 8 > a
Definition: misc_types.hh:65
gem5::PMP::shouldCheckPMP
bool shouldCheckPMP(RiscvISA::PrivilegeMode pmode, BaseMMU::Mode mode, ThreadContext *tc)
This function is called during a memory access to determine if the pmp table should be consulted for ...
Definition: pmp.cc:231
gem5::PMP::pmpUpdateRule
void pmpUpdateRule(uint32_t pmp_index)
pmpUpdateRule updates the pmp rule for a given pmp entry depending on the value of pmpaddr and pmpcfg...
Definition: pmp.cc:167
gem5::mbits
constexpr T mbits(T val, unsigned first, unsigned last)
Mask off the given bits in place like bits() but without shifting.
Definition: bitfield.hh:103
gem5::X86ISA::base
Bitfield< 51, 12 > base
Definition: pagetable.hh:141
gem5::ctz64
constexpr int ctz64(uint64_t value)
Count trailing zeros in a 64-bit value.
Definition: bitfield.hh:409
gem5::ArmISA::i
Bitfield< 7 > i
Definition: misc_types.hh:66
gem5::PMP::PMP_NAPOT
@ PMP_NAPOT
Definition: pmp.hh:76
isa.hh
request.hh
misc.hh
gem5::BaseMMU::Execute
@ Execute
Definition: mmu.hh:53
gem5::ArmISA::t1
Bitfield< 1 > t1
Definition: misc_types.hh:232
gem5::SimObject::Params
SimObjectParams Params
Definition: sim_object.hh:170
pmp.hh
gem5::ThreadContext
ThreadContext is the external interface to all thread state for anything outside of the CPU.
Definition: thread_context.hh:93
gem5::RiscvISA::LOAD_ACCESS
@ LOAD_ACCESS
Definition: faults.hh:74
gem5::Fault
std::shared_ptr< FaultBase > Fault
Definition: types.hh:255
gem5::PMP::numRules
int numRules
variable to keep track of active number of rules any time
Definition: pmp.hh:92
sim_object.hh
DPRINTF
#define DPRINTF(x,...)
Definition: trace.hh:186
gem5::PMP::pmpCheck
Fault pmpCheck(const RequestPtr &req, BaseMMU::Mode mode, RiscvISA::PrivilegeMode pmode, ThreadContext *tc, Addr vaddr=0)
pmpCheck checks if a particular memory access is allowed based on the pmp rules.
Definition: pmp.cc:56
gem5::RiscvISA::INST_ACCESS
@ INST_ACCESS
Definition: faults.hh:70
gem5::RequestPtr
std::shared_ptr< Request > RequestPtr
Definition: request.hh:92
gem5::PMP::PMP_NA4
@ PMP_NA4
Definition: pmp.hh:75
gem5::RiscvISA::STORE_ACCESS
@ STORE_ACCESS
Definition: faults.hh:77
gem5::PMP::createAddrfault
Fault createAddrfault(Addr vaddr, BaseMMU::Mode mode)
createAddrfault creates an address fault if the pmp checks fail to pass for a given access.
Definition: pmp.cc:130
gem5::SimObject
Abstract superclass for simulation objects.
Definition: sim_object.hh:146
gem5::ThreadContext::readMiscRegNoEffect
virtual RegVal readMiscRegNoEffect(RegIndex misc_reg) const =0
gem5::RiscvISA::ExceptionCode
ExceptionCode
Definition: faults.hh:67
gem5::Addr
uint64_t Addr
Address type This will probably be moved somewhere else in the near future.
Definition: types.hh:147
gem5::PMP::PMP_EXEC
const uint8_t PMP_EXEC
pmpcfg address range execute permission mask
Definition: pmp.hh:86
gem5::PMP::pmpUpdateAddr
void pmpUpdateAddr(uint32_t pmp_index, Addr this_addr)
pmpUpdateAddr updates the pmpaddr for a pmp entry and calls pmpUpdateRule to update the rule of corre...
Definition: pmp.cc:216
addr_range.hh
gem5::PMP::PMP_WRITE
const uint8_t PMP_WRITE
pmpcfg address range write permission mask
Definition: pmp.hh:83
gem5::PMP::pmpDecodeNapot
AddrRange pmpDecodeNapot(Addr pmpaddr)
This function decodes a pmpaddr register value into an address range when A field of pmpcfg register ...
Definition: pmp.cc:254
gem5::PMP::pmpGetAField
uint8_t pmpGetAField(uint8_t cfg)
pmpGetAField extracts the A field (address matching mode) from an input pmpcfg register
Definition: pmp.cc:145
warn_if
#define warn_if(cond,...)
Conditional warning macro that checks the supplied condition and only prints a warning if the conditi...
Definition: logging.hh:272
gem5::PMP::PMP_LOCK
const uint8_t PMP_LOCK
pmpcfg address range locked mask
Definition: pmp.hh:89
gem5::PMP::PMP_TOR
@ PMP_TOR
Definition: pmp.hh:74
types.hh
gem5::MipsISA::vaddr
vaddr
Definition: pra_constants.hh:278
gem5::AddrRange
The AddrRange class encapsulates an address range, and supports a number of tests to check if two ran...
Definition: addr_range.hh:71
gem5::PMP::pmpUpdateCfg
void pmpUpdateCfg(uint32_t pmp_index, uint8_t this_cfg)
pmpUpdateCfg updates the pmpcfg for a pmp entry and calls pmpUpdateRule to update the rule of corresp...
Definition: pmp.cc:154
gem5::PMP::PMP_READ
const uint8_t PMP_READ
pmpcfg address range read permission mask
Definition: pmp.hh:80
gem5::PMP::pmpEntries
int pmpEntries
maximum number of entries in the pmp table
Definition: pmp.hh:61
gem5
Reference material can be found at the JEDEC website: UFS standard http://www.jedec....
Definition: decoder.cc:40
thread_context.hh
gem5::PMP::pmpTable
std::vector< PmpEntry > pmpTable
a table of pmp entries
Definition: pmp.hh:106
gem5::ArmISA::status
Bitfield< 5, 0 > status
Definition: misc_types.hh:422
gem5::ArmISA::mode
Bitfield< 4, 0 > mode
Definition: misc_types.hh:73

Generated on Tue Sep 21 2021 12:24:51 for gem5 by doxygen 1.8.17