49#include "debug/Checkpoint.hh"
50#include "debug/SMMUv3.hh"
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),
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();
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");
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);
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);
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");
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"),
741 ADD_STAT(translationTimeDist, statistics::units::
Tick::get(),
742 "Time to translate address"),
744 "Time to walk page tables")
746 using namespace statistics;
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.
void invalidateVAA(Addr va, uint16_t vmid)
void invalidateVA(Addr va, uint16_t asid, uint16_t vmid)
void invalidateVMID(uint16_t vmid)
void invalidateASID(uint16_t asid, uint16_t vmid)
The ClockedObject class extends the SimObject with a clock and accessor functions to relate ticks to ...
Tick nextCycle() const
Based on the clock of the object, determine the start tick of the first cycle that is at least one cy...
void invalidateSID(uint32_t sid)
void invalidateSSID(uint32_t sid, uint32_t ssid)
void invalidateVMID(uint16_t vmid)
void invalidateIPA(Addr ipa, uint16_t vmid)
virtual std::string name() const
A Packet is used to encapsulate a transfer between two objects in the memory system (e....
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.
bool isConnected() const
Is this port currently connected to a peer?
Tick sendAtomic(PacketPtr pkt)
Send an atomic request packet, where the data is moved and the state is updated in zero time,...
bool sendTimingReq(PacketPtr pkt)
Attempt to send a timing request to the responder port by calling its corresponding receive function.
void sendRangeChange() const
Called by the owner to send a range change.
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
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.
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)
bool isAtomicMode() const
Is the system in atomic mode?
bool isTimingMode() const
Is the system in timing mode?
void invalidateVAA(Addr va, uint16_t vmid, const bool leaf_only)
void invalidateVMID(uint16_t vmid)
void invalidateASID(uint16_t asid, uint16_t vmid)
void invalidateVA(Addr va, uint16_t asid, uint16_t vmid, const bool leaf_only)
Derived & flags(Flags _flags)
Set the flags and marks this stat to print at the end of simulation.
Distribution & init(Counter min, Counter max, Counter bkt)
Set the parameters of this distribution.
#define ADD_STAT(n,...)
Convenience macro to add a stat to a statistics group.
Addr start() const
Get the start address of the range.
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 - Pranith Kumar Copyright (c) 2020 Inria 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()