gem5 [DEVELOP-FOR-25.0]
Loading...
Searching...
No Matches
smmu_v3.cc
Go to the documentation of this file.
1/*
2 * Copyright (c) 2013, 2018-2020, 2024 Arm Limited
3 * All rights reserved
4 *
5 * The license below extends only to copyright in the software and shall
6 * not be construed as granting a license to any other intellectual
7 * property including but not limited to intellectual property relating
8 * to a hardware implementation of the functionality of the software
9 * licensed hereunder. You may use the software subject to the license
10 * terms below provided that you ensure that this notice is replicated
11 * unmodified and in its entirety in all distributions of the software,
12 * modified or unmodified, in source code or in binary form.
13 *
14 * Redistribution and use in source and binary forms, with or without
15 * modification, are permitted provided that the following conditions are
16 * met: redistributions of source code must retain the above copyright
17 * notice, this list of conditions and the following disclaimer;
18 * redistributions in binary form must reproduce the above copyright
19 * notice, this list of conditions and the following disclaimer in the
20 * documentation and/or other materials provided with the distribution;
21 * neither the name of the copyright holders nor the names of its
22 * contributors may be used to endorse or promote products derived from
23 * this software without specific prior written permission.
24 *
25 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
26 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
27 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
28 * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
29 * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
30 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
31 * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
32 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
33 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
34 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
35 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
36 */
37
38#include "dev/arm/smmu_v3.hh"
39
40#include <cstddef>
41#include <cstring>
42
43#include "base/bitfield.hh"
44#include "base/cast.hh"
45#include "base/compiler.hh"
46#include "base/logging.hh"
47#include "base/trace.hh"
48#include "base/types.hh"
49#include "debug/Checkpoint.hh"
50#include "debug/SMMUv3.hh"
51#include "dev/arm/base_gic.hh"
53#include "mem/packet_access.hh"
54#include "sim/system.hh"
55
56namespace gem5
57{
58
59SMMUv3::SMMUv3(const SMMUv3Params &params) :
62 requestorId(params.system->getRequestorId(this)),
63 requestPort(name() + ".request", *this),
64 tableWalkPort(name() + ".walker", *this),
65 controlPort(name() + ".control", *this, params.reg_map),
66 eventqInterrupt(params.eventq_irq ? params.eventq_irq->get() : nullptr),
67 tlb(params.tlb_entries, params.tlb_assoc, params.tlb_policy, this),
68 configCache(params.cfg_entries, params.cfg_assoc, params.cfg_policy, this),
69 ipaCache(params.ipa_entries, params.ipa_assoc, params.ipa_policy, this),
70 walkCache({ { params.walk_S1L0, params.walk_S1L1,
71 params.walk_S1L2, params.walk_S1L3,
72 params.walk_S2L0, params.walk_S2L1,
73 params.walk_S2L2, params.walk_S2L3 } },
74 params.walk_assoc, params.walk_policy, this),
75 tlbEnable(params.tlb_enable),
76 configCacheEnable(params.cfg_enable),
77 ipaCacheEnable(params.ipa_enable),
78 walkCacheEnable(params.walk_enable),
79 tableWalkPortEnable(false),
80 walkCacheNonfinalEnable(params.wc_nonfinal_enable),
81 walkCacheS1Levels(params.wc_s1_levels),
82 walkCacheS2Levels(params.wc_s2_levels),
83 requestPortWidth(params.request_port_width),
84 tlbSem(params.tlb_slots),
85 ifcSmmuSem(1),
86 smmuIfcSem(1),
87 configSem(params.cfg_slots),
88 ipaSem(params.ipa_slots),
89 walkSem(params.walk_slots),
90 requestPortSem(1),
91 transSem(params.xlate_slots),
92 ptwSem(params.ptw_slots),
93 cycleSem(1),
94 tlbLat(params.tlb_lat),
95 ifcSmmuLat(params.ifc_smmu_lat),
96 smmuIfcLat(params.smmu_ifc_lat),
97 configLat(params.cfg_lat),
98 ipaLat(params.ipa_lat),
99 walkLat(params.walk_lat),
100 stats(this),
101 deviceInterfaces(params.device_interfaces),
102 commandExecutor(name() + ".cmd_exec", *this),
103 regsMap(params.reg_map),
104 processCommandsEvent(*this)
105{
106 fatal_if(regsMap.size() != SMMU_REG_SIZE,
107 "Invalid register map size: %#x different than SMMU_REG_SIZE = %#x\n",
108 regsMap.size(), SMMU_REG_SIZE);
109
110 // Init smmu registers to 0
111 memset(&regs, 0, sizeof(regs));
112
113 // Setup RO ID registers
114 regs.idr0 = params.smmu_idr0;
115 regs.idr1 = params.smmu_idr1;
116 regs.idr2 = params.smmu_idr2;
117 regs.idr3 = params.smmu_idr3;
118 regs.idr4 = params.smmu_idr4;
119 regs.idr5 = params.smmu_idr5;
120 regs.iidr = params.smmu_iidr;
121 regs.aidr = params.smmu_aidr;
122
123 // TODO: At the moment it possible to set the ID registers to hold
124 // any possible value. It would be nice to have a sanity check here
125 // at construction time in case some idx registers are programmed to
126 // store an unallowed values or if the are configuration conflicts.
127 warn("SMMUv3 IDx register values unchecked\n");
128
129 for (auto ifc : deviceInterfaces)
130 ifc->setSMMU(this);
131}
132
133bool
135{
136 DPRINTF(SMMUv3, "[t] requestor resp addr=%#x size=%#x\n",
137 pkt->getAddr(), pkt->getSize());
138
139 // @todo: We need to pay for this and not just zero it out
140 pkt->headerDelay = pkt->payloadDelay = 0;
141
142 SMMUProcess *proc =
144
145 runProcessTiming(proc, pkt);
146
147 return true;
148}
149
150void
152{
153 assert(!packetsToRetry.empty());
154
155 while (!packetsToRetry.empty()) {
156 SMMUAction a = packetsToRetry.front();
157
158 assert(a.type==ACTION_SEND_REQ || a.type==ACTION_SEND_REQ_FINAL);
159
160 DPRINTF(SMMUv3, "[t] requestor retr addr=%#x size=%#x\n",
161 a.pkt->getAddr(), a.pkt->getSize());
162
163 if (!requestPort.sendTimingReq(a.pkt))
164 break;
165
166 packetsToRetry.pop();
167
168 /*
169 * ACTION_SEND_REQ_FINAL means that we have just forwarded the packet
170 * on the requestor interface; this means that we no longer hold on to
171 * that transaction and therefore can accept a new one.
172 * If the response port was stalled then unstall it (send retry).
173 */
174 if (a.type == ACTION_SEND_REQ_FINAL)
176 }
177}
178
179bool
181{
182 DPRINTF(SMMUv3, "[t] requestor HWTW resp addr=%#x size=%#x\n",
183 pkt->getAddr(), pkt->getSize());
184
185 // @todo: We need to pay for this and not just zero it out
186 pkt->headerDelay = pkt->payloadDelay = 0;
187
188 SMMUProcess *proc =
190
191 runProcessTiming(proc, pkt);
192
193 return true;
194}
195
196void
198{
199 assert(tableWalkPortEnable);
200 assert(!packetsTableWalkToRetry.empty());
201
202 while (!packetsTableWalkToRetry.empty()) {
204
205 assert(a.type==ACTION_SEND_REQ);
206
207 DPRINTF(SMMUv3, "[t] requestor HWTW retr addr=%#x size=%#x\n",
208 a.pkt->getAddr(), a.pkt->getSize());
209
210 if (!tableWalkPort.sendTimingReq(a.pkt))
211 break;
212
214 }
215}
216
217void
219{
220 for (auto ifc : deviceInterfaces) {
221 ifc->scheduleDeviceRetry();
222 }
223}
224
227{
228 if (system.isAtomicMode()) {
229 return runProcessAtomic(proc, pkt);
230 } else if (system.isTimingMode()) {
231 return runProcessTiming(proc, pkt);
232 } else {
233 panic("Not in timing or atomic mode!");
234 }
235}
236
239{
240 SMMUAction action;
241 Tick delay = 0;
242 bool finished = false;
243
244 do {
245 action = proc->run(pkt);
246
247 switch (action.type) {
248 case ACTION_SEND_REQ:
249 // Send an MMU initiated request on the table walk port if
250 // it is enabled. Otherwise, fall through and handle same
251 // as the final ACTION_SEND_REQ_FINAL request.
253 delay += tableWalkPort.sendAtomic(action.pkt);
254 pkt = action.pkt;
255 break;
256 }
257 [[fallthrough]];
259 delay += requestPort.sendAtomic(action.pkt);
260 pkt = action.pkt;
261 break;
262
263 case ACTION_SEND_RESP:
265 case ACTION_SLEEP:
266 finished = true;
267 break;
268
269 case ACTION_DELAY:
270 delay += action.delay;
271 break;
272
273 case ACTION_TERMINATE:
274 panic("ACTION_TERMINATE in atomic mode\n");
275
276 default:
277 panic("Unknown action\n");
278 }
279 } while (!finished);
280
281 action.delay = delay;
282
283 return action;
284}
285
288{
289 SMMUAction action = proc->run(pkt);
290
291 switch (action.type) {
292 case ACTION_SEND_REQ:
293 // Send an MMU initiated request on the table walk port if it is
294 // enabled. Otherwise, fall through and handle same as the final
295 // ACTION_SEND_REQ_FINAL request.
297 action.pkt->pushSenderState(proc);
298
299 DPRINTF(SMMUv3, "[t] requestor HWTW req addr=%#x size=%#x\n",
300 action.pkt->getAddr(), action.pkt->getSize());
301
302 if (packetsTableWalkToRetry.empty()
303 && tableWalkPort.sendTimingReq(action.pkt)) {
305 } else {
306 DPRINTF(SMMUv3, "[t] requestor HWTW req needs retry,"
307 " qlen=%d\n", packetsTableWalkToRetry.size());
308 packetsTableWalkToRetry.push(action);
309 }
310
311 break;
312 }
313 [[fallthrough]];
315 action.pkt->pushSenderState(proc);
316
317 DPRINTF(SMMUv3, "[t] requestor req addr=%#x size=%#x\n",
318 action.pkt->getAddr(), action.pkt->getSize());
319
320 if (packetsToRetry.empty() &&
321 requestPort.sendTimingReq(action.pkt)) {
323 } else {
324 DPRINTF(SMMUv3, "[t] requestor req needs retry, qlen=%d\n",
325 packetsToRetry.size());
326 packetsToRetry.push(action);
327 }
328
329 break;
330
331 case ACTION_SEND_RESP:
332 // @todo: We need to pay for this and not just zero it out
333 action.pkt->headerDelay = action.pkt->payloadDelay = 0;
334
335 DPRINTF(SMMUv3, "[t] responder resp addr=%#x size=%#x\n",
336 action.pkt->getAddr(),
337 action.pkt->getSize());
338
339 assert(action.ifc);
340 action.ifc->schedTimingResp(action.pkt);
341
342 delete proc;
343 break;
344
346 // @todo: We need to pay for this and not just zero it out
347 action.pkt->headerDelay = action.pkt->payloadDelay = 0;
348
349 DPRINTF(SMMUv3, "[t] ATS responder resp addr=%#x size=%#x\n",
350 action.pkt->getAddr(), action.pkt->getSize());
351
352 assert(action.ifc);
353 action.ifc->schedAtsTimingResp(action.pkt);
354
355 delete proc;
356 break;
357
358 case ACTION_DELAY:
359 case ACTION_SLEEP:
360 break;
361
362 case ACTION_TERMINATE:
363 delete proc;
364 break;
365
366 default:
367 panic("Unknown action\n");
368 }
369
370 return action;
371}
372
373void
375{
376 DPRINTF(SMMUv3, "processCommands()\n");
377
378 if (system.isAtomicMode()) {
380 (void) a;
381 } else if (system.isTimingMode()) {
382 if (!commandExecutor.isBusy())
384 } else {
385 panic("Not in timing or atomic mode!");
386 }
387}
388
389void
391{
392 switch (cmd.dw0.type) {
393 case CMD_PRF_CONFIG:
394 DPRINTF(SMMUv3, "CMD_PREFETCH_CONFIG - ignored\n");
395 break;
396
397 case CMD_PRF_ADDR:
398 DPRINTF(SMMUv3, "CMD_PREFETCH_ADDR - ignored\n");
399 break;
400
401 case CMD_CFGI_STE: {
402 DPRINTF(SMMUv3, "CMD_CFGI_STE sid=%#x\n", cmd.dw0.sid);
403 configCache.invalidateSID(cmd.dw0.sid);
404
405 for (auto dev_interface : deviceInterfaces) {
406 dev_interface->microTLB->invalidateSID(cmd.dw0.sid);
407 dev_interface->mainTLB->invalidateSID(cmd.dw0.sid);
408 }
409 break;
410 }
411
412 case CMD_CFGI_STE_RANGE: {
413 const auto range = cmd.dw1.range;
414 if (range == 31) {
415 // CMD_CFGI_ALL is an alias of CMD_CFGI_STE_RANGE with
416 // range = 31
417 DPRINTF(SMMUv3, "CMD_CFGI_ALL\n");
418 configCache.invalidateAll();
419
420 for (auto dev_interface : deviceInterfaces) {
421 dev_interface->microTLB->invalidateAll();
422 dev_interface->mainTLB->invalidateAll();
423 }
424 } else {
425 DPRINTF(SMMUv3, "CMD_CFGI_STE_RANGE\n");
426 const auto start_sid = cmd.dw0.sid & ~((1 << (range + 1)) - 1);
427 const auto end_sid = start_sid + (1 << (range + 1)) - 1;
428 for (auto sid = start_sid; sid <= end_sid; sid++) {
429 configCache.invalidateSID(sid);
430
431 for (auto dev_interface : deviceInterfaces) {
432 dev_interface->microTLB->invalidateSID(sid);
433 dev_interface->mainTLB->invalidateSID(sid);
434 }
435 }
436 }
437 break;
438 }
439
440 case CMD_CFGI_CD: {
441 DPRINTF(SMMUv3, "CMD_CFGI_CD sid=%#x ssid=%#x\n",
442 cmd.dw0.sid, cmd.dw0.ssid);
443 configCache.invalidateSSID(cmd.dw0.sid, cmd.dw0.ssid);
444
445 for (auto dev_interface : deviceInterfaces) {
446 dev_interface->microTLB->invalidateSSID(
447 cmd.dw0.sid, cmd.dw0.ssid);
448 dev_interface->mainTLB->invalidateSSID(
449 cmd.dw0.sid, cmd.dw0.ssid);
450 }
451 break;
452 }
453
454 case CMD_CFGI_CD_ALL: {
455 DPRINTF(SMMUv3, "CMD_CFGI_CD_ALL sid=%#x\n", cmd.dw0.sid);
456 configCache.invalidateSID(cmd.dw0.sid);
457
458 for (auto dev_interface : deviceInterfaces) {
459 dev_interface->microTLB->invalidateSID(cmd.dw0.sid);
460 dev_interface->mainTLB->invalidateSID(cmd.dw0.sid);
461 }
462 break;
463 }
464
465 case CMD_TLBI_NH_ALL: {
466 DPRINTF(SMMUv3, "CMD_TLBI_NH_ALL vmid=%#x\n", cmd.dw0.vmid);
467 for (auto dev_interface : deviceInterfaces) {
468 dev_interface->microTLB->invalidateVMID(cmd.dw0.vmid);
469 dev_interface->mainTLB->invalidateVMID(cmd.dw0.vmid);
470 }
471 tlb.invalidateVMID(cmd.dw0.vmid);
472 walkCache.invalidateVMID(cmd.dw0.vmid);
473 break;
474 }
475
476 case CMD_TLBI_NH_ASID: {
477 DPRINTF(SMMUv3, "CMD_TLBI_NH_ASID asid=%#x vmid=%#x\n",
478 cmd.dw0.asid, cmd.dw0.vmid);
479 for (auto dev_interface : deviceInterfaces) {
480 dev_interface->microTLB->invalidateASID(
481 cmd.dw0.asid, cmd.dw0.vmid);
482 dev_interface->mainTLB->invalidateASID(
483 cmd.dw0.asid, cmd.dw0.vmid);
484 }
485 tlb.invalidateASID(cmd.dw0.asid, cmd.dw0.vmid);
486 walkCache.invalidateASID(cmd.dw0.asid, cmd.dw0.vmid);
487 break;
488 }
489
490 case CMD_TLBI_NH_VAA: {
491 const Addr addr = cmd.addr();
492 DPRINTF(SMMUv3, "CMD_TLBI_NH_VAA va=%#08x vmid=%#x\n",
493 addr, cmd.dw0.vmid);
494 for (auto dev_interface : deviceInterfaces) {
495 dev_interface->microTLB->invalidateVAA(
496 addr, cmd.dw0.vmid);
497 dev_interface->mainTLB->invalidateVAA(
498 addr, cmd.dw0.vmid);
499 }
500 tlb.invalidateVAA(addr, cmd.dw0.vmid);
501 const bool leaf_only = cmd.dw1.leaf ? true : false;
502 walkCache.invalidateVAA(addr, cmd.dw0.vmid, leaf_only);
503 break;
504 }
505
506 case CMD_TLBI_NH_VA: {
507 const Addr addr = cmd.addr();
508 DPRINTF(SMMUv3, "CMD_TLBI_NH_VA va=%#08x asid=%#x vmid=%#x\n",
509 addr, cmd.dw0.asid, cmd.dw0.vmid);
510 for (auto dev_interface : deviceInterfaces) {
511 dev_interface->microTLB->invalidateVA(
512 addr, cmd.dw0.asid, cmd.dw0.vmid);
513 dev_interface->mainTLB->invalidateVA(
514 addr, cmd.dw0.asid, cmd.dw0.vmid);
515 }
516 tlb.invalidateVA(addr, cmd.dw0.asid, cmd.dw0.vmid);
517 const bool leaf_only = cmd.dw1.leaf ? true : false;
518 walkCache.invalidateVA(addr, cmd.dw0.asid, cmd.dw0.vmid,
519 leaf_only);
520 break;
521 }
522
523 case CMD_TLBI_S2_IPA: {
524 const Addr addr = cmd.addr();
525 DPRINTF(SMMUv3, "CMD_TLBI_S2_IPA ipa=%#08x vmid=%#x\n",
526 addr, cmd.dw0.vmid);
527 // This does not invalidate TLBs containing
528 // combined Stage1 + Stage2 translations, as per the spec.
529 ipaCache.invalidateIPA(addr, cmd.dw0.vmid);
530
531 if (!cmd.dw1.leaf)
532 walkCache.invalidateVMID(cmd.dw0.vmid);
533 break;
534 }
535
536 case CMD_TLBI_S12_VMALL: {
537 DPRINTF(SMMUv3, "CMD_TLBI_S12_VMALL vmid=%#x\n", cmd.dw0.vmid);
538 for (auto dev_interface : deviceInterfaces) {
539 dev_interface->microTLB->invalidateVMID(cmd.dw0.vmid);
540 dev_interface->mainTLB->invalidateVMID(cmd.dw0.vmid);
541 }
542 tlb.invalidateVMID(cmd.dw0.vmid);
543 ipaCache.invalidateVMID(cmd.dw0.vmid);
544 walkCache.invalidateVMID(cmd.dw0.vmid);
545 break;
546 }
547
548 case CMD_TLBI_NSNH_ALL: {
549 DPRINTF(SMMUv3, "CMD_TLBI_NSNH_ALL\n");
550 for (auto dev_interface : deviceInterfaces) {
551 dev_interface->microTLB->invalidateAll();
552 dev_interface->mainTLB->invalidateAll();
553 }
554 tlb.invalidateAll();
555 ipaCache.invalidateAll();
556 walkCache.invalidateAll();
557 break;
558 }
559
560 case CMD_RESUME:
561 DPRINTF(SMMUv3, "CMD_RESUME\n");
562 panic("resume unimplemented");
563 break;
564
565 default:
566 warn("Unimplemented command %#x\n", cmd.dw0.type);
567 break;
568 }
569}
570
571Tick
573{
574 DPRINTF(SMMUv3, "readControl: addr=%08x size=%d\n",
575 pkt->getAddr(), pkt->getSize());
576
577 int offset = pkt->getAddr() - regsMap.start();
578 assert(offset >= 0 && offset < SMMU_REG_SIZE);
579
580 if (inSecureBlock(offset)) {
581 warn("smmu: secure registers (0x%x) are not implemented\n",
582 offset);
583 }
584
585 auto reg_ptr = regs.data + offset;
586
587 switch (pkt->getSize()) {
588 case sizeof(uint32_t):
589 pkt->setLE<uint32_t>(*reinterpret_cast<uint32_t *>(reg_ptr));
590 break;
591 case sizeof(uint64_t):
592 pkt->setLE<uint64_t>(*reinterpret_cast<uint64_t *>(reg_ptr));
593 break;
594 default:
595 panic("smmu: unallowed access size: %d bytes\n", pkt->getSize());
596 break;
597 }
598
599 pkt->makeAtomicResponse();
600
601 return 0;
602}
603
604Tick
606{
607 int offset = pkt->getAddr() - regsMap.start();
608 assert(offset >= 0 && offset < SMMU_REG_SIZE);
609
610 DPRINTF(SMMUv3, "writeControl: addr=%08x size=%d data=%16x\n",
611 pkt->getAddr(), pkt->getSize(),
612 pkt->getSize() == sizeof(uint64_t) ?
613 pkt->getLE<uint64_t>() : pkt->getLE<uint32_t>());
614
615 switch (offset) {
616 case offsetof(SMMURegs, cr0):
617 assert(pkt->getSize() == sizeof(uint32_t));
618 regs.cr0 = regs.cr0ack = pkt->getLE<uint32_t>();
619 break;
620 case offsetof(SMMURegs, irq_ctrl):
621 assert(pkt->getSize() == sizeof(uint32_t));
622 warn("SMMUv3::%s No support for GERROR and PRI interrupt sources",
623 __func__);
624 regs.irq_ctrl = regs.irq_ctrlack = pkt->getLE<uint32_t>();
625 break;
626
627 case offsetof(SMMURegs, cr1):
628 case offsetof(SMMURegs, cr2):
629 case offsetof(SMMURegs, strtab_base_cfg):
630 case offsetof(SMMURegs, eventq_cons):
631 case offsetof(SMMURegs, eventq_irq_cfg1):
632 case offsetof(SMMURegs, priq_cons):
633 assert(pkt->getSize() == sizeof(uint32_t));
634 *reinterpret_cast<uint32_t *>(regs.data + offset) =
635 pkt->getLE<uint32_t>();
636 break;
637
638 case offsetof(SMMURegs, cmdq_cons):
639 assert(pkt->getSize() == sizeof(uint32_t));
640 if (regs.cr0 & CR0_CMDQEN_MASK) {
641 warn("CMDQ is enabled: ignoring write to CMDQ_CONS\n");
642 } else {
643 *reinterpret_cast<uint32_t *>(regs.data + offset) =
644 pkt->getLE<uint32_t>();
645 }
646 break;
647
648 case offsetof(SMMURegs, cmdq_prod):
649 assert(pkt->getSize() == sizeof(uint32_t));
650 *reinterpret_cast<uint32_t *>(regs.data + offset) =
651 pkt->getLE<uint32_t>();
653 break;
654
655 case offsetof(SMMURegs, strtab_base):
656 case offsetof(SMMURegs, eventq_irq_cfg0):
657 assert(pkt->getSize() == sizeof(uint64_t));
658 *reinterpret_cast<uint64_t *>(regs.data + offset) =
659 pkt->getLE<uint64_t>();
660 break;
661
662 case offsetof(SMMURegs, cmdq_base):
663 assert(pkt->getSize() == sizeof(uint64_t));
664 if (regs.cr0 & CR0_CMDQEN_MASK) {
665 warn("CMDQ is enabled: ignoring write to CMDQ_BASE\n");
666 } else {
667 *reinterpret_cast<uint64_t *>(regs.data + offset) =
668 pkt->getLE<uint64_t>();
669 regs.cmdq_cons = 0;
670 regs.cmdq_prod = 0;
671 }
672 break;
673
674 case offsetof(SMMURegs, eventq_base):
675 assert(pkt->getSize() == sizeof(uint64_t));
676 *reinterpret_cast<uint64_t *>(regs.data + offset) =
677 pkt->getLE<uint64_t>();
678 regs.eventq_cons = 0;
679 regs.eventq_prod = 0;
680 break;
681
682 case offsetof(SMMURegs, priq_base):
683 assert(pkt->getSize() == sizeof(uint64_t));
684 *reinterpret_cast<uint64_t *>(regs.data + offset) =
685 pkt->getLE<uint64_t>();
686 regs.priq_cons = 0;
687 regs.priq_prod = 0;
688 break;
689
690 default:
691 if (inSecureBlock(offset)) {
692 warn("smmu: secure registers (0x%x) are not implemented\n",
693 offset);
694 } else {
695 warn("smmu: write to read-only/undefined register at 0x%x\n",
696 offset);
697 }
698 }
699
700 pkt->makeAtomicResponse();
701
702 return 0;
703}
704
705bool
706SMMUv3::inSecureBlock(uint32_t offs) const
707{
708 if (offs >= offsetof(SMMURegs, _secure_regs) && offs < SMMU_SECURE_SZ)
709 return true;
710 else
711 return false;
712}
713
714void
716{
717 // make sure both sides are connected and have the same block size
718 if (!requestPort.isConnected())
719 fatal("Request port is not connected.\n");
720
721 // If the second request port is connected for the table walks, enable
722 // the mode to send table walks through this port instead
723 if (tableWalkPort.isConnected())
724 tableWalkPortEnable = true;
725
726 // notify the request side of our address ranges
727 for (auto ifc : deviceInterfaces) {
728 ifc->sendRange();
729 }
730
731 if (controlPort.isConnected())
732 controlPort.sendRangeChange();
733}
734
736 : statistics::Group(parent),
737 ADD_STAT(steL1Fetches, statistics::units::Count::get(), "STE L1 fetches"),
738 ADD_STAT(steFetches, statistics::units::Count::get(), "STE fetches"),
739 ADD_STAT(cdL1Fetches, statistics::units::Count::get(), "CD L1 fetches"),
740 ADD_STAT(cdFetches, statistics::units::Count::get(), "CD fetches"),
742 "Time to translate address"),
744 "Time to walk page tables")
745{
746 using namespace statistics;
747
749 .flags(pdf);
750
752 .flags(pdf);
753
755 .flags(pdf);
756
758 .flags(pdf);
759
761 .init(0, 2000000, 2000)
762 .flags(pdf);
763
765 .init(0, 2000000, 2000)
766 .flags(pdf);
767}
768
771{
772 // Wait until the Command Executor is not busy
773 if (commandExecutor.isBusy()) {
775 }
776 return DrainState::Drained;
777}
778
779void
781{
782 DPRINTF(Checkpoint, "Serializing SMMUv3\n");
783
784 SERIALIZE_ARRAY(regs.data, sizeof(regs.data) / sizeof(regs.data[0]));
785}
786
787void
789{
790 DPRINTF(Checkpoint, "Unserializing SMMUv3\n");
791
792 UNSERIALIZE_ARRAY(regs.data, sizeof(regs.data) / sizeof(regs.data[0]));
793}
794
795Port&
796SMMUv3::getPort(const std::string &name, PortID id)
797{
798 if (name == "request") {
799 return requestPort;
800 } else if (name == "walker") {
801 return tableWalkPort;
802 } else if (name == "control") {
803 return controlPort;
804 } else {
805 return ClockedObject::getPort(name, id);
806 }
807}
808
809} // namespace gem5
#define DPRINTF(x,...)
Definition trace.hh:209
Defines global host-dependent types: Counter, Tick, and (indirectly) {int,uint}{8,...
Base class for ARM GIC implementations.
ClockedObject(const ClockedObjectParams &p)
Tick nextCycle() const
Based on the clock of the object, determine the start tick of the first cycle that is at least one cy...
virtual std::string name() const
Definition named.hh:60
Addr getAddr() const
Definition packet.hh:807
void setLE(T v)
Set the value in the data pointer to v as little endian.
uint32_t payloadDelay
The extra pipelining delay from seeing the packet until the end of payload is transmitted by the comp...
Definition packet.hh:449
uint32_t headerDelay
The extra delay from seeing the packet until the header is transmitted.
Definition packet.hh:431
void pushSenderState(SenderState *sender_state)
Push a new sender state to the packet and make the current sender state the predecessor of the new on...
Definition packet.cc:334
SenderState * popSenderState()
Pop the top of the state stack and return a pointer to it.
Definition packet.cc:342
unsigned getSize() const
Definition packet.hh:817
void makeAtomicResponse()
Definition packet.hh:1074
T getLE() const
Get the data in the packet byte swapped from little endian to host endian.
Ports are used to interface objects to each other.
Definition port.hh:62
SMMUAction run(PacketPtr pkt)
void schedAtsTimingResp(PacketPtr pkt)
void schedTimingResp(PacketPtr pkt)
const System & system
Definition smmu_v3.hh:95
SMMUCommandExecProcess commandExecutor
Definition smmu_v3.hh:156
const AddrRange regsMap
Definition smmu_v3.hh:158
Tick readControl(PacketPtr pkt)
Definition smmu_v3.cc:572
void recvReqRetry()
Definition smmu_v3.cc:151
void serialize(CheckpointOut &cp) const override
Serialize an object.
Definition smmu_v3.cc:780
SMMUAction runProcess(SMMUProcess *proc, PacketPtr pkt)
Definition smmu_v3.cc:226
std::vector< SMMUv3DeviceInterface * > deviceInterfaces
Definition smmu_v3.hh:154
void unserialize(CheckpointIn &cp) override
Unserialize an object.
Definition smmu_v3.cc:788
ARMArchTLB tlb
Definition smmu_v3.hh:106
ConfigCache configCache
Definition smmu_v3.hh:107
SMMUControlPort controlPort
Definition smmu_v3.hh:100
SMMUTableWalkPort tableWalkPort
Definition smmu_v3.hh:99
virtual void init() override
init() is called after all C++ SimObjects have been created and all ports are connected.
Definition smmu_v3.cc:715
WalkCache walkCache
Definition smmu_v3.hh:109
SMMUAction runProcessAtomic(SMMUProcess *proc, PacketPtr pkt)
Definition smmu_v3.cc:238
bool recvTimingResp(PacketPtr pkt)
Definition smmu_v3.cc:134
bool inSecureBlock(uint32_t offs) const
Definition smmu_v3.cc:706
ArmInterruptPin *const eventqInterrupt
Definition smmu_v3.hh:104
virtual Port & getPort(const std::string &name, PortID id=InvalidPortID) override
Get a port with a given name and index.
Definition smmu_v3.cc:796
Tick writeControl(PacketPtr pkt)
Definition smmu_v3.cc:605
SMMURequestPort requestPort
Definition smmu_v3.hh:98
void scheduleDeviceRetries()
Definition smmu_v3.cc:218
std::queue< SMMUAction > packetsTableWalkToRetry
Definition smmu_v3.hh:164
DrainState drain() override
Provide a default implementation of the drain interface for objects that don't need draining.
Definition smmu_v3.cc:770
IPACache ipaCache
Definition smmu_v3.hh:108
bool tableWalkPortEnable
Definition smmu_v3.hh:115
const RequestorID requestorId
Definition smmu_v3.hh:96
std::queue< SMMUAction > packetsToRetry
Definition smmu_v3.hh:163
void processCommand(const SMMUCommand &cmd)
Definition smmu_v3.cc:390
void tableWalkRecvReqRetry()
Definition smmu_v3.cc:197
SMMURegs regs
Definition smmu_v3.hh:159
SMMUv3(const SMMUv3Params &p)
Definition smmu_v3.cc:59
MemberEventWrapper<&SMMUv3::processCommands > processCommandsEvent
Definition smmu_v3.hh:174
void processCommands()
Definition smmu_v3.cc:374
SMMUAction runProcessTiming(SMMUProcess *proc, PacketPtr pkt)
Definition smmu_v3.cc:287
bool tableWalkRecvTimingResp(PacketPtr pkt)
Definition smmu_v3.cc:180
friend class SMMUProcess
Definition smmu_v3.hh:90
Statistics container.
Definition group.hh:93
#define ADD_STAT(n,...)
Convenience macro to add a stat to a statistics group.
Definition group.hh:75
DrainState
Object drain/handover states.
Definition drain.hh:75
@ Draining
Draining buffers pending serialization/handover.
Definition drain.hh:77
@ Drained
Buffers drained, ready for serialization/handover.
Definition drain.hh:78
void schedule(Event &event, Tick when)
Definition eventq.hh:1012
#define panic(...)
This implements a cprintf based panic() function.
Definition logging.hh:220
#define fatal_if(cond,...)
Conditional fatal macro that checks the supplied condition and only causes a fatal error if the condi...
Definition logging.hh:268
#define fatal(...)
This implements a cprintf based fatal() function.
Definition logging.hh:232
#define UNSERIALIZE_ARRAY(member, size)
Definition serialize.hh:618
#define SERIALIZE_ARRAY(member, size)
Definition serialize.hh:610
const Params & params() const
virtual Port & getPort(const std::string &if_name, PortID idx=InvalidPortID)
Get a port with a given name and index.
#define warn(...)
Definition logging.hh:288
Bitfield< 23, 0 > offset
Definition types.hh:144
Bitfield< 8 > a
Definition misc_types.hh:66
Bitfield< 3 > addr
Definition types.hh:84
Units for Stats.
Definition units.hh:113
const FlagsType pdf
Print the percent of the total that this entry represents.
Definition info.hh:61
Copyright (c) 2024 Arm Limited All rights reserved.
Definition binary32.hh:36
T safe_cast(U &&ref_or_ptr)
Definition cast.hh:74
@ CR0_CMDQEN_MASK
std::ostream CheckpointOut
Definition serialize.hh:66
uint64_t Addr
Address type This will probably be moved somewhere else in the near future.
Definition types.hh:147
int16_t PortID
Port index/ID type, and a symbolic name for an invalid port id.
Definition types.hh:245
uint64_t Tick
Tick count type.
Definition types.hh:58
@ CMD_CFGI_STE
@ CMD_TLBI_S2_IPA
@ CMD_TLBI_S12_VMALL
@ CMD_CFGI_STE_RANGE
@ CMD_TLBI_NH_ASID
@ CMD_TLBI_NH_VA
@ CMD_CFGI_CD_ALL
@ CMD_PRF_CONFIG
@ CMD_TLBI_NSNH_ALL
@ CMD_CFGI_CD
@ CMD_TLBI_NH_ALL
@ CMD_PRF_ADDR
@ CMD_TLBI_NH_VAA
Packet * PacketPtr
@ SMMU_SECURE_SZ
@ SMMU_REG_SIZE
@ ACTION_SEND_RESP
@ ACTION_DELAY
@ ACTION_SLEEP
@ ACTION_TERMINATE
@ ACTION_SEND_REQ
@ ACTION_SEND_RESP_ATS
@ ACTION_SEND_REQ_FINAL
This is an implementation of the SMMUv3 architecture.
SMMUActionType type
SMMUv3DeviceInterface * ifc
Bitfield< 63, 48 > asid
Bitfield< 63, 32 > sid
Bitfield< 47, 32 > vmid
Bitfield< 31, 12 > ssid
Bitfield< 4, 0 > range
uint64_t addr() const
SMMUv3Stats(statistics::Group *parent)
Definition smmu_v3.cc:735
statistics::Distribution ptwTimeDist
Definition smmu_v3.hh:151
statistics::Scalar cdL1Fetches
Definition smmu_v3.hh:148
statistics::Scalar steL1Fetches
Definition smmu_v3.hh:146
statistics::Scalar steFetches
Definition smmu_v3.hh:147
statistics::Distribution translationTimeDist
Definition smmu_v3.hh:150
statistics::Scalar cdFetches
Definition smmu_v3.hh:149
const std::string & name()
Definition trace.cc:48

Generated on Mon May 26 2025 09:19:09 for gem5 by doxygen 1.13.2