49#include "debug/Checkpoint.hh"
50#include "debug/SMMUv3.hh"
54#include "params/SMMUv3.hh"
75 params.walk_assoc, params.walk_policy,
this),
76 tlbEnable(params.tlb_enable),
77 configCacheEnable(params.cfg_enable),
78 ipaCacheEnable(params.ipa_enable),
79 walkCacheEnable(params.walk_enable),
80 tableWalkPortEnable(
false),
81 walkCacheNonfinalEnable(params.wc_nonfinal_enable),
82 walkCacheS1Levels(params.wc_s1_levels),
83 walkCacheS2Levels(params.wc_s2_levels),
84 requestPortWidth(params.request_port_width),
85 tlbSem(params.tlb_slots),
88 configSem(params.cfg_slots),
89 ipaSem(params.ipa_slots),
90 walkSem(params.walk_slots),
92 transSem(params.xlate_slots),
93 ptwSem(params.ptw_slots),
95 tlbLat(params.tlb_lat),
96 ifcSmmuLat(params.ifc_smmu_lat),
97 smmuIfcLat(params.smmu_ifc_lat),
98 configLat(params.cfg_lat),
99 ipaLat(params.ipa_lat),
100 walkLat(params.walk_lat),
102 deviceInterfaces(params.device_interfaces),
103 commandExecutor(
name() +
".cmd_exec", *
this),
104 regsMap(params.reg_map),
105 processCommandsEvent(*
this)
108 "Invalid register map size: %#x different than SMMU_REG_SIZE = %#x\n",
112 memset(®s, 0,
sizeof(regs));
115 regs.idr0 = params.smmu_idr0;
116 regs.idr1 = params.smmu_idr1;
117 regs.idr2 = params.smmu_idr2;
118 regs.idr3 = params.smmu_idr3;
119 regs.idr4 = params.smmu_idr4;
120 regs.idr5 = params.smmu_idr5;
121 regs.iidr = params.smmu_iidr;
122 regs.aidr = params.smmu_aidr;
128 warn(
"SMMUv3 IDx register values unchecked\n");
130 for (
auto ifc : deviceInterfaces)
162 a.pkt->getAddr(),
a.pkt->getSize());
183 DPRINTF(
SMMUv3,
"[t] requestor HWTW resp addr=%#x size=%#x\n",
208 DPRINTF(
SMMUv3,
"[t] requestor HWTW retr addr=%#x size=%#x\n",
209 a.pkt->getAddr(),
a.pkt->getSize());
222 ifc->scheduleDeviceRetry();
229 if (
system.isAtomicMode()) {
231 }
else if (
system.isTimingMode()) {
234 panic(
"Not in timing or atomic mode!");
243 bool finished =
false;
246 action = proc->
run(pkt);
248 switch (action.
type) {
271 delay += action.
delay;
275 panic(
"ACTION_TERMINATE in atomic mode\n");
278 panic(
"Unknown action\n");
282 action.
delay = delay;
292 switch (action.
type) {
300 DPRINTF(
SMMUv3,
"[t] requestor HWTW req addr=%#x size=%#x\n",
350 DPRINTF(
SMMUv3,
"[t] ATS responder resp addr=%#x size=%#x\n",
368 panic(
"Unknown action\n");
379 if (
system.isAtomicMode()) {
382 }
else if (
system.isTimingMode()) {
386 panic(
"Not in timing or atomic mode!");
393 switch (cmd.dw0.
type) {
407 dev_interface->microTLB->invalidateSID(cmd.dw0.
sid);
408 dev_interface->mainTLB->invalidateSID(cmd.dw0.
sid);
414 const auto range = cmd.dw1.
range;
422 dev_interface->microTLB->invalidateAll();
423 dev_interface->mainTLB->invalidateAll();
427 const auto start_sid = cmd.dw0.
sid & ~((1 << (range + 1)) - 1);
428 const auto end_sid = start_sid + (1 << (range + 1)) - 1;
429 for (
auto sid = start_sid; sid <= end_sid; sid++) {
433 dev_interface->microTLB->invalidateSID(sid);
434 dev_interface->mainTLB->invalidateSID(sid);
447 dev_interface->microTLB->invalidateSSID(
449 dev_interface->mainTLB->invalidateSSID(
460 dev_interface->microTLB->invalidateSID(cmd.dw0.
sid);
461 dev_interface->mainTLB->invalidateSID(cmd.dw0.
sid);
469 dev_interface->microTLB->invalidateVMID(cmd.dw0.
vmid);
470 dev_interface->mainTLB->invalidateVMID(cmd.dw0.
vmid);
472 tlb.invalidateVMID(cmd.dw0.
vmid);
481 dev_interface->microTLB->invalidateASID(
483 dev_interface->mainTLB->invalidateASID(
496 dev_interface->microTLB->invalidateVAA(
498 dev_interface->mainTLB->invalidateVAA(
502 const bool leaf_only = cmd.dw1.leaf ? true :
false;
509 DPRINTF(
SMMUv3,
"CMD_TLBI_NH_VA va=%#08x asid=%#x vmid=%#x\n",
512 dev_interface->microTLB->invalidateVA(
514 dev_interface->mainTLB->invalidateVA(
518 const bool leaf_only = cmd.dw1.leaf ? true :
false;
540 dev_interface->microTLB->invalidateVMID(cmd.dw0.
vmid);
541 dev_interface->mainTLB->invalidateVMID(cmd.dw0.
vmid);
543 tlb.invalidateVMID(cmd.dw0.
vmid);
552 dev_interface->microTLB->invalidateAll();
553 dev_interface->mainTLB->invalidateAll();
563 panic(
"resume unimplemented");
567 warn(
"Unimplemented command %#x\n", cmd.dw0.
type);
582 warn(
"smmu: secure registers (0x%x) are not implemented\n",
589 case sizeof(uint32_t):
590 pkt->
setLE<uint32_t>(*
reinterpret_cast<uint32_t *
>(reg_ptr));
592 case sizeof(uint64_t):
593 pkt->
setLE<uint64_t>(*
reinterpret_cast<uint64_t *
>(reg_ptr));
596 panic(
"smmu: unallowed access size: %d bytes\n", pkt->
getSize());
611 DPRINTF(
SMMUv3,
"writeControl: addr=%08x size=%d data=%16x\n",
613 pkt->
getSize() ==
sizeof(uint64_t) ?
614 pkt->
getLE<uint64_t>() : pkt->
getLE<uint32_t>());
617 case offsetof(SMMURegs, cr0):
618 assert(pkt->
getSize() ==
sizeof(uint32_t));
621 case offsetof(SMMURegs, irq_ctrl):
622 assert(pkt->
getSize() ==
sizeof(uint32_t));
623 warn(
"SMMUv3::%s No support for GERROR and PRI interrupt sources",
628 case offsetof(SMMURegs,
cr1):
629 case offsetof(SMMURegs, cr2):
630 case offsetof(SMMURegs, strtab_base_cfg):
631 case offsetof(SMMURegs, eventq_cons):
632 case offsetof(SMMURegs, eventq_irq_cfg1):
633 case offsetof(SMMURegs, priq_cons):
634 assert(pkt->
getSize() ==
sizeof(uint32_t));
635 *
reinterpret_cast<uint32_t *
>(
regs.data +
offset) =
636 pkt->
getLE<uint32_t>();
639 case offsetof(SMMURegs, cmdq_cons):
640 assert(pkt->
getSize() ==
sizeof(uint32_t));
642 warn(
"CMDQ is enabled: ignoring write to CMDQ_CONS\n");
644 *
reinterpret_cast<uint32_t *
>(
regs.data +
offset) =
645 pkt->
getLE<uint32_t>();
649 case offsetof(SMMURegs, cmdq_prod):
650 assert(pkt->
getSize() ==
sizeof(uint32_t));
651 *
reinterpret_cast<uint32_t *
>(
regs.data +
offset) =
652 pkt->
getLE<uint32_t>();
656 case offsetof(SMMURegs, strtab_base):
657 case offsetof(SMMURegs, eventq_irq_cfg0):
658 assert(pkt->
getSize() ==
sizeof(uint64_t));
659 *
reinterpret_cast<uint64_t *
>(
regs.data +
offset) =
660 pkt->
getLE<uint64_t>();
663 case offsetof(SMMURegs, cmdq_base):
664 assert(pkt->
getSize() ==
sizeof(uint64_t));
666 warn(
"CMDQ is enabled: ignoring write to CMDQ_BASE\n");
668 *
reinterpret_cast<uint64_t *
>(
regs.data +
offset) =
669 pkt->
getLE<uint64_t>();
675 case offsetof(SMMURegs, eventq_base):
676 assert(pkt->
getSize() ==
sizeof(uint64_t));
677 *
reinterpret_cast<uint64_t *
>(
regs.data +
offset) =
678 pkt->
getLE<uint64_t>();
679 regs.eventq_cons = 0;
680 regs.eventq_prod = 0;
683 case offsetof(SMMURegs, priq_base):
684 assert(pkt->
getSize() ==
sizeof(uint64_t));
685 *
reinterpret_cast<uint64_t *
>(
regs.data +
offset) =
686 pkt->
getLE<uint64_t>();
693 warn(
"smmu: secure registers (0x%x) are not implemented\n",
696 warn(
"smmu: write to read-only/undefined register at 0x%x\n",
709 if (offs >= offsetof(SMMURegs, _secure_regs) && offs <
SMMU_SECURE_SZ)
720 fatal(
"Request port is not connected.\n");
743 "Time to translate address"),
745 "Time to walk page tables")
762 .init(0, 2000000, 2000)
766 .init(0, 2000000, 2000)
783 DPRINTF(Checkpoint,
"Serializing SMMUv3\n");
791 DPRINTF(Checkpoint,
"Unserializing SMMUv3\n");
799 if (
name ==
"request") {
801 }
else if (
name ==
"walker") {
803 }
else if (
name ==
"control") {
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
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...
uint32_t headerDelay
The extra delay from seeing the packet until the header is transmitted.
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...
SenderState * popSenderState()
Pop the top of the state stack and return a pointer to it.
void makeAtomicResponse()
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.
SMMUAction run(PacketPtr pkt)
void schedAtsTimingResp(PacketPtr pkt)
void schedTimingResp(PacketPtr pkt)
SMMUCommandExecProcess commandExecutor
Tick readControl(PacketPtr pkt)
void serialize(CheckpointOut &cp) const override
Serialize an object.
SMMUAction runProcess(SMMUProcess *proc, PacketPtr pkt)
std::vector< SMMUv3DeviceInterface * > deviceInterfaces
void unserialize(CheckpointIn &cp) override
Unserialize an object.
SMMUControlPort controlPort
SMMUTableWalkPort tableWalkPort
virtual void init() override
init() is called after all C++ SimObjects have been created and all ports are connected.
SMMUAction runProcessAtomic(SMMUProcess *proc, PacketPtr pkt)
bool recvTimingResp(PacketPtr pkt)
bool inSecureBlock(uint32_t offs) const
ArmInterruptPin *const eventqInterrupt
virtual Port & getPort(const std::string &name, PortID id=InvalidPortID) override
Get a port with a given name and index.
Tick writeControl(PacketPtr pkt)
SMMURequestPort requestPort
void scheduleDeviceRetries()
std::queue< SMMUAction > packetsTableWalkToRetry
DrainState drain() override
Provide a default implementation of the drain interface for objects that don't need draining.
const RequestorID requestorId
std::queue< SMMUAction > packetsToRetry
void processCommand(const SMMUCommand &cmd)
void tableWalkRecvReqRetry()
SMMUv3(const SMMUv3Params &p)
MemberEventWrapper<&SMMUv3::processCommands > processCommandsEvent
SMMUAction runProcessTiming(SMMUProcess *proc, PacketPtr pkt)
bool tableWalkRecvTimingResp(PacketPtr pkt)
#define ADD_STAT(n,...)
Convenience macro to add a stat to a statistics group.
DrainState
Object drain/handover states.
@ Draining
Draining buffers pending serialization/handover.
@ Drained
Buffers drained, ready for serialization/handover.
void schedule(Event &event, Tick when)
#define panic(...)
This implements a cprintf based panic() function.
#define fatal_if(cond,...)
Conditional fatal macro that checks the supplied condition and only causes a fatal error if the condi...
#define fatal(...)
This implements a cprintf based fatal() function.
#define UNSERIALIZE_ARRAY(member, size)
#define SERIALIZE_ARRAY(member, size)
const Params & params() const
virtual Port & getPort(const std::string &if_name, PortID idx=InvalidPortID)
Get a port with a given name and index.
const FlagsType pdf
Print the percent of the total that this entry represents.
Copyright (c) 2024 Arm Limited All rights reserved.
T safe_cast(U &&ref_or_ptr)
std::ostream CheckpointOut
uint64_t Addr
Address type This will probably be moved somewhere else in the near future.
int16_t PortID
Port index/ID type, and a symbolic name for an invalid port id.
uint64_t Tick
Tick count type.
This is an implementation of the SMMUv3 architecture.
SMMUv3DeviceInterface * ifc
SMMUv3Stats(statistics::Group *parent)
statistics::Distribution ptwTimeDist
statistics::Scalar cdL1Fetches
statistics::Scalar steL1Fetches
statistics::Scalar steFetches
statistics::Distribution translationTimeDist
statistics::Scalar cdFetches
const std::string & name()