gem5 v24.0.0.0
Loading...
Searching...
No Matches
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"
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
44namespace gem5
45{
46
47namespace RiscvISA
48{
49
50PMP::PMP(const Params &params) :
51 SimObject(params),
52 pmpEntries(params.pmp_entries),
53 numRules(0),
54 hasLockEntry(false)
55{
56 pmpTable.resize(pmpEntries);
57}
58
62{
63 // First determine if pmp table should be consulted
64 if (!shouldCheckPMP(pmode, tc))
65 return NoFault;
66
67 if (req->hasVaddr()) {
68 DPRINTF(PMP, "Checking pmp permissions for va: %#x , pa: %#x\n",
69 req->getVaddr(), req->getPaddr());
70 }
71 else { // this access is corresponding to a page table walk
72 DPRINTF(PMP, "Checking pmp permissions for pa: %#x\n",
73 req->getPaddr());
74 }
75
76 // match_index will be used to identify the pmp entry
77 // which matched for the given address
78 int match_index = -1;
79
80 // all pmp entries need to be looked from the lowest to
81 // the highest number
82 for (int i = 0; i < pmpTable.size(); i++) {
83 AddrRange pmp_range = pmpTable[i].pmpAddr;
84 if (pmp_range.contains(req->getPaddr()) &&
85 pmp_range.contains(req->getPaddr() + req->getSize() - 1)) {
86 // according to specs address is only matched,
87 // when (addr) and (addr + request_size - 1) are both
88 // within the pmp range
89 match_index = i;
90 }
91
92 if ((match_index > -1)
93 && (PMP_OFF != pmpGetAField(pmpTable[match_index].pmpCfg))) {
94 uint8_t this_cfg = pmpTable[match_index].pmpCfg;
95
96 if ((pmode == PrivilegeMode::PRV_M) &&
97 (PMP_LOCK & this_cfg) == 0) {
98 return NoFault;
99 } else if ((mode == BaseMMU::Mode::Read) &&
100 (PMP_READ & this_cfg)) {
101 return NoFault;
102 } else if ((mode == BaseMMU::Mode::Write) &&
103 (PMP_WRITE & this_cfg)) {
104 return NoFault;
105 } else if ((mode == BaseMMU::Mode::Execute) &&
106 (PMP_EXEC & this_cfg)) {
107 return NoFault;
108 } else {
109 if (req->hasVaddr()) {
110 return createAddrfault(req->getVaddr(), mode);
111 } else {
112 return createAddrfault(vaddr, mode);
113 }
114 }
115 }
116 }
117 // if no entry matched and we are not in M mode return fault
118 if (pmode == PrivilegeMode::PRV_M) {
119 return NoFault;
120 } else if (req->hasVaddr()) {
121 return createAddrfault(req->getVaddr(), mode);
122 } else {
123 return createAddrfault(vaddr, mode);
124 }
125}
126
127Fault
129{
130 ExceptionCode code;
131 if (mode == BaseMMU::Read) {
133 } else if (mode == BaseMMU::Write) {
135 } else {
137 }
138 warn("pmp access fault.\n");
139 return std::make_shared<AddressFault>(vaddr, code);
140}
141
142inline uint8_t
144{
145 // to get a field from pmpcfg register
146 uint8_t a = cfg >> 3;
147 return a & 0x03;
148}
149
150
151bool
152PMP::pmpUpdateCfg(uint32_t pmp_index, uint8_t this_cfg)
153{
154 if (pmp_index >= pmpEntries) {
155 DPRINTF(PMP, "Can't update pmp entry config %u"
156 " because the index exceed the size of pmp entries %u",
157 pmp_index, pmpEntries);
158 return false;
159 }
160
161 DPRINTF(PMP, "Update pmp config with %u for pmp entry: %u \n",
162 (unsigned)this_cfg, pmp_index);
163 if (pmpTable[pmp_index].pmpCfg & PMP_LOCK) {
164 DPRINTF(PMP, "Update pmp entry config %u failed because it locked\n",
165 pmp_index);
166 return false;
167 }
168 pmpTable[pmp_index].pmpCfg = this_cfg;
169 pmpUpdateRule(pmp_index);
170 return true;
171}
172
173void
174PMP::pmpUpdateRule(uint32_t pmp_index)
175{
176 // In qemu, the rule is updated whenever
177 // pmpaddr/pmpcfg is written
178
179 numRules = 0;
180 hasLockEntry = false;
181 Addr prevAddr = 0;
182
183 if (pmp_index >= 1) {
184 prevAddr = pmpTable[pmp_index - 1].rawAddr;
185 }
186
187 Addr this_addr = pmpTable[pmp_index].rawAddr;
188 uint8_t this_cfg = pmpTable[pmp_index].pmpCfg;
189 AddrRange this_range;
190
191 switch (pmpGetAField(this_cfg)) {
192 // checking the address matching mode of pmp entry
193 case PMP_OFF:
194 // null region (pmp disabled)
195 this_range = AddrRange(0, 0);
196 break;
197 case PMP_TOR:
198 // top of range mode
199 this_range = AddrRange(prevAddr << 2, (this_addr << 2));
200 break;
201 case PMP_NA4:
202 // naturally aligned four byte region
203 this_range = AddrRange(this_addr << 2, ((this_addr << 2) + 4));
204 break;
205 case PMP_NAPOT:
206 // naturally aligned power of two region, >= 8 bytes
207 this_range = AddrRange(pmpDecodeNapot(this_addr));
208 break;
209 default:
210 this_range = AddrRange(0,0);
211 }
212
213 pmpTable[pmp_index].pmpAddr = this_range;
214
215 for (int i = 0; i < pmpEntries; i++) {
216 const uint8_t a_field = pmpGetAField(pmpTable[i].pmpCfg);
217 if (PMP_OFF != a_field) {
218 numRules++;
219 }
220 hasLockEntry |= ((pmpTable[i].pmpCfg & PMP_LOCK) != 0);
221 }
222
223 if (hasLockEntry) {
224 DPRINTF(PMP, "Find lock entry\n");
225 }
226}
227
228void
230{
231 for (uint32_t i = 0; i < pmpTable.size(); i++) {
232 pmpTable[i].pmpCfg &= ~(PMP_A_MASK | PMP_LOCK);
234 }
235}
236
237bool
238PMP::pmpUpdateAddr(uint32_t pmp_index, Addr this_addr)
239{
240 if (pmp_index >= pmpEntries) {
241 DPRINTF(PMP, "Can't update pmp entry address %u"
242 " because the index exceed the size of pmp entries %u",
243 pmp_index, pmpEntries);
244 return false;
245 }
246
247 DPRINTF(PMP, "Update pmp addr %#x for pmp entry %u \n",
248 (this_addr << 2), pmp_index);
249
250 if (pmpTable[pmp_index].pmpCfg & PMP_LOCK) {
251 DPRINTF(PMP, "Update pmp entry %u failed because the lock bit set\n",
252 pmp_index);
253 return false;
254 } else if (pmp_index < pmpTable.size() - 1 &&
255 ((pmpTable[pmp_index+1].pmpCfg & PMP_LOCK) != 0) &&
256 pmpGetAField(pmpTable[pmp_index+1].pmpCfg) == PMP_TOR) {
257 DPRINTF(PMP, "Update pmp entry %u failed because the entry %u lock bit"
258 " set and A field is TOR\n",
259 pmp_index, pmp_index+1);
260 return false;
261 }
262
263 // just writing the raw addr in the pmp table
264 // will convert it into a range, once cfg
265 // reg is written
266 pmpTable[pmp_index].rawAddr = this_addr;
267 for (int index = 0; index < pmpEntries; index++) {
269 }
270
271 return true;
272}
273
274bool
276{
277 // The privilege mode of memory read and write
278 // is modified by TLB. It can just simply check if
279 // the numRule is not zero, then return true if
280 // privilege mode is not M or has any lock entry
281 return numRules != 0 && (pmode != PrivilegeMode::PRV_M || hasLockEntry);
282}
283
286{
287 if (pmpaddr == -1) {
288 AddrRange this_range(0, -1);
289 return this_range;
290 } else {
291 uint64_t t1 = ctz64(~pmpaddr);
292 uint64_t range = (1ULL << (t1+3));
293
294 // pmpaddr reg encodes bits 55-2 of a
295 // 56 bit physical address for RV64
296 uint64_t base = mbits(pmpaddr, 63, t1) << 2;
297 AddrRange this_range(base, base+range);
298 return this_range;
299 }
300}
301
302} // namespace RiscvISA
303} // namespace gem5
#define DPRINTF(x,...)
Definition trace.hh:210
Defines global host-dependent types: Counter, Tick, and (indirectly) {int,uint}{8,...
The AddrRange class encapsulates an address range, and supports a number of tests to check if two ran...
Definition addr_range.hh:82
This class helps to implement RISCV's physical memory protection (pmp) primitive.
Definition pmp.hh:58
const uint8_t PMP_EXEC
pmpcfg address range execute permission mask
Definition pmp.hh:90
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:128
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:238
std::vector< PmpEntry > pmpTable
a table of pmp entries
Definition pmp.hh:116
const uint8_t PMP_LOCK
pmpcfg address range locked mask
Definition pmp.hh:96
void pmpReset()
pmpReset reset when reset signal in trigger from CPU.
Definition pmp.cc:229
uint8_t pmpGetAField(uint8_t cfg)
pmpGetAField extracts the A field (address matching mode) from an input pmpcfg register
Definition pmp.cc:143
const uint8_t PMP_READ
pmpcfg address range read permission mask
Definition pmp.hh:84
const uint8_t PMP_A_MASK
pmpcfg A field mask
Definition pmp.hh:93
bool hasLockEntry
variable to keep track of any lock of entry
Definition pmp.hh:102
Fault pmpCheck(const RequestPtr &req, BaseMMU::Mode mode, PrivilegeMode pmode, ThreadContext *tc, Addr vaddr=0)
pmpCheck checks if a particular memory access is allowed based on the pmp rules.
Definition pmp.cc:60
int pmpEntries
maximum number of entries in the pmp table
Definition pmp.hh:65
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:174
AddrRange pmpDecodeNapot(Addr pmpaddr)
This function decodes a pmpaddr register value into an address range when A field of pmpcfg register ...
Definition pmp.cc:285
int numRules
variable to keep track of active number of rules any time
Definition pmp.hh:99
const uint8_t PMP_WRITE
pmpcfg address range write permission mask
Definition pmp.hh:87
PMP(const Params &params)
Definition pmp.cc:50
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:152
bool shouldCheckPMP(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:275
Abstract superclass for simulation objects.
SimObjectParams Params
ThreadContext is the external interface to all thread state for anything outside of the CPU.
bool contains(const Addr &a) const
Determine if the range contains an address.
constexpr T mbits(T val, unsigned first, unsigned last)
Mask off the given bits in place like bits() but without shifting.
Definition bitfield.hh:106
constexpr int ctz64(uint64_t value)
Count trailing zeros in a 64-bit value.
Definition bitfield.hh:487
#define warn(...)
Definition logging.hh:256
Bitfield< 1 > t1
Bitfield< 6 > a
Definition pagetable.hh:69
Bitfield< 30, 0 > index
Bitfield< 2 > i
Bitfield< 51, 12 > base
Definition pagetable.hh:141
Copyright (c) 2024 - Pranith Kumar Copyright (c) 2020 Inria All rights reserved.
Definition binary32.hh:36
std::shared_ptr< FaultBase > Fault
Definition types.hh:249
std::shared_ptr< Request > RequestPtr
Definition request.hh:94
uint64_t Addr
Address type This will probably be moved somewhere else in the near future.
Definition types.hh:147
constexpr decltype(nullptr) NoFault
Definition types.hh:253
PMP header file.
Declaration of a request, the overall memory request consisting of the parts of the request that are ...

Generated on Tue Jun 18 2024 16:24:00 for gem5 by doxygen 1.11.0