gem5  [DEVELOP-FOR-23.0]
All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Macros Modules Pages
pmp.cc
Go to the documentation of this file.
1 /*
2  * Copyright (c) 2021 The Regents of the University of California
3  * Copyright (c) 2023 Google LLC
4  * All rights reserved.
5  *
6  * Redistribution and use in source and binary forms, with or without
7  * modification, are permitted provided that the following conditions are
8  * met: redistributions of source code must retain the above copyright
9  * notice, this list of conditions and the following disclaimer;
10  * redistributions in binary form must reproduce the above copyright
11  * notice, this list of conditions and the following disclaimer in the
12  * documentation and/or other materials provided with the distribution;
13  * neither the name of the copyright holders nor the names of its
14  * contributors may be used to endorse or promote products derived from
15  * this software without specific prior written permission.
16  *
17  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
18  * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
19  * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
20  * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
21  * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
22  * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
23  * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
24  * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
25  * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
26  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
27  * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
28  */
29 
30 #include "arch/riscv/pmp.hh"
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  hasLockEntry(false)
52 {
53  pmpTable.resize(pmpEntries);
54 }
55 
56 Fault
59  Addr vaddr)
60 {
61  // First determine if pmp table should be consulted
62  if (!shouldCheckPMP(pmode, tc))
63  return NoFault;
64 
65  if (req->hasVaddr()) {
66  DPRINTF(PMP, "Checking pmp permissions for va: %#x , pa: %#x\n",
67  req->getVaddr(), req->getPaddr());
68  }
69  else { // this access is corresponding to a page table walk
70  DPRINTF(PMP, "Checking pmp permissions for pa: %#x\n",
71  req->getPaddr());
72  }
73 
74  // match_index will be used to identify the pmp entry
75  // which matched for the given address
76  int match_index = -1;
77 
78  // all pmp entries need to be looked from the lowest to
79  // the highest number
80  for (int i = 0; i < pmpTable.size(); i++) {
81  AddrRange pmp_range = pmpTable[i].pmpAddr;
82  if (pmp_range.contains(req->getPaddr()) &&
83  pmp_range.contains(req->getPaddr() + req->getSize() - 1)) {
84  // according to specs address is only matched,
85  // when (addr) and (addr + request_size - 1) are both
86  // within the pmp range
87  match_index = i;
88  }
89 
90  if ((match_index > -1)
91  && (PMP_OFF != pmpGetAField(pmpTable[match_index].pmpCfg))) {
92  uint8_t this_cfg = pmpTable[match_index].pmpCfg;
93 
94  if ((pmode == RiscvISA::PrivilegeMode::PRV_M) &&
95  (PMP_LOCK & this_cfg) == 0) {
96  return NoFault;
97  } else if ((mode == BaseMMU::Mode::Read) &&
98  (PMP_READ & this_cfg)) {
99  return NoFault;
100  } else if ((mode == BaseMMU::Mode::Write) &&
101  (PMP_WRITE & this_cfg)) {
102  return NoFault;
103  } else if ((mode == BaseMMU::Mode::Execute) &&
104  (PMP_EXEC & this_cfg)) {
105  return NoFault;
106  } else {
107  if (req->hasVaddr()) {
108  return createAddrfault(req->getVaddr(), mode);
109  } else {
110  return createAddrfault(vaddr, mode);
111  }
112  }
113  }
114  }
115  // if no entry matched and we are not in M mode return fault
116  if (pmode == RiscvISA::PrivilegeMode::PRV_M) {
117  return NoFault;
118  } else if (req->hasVaddr()) {
119  return createAddrfault(req->getVaddr(), mode);
120  } else {
121  return createAddrfault(vaddr, mode);
122  }
123 }
124 
125 Fault
127 {
129  if (mode == BaseMMU::Read) {
131  } else if (mode == BaseMMU::Write) {
133  } else {
135  }
136  warn("pmp access fault.\n");
137  return std::make_shared<RiscvISA::AddressFault>(vaddr, code);
138 }
139 
140 inline uint8_t
141 PMP::pmpGetAField(uint8_t cfg)
142 {
143  // to get a field from pmpcfg register
144  uint8_t a = cfg >> 3;
145  return a & 0x03;
146 }
147 
148 
149 bool
150 PMP::pmpUpdateCfg(uint32_t pmp_index, uint8_t this_cfg)
151 {
152  if (pmp_index >= pmpEntries) {
153  DPRINTF(PMP, "Can't update pmp entry config %u"
154  " because the index exceed the size of pmp entries %u",
155  pmp_index, pmpEntries);
156  return false;
157  }
158 
159  DPRINTF(PMP, "Update pmp config with %u for pmp entry: %u \n",
160  (unsigned)this_cfg, pmp_index);
161  if (pmpTable[pmp_index].pmpCfg & PMP_LOCK) {
162  DPRINTF(PMP, "Update pmp entry config %u failed because it locked\n",
163  pmp_index);
164  return false;
165  }
166  pmpTable[pmp_index].pmpCfg = this_cfg;
167  pmpUpdateRule(pmp_index);
168  return true;
169 }
170 
171 void
172 PMP::pmpUpdateRule(uint32_t pmp_index)
173 {
174  // In qemu, the rule is updated whenever
175  // pmpaddr/pmpcfg is written
176 
177  numRules = 0;
178  hasLockEntry = false;
179  Addr prevAddr = 0;
180 
181  if (pmp_index >= 1) {
182  prevAddr = pmpTable[pmp_index - 1].rawAddr;
183  }
184 
185  Addr this_addr = pmpTable[pmp_index].rawAddr;
186  uint8_t this_cfg = pmpTable[pmp_index].pmpCfg;
187  AddrRange this_range;
188 
189  switch (pmpGetAField(this_cfg)) {
190  // checking the address matching mode of pmp entry
191  case PMP_OFF:
192  // null region (pmp disabled)
193  this_range = AddrRange(0, 0);
194  break;
195  case PMP_TOR:
196  // top of range mode
197  this_range = AddrRange(prevAddr << 2, (this_addr << 2));
198  break;
199  case PMP_NA4:
200  // naturally aligned four byte region
201  this_range = AddrRange(this_addr << 2, ((this_addr << 2) + 4));
202  break;
203  case PMP_NAPOT:
204  // naturally aligned power of two region, >= 8 bytes
205  this_range = AddrRange(pmpDecodeNapot(this_addr));
206  break;
207  default:
208  this_range = AddrRange(0,0);
209  }
210 
211  pmpTable[pmp_index].pmpAddr = this_range;
212 
213  for (int i = 0; i < pmpEntries; i++) {
214  const uint8_t a_field = pmpGetAField(pmpTable[i].pmpCfg);
215  if (PMP_OFF != a_field) {
216  numRules++;
217  }
218  hasLockEntry |= ((pmpTable[i].pmpCfg & PMP_LOCK) != 0);
219  }
220 
221  if (hasLockEntry) {
222  DPRINTF(PMP, "Find lock entry\n");
223  }
224 }
225 
226 void
228 {
229  for (uint32_t i = 0; i < pmpTable.size(); i++) {
230  pmpTable[i].pmpCfg &= ~(PMP_A_MASK | PMP_LOCK);
231  pmpUpdateRule(i);
232  }
233 }
234 
235 bool
236 PMP::pmpUpdateAddr(uint32_t pmp_index, Addr this_addr)
237 {
238  if (pmp_index >= pmpEntries) {
239  DPRINTF(PMP, "Can't update pmp entry address %u"
240  " because the index exceed the size of pmp entries %u",
241  pmp_index, pmpEntries);
242  return false;
243  }
244 
245  DPRINTF(PMP, "Update pmp addr %#x for pmp entry %u \n",
246  (this_addr << 2), pmp_index);
247 
248  if (pmpTable[pmp_index].pmpCfg & PMP_LOCK) {
249  DPRINTF(PMP, "Update pmp entry %u failed because the lock bit set\n",
250  pmp_index);
251  return false;
252  } else if (pmp_index < pmpTable.size() - 1 &&
253  ((pmpTable[pmp_index+1].pmpCfg & PMP_LOCK) != 0) &&
254  pmpGetAField(pmpTable[pmp_index+1].pmpCfg) == PMP_TOR) {
255  DPRINTF(PMP, "Update pmp entry %u failed because the entry %u lock bit"
256  " set and A field is TOR\n",
257  pmp_index, pmp_index+1);
258  return false;
259  }
260 
261  // just writing the raw addr in the pmp table
262  // will convert it into a range, once cfg
263  // reg is written
264  pmpTable[pmp_index].rawAddr = this_addr;
265  for (int index = 0; index < pmpEntries; index++) {
267  }
268 
269  return true;
270 }
271 
272 bool
274 {
275  // The privilege mode of memory read and write
276  // is modified by TLB. It can just simply check if
277  // the numRule is not zero, then return true if
278  // privilege mode is not M or has any lock entry
279  return numRules != 0 && (
281 }
282 
283 AddrRange
285 {
286  if (pmpaddr == -1) {
287  AddrRange this_range(0, -1);
288  return this_range;
289  } else {
290  uint64_t t1 = ctz64(~pmpaddr);
291  uint64_t range = (1ULL << (t1+3));
292 
293  // pmpaddr reg encodes bits 55-2 of a
294  // 56 bit physical address for RV64
295  uint64_t base = mbits(pmpaddr, 63, t1) << 2;
296  AddrRange this_range(base, base+range);
297  return this_range;
298  }
299 }
300 
301 } // namespace gem5
gem5::PMP
This class helps to implement RISCV's physical memory protection (pmp) primitive.
Definition: pmp.hh:54
gem5::BaseMMU::Read
@ Read
Definition: mmu.hh:56
gem5::NoFault
constexpr decltype(nullptr) NoFault
Definition: types.hh:253
gem5::RiscvISA::PRV_M
@ PRV_M
Definition: isa.hh:59
warn
#define warn(...)
Definition: logging.hh:256
gem5::PMP::PMP_OFF
@ PMP_OFF
Definition: pmp.hh:74
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:56
gem5::BaseMMU::Write
@ Write
Definition: mmu.hh:56
gem5::AddrRange::contains
bool contains(const Addr &a) const
Determine if the range contains an address.
Definition: addr_range.hh:471
tlb.hh
gem5::RiscvISA::PrivilegeMode
PrivilegeMode
Definition: isa.hh:55
gem5::PMP::shouldCheckPMP
bool shouldCheckPMP(RiscvISA::PrivilegeMode pmode, ThreadContext *tc)
This function is called during a memory access to determine if the pmp table should be consulted for ...
Definition: pmp.cc:273
gem5::ArmISA::a
Bitfield< 8 > a
Definition: misc_types.hh:66
gem5::PMP::hasLockEntry
bool hasLockEntry
variable to keep track of any lock of entry
Definition: pmp.hh:99
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:172
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:422
gem5::ArmISA::i
Bitfield< 7 > i
Definition: misc_types.hh:67
gem5::PMP::PMP_NAPOT
@ PMP_NAPOT
Definition: pmp.hh:77
isa.hh
request.hh
misc.hh
gem5::PMP::pmpUpdateAddr
bool 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:236
gem5::ArmISA::t1
Bitfield< 1 > t1
Definition: misc_types.hh:282
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:88
gem5::RiscvISA::LOAD_ACCESS
@ LOAD_ACCESS
Definition: faults.hh:74
gem5::Fault
std::shared_ptr< FaultBase > Fault
Definition: types.hh:248
gem5::PMP::numRules
int numRules
variable to keep track of active number of rules any time
Definition: pmp.hh:96
sim_object.hh
DPRINTF
#define DPRINTF(x,...)
Definition: trace.hh:210
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:57
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:76
gem5::RiscvISA::STORE_ACCESS
@ STORE_ACCESS
Definition: faults.hh:77
gem5::PMP::pmpReset
void pmpReset()
pmpReset reset when reset signal in trigger from CPU.
Definition: pmp.cc:227
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:126
gem5::SimObject
Abstract superclass for simulation objects.
Definition: sim_object.hh:146
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:87
addr_range.hh
gem5::PMP::pmpUpdateCfg
bool 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:150
gem5::PMP::PMP_WRITE
const uint8_t PMP_WRITE
pmpcfg address range write permission mask
Definition: pmp.hh:84
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:284
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:141
gem5::PMP::PMP_LOCK
const uint8_t PMP_LOCK
pmpcfg address range locked mask
Definition: pmp.hh:93
gem5::PMP::PMP_TOR
@ PMP_TOR
Definition: pmp.hh:75
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:81
gem5::PMP::PMP_READ
const uint8_t PMP_READ
pmpcfg address range read permission mask
Definition: pmp.hh:81
gem5::PMP::pmpEntries
int pmpEntries
maximum number of entries in the pmp table
Definition: pmp.hh:62
gem5
Reference material can be found at the JEDEC website: UFS standard http://www.jedec....
Definition: gpu_translation_state.hh:37
gem5::PMP::PMP_A_MASK
const uint8_t PMP_A_MASK
pmpcfg A field mask
Definition: pmp.hh:90
thread_context.hh
gem5::PMP::pmpTable
std::vector< PmpEntry > pmpTable
a table of pmp entries
Definition: pmp.hh:113
gem5::ArmISA::mode
Bitfield< 4, 0 > mode
Definition: misc_types.hh:74

Generated on Sun Jul 30 2023 01:56:50 for gem5 by doxygen 1.8.17