gem5  v22.1.0.0
smmu_v3.cc
Go to the documentation of this file.
1 /*
2  * Copyright (c) 2013, 2018-2020 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"
52 #include "mem/packet_access.hh"
53 #include "sim/system.hh"
54 
55 namespace gem5
56 {
57 
58 SMMUv3::SMMUv3(const SMMUv3Params &params) :
59  ClockedObject(params),
60  system(*params.system),
61  requestorId(params.system->getRequestorId(this)),
62  requestPort(name() + ".request", *this),
63  tableWalkPort(name() + ".walker", *this),
64  controlPort(name() + ".control", *this, params.reg_map),
65  irqInterfaceEnable(params.irq_interface_enable),
66  tlb(params.tlb_entries, params.tlb_assoc, params.tlb_policy, this),
67  configCache(params.cfg_entries, params.cfg_assoc, params.cfg_policy, this),
68  ipaCache(params.ipa_entries, params.ipa_assoc, params.ipa_policy, this),
69  walkCache({ { params.walk_S1L0, params.walk_S1L1,
70  params.walk_S1L2, params.walk_S1L3,
71  params.walk_S2L0, params.walk_S2L1,
72  params.walk_S2L2, params.walk_S2L3 } },
73  params.walk_assoc, params.walk_policy, this),
74  tlbEnable(params.tlb_enable),
75  configCacheEnable(params.cfg_enable),
76  ipaCacheEnable(params.ipa_enable),
77  walkCacheEnable(params.walk_enable),
78  tableWalkPortEnable(false),
79  walkCacheNonfinalEnable(params.wc_nonfinal_enable),
80  walkCacheS1Levels(params.wc_s1_levels),
81  walkCacheS2Levels(params.wc_s2_levels),
82  requestPortWidth(params.request_port_width),
83  tlbSem(params.tlb_slots),
84  ifcSmmuSem(1),
85  smmuIfcSem(1),
86  configSem(params.cfg_slots),
87  ipaSem(params.ipa_slots),
88  walkSem(params.walk_slots),
89  requestPortSem(1),
90  transSem(params.xlate_slots),
91  ptwSem(params.ptw_slots),
92  cycleSem(1),
93  tlbLat(params.tlb_lat),
94  ifcSmmuLat(params.ifc_smmu_lat),
95  smmuIfcLat(params.smmu_ifc_lat),
96  configLat(params.cfg_lat),
97  ipaLat(params.ipa_lat),
98  walkLat(params.walk_lat),
99  stats(this),
100  deviceInterfaces(params.device_interfaces),
101  commandExecutor(name() + ".cmd_exec", *this),
102  regsMap(params.reg_map),
103  processCommandsEvent(this)
104 {
105  fatal_if(regsMap.size() != SMMU_REG_SIZE,
106  "Invalid register map size: %#x different than SMMU_REG_SIZE = %#x\n",
107  regsMap.size(), SMMU_REG_SIZE);
108 
109  // Init smmu registers to 0
110  memset(&regs, 0, sizeof(regs));
111 
112  // Setup RO ID registers
113  regs.idr0 = params.smmu_idr0;
114  regs.idr1 = params.smmu_idr1;
115  regs.idr2 = params.smmu_idr2;
116  regs.idr3 = params.smmu_idr3;
117  regs.idr4 = params.smmu_idr4;
118  regs.idr5 = params.smmu_idr5;
119  regs.iidr = params.smmu_iidr;
120  regs.aidr = params.smmu_aidr;
121 
122  // TODO: At the moment it possible to set the ID registers to hold
123  // any possible value. It would be nice to have a sanity check here
124  // at construction time in case some idx registers are programmed to
125  // store an unallowed values or if the are configuration conflicts.
126  warn("SMMUv3 IDx register values unchecked\n");
127 
128  for (auto ifc : deviceInterfaces)
129  ifc->setSMMU(this);
130 }
131 
132 bool
134 {
135  DPRINTF(SMMUv3, "[t] requestor resp addr=%#x size=%#x\n",
136  pkt->getAddr(), pkt->getSize());
137 
138  // @todo: We need to pay for this and not just zero it out
139  pkt->headerDelay = pkt->payloadDelay = 0;
140 
141  SMMUProcess *proc =
142  safe_cast<SMMUProcess *>(pkt->popSenderState());
143 
144  runProcessTiming(proc, pkt);
145 
146  return true;
147 }
148 
149 void
151 {
152  assert(!packetsToRetry.empty());
153 
154  while (!packetsToRetry.empty()) {
155  SMMUAction a = packetsToRetry.front();
156 
157  assert(a.type==ACTION_SEND_REQ || a.type==ACTION_SEND_REQ_FINAL);
158 
159  DPRINTF(SMMUv3, "[t] requestor retr addr=%#x size=%#x\n",
160  a.pkt->getAddr(), a.pkt->getSize());
161 
162  if (!requestPort.sendTimingReq(a.pkt))
163  break;
164 
165  packetsToRetry.pop();
166 
167  /*
168  * ACTION_SEND_REQ_FINAL means that we have just forwarded the packet
169  * on the requestor interface; this means that we no longer hold on to
170  * that transaction and therefore can accept a new one.
171  * If the response port was stalled then unstall it (send retry).
172  */
173  if (a.type == ACTION_SEND_REQ_FINAL)
175  }
176 }
177 
178 bool
180 {
181  DPRINTF(SMMUv3, "[t] requestor HWTW resp addr=%#x size=%#x\n",
182  pkt->getAddr(), pkt->getSize());
183 
184  // @todo: We need to pay for this and not just zero it out
185  pkt->headerDelay = pkt->payloadDelay = 0;
186 
187  SMMUProcess *proc =
188  safe_cast<SMMUProcess *>(pkt->popSenderState());
189 
190  runProcessTiming(proc, pkt);
191 
192  return true;
193 }
194 
195 void
197 {
198  assert(tableWalkPortEnable);
199  assert(!packetsTableWalkToRetry.empty());
200 
201  while (!packetsTableWalkToRetry.empty()) {
203 
204  assert(a.type==ACTION_SEND_REQ);
205 
206  DPRINTF(SMMUv3, "[t] requestor HWTW retr addr=%#x size=%#x\n",
207  a.pkt->getAddr(), a.pkt->getSize());
208 
209  if (!tableWalkPort.sendTimingReq(a.pkt))
210  break;
211 
213  }
214 }
215 
216 void
218 {
219  for (auto ifc : deviceInterfaces) {
220  ifc->scheduleDeviceRetry();
221  }
222 }
223 
226 {
227  if (system.isAtomicMode()) {
228  return runProcessAtomic(proc, pkt);
229  } else if (system.isTimingMode()) {
230  return runProcessTiming(proc, pkt);
231  } else {
232  panic("Not in timing or atomic mode!");
233  }
234 }
235 
238 {
239  SMMUAction action;
240  Tick delay = 0;
241  bool finished = false;
242 
243  do {
244  action = proc->run(pkt);
245 
246  switch (action.type) {
247  case ACTION_SEND_REQ:
248  // Send an MMU initiated request on the table walk port if
249  // it is enabled. Otherwise, fall through and handle same
250  // as the final ACTION_SEND_REQ_FINAL request.
251  if (tableWalkPortEnable) {
252  delay += tableWalkPort.sendAtomic(action.pkt);
253  pkt = action.pkt;
254  break;
255  }
256  [[fallthrough]];
258  delay += requestPort.sendAtomic(action.pkt);
259  pkt = action.pkt;
260  break;
261 
262  case ACTION_SEND_RESP:
264  case ACTION_SLEEP:
265  finished = true;
266  break;
267 
268  case ACTION_DELAY:
269  delay += action.delay;
270  break;
271 
272  case ACTION_TERMINATE:
273  panic("ACTION_TERMINATE in atomic mode\n");
274 
275  default:
276  panic("Unknown action\n");
277  }
278  } while (!finished);
279 
280  action.delay = delay;
281 
282  return action;
283 }
284 
287 {
288  SMMUAction action = proc->run(pkt);
289 
290  switch (action.type) {
291  case ACTION_SEND_REQ:
292  // Send an MMU initiated request on the table walk port if it is
293  // enabled. Otherwise, fall through and handle same as the final
294  // ACTION_SEND_REQ_FINAL request.
295  if (tableWalkPortEnable) {
296  action.pkt->pushSenderState(proc);
297 
298  DPRINTF(SMMUv3, "[t] requestor HWTW req addr=%#x size=%#x\n",
299  action.pkt->getAddr(), action.pkt->getSize());
300 
301  if (packetsTableWalkToRetry.empty()
302  && tableWalkPort.sendTimingReq(action.pkt)) {
304  } else {
305  DPRINTF(SMMUv3, "[t] requestor HWTW req needs retry,"
306  " qlen=%d\n", packetsTableWalkToRetry.size());
307  packetsTableWalkToRetry.push(action);
308  }
309 
310  break;
311  }
312  [[fallthrough]];
314  action.pkt->pushSenderState(proc);
315 
316  DPRINTF(SMMUv3, "[t] requestor req addr=%#x size=%#x\n",
317  action.pkt->getAddr(), action.pkt->getSize());
318 
319  if (packetsToRetry.empty() &&
320  requestPort.sendTimingReq(action.pkt)) {
322  } else {
323  DPRINTF(SMMUv3, "[t] requestor req needs retry, qlen=%d\n",
324  packetsToRetry.size());
325  packetsToRetry.push(action);
326  }
327 
328  break;
329 
330  case ACTION_SEND_RESP:
331  // @todo: We need to pay for this and not just zero it out
332  action.pkt->headerDelay = action.pkt->payloadDelay = 0;
333 
334  DPRINTF(SMMUv3, "[t] responder resp addr=%#x size=%#x\n",
335  action.pkt->getAddr(),
336  action.pkt->getSize());
337 
338  assert(action.ifc);
339  action.ifc->schedTimingResp(action.pkt);
340 
341  delete proc;
342  break;
343 
345  // @todo: We need to pay for this and not just zero it out
346  action.pkt->headerDelay = action.pkt->payloadDelay = 0;
347 
348  DPRINTF(SMMUv3, "[t] ATS responder resp addr=%#x size=%#x\n",
349  action.pkt->getAddr(), action.pkt->getSize());
350 
351  assert(action.ifc);
352  action.ifc->schedAtsTimingResp(action.pkt);
353 
354  delete proc;
355  break;
356 
357  case ACTION_DELAY:
358  case ACTION_SLEEP:
359  break;
360 
361  case ACTION_TERMINATE:
362  delete proc;
363  break;
364 
365  default:
366  panic("Unknown action\n");
367  }
368 
369  return action;
370 }
371 
372 void
374 {
375  DPRINTF(SMMUv3, "processCommands()\n");
376 
377  if (system.isAtomicMode()) {
379  (void) a;
380  } else if (system.isTimingMode()) {
381  if (!commandExecutor.isBusy())
383  } else {
384  panic("Not in timing or atomic mode!");
385  }
386 }
387 
388 void
390 {
391  switch (cmd.dw0.type) {
392  case CMD_PRF_CONFIG:
393  DPRINTF(SMMUv3, "CMD_PREFETCH_CONFIG - ignored\n");
394  break;
395 
396  case CMD_PRF_ADDR:
397  DPRINTF(SMMUv3, "CMD_PREFETCH_ADDR - ignored\n");
398  break;
399 
400  case CMD_CFGI_STE: {
401  DPRINTF(SMMUv3, "CMD_CFGI_STE sid=%#x\n", cmd.dw0.sid);
402  configCache.invalidateSID(cmd.dw0.sid);
403 
404  for (auto dev_interface : deviceInterfaces) {
405  dev_interface->microTLB->invalidateSID(cmd.dw0.sid);
406  dev_interface->mainTLB->invalidateSID(cmd.dw0.sid);
407  }
408  break;
409  }
410 
411  case CMD_CFGI_STE_RANGE: {
412  const auto range = cmd.dw1.range;
413  if (range == 31) {
414  // CMD_CFGI_ALL is an alias of CMD_CFGI_STE_RANGE with
415  // range = 31
416  DPRINTF(SMMUv3, "CMD_CFGI_ALL\n");
418 
419  for (auto dev_interface : deviceInterfaces) {
420  dev_interface->microTLB->invalidateAll();
421  dev_interface->mainTLB->invalidateAll();
422  }
423  } else {
424  DPRINTF(SMMUv3, "CMD_CFGI_STE_RANGE\n");
425  const auto start_sid = cmd.dw0.sid & ~((1 << (range + 1)) - 1);
426  const auto end_sid = start_sid + (1 << (range + 1)) - 1;
427  for (auto sid = start_sid; sid <= end_sid; sid++) {
429 
430  for (auto dev_interface : deviceInterfaces) {
431  dev_interface->microTLB->invalidateSID(sid);
432  dev_interface->mainTLB->invalidateSID(sid);
433  }
434  }
435  }
436  break;
437  }
438 
439  case CMD_CFGI_CD: {
440  DPRINTF(SMMUv3, "CMD_CFGI_CD sid=%#x ssid=%#x\n",
441  cmd.dw0.sid, cmd.dw0.ssid);
442  configCache.invalidateSSID(cmd.dw0.sid, cmd.dw0.ssid);
443 
444  for (auto dev_interface : deviceInterfaces) {
445  dev_interface->microTLB->invalidateSSID(
446  cmd.dw0.sid, cmd.dw0.ssid);
447  dev_interface->mainTLB->invalidateSSID(
448  cmd.dw0.sid, cmd.dw0.ssid);
449  }
450  break;
451  }
452 
453  case CMD_CFGI_CD_ALL: {
454  DPRINTF(SMMUv3, "CMD_CFGI_CD_ALL sid=%#x\n", cmd.dw0.sid);
455  configCache.invalidateSID(cmd.dw0.sid);
456 
457  for (auto dev_interface : deviceInterfaces) {
458  dev_interface->microTLB->invalidateSID(cmd.dw0.sid);
459  dev_interface->mainTLB->invalidateSID(cmd.dw0.sid);
460  }
461  break;
462  }
463 
464  case CMD_TLBI_NH_ALL: {
465  DPRINTF(SMMUv3, "CMD_TLBI_NH_ALL vmid=%#x\n", cmd.dw0.vmid);
466  for (auto dev_interface : deviceInterfaces) {
467  dev_interface->microTLB->invalidateVMID(cmd.dw0.vmid);
468  dev_interface->mainTLB->invalidateVMID(cmd.dw0.vmid);
469  }
470  tlb.invalidateVMID(cmd.dw0.vmid);
471  walkCache.invalidateVMID(cmd.dw0.vmid);
472  break;
473  }
474 
475  case CMD_TLBI_NH_ASID: {
476  DPRINTF(SMMUv3, "CMD_TLBI_NH_ASID asid=%#x vmid=%#x\n",
477  cmd.dw0.asid, cmd.dw0.vmid);
478  for (auto dev_interface : deviceInterfaces) {
479  dev_interface->microTLB->invalidateASID(
480  cmd.dw0.asid, cmd.dw0.vmid);
481  dev_interface->mainTLB->invalidateASID(
482  cmd.dw0.asid, cmd.dw0.vmid);
483  }
484  tlb.invalidateASID(cmd.dw0.asid, cmd.dw0.vmid);
485  walkCache.invalidateASID(cmd.dw0.asid, cmd.dw0.vmid);
486  break;
487  }
488 
489  case CMD_TLBI_NH_VAA: {
490  const Addr addr = cmd.addr();
491  DPRINTF(SMMUv3, "CMD_TLBI_NH_VAA va=%#08x vmid=%#x\n",
492  addr, cmd.dw0.vmid);
493  for (auto dev_interface : deviceInterfaces) {
494  dev_interface->microTLB->invalidateVAA(
495  addr, cmd.dw0.vmid);
496  dev_interface->mainTLB->invalidateVAA(
497  addr, cmd.dw0.vmid);
498  }
499  tlb.invalidateVAA(addr, cmd.dw0.vmid);
500  const bool leaf_only = cmd.dw1.leaf ? true : false;
501  walkCache.invalidateVAA(addr, cmd.dw0.vmid, leaf_only);
502  break;
503  }
504 
505  case CMD_TLBI_NH_VA: {
506  const Addr addr = cmd.addr();
507  DPRINTF(SMMUv3, "CMD_TLBI_NH_VA va=%#08x asid=%#x vmid=%#x\n",
508  addr, cmd.dw0.asid, cmd.dw0.vmid);
509  for (auto dev_interface : deviceInterfaces) {
510  dev_interface->microTLB->invalidateVA(
511  addr, cmd.dw0.asid, cmd.dw0.vmid);
512  dev_interface->mainTLB->invalidateVA(
513  addr, cmd.dw0.asid, cmd.dw0.vmid);
514  }
515  tlb.invalidateVA(addr, cmd.dw0.asid, cmd.dw0.vmid);
516  const bool leaf_only = cmd.dw1.leaf ? true : false;
517  walkCache.invalidateVA(addr, cmd.dw0.asid, cmd.dw0.vmid,
518  leaf_only);
519  break;
520  }
521 
522  case CMD_TLBI_S2_IPA: {
523  const Addr addr = cmd.addr();
524  DPRINTF(SMMUv3, "CMD_TLBI_S2_IPA ipa=%#08x vmid=%#x\n",
525  addr, cmd.dw0.vmid);
526  // This does not invalidate TLBs containing
527  // combined Stage1 + Stage2 translations, as per the spec.
528  ipaCache.invalidateIPA(addr, cmd.dw0.vmid);
529 
530  if (!cmd.dw1.leaf)
531  walkCache.invalidateVMID(cmd.dw0.vmid);
532  break;
533  }
534 
535  case CMD_TLBI_S12_VMALL: {
536  DPRINTF(SMMUv3, "CMD_TLBI_S12_VMALL vmid=%#x\n", cmd.dw0.vmid);
537  for (auto dev_interface : deviceInterfaces) {
538  dev_interface->microTLB->invalidateVMID(cmd.dw0.vmid);
539  dev_interface->mainTLB->invalidateVMID(cmd.dw0.vmid);
540  }
541  tlb.invalidateVMID(cmd.dw0.vmid);
542  ipaCache.invalidateVMID(cmd.dw0.vmid);
543  walkCache.invalidateVMID(cmd.dw0.vmid);
544  break;
545  }
546 
547  case CMD_TLBI_NSNH_ALL: {
548  DPRINTF(SMMUv3, "CMD_TLBI_NSNH_ALL\n");
549  for (auto dev_interface : deviceInterfaces) {
550  dev_interface->microTLB->invalidateAll();
551  dev_interface->mainTLB->invalidateAll();
552  }
553  tlb.invalidateAll();
556  break;
557  }
558 
559  case CMD_RESUME:
560  DPRINTF(SMMUv3, "CMD_RESUME\n");
561  panic("resume unimplemented");
562  break;
563 
564  default:
565  warn("Unimplemented command %#x\n", cmd.dw0.type);
566  break;
567  }
568 }
569 
570 Tick
572 {
573  DPRINTF(SMMUv3, "readControl: addr=%08x size=%d\n",
574  pkt->getAddr(), pkt->getSize());
575 
576  int offset = pkt->getAddr() - regsMap.start();
577  assert(offset >= 0 && offset < SMMU_REG_SIZE);
578 
579  if (inSecureBlock(offset)) {
580  warn("smmu: secure registers (0x%x) are not implemented\n",
581  offset);
582  }
583 
584  auto reg_ptr = regs.data + offset;
585 
586  switch (pkt->getSize()) {
587  case sizeof(uint32_t):
588  pkt->setLE<uint32_t>(*reinterpret_cast<uint32_t *>(reg_ptr));
589  break;
590  case sizeof(uint64_t):
591  pkt->setLE<uint64_t>(*reinterpret_cast<uint64_t *>(reg_ptr));
592  break;
593  default:
594  panic("smmu: unallowed access size: %d bytes\n", pkt->getSize());
595  break;
596  }
597 
598  pkt->makeAtomicResponse();
599 
600  return 0;
601 }
602 
603 Tick
605 {
606  int offset = pkt->getAddr() - regsMap.start();
607  assert(offset >= 0 && offset < SMMU_REG_SIZE);
608 
609  DPRINTF(SMMUv3, "writeControl: addr=%08x size=%d data=%16x\n",
610  pkt->getAddr(), pkt->getSize(),
611  pkt->getSize() == sizeof(uint64_t) ?
612  pkt->getLE<uint64_t>() : pkt->getLE<uint32_t>());
613 
614  switch (offset) {
615  case offsetof(SMMURegs, cr0):
616  assert(pkt->getSize() == sizeof(uint32_t));
617  regs.cr0 = regs.cr0ack = pkt->getLE<uint32_t>();
618  break;
619  case offsetof(SMMURegs, irq_ctrl):
620  assert(pkt->getSize() == sizeof(uint32_t));
621  if (irqInterfaceEnable) {
622  warn("SMMUv3::%s No support for interrupt sources", __func__);
623  regs.irq_ctrl = regs.irq_ctrlack = pkt->getLE<uint32_t>();
624  }
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 
705 bool
706 SMMUv3::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 
714 void
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
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())
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"),
741  ADD_STAT(translationTimeDist, statistics::units::Tick::get(),
742  "Time to translate address"),
743  ADD_STAT(ptwTimeDist, statistics::units::Tick::get(),
744  "Time to walk page tables")
745 {
746  using namespace statistics;
747 
749  .flags(pdf);
750 
751  steFetches
752  .flags(pdf);
753 
755  .flags(pdf);
756 
757  cdFetches
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()) {
774  return DrainState::Draining;
775  }
776  return DrainState::Drained;
777 }
778 
779 void
781 {
782  DPRINTF(Checkpoint, "Serializing SMMUv3\n");
783 
784  SERIALIZE_ARRAY(regs.data, sizeof(regs.data) / sizeof(regs.data[0]));
785 }
786 
787 void
789 {
790  DPRINTF(Checkpoint, "Unserializing SMMUv3\n");
791 
792  UNSERIALIZE_ARRAY(regs.data, sizeof(regs.data) / sizeof(regs.data[0]));
793 }
794 
795 Port&
796 SMMUv3::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:186
Defines global host-dependent types: Counter, Tick, and (indirectly) {int,uint}{8,...
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
Definition: named.hh:47
A Packet is used to encapsulate a transfer between two objects in the memory system (e....
Definition: packet.hh:294
Addr getAddr() const
Definition: packet.hh:805
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:448
uint32_t headerDelay
The extra delay from seeing the packet until the header is transmitted.
Definition: packet.hh:430
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:815
void makeAtomicResponse()
Definition: packet.hh:1071
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
bool isConnected() const
Is this port currently connected to a peer?
Definition: port.hh:133
Tick sendAtomic(PacketPtr pkt)
Send an atomic request packet, where the data is moved and the state is updated in zero time,...
Definition: port.hh:464
bool sendTimingReq(PacketPtr pkt)
Attempt to send a timing request to the responder port by calling its corresponding receive function.
Definition: port.hh:495
void sendRangeChange() const
Called by the owner to send a range change.
Definition: port.hh:296
SMMUAction run(PacketPtr pkt)
void schedAtsTimingResp(PacketPtr pkt)
void schedTimingResp(PacketPtr pkt)
const System & system
Definition: smmu_v3.hh:93
SMMUCommandExecProcess commandExecutor
Definition: smmu_v3.hh:152
const AddrRange regsMap
Definition: smmu_v3.hh:154
Tick readControl(PacketPtr pkt)
Definition: smmu_v3.cc:571
const bool irqInterfaceEnable
Definition: smmu_v3.hh:100
void recvReqRetry()
Definition: smmu_v3.cc:150
void serialize(CheckpointOut &cp) const override
Serialize an object.
Definition: smmu_v3.cc:780
SMMUAction runProcess(SMMUProcess *proc, PacketPtr pkt)
Definition: smmu_v3.cc:225
std::vector< SMMUv3DeviceInterface * > deviceInterfaces
Definition: smmu_v3.hh:150
void unserialize(CheckpointIn &cp) override
Unserialize an object.
Definition: smmu_v3.cc:788
ARMArchTLB tlb
Definition: smmu_v3.hh:102
ConfigCache configCache
Definition: smmu_v3.hh:103
SMMUControlPort controlPort
Definition: smmu_v3.hh:98
SMMUTableWalkPort tableWalkPort
Definition: smmu_v3.hh:97
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:105
SMMUAction runProcessAtomic(SMMUProcess *proc, PacketPtr pkt)
Definition: smmu_v3.cc:237
bool recvTimingResp(PacketPtr pkt)
Definition: smmu_v3.cc:133
bool inSecureBlock(uint32_t offs) const
Definition: smmu_v3.cc:706
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:604
SMMURequestPort requestPort
Definition: smmu_v3.hh:96
void scheduleDeviceRetries()
Definition: smmu_v3.cc:217
std::queue< SMMUAction > packetsTableWalkToRetry
Definition: smmu_v3.hh:160
DrainState drain() override
Draining is the process of clearing out the states of SimObjects.These are the SimObjects that are pa...
Definition: smmu_v3.cc:770
IPACache ipaCache
Definition: smmu_v3.hh:104
bool tableWalkPortEnable
Definition: smmu_v3.hh:111
EventWrapper< SMMUv3, &SMMUv3::processCommands > processCommandsEvent
Definition: smmu_v3.hh:170
std::queue< SMMUAction > packetsToRetry
Definition: smmu_v3.hh:159
void processCommand(const SMMUCommand &cmd)
Definition: smmu_v3.cc:389
void tableWalkRecvReqRetry()
Definition: smmu_v3.cc:196
SMMURegs regs
Definition: smmu_v3.hh:155
SMMUv3(const SMMUv3Params &p)
Definition: smmu_v3.cc:58
void processCommands()
Definition: smmu_v3.cc:373
SMMUAction runProcessTiming(SMMUProcess *proc, PacketPtr pkt)
Definition: smmu_v3.cc:286
bool tableWalkRecvTimingResp(PacketPtr pkt)
Definition: smmu_v3.cc:179
bool isAtomicMode() const
Is the system in atomic mode?
Definition: system.hh:261
bool isTimingMode() const
Is the system in timing mode?
Definition: system.hh:273
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.
Definition: statistics.hh:358
Distribution & init(Counter min, Counter max, Counter bkt)
Set the parameters of this distribution.
Definition: statistics.hh:2113
Statistics container.
Definition: group.hh:94
#define ADD_STAT(n,...)
Convenience macro to add a stat to a statistics group.
Definition: group.hh:75
Addr start() const
Get the start address of the range.
Definition: addr_range.hh:343
DrainState
Object drain/handover states.
Definition: drain.hh:75
@ Draining
Draining buffers pending serialization/handover.
@ Drained
Buffers drained, ready for serialization/handover.
void schedule(Event &event, Tick when)
Definition: eventq.hh:1019
#define panic(...)
This implements a cprintf based panic() function.
Definition: logging.hh:178
#define fatal_if(cond,...)
Conditional fatal macro that checks the supplied condition and only causes a fatal error if the condi...
Definition: logging.hh:226
#define fatal(...)
This implements a cprintf based fatal() function.
Definition: logging.hh:190
#define UNSERIALIZE_ARRAY(member, size)
Definition: serialize.hh:618
#define SERIALIZE_ARRAY(member, size)
Definition: serialize.hh:610
const Params & params() const
Definition: sim_object.hh:176
virtual Port & getPort(const std::string &if_name, PortID idx=InvalidPortID)
Get a port with a given name and index.
Definition: sim_object.cc:126
#define warn(...)
Definition: logging.hh:246
Bitfield< 23, 0 > offset
Definition: types.hh:144
Bitfield< 8 > a
Definition: misc_types.hh:66
Bitfield< 59, 56 > tlb
Definition: misc_types.hh:92
Bitfield< 15 > system
Definition: misc.hh:1004
Bitfield< 3 > addr
Definition: types.hh:84
const FlagsType pdf
Print the percent of the total that this entry represents.
Definition: info.hh:62
Reference material can be found at the JEDEC website: UFS standard http://www.jedec....
@ SMMU_SECURE_SZ
Definition: smmu_v3_defs.hh:50
@ SMMU_REG_SIZE
Definition: smmu_v3_defs.hh:53
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_RESUME
@ 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
@ CR0_CMDQEN_MASK
@ ACTION_SEND_RESP
Definition: smmu_v3_proc.hh:63
@ ACTION_DELAY
Definition: smmu_v3_proc.hh:65
@ ACTION_SLEEP
Definition: smmu_v3_proc.hh:66
@ ACTION_TERMINATE
Definition: smmu_v3_proc.hh:67
@ ACTION_SEND_REQ
Definition: smmu_v3_proc.hh:61
@ ACTION_SEND_RESP_ATS
Definition: smmu_v3_proc.hh:64
@ ACTION_SEND_REQ_FINAL
Definition: smmu_v3_proc.hh:62
This is an implementation of the SMMUv3 architecture.
SMMUActionType type
Definition: smmu_v3_proc.hh:72
SMMUv3DeviceInterface * ifc
Definition: smmu_v3_proc.hh:74
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:147
statistics::Scalar cdL1Fetches
Definition: smmu_v3.hh:144
statistics::Scalar steL1Fetches
Definition: smmu_v3.hh:142
statistics::Scalar steFetches
Definition: smmu_v3.hh:143
statistics::Distribution translationTimeDist
Definition: smmu_v3.hh:146
statistics::Scalar cdFetches
Definition: smmu_v3.hh:145
const std::string & name()
Definition: trace.cc:49
uint8_t data[SMMU_REG_SIZE]
uint32_t cmdq_prod
uint32_t eventq_prod
uint32_t irq_ctrl
uint32_t irq_ctrlack
uint32_t cmdq_cons
uint32_t priq_cons
uint32_t eventq_cons
uint32_t priq_prod

Generated on Wed Dec 21 2022 10:22:33 for gem5 by doxygen 1.9.1