49#include "debug/Checkpoint.hh"
50#include "debug/SMMUv3.hh"
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),
87 configSem(params.cfg_slots),
88 ipaSem(params.ipa_slots),
89 walkSem(params.walk_slots),
91 transSem(params.xlate_slots),
92 ptwSem(params.ptw_slots),
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),
101 deviceInterfaces(params.device_interfaces),
102 commandExecutor(
name() +
".cmd_exec", *
this),
103 regsMap(params.reg_map),
104 processCommandsEvent(*
this)
107 "Invalid register map size: %#x different than SMMU_REG_SIZE = %#x\n",
111 memset(®s, 0,
sizeof(regs));
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;
127 warn(
"SMMUv3 IDx register values unchecked\n");
129 for (
auto ifc : deviceInterfaces)
161 a.pkt->getAddr(),
a.pkt->getSize());
182 DPRINTF(
SMMUv3,
"[t] requestor HWTW resp addr=%#x size=%#x\n",
207 DPRINTF(
SMMUv3,
"[t] requestor HWTW retr addr=%#x size=%#x\n",
208 a.pkt->getAddr(),
a.pkt->getSize());
221 ifc->scheduleDeviceRetry();
228 if (
system.isAtomicMode()) {
230 }
else if (
system.isTimingMode()) {
233 panic(
"Not in timing or atomic mode!");
242 bool finished =
false;
245 action = proc->
run(pkt);
247 switch (action.
type) {
270 delay += action.
delay;
274 panic(
"ACTION_TERMINATE in atomic mode\n");
277 panic(
"Unknown action\n");
281 action.
delay = delay;
291 switch (action.
type) {
299 DPRINTF(
SMMUv3,
"[t] requestor HWTW req addr=%#x size=%#x\n",
349 DPRINTF(
SMMUv3,
"[t] ATS responder resp addr=%#x size=%#x\n",
367 panic(
"Unknown action\n");
378 if (
system.isAtomicMode()) {
381 }
else if (
system.isTimingMode()) {
385 panic(
"Not in timing or atomic mode!");
392 switch (cmd.dw0.
type) {
406 dev_interface->microTLB->invalidateSID(cmd.dw0.
sid);
407 dev_interface->mainTLB->invalidateSID(cmd.dw0.
sid);
413 const auto range = cmd.dw1.
range;
421 dev_interface->microTLB->invalidateAll();
422 dev_interface->mainTLB->invalidateAll();
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++) {
432 dev_interface->microTLB->invalidateSID(sid);
433 dev_interface->mainTLB->invalidateSID(sid);
446 dev_interface->microTLB->invalidateSSID(
448 dev_interface->mainTLB->invalidateSSID(
459 dev_interface->microTLB->invalidateSID(cmd.dw0.
sid);
460 dev_interface->mainTLB->invalidateSID(cmd.dw0.
sid);
468 dev_interface->microTLB->invalidateVMID(cmd.dw0.
vmid);
469 dev_interface->mainTLB->invalidateVMID(cmd.dw0.
vmid);
471 tlb.invalidateVMID(cmd.dw0.
vmid);
480 dev_interface->microTLB->invalidateASID(
482 dev_interface->mainTLB->invalidateASID(
495 dev_interface->microTLB->invalidateVAA(
497 dev_interface->mainTLB->invalidateVAA(
501 const bool leaf_only = cmd.dw1.leaf ? true :
false;
508 DPRINTF(
SMMUv3,
"CMD_TLBI_NH_VA va=%#08x asid=%#x vmid=%#x\n",
511 dev_interface->microTLB->invalidateVA(
513 dev_interface->mainTLB->invalidateVA(
517 const bool leaf_only = cmd.dw1.leaf ? true :
false;
539 dev_interface->microTLB->invalidateVMID(cmd.dw0.
vmid);
540 dev_interface->mainTLB->invalidateVMID(cmd.dw0.
vmid);
542 tlb.invalidateVMID(cmd.dw0.
vmid);
551 dev_interface->microTLB->invalidateAll();
552 dev_interface->mainTLB->invalidateAll();
562 panic(
"resume unimplemented");
566 warn(
"Unimplemented command %#x\n", cmd.dw0.
type);
581 warn(
"smmu: secure registers (0x%x) are not implemented\n",
588 case sizeof(uint32_t):
589 pkt->
setLE<uint32_t>(*
reinterpret_cast<uint32_t *
>(reg_ptr));
591 case sizeof(uint64_t):
592 pkt->
setLE<uint64_t>(*
reinterpret_cast<uint64_t *
>(reg_ptr));
595 panic(
"smmu: unallowed access size: %d bytes\n", pkt->
getSize());
610 DPRINTF(
SMMUv3,
"writeControl: addr=%08x size=%d data=%16x\n",
612 pkt->
getSize() ==
sizeof(uint64_t) ?
613 pkt->
getLE<uint64_t>() : pkt->
getLE<uint32_t>());
616 case offsetof(SMMURegs, cr0):
617 assert(pkt->
getSize() ==
sizeof(uint32_t));
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",
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>();
638 case offsetof(SMMURegs, cmdq_cons):
639 assert(pkt->
getSize() ==
sizeof(uint32_t));
641 warn(
"CMDQ is enabled: ignoring write to CMDQ_CONS\n");
643 *
reinterpret_cast<uint32_t *
>(
regs.data +
offset) =
644 pkt->
getLE<uint32_t>();
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>();
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>();
662 case offsetof(SMMURegs, cmdq_base):
663 assert(pkt->
getSize() ==
sizeof(uint64_t));
665 warn(
"CMDQ is enabled: ignoring write to CMDQ_BASE\n");
667 *
reinterpret_cast<uint64_t *
>(
regs.data +
offset) =
668 pkt->
getLE<uint64_t>();
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;
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>();
692 warn(
"smmu: secure registers (0x%x) are not implemented\n",
695 warn(
"smmu: write to read-only/undefined register at 0x%x\n",
708 if (offs >= offsetof(SMMURegs, _secure_regs) && offs <
SMMU_SECURE_SZ)
719 fatal(
"Request port is not connected.\n");
742 "Time to translate address"),
744 "Time to walk page tables")
761 .init(0, 2000000, 2000)
765 .init(0, 2000000, 2000)
782 DPRINTF(Checkpoint,
"Serializing SMMUv3\n");
790 DPRINTF(Checkpoint,
"Unserializing SMMUv3\n");
798 if (
name ==
"request") {
800 }
else if (
name ==
"walker") {
802 }
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()