gem5  v22.1.0.0
gic_v3_distributor.cc
Go to the documentation of this file.
1 /*
2  * Copyright (c) 2019-2022 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  * Copyright (c) 2018 Metempsy Technology Consulting
15  * All rights reserved.
16  *
17  * Redistribution and use in source and binary forms, with or without
18  * modification, are permitted provided that the following conditions are
19  * met: redistributions of source code must retain the above copyright
20  * notice, this list of conditions and the following disclaimer;
21  * redistributions in binary form must reproduce the above copyright
22  * notice, this list of conditions and the following disclaimer in the
23  * documentation and/or other materials provided with the distribution;
24  * neither the name of the copyright holders nor the names of its
25  * contributors may be used to endorse or promote products derived from
26  * this software without specific prior written permission.
27  *
28  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
29  * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
30  * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
31  * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
32  * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
33  * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
34  * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
35  * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
36  * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
37  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
38  * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
39  */
40 
42 
43 #include <algorithm>
44 
45 #include "base/compiler.hh"
46 #include "base/intmath.hh"
47 #include "debug/GIC.hh"
48 #include "dev/arm/gic_v3.hh"
51 
52 namespace gem5
53 {
54 
55 const AddrRange Gicv3Distributor::GICD_IGROUPR (0x0080, 0x0100);
56 const AddrRange Gicv3Distributor::GICD_ISENABLER (0x0100, 0x0180);
57 const AddrRange Gicv3Distributor::GICD_ICENABLER (0x0180, 0x0200);
58 const AddrRange Gicv3Distributor::GICD_ISPENDR (0x0200, 0x0280);
59 const AddrRange Gicv3Distributor::GICD_ICPENDR (0x0280, 0x0300);
60 const AddrRange Gicv3Distributor::GICD_ISACTIVER (0x0300, 0x0380);
61 const AddrRange Gicv3Distributor::GICD_ICACTIVER (0x0380, 0x0400);
62 const AddrRange Gicv3Distributor::GICD_IPRIORITYR(0x0400, 0x0800);
63 const AddrRange Gicv3Distributor::GICD_ITARGETSR (0x0800, 0x0c00);
64 const AddrRange Gicv3Distributor::GICD_ICFGR (0x0c00, 0x0d00);
65 const AddrRange Gicv3Distributor::GICD_IGRPMODR (0x0d00, 0x0d80);
66 const AddrRange Gicv3Distributor::GICD_NSACR (0x0e00, 0x0f00);
67 const AddrRange Gicv3Distributor::GICD_CPENDSGIR (0x0f10, 0x0f20);
68 const AddrRange Gicv3Distributor::GICD_SPENDSGIR (0x0f20, 0x0f30);
69 const AddrRange Gicv3Distributor::GICD_IROUTER (0x6000, 0x7fe0);
70 
72  : gic(gic),
73  itLines(it_lines),
74  ARE(true),
75  EnableGrp1S(0),
76  EnableGrp1NS(0),
77  EnableGrp0(0),
78  irqGroup(it_lines, 0),
79  irqEnabled(it_lines, false),
80  irqPending(it_lines, false),
81  irqPendingIspendr(it_lines, false),
82  irqActive(it_lines, false),
83  irqPriority(it_lines, 0xAA),
84  irqConfig(it_lines, Gicv3::INT_LEVEL_SENSITIVE),
85  irqGrpmod(it_lines, 0),
86  irqNsacr(it_lines, 0),
87  irqAffinityRouting(it_lines, 0),
88  gicdTyper(0),
89  gicdPidr0(0x92),
90  gicdPidr1(0xb4),
91  gicdPidr2(gic->params().gicv4 ? 0x4b : 0x3b),
92  gicdPidr3(0),
93  gicdPidr4(0x44)
94 {
95  panic_if(it_lines > Gicv3::INTID_SECURE, "Invalid value for it_lines!");
96  /*
97  * RSS [26] == 1
98  * (The implementation does supports targeted SGIs with affinity
99  * level 0 values of 0 - 255)
100  * No1N [25] == 1
101  * (1 of N SPI interrupts are not supported)
102  * A3V [24] == 1
103  * (Supports nonzero values of Affinity level 3)
104  * IDbits [23:19] == 0xf
105  * (The number of interrupt identifier bits supported, minus one)
106  * DVIS [18] == 0
107  * (The implementation does not support Direct Virtual LPI
108  * injection)
109  * LPIS [17] == 1
110  * (The implementation does not support LPIs)
111  * MBIS [16] == 1
112  * (The implementation supports message-based interrupts
113  * by writing to Distributor registers)
114  * SecurityExtn [10] == X
115  * (The GIC implementation supports two Security states)
116  * CPUNumber [7:5] == 0
117  * (since for us ARE is always 1 [(ARE = 0) == Gicv2 legacy])
118  * ITLinesNumber [4:0] == N
119  * (MaxSPIIntId = 32 (N + 1) - 1)
120  */
121  bool have_security = gic->getSystem()->has(ArmExtension::SECURITY);
122  int max_spi_int_id = itLines - 1;
123  int it_lines_number = divCeil(max_spi_int_id + 1, 32) - 1;
124  gicdTyper = (1 << 26) | (1 << 25) | (1 << 24) | (IDBITS << 19) |
125  (1 << 17) | (1 << 16) |
126  ((have_security ? 1 : 0) << 10) |
127  (it_lines_number << 0);
128 
129  if (have_security) {
130  DS = false;
131  } else {
132  DS = true;
133  }
134 }
135 
136 void
138 {
139 }
140 
141 uint64_t
142 Gicv3Distributor::read(Addr addr, size_t size, bool is_secure_access)
143 {
144  if (GICD_IGROUPR.contains(addr)) { // Interrupt Group Registers
145  uint64_t val = 0x0;
146 
147  if (!DS && !is_secure_access) {
148  // RAZ/WI for non-secure accesses
149  return 0;
150  }
151 
152  int first_intid = (addr - GICD_IGROUPR.start()) * 8;
153 
154  if (isNotSPI(first_intid)) {
155  return 0;
156  }
157 
158  for (int i = 0, int_id = first_intid; i < 8 * size && int_id < itLines;
159  i++, int_id++) {
160  val |= irqGroup[int_id] << i;
161  }
162 
163  return val;
164  } else if (GICD_ISENABLER.contains(addr)) {
165  // Interrupt Set-Enable Registers
166  uint64_t val = 0x0;
167  int first_intid = (addr - GICD_ISENABLER.start()) * 8;
168 
169  if (isNotSPI(first_intid)) {
170  return 0;
171  }
172 
173  for (int i = 0, int_id = first_intid; i < 8 * size && int_id < itLines;
174  i++, int_id++) {
175 
176  if (nsAccessToSecInt(int_id, is_secure_access))
177  {
178  continue;
179  }
180 
181  val |= irqEnabled[int_id] << i;
182  }
183 
184  return val;
185  } else if (GICD_ICENABLER.contains(addr)) {
186  // Interrupt Clear-Enable Registers
187  uint64_t val = 0x0;
188  int first_intid = (addr - GICD_ICENABLER.start()) * 8;
189 
190  if (isNotSPI(first_intid)) {
191  return 0;
192  }
193 
194  for (int i = 0, int_id = first_intid; i < 8 * size && int_id < itLines;
195  i++, int_id++) {
196 
197  if (nsAccessToSecInt(int_id, is_secure_access))
198  {
199  continue;
200  }
201 
202  val |= (irqEnabled[int_id] << i);
203  }
204 
205  return val;
206  } else if (GICD_ISPENDR.contains(addr)) {
207  // Interrupt Set-Pending Registers
208  uint64_t val = 0x0;
209  int first_intid = (addr - GICD_ISPENDR.start()) * 8;
210 
211  if (isNotSPI(first_intid)) {
212  return 0;
213  }
214 
215  for (int i = 0, int_id = first_intid; i < 8 * size && int_id < itLines;
216  i++, int_id++) {
217 
218  if (nsAccessToSecInt(int_id, is_secure_access))
219  {
220  if (irqNsacr[int_id] == 0) {
221  // Group 0 or Secure Group 1 interrupts are RAZ/WI
222  continue;
223  }
224  }
225 
226  val |= (irqPending[int_id] << i);
227  }
228 
229  return val;
230  } else if (GICD_ICPENDR.contains(addr)) {
231  // Interrupt Clear-Pending Registers
232  uint64_t val = 0x0;
233  int first_intid = (addr - GICD_ICPENDR.start()) * 8;
234 
235  if (isNotSPI(first_intid)) {
236  return 0;
237  }
238 
239  for (int i = 0, int_id = first_intid; i < 8 * size && int_id < itLines;
240  i++, int_id++) {
241 
242  if (nsAccessToSecInt(int_id, is_secure_access))
243  {
244  if (irqNsacr[int_id] < 2) {
245  // Group 0 or Secure Group 1 interrupts are RAZ/WI
246  continue;
247  }
248  }
249 
250  val |= (irqPending[int_id] << i);
251  }
252 
253  return val;
254  } else if (GICD_ISACTIVER.contains(addr)) {
255  // Interrupt Set-Active Registers
256  int first_intid = (addr - GICD_ISACTIVER.start()) * 8;
257 
258  if (isNotSPI(first_intid)) {
259  return 0;
260  }
261 
262  uint64_t val = 0x0;
263 
264  for (int i = 0, int_id = first_intid; i < 8 * size && int_id < itLines;
265  i++, int_id++) {
266 
267  if (nsAccessToSecInt(int_id, is_secure_access))
268  {
269  // Group 0 or Secure Group 1 interrupts are RAZ/WI
270  if (irqNsacr[int_id] < 2) {
271  continue;
272  }
273  }
274 
275  val |= (irqActive[int_id] << i);
276  }
277 
278  return val;
279  } else if (GICD_ICACTIVER.contains(addr)) {
280  // Interrupt Clear-Active Registers
281  int first_intid = (addr - GICD_ICACTIVER.start()) * 8;
282 
283  if (isNotSPI(first_intid)) {
284  return 0;
285  }
286 
287  uint64_t val = 0x0;
288 
289  for (int i = 0, int_id = first_intid; i < 8 * size && int_id < itLines;
290  i++, int_id++) {
291 
292  if (nsAccessToSecInt(int_id, is_secure_access))
293  {
294  if (irqNsacr[int_id] < 2) {
295  continue;
296  }
297  }
298 
299  val |= (irqActive[int_id] << i);
300  }
301 
302  return val;
303  } else if (GICD_IPRIORITYR.contains(addr)) {
304  // Interrupt Priority Registers
305  uint64_t val = 0x0;
306  int first_intid = addr - GICD_IPRIORITYR.start();
307 
308  if (isNotSPI(first_intid)) {
309  return 0;
310  }
311 
312  for (int i = 0, int_id = first_intid; i < size && int_id < itLines;
313  i++, int_id++) {
314 
315  uint8_t prio = irqPriority[int_id];
316 
317  if (!DS && !is_secure_access) {
318  if (getIntGroup(int_id) != Gicv3::G1NS) {
319  // RAZ/WI for non-secure accesses for secure interrupts
320  continue;
321  } else {
322  // NS view
323  prio = (prio << 1) & 0xff;
324  }
325  }
326 
327  val |= prio << (i * 8);
328  }
329 
330  return val;
331  } else if (GICD_ITARGETSR.contains(addr)) {
332  // Interrupt Processor Targets Registers
333  // ARE always on, RAZ/WI
334  warn("Gicv3Distributor::read(): "
335  "GICD_ITARGETSR is RAZ/WI, legacy not supported!\n");
336  return 0;
337  } else if (GICD_ICFGR.contains(addr)) {
338  // Interrupt Configuration Registers
339  int first_intid = (addr - GICD_ICFGR.start()) * 4;
340 
341  if (isNotSPI(first_intid)) {
342  return 0;
343  }
344 
345  uint64_t val = 0x0;
346 
347  for (int i = 0, int_id = first_intid; i < 8 * size && int_id < itLines;
348  i = i + 2, int_id++) {
349 
350  if (nsAccessToSecInt(int_id, is_secure_access))
351  {
352  continue;
353  }
354 
355  if (irqConfig[int_id] == Gicv3::INT_EDGE_TRIGGERED) {
356  val |= (0x2 << i);
357  }
358  }
359 
360  return val;
361  } else if (GICD_IGRPMODR.contains(addr)) {
362  // Interrupt Group Modifier Registers
363  if (DS) {
364  // RAZ/WI if security disabled
365  return 0;
366  } else {
367  if (!is_secure_access) {
368  // RAZ/WI for non-secure accesses
369  return 0;
370  } else {
371  int first_intid = (addr - GICD_IGRPMODR.start()) * 8;
372 
373  if (isNotSPI(first_intid)) {
374  return 0;
375  }
376 
377  uint64_t val = 0x0;
378 
379  for (int i = 0, int_id = first_intid;
380  i < 8 * size && int_id < itLines; i++, int_id++) {
381  val |= irqGrpmod[int_id] << i;
382  }
383 
384  return val;
385  }
386  }
387  } else if (GICD_NSACR.contains(addr)) {
388  // Non-secure Access Control Registers
389  // 2 bits per interrupt
390  int first_intid = (addr - GICD_NSACR.start()) * 4;
391 
392  if (isNotSPI(first_intid)) {
393  return 0;
394  }
395 
396  if (DS || (!DS && !is_secure_access)) {
397  return 0;
398  }
399 
400  uint64_t val = 0x0;
401 
402  for (int i = 0, int_id = first_intid;
403  i < 8 * size && int_id < itLines; i = i + 2, int_id++) {
404  val |= irqNsacr[int_id] << i;
405  }
406 
407  return val;
408  } else if (GICD_CPENDSGIR.contains(addr)) { // SGI Clear-Pending Registers
409  // ARE always on, RAZ/WI
410  warn("Gicv3Distributor::read(): "
411  "GICD_CPENDSGIR is RAZ/WI, legacy not supported!\n");
412  return 0x0;
413  } else if (GICD_SPENDSGIR.contains(addr)) { // SGI Set-Pending Registers
414  // ARE always on, RAZ/WI
415  warn("Gicv3Distributor::read(): "
416  "GICD_SPENDSGIR is RAZ/WI, legacy not supported!\n");
417  return 0x0;
418  } else if (GICD_IROUTER.contains(addr)) { // Interrupt Routing Registers
419  // 64 bit registers. 2 or 1 access.
420  int int_id = (addr - GICD_IROUTER.start()) / 8;
421 
422  if (isNotSPI(int_id)) {
423  return 0;
424  }
425 
426  if (nsAccessToSecInt(int_id, is_secure_access))
427  {
428  if (irqNsacr[int_id] < 3) {
429  return 0;
430  }
431  }
432 
433  if (size == 4) {
434  if (addr & 7) { // high half of 64 bit register
435  return irqAffinityRouting[int_id] >> 32;
436  } else { // high low of 64 bit register
437  return irqAffinityRouting[int_id] & 0xFFFFFFFF;
438  }
439  } else {
440  return irqAffinityRouting[int_id];
441  }
442  }
443 
444  switch (addr) {
445  case GICD_CTLR: // Control Register
446  if (!DS) {
447  if (is_secure_access) {
448  // E1NWF [7] RAZ/WI
449  // DS [6] - Disable Security
450  // ARE_NS [5] RAO/WI
451  // ARE_S [4] RAO/WI
452  // EnableGrp1S [2]
453  // EnableGrp1NS [1]
454  // EnableGrp0 [0]
455  return (EnableGrp0 << 0) |
456  (EnableGrp1NS << 1) |
457  (EnableGrp1S << 2) |
458  (1 << 4) |
459  (1 << 5) |
460  (DS << 6);
461  } else {
462  // ARE_NS [4] RAO/WI;
463  // EnableGrp1A [1] is a read-write alias of the Secure
464  // GICD_CTLR.EnableGrp1NS
465  // EnableGrp1 [0] RES0
466  return (1 << 4) | (EnableGrp1NS << 1);
467  }
468  } else {
469  return (DS << 6) | (ARE << 4) |
470  (EnableGrp1NS << 1) | (EnableGrp0 << 0);
471  }
472 
473  case GICD_TYPER: // Interrupt Controller Type Register
474  return gicdTyper;
475 
476  case GICD_IIDR: // Implementer Identification Register
477  //return 0x43b; // ARM JEP106 code (r0p0 GIC-500)
478  return 0;
479 
480  case GICD_TYPER2: // Interrupt Controller Type Register 2
481  return 0; // RES0
482 
483  case GICD_STATUSR: // Error Reporting Status Register
484  // Optional register, RAZ/WI
485  return 0x0;
486 
487  case GICD_PIDR0: // Peripheral ID0 Register
488  return gicdPidr0;
489 
490  case GICD_PIDR1: // Peripheral ID1 Register
491  return gicdPidr1;
492 
493  case GICD_PIDR2: // Peripheral ID2 Register
494  return gicdPidr2;
495 
496  case GICD_PIDR3: // Peripheral ID3 Register
497  return gicdPidr3;
498 
499  case GICD_PIDR4: // Peripheral ID4 Register
500  return gicdPidr4;
501 
502  case GICD_PIDR5: // Peripheral ID5 Register
503  case GICD_PIDR6: // Peripheral ID6 Register
504  case GICD_PIDR7: // Peripheral ID7 Register
505  return 0; // RES0
506 
507  default:
508  panic("Gicv3Distributor::read(): invalid offset %#x\n", addr);
509  break;
510  }
511 }
512 
513 void
514 Gicv3Distributor::write(Addr addr, uint64_t data, size_t size,
515  bool is_secure_access)
516 {
517  if (GICD_IGROUPR.contains(addr)) { // Interrupt Group Registers
518  if (!DS && !is_secure_access) {
519  // RAZ/WI for non-secure accesses
520  return;
521  }
522 
523  int first_intid = (addr - GICD_IGROUPR.start()) * 8;
524 
525  if (isNotSPI(first_intid)) {
526  return;
527  }
528 
529  for (int i = 0, int_id = first_intid; i < 8 * size && int_id < itLines;
530  i++, int_id++) {
531  irqGroup[int_id] = data & (1 << i) ? 1 : 0;
532  DPRINTF(GIC, "Gicv3Distributor::write(): int_id %d group %d\n",
533  int_id, irqGroup[int_id]);
534  }
535 
536  return;
537  } else if (GICD_ISENABLER.contains(addr)) {
538  // Interrupt Set-Enable Registers
539  int first_intid = (addr - GICD_ISENABLER.start()) * 8;
540 
541  if (isNotSPI(first_intid)) {
542  return;
543  }
544 
545  for (int i = 0, int_id = first_intid; i < 8 * size && int_id < itLines;
546  i++, int_id++) {
547 
548  if (nsAccessToSecInt(int_id, is_secure_access))
549  {
550  continue;
551  }
552 
553  bool enable = data & (1 << i) ? 1 : 0;
554 
555  if (enable) {
556  if (!irqEnabled[int_id]) {
557  DPRINTF(GIC, "Gicv3Distributor::write(): "
558  "int_id %d enabled\n", int_id);
559  }
560 
561  irqEnabled[int_id] = true;
562  }
563  }
564 
565  return;
566  } else if (GICD_ICENABLER.contains(addr)) {
567  // Interrupt Clear-Enable Registers
568  int first_intid = (addr - GICD_ICENABLER.start()) * 8;
569 
570  if (isNotSPI(first_intid)) {
571  return;
572  }
573 
574  for (int i = 0, int_id = first_intid; i < 8 * size && int_id < itLines;
575  i++, int_id++) {
576 
577  if (nsAccessToSecInt(int_id, is_secure_access))
578  {
579  continue;
580  }
581 
582  bool disable = data & (1 << i) ? 1 : 0;
583 
584  if (disable) {
585  if (irqEnabled[int_id]) {
586  DPRINTF(GIC, "Gicv3Distributor::write(): "
587  "int_id %d disabled\n", int_id);
588  }
589 
590  irqEnabled[int_id] = false;
591  }
592  }
593 
594  return;
595  } else if (GICD_ISPENDR.contains(addr)) {
596  // Interrupt Set-Pending Registers
597  int first_intid = (addr - GICD_ISPENDR.start()) * 8;
598 
599  if (isNotSPI(first_intid)) {
600  return;
601  }
602 
603  for (int i = 0, int_id = first_intid; i < 8 * size && int_id < itLines;
604  i++, int_id++) {
605 
606  if (nsAccessToSecInt(int_id, is_secure_access))
607  {
608  if (irqNsacr[int_id] == 0) {
609  // Group 0 or Secure Group 1 interrupts are RAZ/WI
610  continue;
611  }
612  }
613 
614  bool pending = data & (1 << i) ? 1 : 0;
615 
616  if (pending) {
617  DPRINTF(GIC, "Gicv3Distributor::write() (GICD_ISPENDR): "
618  "int_id %d (SPI) pending bit set\n", int_id);
619  irqPending[int_id] = true;
620  irqPendingIspendr[int_id] = true;
621  }
622  }
623 
624  update();
625  return;
626  } else if (GICD_ICPENDR.contains(addr)) {
627  // Interrupt Clear-Pending Registers
628  int first_intid = (addr - GICD_ICPENDR.start()) * 8;
629 
630  if (isNotSPI(first_intid)) {
631  return;
632  }
633 
634  for (int i = 0, int_id = first_intid; i < 8 * size && int_id < itLines;
635  i++, int_id++) {
636 
637  if (nsAccessToSecInt(int_id, is_secure_access))
638  {
639  if (irqNsacr[int_id] < 2) {
640  // Group 0 or Secure Group 1 interrupts are RAZ/WI
641  continue;
642  }
643  }
644 
645  bool clear = data & (1 << i) ? 1 : 0;
646 
647  if (clear && treatAsEdgeTriggered(int_id)) {
648  irqPending[int_id] = false;
649  clearIrqCpuInterface(int_id);
650  }
651  }
652 
653  update();
654  return;
655  } else if (GICD_ISACTIVER.contains(addr)) {
656  // Interrupt Set-Active Registers
657  int first_intid = (addr - GICD_ISACTIVER.start()) * 8;
658 
659  if (isNotSPI(first_intid)) {
660  return;
661  }
662 
663  for (int i = 0, int_id = first_intid; i < 8 * size && int_id < itLines;
664  i++, int_id++) {
665 
666  if (nsAccessToSecInt(int_id, is_secure_access))
667  {
668  continue;
669  }
670 
671  bool active = data & (1 << i) ? 1 : 0;
672 
673  if (active) {
674  irqActive[int_id] = 1;
675  }
676  }
677 
678  return;
679  } else if (GICD_ICACTIVER.contains(addr)) {
680  // Interrupt Clear-Active Registers
681  int first_intid = (addr - GICD_ICACTIVER.start()) * 8;
682 
683  if (isNotSPI(first_intid)) {
684  return;
685  }
686 
687  for (int i = 0, int_id = first_intid; i < 8 * size && int_id < itLines;
688  i++, int_id++) {
689 
690  if (nsAccessToSecInt(int_id, is_secure_access))
691  {
692  continue;
693  }
694 
695  bool clear = data & (1 << i) ? 1 : 0;
696 
697  if (clear) {
698  if (irqActive[int_id]) {
699  DPRINTF(GIC, "Gicv3Distributor::write(): "
700  "int_id %d active cleared\n", int_id);
701  }
702 
703  irqActive[int_id] = false;
704  }
705  }
706 
707  return;
708  } else if (GICD_IPRIORITYR.contains(addr)) {
709  // Interrupt Priority Registers
710  int first_intid = addr - GICD_IPRIORITYR.start();
711 
712  if (isNotSPI(first_intid)) {
713  return;
714  }
715 
716  for (int i = 0, int_id = first_intid; i < size && int_id < itLines;
717  i++, int_id++) {
718  uint8_t prio = bits(data, (i + 1) * 8 - 1, (i * 8));
719 
720  if (!DS && !is_secure_access) {
721  if (getIntGroup(int_id) != Gicv3::G1NS) {
722  // RAZ/WI for non-secure accesses to secure interrupts
723  continue;
724  } else {
725  prio = 0x80 | (prio >> 1);
726  }
727  }
728 
729  irqPriority[int_id] = prio;
730  DPRINTF(GIC, "Gicv3Distributor::write(): int_id %d priority %d\n",
731  int_id, irqPriority[int_id]);
732  }
733 
734  return;
735  } else if (GICD_ITARGETSR.contains(addr)) {
736  // Interrupt Processor Targets Registers
737  // ARE always on, RAZ/WI
738  warn("Gicv3Distributor::write(): "
739  "GICD_ITARGETSR is RAZ/WI, legacy not supported!\n");
740  return;
741  } else if (GICD_ICFGR.contains(addr)) {
742  // Interrupt Configuration Registers
743  // for x = 0 to 15:
744  // GICD_ICFGR[2x] = RES0
745  // GICD_ICFGR[2x + 1] =
746  // 0 level-sensitive
747  // 1 edge-triggered
748  int first_intid = (addr - GICD_ICFGR.start()) * 4;
749 
750  if (isNotSPI(first_intid)) {
751  return;
752  }
753 
754  for (int i = 0, int_id = first_intid; i < 8 * size && int_id < itLines;
755  i = i + 2, int_id++) {
756 
757  if (nsAccessToSecInt(int_id, is_secure_access)) {
758  continue;
759  }
760 
761  irqConfig[int_id] = data & (0x2 << i) ?
764  DPRINTF(GIC, "Gicv3Distributor::write(): int_id %d config %d\n",
765  int_id, irqConfig[int_id]);
766  }
767 
768  return;
769  } else if (GICD_IGRPMODR.contains(addr)) {
770  // Interrupt Group Modifier Registers
771  if (DS) {
772  return;
773  } else {
774  if (!is_secure_access) {
775  // RAZ/WI for non-secure accesses
776  return;
777  } else {
778  int first_intid = (addr - GICD_IGRPMODR.start()) * 8;
779 
780  if (isNotSPI(first_intid)) {
781  return;
782  }
783 
784  for (int i = 0, int_id = first_intid;
785  i < 8 * size && int_id < itLines; i++, int_id++) {
786  irqGrpmod[int_id] = bits(data, i);
787  }
788 
789  return ;
790  }
791  }
792 
793  } else if (GICD_NSACR.contains(addr)) {
794  // Non-secure Access Control Registers
795  // 2 bits per interrupt
796  int first_intid = (addr - GICD_NSACR.start()) * 4;
797 
798  if (isNotSPI(first_intid)) {
799  return;
800  }
801 
802  if (DS || (!DS && !is_secure_access)) {
803  return;
804  }
805 
806  for (int i = 0, int_id = first_intid;
807  i < 8 * size && int_id < itLines; i = i + 2, int_id++) {
808  irqNsacr[int_id] = (data >> (2 * int_id)) & 0x3;
809  }
810 
811  return;
812  } else if (GICD_IROUTER.contains(addr)) { // Interrupt Routing Registers
813  // 64 bit registers. 2 accesses.
814  int int_id = (addr - GICD_IROUTER.start()) / 8;
815 
816  if (isNotSPI(int_id)) {
817  return;
818  }
819 
820  if (nsAccessToSecInt(int_id, is_secure_access))
821  {
822  if (irqNsacr[int_id] < 3) {
823  // Group 0 or Secure Group 1 interrupts are RAZ/WI
824  return;
825  }
826  }
827 
828  if (size == 4) {
829  if (addr & 7) { // high half of 64 bit register
830  irqAffinityRouting[int_id] =
831  (irqAffinityRouting[int_id] & 0xffffffff) | (data << 32);
832  } else { // low half of 64 bit register
833  irqAffinityRouting[int_id] =
834  (irqAffinityRouting[int_id] & 0xffffffff00000000) |
835  (data & 0xffffffff);
836  }
837  } else {
838  irqAffinityRouting[int_id] = data;
839  }
840 
841  DPRINTF(GIC, "Gicv3Distributor::write(): "
842  "int_id %d GICD_IROUTER %#llx\n",
843  int_id, irqAffinityRouting[int_id]);
844  return;
845  }
846 
847  switch (addr) {
848  case GICD_CTLR: // Control Register
849  if (DS) {
850  /*
851  * E1NWF [7]
852  * 1 of N wakeup functionality not supported, RAZ/WI
853  * DS [6] - RAO/WI
854  * ARE [4]
855  * affinity routing always on, no GICv2 legacy, RAO/WI
856  * EnableGrp1 [1]
857  * EnableGrp0 [0]
858  */
859  if ((data & (1 << 4)) == 0) {
860  warn("Gicv3Distributor::write(): "
861  "setting ARE to 0 is not supported!\n");
862  }
863 
865  EnableGrp0 = data & GICD_CTLR_ENABLEGRP0;
866  DPRINTF(GIC, "Gicv3Distributor::write(): (DS 1)"
867  "EnableGrp1NS %d EnableGrp0 %d\n",
869  } else {
870  if (is_secure_access) {
871  /*
872  * E1NWF [7]
873  * 1 of N wakeup functionality not supported, RAZ/WI
874  * DS [6]
875  * ARE_NS [5]
876  * affinity routing always on, no GICv2 legacy, RAO/WI
877  * ARE_S [4]
878  * affinity routing always on, no GICv2 legacy, RAO/WI
879  * EnableGrp1S [2]
880  * EnableGrp1NS [1]
881  * EnableGrp0 [0]
882  */
883  if ((data & (1 << 5)) == 0) {
884  warn("Gicv3Distributor::write(): "
885  "setting ARE_NS to 0 is not supported!\n");
886  }
887 
888  if ((data & (1 << 4)) == 0) {
889  warn("Gicv3Distributor::write(): "
890  "setting ARE_S to 0 is not supported!\n");
891  }
892 
893  DS = data & GICD_CTLR_DS;
896  EnableGrp0 = data & GICD_CTLR_ENABLEGRP0;
897  DPRINTF(GIC, "Gicv3Distributor::write(): (DS 0 secure)"
898  "DS %d "
899  "EnableGrp1S %d EnableGrp1NS %d EnableGrp0 %d\n",
901 
902  if (data & GICD_CTLR_DS) {
903  EnableGrp1S = 0;
904  }
905  } else {
906  /*
907  * ARE_NS [4] RAO/WI;
908  * EnableGrp1A [1] is a read-write alias of the Secure
909  * GICD_CTLR.EnableGrp1NS
910  * EnableGrp1 [0] RES0
911  */
912  if ((data & (1 << 4)) == 0) {
913  warn("Gicv3Distributor::write(): "
914  "setting ARE_NS to 0 is not supported!\n");
915  }
916 
918  DPRINTF(GIC, "Gicv3Distributor::write(): (DS 0 non-secure)"
919  "EnableGrp1NS %d\n", EnableGrp1NS);
920  }
921  }
922 
923  update();
924 
925  break;
926 
927  case GICD_SGIR: // Error Reporting Status Register
928  // Only if affinity routing is disabled, RES0
929  break;
930 
931  case GICD_SETSPI_NSR: {
932  // Writes to this register have no effect if:
933  // * The value written specifies an invalid SPI.
934  // * The SPI is already pending.
935  // * The value written specifies a Secure SPI, the value is
936  // written by a Non-secure access, and the value of the
937  // corresponding GICD_NSACR<n> register is 0.
938  const uint32_t intid = bits(data, 9, 0);
939  if (isNotSPI(intid) || irqPending[intid] ||
940  (nsAccessToSecInt(intid, is_secure_access) &&
941  irqNsacr[intid] == 0)) {
942  return;
943  } else {
944  // Valid SPI, set interrupt pending
945  sendInt(intid);
946  }
947  break;
948  }
949 
950  case GICD_CLRSPI_NSR: {
951  // Writes to this register have no effect if:
952  // * The value written specifies an invalid SPI.
953  // * The SPI is not pending.
954  // * The value written specifies a Secure SPI, the value is
955  // written by a Non-secure access, and the value of the
956  // corresponding GICD_NSACR<n> register is less than 0b10.
957  const uint32_t intid = bits(data, 9, 0);
958  if (isNotSPI(intid) || !irqPending[intid] ||
959  (nsAccessToSecInt(intid, is_secure_access) &&
960  irqNsacr[intid] < 2)) {
961  return;
962  } else {
963  // Valid SPI, clear interrupt pending
964  deassertSPI(intid);
965  }
966  break;
967  }
968 
969  case GICD_SETSPI_SR: {
970  // Writes to this register have no effect if:
971  // * GICD_CTLR.DS = 1 (WI)
972  // * The value written specifies an invalid SPI.
973  // * The SPI is already pending.
974  // * The value is written by a Non-secure access.
975  const uint32_t intid = bits(data, 9, 0);
976  if (DS || isNotSPI(intid) || irqPending[intid] || !is_secure_access) {
977  return;
978  } else {
979  // Valid SPI, set interrupt pending
980  sendInt(intid);
981  }
982  break;
983  }
984 
985  case GICD_CLRSPI_SR: {
986  // Writes to this register have no effect if:
987  // * GICD_CTLR.DS = 1 (WI)
988  // * The value written specifies an invalid SPI.
989  // * The SPI is not pending.
990  // * The value is written by a Non-secure access.
991  const uint32_t intid = bits(data, 9, 0);
992  if (DS || isNotSPI(intid) || !irqPending[intid] || !is_secure_access) {
993  return;
994  } else {
995  // Valid SPI, clear interrupt pending
996  deassertSPI(intid);
997  }
998  break;
999  }
1000 
1001  default:
1002  panic("Gicv3Distributor::write(): invalid offset %#x\n", addr);
1003  break;
1004  }
1005 }
1006 
1007 void
1009 {
1010  panic_if(int_id < Gicv3::SGI_MAX + Gicv3::PPI_MAX, "Invalid SPI!");
1011  panic_if(int_id > itLines, "Invalid SPI!");
1012  irqPending[int_id] = true;
1013  irqPendingIspendr[int_id] = false;
1014  DPRINTF(GIC, "Gicv3Distributor::sendInt(): "
1015  "int_id %d (SPI) pending bit set\n", int_id);
1016  update();
1017 }
1018 
1019 void
1021 {
1022  // Edge-triggered interrupts remain pending until software
1023  // writes GICD_ICPENDR, GICD_CLRSPI_* or activates them via ICC_IAR
1024  if (isLevelSensitive(int_id)) {
1025  deassertSPI(int_id);
1026  }
1027 }
1028 
1029 void
1031 {
1032  panic_if(int_id < Gicv3::SGI_MAX + Gicv3::PPI_MAX, "Invalid SPI!");
1033  panic_if(int_id > itLines, "Invalid SPI!");
1034  irqPending[int_id] = false;
1035  clearIrqCpuInterface(int_id);
1036 
1037  update();
1038 }
1039 
1041 Gicv3Distributor::route(uint32_t int_id)
1042 {
1043  IROUTER affinity_routing = irqAffinityRouting[int_id];
1044  Gicv3Redistributor * target_redistributor = nullptr;
1045 
1046  const Gicv3::GroupId int_group = getIntGroup(int_id);
1047 
1048  if (affinity_routing.IRM) {
1049  // Interrupts routed to any PE defined as a participating node
1050  for (int i = 0; i < gic->getSystem()->threads.size(); i++) {
1051  Gicv3Redistributor * redistributor_i =
1053 
1054  if (redistributor_i->
1055  canBeSelectedFor1toNInterrupt(int_group)) {
1056  target_redistributor = redistributor_i;
1057  break;
1058  }
1059  }
1060  } else {
1061  uint32_t affinity = (affinity_routing.Aff3 << 24) |
1062  (affinity_routing.Aff2 << 16) |
1063  (affinity_routing.Aff1 << 8) |
1064  (affinity_routing.Aff0 << 0);
1065  target_redistributor =
1066  gic->getRedistributorByAffinity(affinity);
1067  }
1068 
1069  if (!target_redistributor) {
1070  // Interrrupts targeting not present cpus must remain pending
1071  return nullptr;
1072  } else {
1073  return target_redistributor->getCPUInterface();
1074  }
1075 }
1076 
1077 void
1079 {
1080  auto cpu_interface = route(int_id);
1081  if (cpu_interface)
1082  cpu_interface->resetHppi(int_id);
1083 }
1084 
1085 void
1087 {
1088  if (gic->blockIntUpdate())
1089  return;
1090 
1091  // Find the highest priority pending SPI
1092  for (int int_id = Gicv3::SGI_MAX + Gicv3::PPI_MAX; int_id < itLines;
1093  int_id++) {
1094  Gicv3::GroupId int_group = getIntGroup(int_id);
1095  bool group_enabled = groupEnabled(int_group);
1096 
1097  if (irqPending[int_id] && irqEnabled[int_id] &&
1098  !irqActive[int_id] && group_enabled) {
1099 
1100  // Find the cpu interface where to route the interrupt
1101  Gicv3CPUInterface *target_cpu_interface = route(int_id);
1102 
1103  // Invalid routing
1104  if (!target_cpu_interface) continue;
1105 
1106  if ((irqPriority[int_id] < target_cpu_interface->hppi.prio) ||
1107  (irqPriority[int_id] == target_cpu_interface->hppi.prio &&
1108  int_id < target_cpu_interface->hppi.intid)) {
1109 
1110  target_cpu_interface->hppi.intid = int_id;
1111  target_cpu_interface->hppi.prio = irqPriority[int_id];
1112  target_cpu_interface->hppi.group = int_group;
1113  }
1114  }
1115  }
1116 
1117  // Update all redistributors
1118  for (int i = 0; i < gic->getSystem()->threads.size(); i++) {
1120  }
1121 }
1122 
1124 Gicv3Distributor::intStatus(uint32_t int_id) const
1125 {
1126  panic_if(int_id < Gicv3::SGI_MAX + Gicv3::PPI_MAX, "Invalid SPI!");
1127  panic_if(int_id > itLines, "Invalid SPI!");
1128 
1129  if (irqPending[int_id]) {
1130  if (irqActive[int_id]) {
1132  }
1133 
1134  return Gicv3::INT_PENDING;
1135  } else if (irqActive[int_id]) {
1136  return Gicv3::INT_ACTIVE;
1137  } else {
1138  return Gicv3::INT_INACTIVE;
1139  }
1140 }
1141 
1144 {
1145  panic_if(int_id < Gicv3::SGI_MAX + Gicv3::PPI_MAX, "Invalid SPI!");
1146  panic_if(int_id > itLines, "Invalid SPI!");
1147 
1148  if (DS) {
1149  if (irqGroup[int_id] == 1) {
1150  return Gicv3::G1NS;
1151  } else {
1152  return Gicv3::G0S;
1153  }
1154  } else {
1155  if (irqGrpmod[int_id] == 0 && irqGroup[int_id] == 0) {
1156  return Gicv3::G0S;
1157  } else if (irqGrpmod[int_id] == 0 && irqGroup[int_id] == 1) {
1158  return Gicv3::G1NS;
1159  } else if (irqGrpmod[int_id] == 1 && irqGroup[int_id] == 0) {
1160  return Gicv3::G1S;
1161  } else if (irqGrpmod[int_id] == 1 && irqGroup[int_id] == 1) {
1162  return Gicv3::G1NS;
1163  }
1164  }
1165 
1166  GEM5_UNREACHABLE;
1167 }
1168 
1169 void
1171 {
1172  if (treatAsEdgeTriggered(int_id)) {
1173  irqPending[int_id] = false;
1174  }
1175  irqActive[int_id] = true;
1176 }
1177 
1178 void
1180 {
1181  irqActive[int_id] = false;
1182 }
1183 
1184 void
1186 {
1187  const size_t size = itLines / 8;
1188 
1189  gic->copyDistRegister(from, to, GICD_CTLR);
1190 
1192  gic->clearDistRange(to, GICD_ICPENDR.start(), size);
1194 
1195  gic->copyDistRange(from, to, GICD_IGROUPR.start(), size);
1196  gic->copyDistRange(from, to, GICD_ISENABLER.start(), size);
1197  gic->copyDistRange(from, to, GICD_ISPENDR.start(), size);
1198  gic->copyDistRange(from, to, GICD_ISACTIVER.start(), size);
1199  gic->copyDistRange(from, to, GICD_IPRIORITYR.start(), size);
1200  gic->copyDistRange(from, to, GICD_ITARGETSR.start(), size);
1201  gic->copyDistRange(from, to, GICD_ICFGR.start(), size);
1202  gic->copyDistRange(from, to, GICD_IGRPMODR.start(), size);
1203  gic->copyDistRange(from, to, GICD_NSACR.start(), size);
1204  gic->copyDistRange(from, to, GICD_IROUTER.start(), size);
1205 }
1206 
1207 void
1209 {
1225 }
1226 
1227 void
1229 {
1245 }
1246 
1247 } // namespace gem5
#define DPRINTF(x,...)
Definition: trace.hh:186
const char data[]
bool has(ArmExtension ext) const
Definition: system.hh:155
ArmSystem * getSystem() const
Definition: base_gic.hh:114
virtual bool blockIntUpdate() const
When trasferring the state between two GICs (essentially writing architectural registers) an interrup...
Definition: base_gic.hh:130
std::vector< uint8_t > irqPriority
std::vector< bool > irqActive
static const AddrRange GICD_IGROUPR
static const AddrRange GICD_ISPENDR
static const AddrRange GICD_ICFGR
static const AddrRange GICD_ICACTIVER
std::vector< uint8_t > irqGrpmod
void sendInt(uint32_t int_id)
std::vector< bool > irqPending
void unserialize(CheckpointIn &cp) override
Unserialize an object.
std::vector< bool > irqEnabled
static const AddrRange GICD_NSACR
bool groupEnabled(Gicv3::GroupId group) const
bool isNotSPI(uint32_t int_id) const
std::vector< uint8_t > irqNsacr
void clearInt(uint32_t int_id)
static const AddrRange GICD_IGRPMODR
std::vector< uint8_t > irqGroup
std::vector< IROUTER > irqAffinityRouting
static const uint32_t IDBITS
static const AddrRange GICD_ISENABLER
bool treatAsEdgeTriggered(uint32_t int_id) const
This helper is used to check if an interrupt should be treated as edge triggered in the following sce...
Gicv3::IntStatus intStatus(uint32_t int_id) const
void copy(Gicv3Registers *from, Gicv3Registers *to)
static const uint32_t GICD_CTLR_ENABLEGRP1A
std::vector< Gicv3::IntTriggerType > irqConfig
static const AddrRange GICD_SPENDSGIR
void activateIRQ(uint32_t int_id)
Gicv3CPUInterface * route(uint32_t int_id)
static const AddrRange GICD_ICENABLER
static const AddrRange GICD_IROUTER
static const AddrRange GICD_ICPENDR
bool nsAccessToSecInt(uint32_t int_id, bool is_secure_access) const
std::vector< bool > irqPendingIspendr
bool isLevelSensitive(uint32_t int_id) const
void write(Addr addr, uint64_t data, size_t size, bool is_secure_access)
static const AddrRange GICD_ITARGETSR
void deactivateIRQ(uint32_t int_id)
static const AddrRange GICD_IPRIORITYR
void deassertSPI(uint32_t int_id)
Gicv3::GroupId getIntGroup(int int_id) const
static const uint32_t GICD_CTLR_ENABLEGRP1NS
void clearIrqCpuInterface(uint32_t int_id)
Gicv3Distributor(Gicv3 *gic, uint32_t it_lines)
static const uint32_t GICD_CTLR_ENABLEGRP1S
uint64_t read(Addr addr, size_t size, bool is_secure_access)
static const AddrRange GICD_ISACTIVER
void serialize(CheckpointOut &cp) const override
Serialize an object.
static const uint32_t GICD_CTLR_DS
static const AddrRange GICD_CPENDSGIR
Gicv3CPUInterface * getCPUInterface() const
static void clearDistRange(Gicv3Registers *to, Addr daddr, size_t size)
Definition: gic_v3.cc:124
static void copyDistRegister(Gicv3Registers *from, Gicv3Registers *to, Addr daddr)
Definition: gic_v3.cc:58
static void copyDistRange(Gicv3Registers *from, Gicv3Registers *to, Addr daddr, size_t size)
Definition: gic_v3.cc:115
static const int SGI_MAX
Definition: gic_v3.hh:119
@ INT_LEVEL_SENSITIVE
Definition: gic_v3.hh:142
@ INT_EDGE_TRIGGERED
Definition: gic_v3.hh:143
@ INT_ACTIVE_PENDING
Definition: gic_v3.hh:129
@ INT_ACTIVE
Definition: gic_v3.hh:128
@ INT_PENDING
Definition: gic_v3.hh:127
@ INT_INACTIVE
Definition: gic_v3.hh:126
static const int PPI_MAX
Definition: gic_v3.hh:121
Gicv3Redistributor * getRedistributorByAffinity(const ArmISA::Affinity &aff) const
Definition: gic_v3.cc:324
Gicv3Redistributor * getRedistributor(ContextID context_id) const
Definition: gic_v3.hh:191
static const int INTID_SECURE
Definition: gic_v3.hh:114
bool contains(const Addr &a) const
Determine if the range contains an address.
Definition: addr_range.hh:471
Addr start() const
Get the start address of the range.
Definition: addr_range.hh:343
static constexpr T divCeil(const T &a, const U &b)
Definition: intmath.hh:110
constexpr T bits(T val, unsigned first, unsigned last)
Extract the bitfield from position 'first' to 'last' (inclusive) from 'val' and right justify it.
Definition: bitfield.hh:76
#define panic(...)
This implements a cprintf based panic() function.
Definition: logging.hh:178
#define panic_if(cond,...)
Conditional panic macro that checks the supplied condition and only panics if the condition is true a...
Definition: logging.hh:204
#define UNSERIALIZE_CONTAINER(member)
Definition: serialize.hh:634
#define SERIALIZE_CONTAINER(member)
Definition: serialize.hh:626
#define warn(...)
Definition: logging.hh:246
Bitfield< 7 > i
Definition: misc_types.hh:67
Bitfield< 27, 24 > gic
Definition: misc_types.hh:175
Bitfield< 25, 21 > to
Definition: types.hh:96
Bitfield< 11 > enable
Definition: misc.hh:1058
Bitfield< 63 > val
Definition: misc.hh:776
Bitfield< 3 > addr
Definition: types.hh:84
void disable()
Definition: trace.cc:100
Reference material can be found at the JEDEC website: UFS standard http://www.jedec....
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
#define UNSERIALIZE_SCALAR(scalar)
Definition: serialize.hh:575
#define SERIALIZE_SCALAR(scalar)
Definition: serialize.hh:568

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