gic_v3_redistributor.cc (13922:725a593e8e9d) gic_v3_redistributor.cc (13923:a7d1f05a0477)
1/*
2 * Copyright (c) 2018 Metempsy Technology Consulting
3 * All rights reserved.
4 *
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions are
7 * met: redistributions of source code must retain the above copyright
8 * notice, this list of conditions and the following disclaimer;
9 * redistributions in binary form must reproduce the above copyright
10 * notice, this list of conditions and the following disclaimer in the
11 * documentation and/or other materials provided with the distribution;
12 * neither the name of the copyright holders nor the names of its
13 * contributors may be used to endorse or promote products derived from
14 * this software without specific prior written permission.
15 *
16 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
17 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
18 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
19 * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
20 * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
21 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
22 * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
23 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
24 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
25 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
26 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
27 *
28 * Authors: Jairo Balart
29 */
30
31#include "dev/arm/gic_v3_redistributor.hh"
32
33#include "arch/arm/utility.hh"
34#include "debug/GIC.hh"
35#include "dev/arm/gic_v3_cpu_interface.hh"
36#include "dev/arm/gic_v3_distributor.hh"
37#include "mem/fs_translating_port_proxy.hh"
38
39const AddrRange Gicv3Redistributor::GICR_IPRIORITYR(SGI_base + 0x0400,
40 SGI_base + 0x041f);
41
42Gicv3Redistributor::Gicv3Redistributor(Gicv3 * gic, uint32_t cpu_id)
43 : gic(gic),
44 distributor(nullptr),
45 cpuInterface(nullptr),
46 cpuId(cpu_id),
47 irqGroup(Gicv3::SGI_MAX + Gicv3::PPI_MAX),
48 irqEnabled(Gicv3::SGI_MAX + Gicv3::PPI_MAX),
49 irqPending(Gicv3::SGI_MAX + Gicv3::PPI_MAX),
50 irqActive(Gicv3::SGI_MAX + Gicv3::PPI_MAX),
51 irqPriority(Gicv3::SGI_MAX + Gicv3::PPI_MAX),
52 irqConfig(Gicv3::SGI_MAX + Gicv3::PPI_MAX),
53 irqGrpmod(Gicv3::SGI_MAX + Gicv3::PPI_MAX),
54 irqNsacr(Gicv3::SGI_MAX + Gicv3::PPI_MAX),
55 addrRangeSize(gic->params()->gicv4 ? 0x40000 : 0x20000)
56{
57}
58
59void
60Gicv3Redistributor::init()
61{
62 distributor = gic->getDistributor();
63 cpuInterface = gic->getCPUInterface(cpuId);
64}
65
66void
67Gicv3Redistributor::initState()
68{
69 reset();
70}
71
72void
73Gicv3Redistributor::reset()
74{
75 peInLowPowerState = true;
76 std::fill(irqGroup.begin(), irqGroup.end(), 0);
77 std::fill(irqEnabled.begin(), irqEnabled.end(), false);
78 std::fill(irqPending.begin(), irqPending.end(), false);
79 std::fill(irqActive.begin(), irqActive.end(), false);
80 std::fill(irqPriority.begin(), irqPriority.end(), 0);
81
82 // SGIs have edge-triggered behavior
83 for (uint32_t int_id = 0; int_id < Gicv3::SGI_MAX; int_id++) {
84 irqConfig[int_id] = Gicv3::INT_EDGE_TRIGGERED;
85 }
86
87 std::fill(irqGrpmod.begin(), irqGrpmod.end(), 0);
88 std::fill(irqNsacr.begin(), irqNsacr.end(), 0);
89 DPG1S = false;
90 DPG1NS = false;
91 DPG0 = false;
92 EnableLPIs = false;
93 lpiConfigurationTablePtr = 0;
94 lpiIDBits = 0;
95 lpiPendingTablePtr = 0;
96}
97
98uint64_t
99Gicv3Redistributor::read(Addr addr, size_t size, bool is_secure_access)
100{
101 if (GICR_IPRIORITYR.contains(addr)) { // Interrupt Priority Registers
102 uint64_t value = 0;
103 int first_intid = addr - GICR_IPRIORITYR.start();
104
105 for (int i = 0, int_id = first_intid; i < size; i++, int_id++) {
106 uint8_t prio = irqPriority[int_id];
107
108 if (!distributor->DS && !is_secure_access) {
109 if (getIntGroup(int_id) != Gicv3::G1NS) {
110 // RAZ/WI for non-secure accesses for secure interrupts
111 continue;
112 } else {
113 // NS view
114 prio = (prio << 1) & 0xff;
115 }
116 }
117
118 value |= prio << (i * 8);
119 }
120
121 return value;
122 }
123
124 switch (addr) {
125 case GICR_CTLR: { // Control Register
126 uint64_t value = 0;
127
128 if (DPG1S) {
129 value |= GICR_CTLR_DPG1S;
130 }
131
132 if (DPG1NS) {
133 value |= GICR_CTLR_DPG1NS;
134 }
135
136 if (DPG0) {
137 value |= GICR_CTLR_DPG0;
138 }
139
140 if (EnableLPIs) {
141 value |= GICR_CTLR_ENABLE_LPIS;
142 }
143
144 return value;
145 }
146
147 case GICR_IIDR: // Implementer Identification Register
148 //return 0x43b; // r0p0 GIC-500
149 return 0;
150
151 case GICR_TYPER: { // Type Register
152 /*
153 * Affinity_Value [63:32] == X
154 * (The identity of the PE associated with this Redistributor)
155 * CommonLPIAff [25:24] == 01
156 * (All Redistributors with the same Aff3 value must share an
157 * LPI Configuration table)
158 * Processor_Number [23:8] == X
159 * (A unique identifier for the PE)
160 * DPGS [5] == 1
161 * (GICR_CTLR.DPG* bits are supported)
162 * Last [4] == X
163 * (This Redistributor is the highest-numbered Redistributor in
164 * a series of contiguous Redistributor pages)
165 * DirectLPI [3] == 1
166 * (direct injection of LPIs supported)
167 * VLPIS [1] == 0
168 * (virtual LPIs not supported)
169 * PLPIS [0] == 1
170 * (physical LPIs supported)
171 */
172 uint64_t affinity = getAffinity();
173 int last = cpuId == (gic->getSystem()->numContexts() - 1);
174 return (affinity << 32) | (1 << 24) | (cpuId << 8) |
175 (1 << 5) | (last << 4) | (1 << 3) | (1 << 0);
176 }
177
178 case GICR_WAKER: // Wake Register
179 if (!distributor->DS && !is_secure_access) {
180 // RAZ/WI for non-secure accesses
181 return 0;
182 }
183
184 if (peInLowPowerState) {
185 return GICR_WAKER_ChildrenAsleep | GICR_WAKER_ProcessorSleep;
186 } else {
187 return 0;
188 }
189
190 case GICR_PIDR0: { // Peripheral ID0 Register
191 return 0x92; // Part number, bits[7:0]
192 }
193
194 case GICR_PIDR1: { // Peripheral ID1 Register
195 uint8_t des_0 = 0xB; // JEP106 identification code, bits[3:0]
196 uint8_t part_1 = 0x4; // Part number, bits[11:8]
197 return (des_0 << 4) | (part_1 << 0);
198 }
199
200 case GICR_PIDR2: { // Peripheral ID2 Register
201 uint8_t arch_rev = 0x3; // 0x3 GICv3
202 uint8_t jedec = 0x1; // JEP code
203 uint8_t des_1 = 0x3; // JEP106 identification code, bits[6:4]
204 return (arch_rev << 4) | (jedec << 3) | (des_1 << 0);
205 }
206
207 case GICR_PIDR3: // Peripheral ID3 Register
208 return 0x0; // Implementation defined
209
210 case GICR_PIDR4: { // Peripheral ID4 Register
211 uint8_t size = 0x4; // 64 KB software visible page
212 uint8_t des_2 = 0x4; // ARM implementation
213 return (size << 4) | (des_2 << 0);
214 }
215
216 case GICR_PIDR5: // Peripheral ID5 Register
217 case GICR_PIDR6: // Peripheral ID6 Register
218 case GICR_PIDR7: // Peripheral ID7 Register
219 return 0; // RES0
220
221 case GICR_IGROUPR0: { // Interrupt Group Register 0
222 uint64_t value = 0;
223
224 if (!distributor->DS && !is_secure_access) {
225 // RAZ/WI for non-secure accesses
226 return 0;
227 }
228
229 for (int int_id = 0; int_id < 8 * size; int_id++) {
230 value |= (irqGroup[int_id] << int_id);
231 }
232
233 return value;
234 }
235
236 case GICR_ISENABLER0: // Interrupt Set-Enable Register 0
237 case GICR_ICENABLER0: { // Interrupt Clear-Enable Register 0
238 uint64_t value = 0;
239
240 for (int int_id = 0; int_id < 8 * size; int_id++) {
241 if (!distributor->DS && !is_secure_access) {
242 // RAZ/WI for non-secure accesses for secure interrupts
243 if (getIntGroup(int_id) != Gicv3::G1NS) {
244 continue;
245 }
246 }
247
248 if (irqEnabled[int_id]) {
249 value |= (1 << int_id);
250 }
251 }
252
253 return value;
254 }
255
256 case GICR_ISPENDR0: // Interrupt Set-Pending Register 0
257 case GICR_ICPENDR0: { // Interrupt Clear-Pending Register 0
258 uint64_t value = 0;
259
260 for (int int_id = 0; int_id < 8 * size; int_id++) {
261 if (!distributor->DS && !is_secure_access) {
262 // RAZ/WI for non-secure accesses for secure interrupts
263 if (getIntGroup(int_id) != Gicv3::G1NS) {
264 continue;
265 }
266 }
267
268 value |= (irqPending[int_id] << int_id);
269 }
270
271 return value;
272 }
273
274 case GICR_ISACTIVER0: // Interrupt Set-Active Register 0
275 case GICR_ICACTIVER0: { // Interrupt Clear-Active Register 0
276 uint64_t value = 0;
277
278 for (int int_id = 0; int_id < 8 * size; int_id++) {
279 if (!distributor->DS && !is_secure_access) {
280 // RAZ/WI for non-secure accesses for secure interrupts
281 if (getIntGroup(int_id) != Gicv3::G1NS) {
282 continue;
283 }
284 }
285
286 value |= irqActive[int_id] << int_id;
287 }
288
289 return value;
290 }
291
292 case GICR_ICFGR0: // SGI Configuration Register
293 case GICR_ICFGR1: { // PPI Configuration Register
294 uint64_t value = 0;
295 uint32_t first_int_id = addr == GICR_ICFGR0 ? 0 : Gicv3::SGI_MAX;
296
297 for (int i = 0, int_id = first_int_id; i < 32;
298 i = i + 2, int_id++) {
299 if (!distributor->DS && !is_secure_access) {
300 // RAZ/WI for non-secure accesses for secure interrupts
301 if (getIntGroup(int_id) != Gicv3::G1NS) {
302 continue;
303 }
304 }
305
306 if (irqConfig[int_id] == Gicv3::INT_EDGE_TRIGGERED) {
307 value |= (0x2) << i;
308 }
309 }
310
311 return value;
312 }
313
314 case GICR_IGRPMODR0: { // Interrupt Group Modifier Register 0
315 uint64_t value = 0;
316
317 if (distributor->DS) {
318 value = 0;
319 } else {
320 if (!is_secure_access) {
321 // RAZ/WI for non-secure accesses
322 value = 0;
323 } else {
324 for (int int_id = 0; int_id < 8 * size; int_id++) {
325 value |= irqGrpmod[int_id] << int_id;
326 }
327 }
328 }
329
330 return value;
331 }
332
333 case GICR_NSACR: { // Non-secure Access Control Register
334 uint64_t value = 0;
335
336 if (distributor->DS) {
337 // RAZ/WI
338 value = 0;
339 } else {
340 if (!is_secure_access) {
341 // RAZ/WI
342 value = 0;
343 } else {
344 for (int i = 0, int_id = 0; i < 8 * size;
345 i = i + 2, int_id++) {
346 value |= irqNsacr[int_id] << i;
347 }
348 }
349 }
350
351 return value;
352 }
353
354 case GICR_PROPBASER: // Redistributor Properties Base Address Register
355 // OuterCache, bits [58:56]
356 // 000 Memory type defined in InnerCache field
357 // Physical_Address, bits [51:12]
358 // Bits [51:12] of the physical address containing the LPI
359 // Configuration table
360 // Shareability, bits [11:10]
361 // 00 Non-shareable
362 // InnerCache, bits [9:7]
363 // 000 Device-nGnRnE
364 // IDbits, bits [4:0]
365 // limited by GICD_TYPER.IDbits
366 return lpiConfigurationTablePtr | lpiIDBits;
367
368 // Redistributor LPI Pending Table Base Address Register
369 case GICR_PENDBASER:
370 // PTZ, bit [62]
371 // Pending Table Zero
372 // OuterCache, bits [58:56]
373 // 000 Memory type defined in InnerCache field
374 // Physical_Address, bits [51:16]
375 // Bits [51:16] of the physical address containing the LPI Pending
376 // table
377 // Shareability, bits [11:10]
378 // 00 Non-shareable
379 // InnerCache, bits [9:7]
380 // 000 Device-nGnRnE
381 return lpiPendingTablePtr;
382
383 // Redistributor Synchronize Register
384 case GICR_SYNCR:
385 return 0;
386
387 default:
388 panic("Gicv3Redistributor::read(): invalid offset %#x\n", addr);
389 break;
390 }
391}
392
393void
394Gicv3Redistributor::write(Addr addr, uint64_t data, size_t size,
395 bool is_secure_access)
396{
397 if (GICR_IPRIORITYR.contains(addr)) { // Interrupt Priority Registers
398 int first_intid = addr - GICR_IPRIORITYR.start();
399
400 for (int i = 0, int_id = first_intid; i < size; i++, int_id++) {
401 uint8_t prio = bits(data, (i + 1) * 8 - 1, (i * 8));
402
403 if (!distributor->DS && !is_secure_access) {
404 if (getIntGroup(int_id) != Gicv3::G1NS) {
405 // RAZ/WI for non-secure accesses for secure interrupts
406 continue;
407 } else {
408 // NS view
409 prio = 0x80 | (prio >> 1);
410 }
411 }
412
413 irqPriority[int_id] = prio;
414 DPRINTF(GIC, "Gicv3Redistributor::write(): "
415 "int_id %d priority %d\n", int_id, irqPriority[int_id]);
416 }
417
418 return;
419 }
420
421 switch (addr) {
422 case GICR_CTLR: {
423 // GICR_TYPER.LPIS is 0 so EnableLPIs is RES0
424 EnableLPIs = data & GICR_CTLR_ENABLE_LPIS;
425 DPG1S = data & GICR_CTLR_DPG1S;
426 DPG1NS = data & GICR_CTLR_DPG1NS;
427 DPG0 = data & GICR_CTLR_DPG0;
428 break;
429 }
430
431 case GICR_WAKER: // Wake Register
432 if (!distributor->DS && !is_secure_access) {
433 // RAZ/WI for non-secure accesses
434 return;
435 }
436
437 if (not peInLowPowerState and
438 (data & GICR_WAKER_ProcessorSleep)) {
439 DPRINTF(GIC, "Gicv3Redistributor::write(): "
440 "PE entering in low power state\n");
441 } else if (peInLowPowerState and
442 not(data & GICR_WAKER_ProcessorSleep)) {
443 DPRINTF(GIC, "Gicv3Redistributor::write(): powering up PE\n");
444 }
445
446 peInLowPowerState = data & GICR_WAKER_ProcessorSleep;
447 break;
448
449 case GICR_IGROUPR0: // Interrupt Group Register 0
450 if (!distributor->DS && !is_secure_access) {
451 // RAZ/WI for non-secure accesses
452 return;
453 }
454
455 for (int int_id = 0; int_id < 8 * size; int_id++) {
456 irqGroup[int_id] = data & (1 << int_id) ? 1 : 0;
457 DPRINTF(GIC, "Gicv3Redistributor::write(): "
458 "int_id %d group %d\n", int_id, irqGroup[int_id]);
459 }
460
461 break;
462
463 case GICR_ISENABLER0: // Interrupt Set-Enable Register 0
464 for (int int_id = 0; int_id < 8 * size; int_id++) {
465 if (!distributor->DS && !is_secure_access) {
466 // RAZ/WI for non-secure accesses for secure interrupts
467 if (getIntGroup(int_id) != Gicv3::G1NS) {
468 continue;
469 }
470 }
471
472 bool enable = data & (1 << int_id) ? 1 : 0;
473
474 if (enable) {
475 irqEnabled[int_id] = true;
476 }
477
478 DPRINTF(GIC, "Gicv3Redistributor::write(): "
479 "int_id %d enable %i\n", int_id, irqEnabled[int_id]);
480 }
481
482 break;
483
484 case GICR_ICENABLER0: // Interrupt Clear-Enable Register 0
485 for (int int_id = 0; int_id < 8 * size; int_id++) {
486 if (!distributor->DS && !is_secure_access) {
487 // RAZ/WI for non-secure accesses for secure interrupts
488 if (getIntGroup(int_id) != Gicv3::G1NS) {
489 continue;
490 }
491 }
492
493 bool disable = data & (1 << int_id) ? 1 : 0;
494
495 if (disable) {
496 irqEnabled[int_id] = false;
497 }
498
499 DPRINTF(GIC, "Gicv3Redistributor::write(): "
500 "int_id %d enable %i\n", int_id, irqEnabled[int_id]);
501 }
502
503 break;
504
505 case GICR_ISPENDR0: // Interrupt Set-Pending Register 0
506 for (int int_id = 0; int_id < 8 * size; int_id++) {
507 if (!distributor->DS && !is_secure_access) {
508 // RAZ/WI for non-secure accesses for secure interrupts
509 if (getIntGroup(int_id) != Gicv3::G1NS) {
510 continue;
511 }
512 }
513
514 bool pending = data & (1 << int_id) ? 1 : 0;
515
516 if (pending) {
517 DPRINTF(GIC, "Gicv3Redistributor::write() "
518 "(GICR_ISPENDR0): int_id %d (PPI) "
519 "pending bit set\n", int_id);
520 irqPending[int_id] = true;
521 }
522 }
523
524 updateAndInformCPUInterface();
525 break;
526
527 case GICR_ICPENDR0:// Interrupt Clear-Pending Register 0
528 for (int int_id = 0; int_id < 8 * size; int_id++) {
529 if (!distributor->DS && !is_secure_access) {
530 // RAZ/WI for non-secure accesses for secure interrupts
531 if (getIntGroup(int_id) != Gicv3::G1NS) {
532 continue;
533 }
534 }
535
536 bool clear = data & (1 << int_id) ? 1 : 0;
537
538 if (clear) {
539 irqPending[int_id] = false;
540 }
541 }
542
543 break;
544
545 case GICR_ISACTIVER0: // Interrupt Set-Active Register 0
546 for (int int_id = 0; int_id < 8 * size; int_id++) {
547 if (!distributor->DS && !is_secure_access) {
548 // RAZ/WI for non-secure accesses for secure interrupts
549 if (getIntGroup(int_id) != Gicv3::G1NS) {
550 continue;
551 }
552 }
553
554 bool activate = data & (1 << int_id) ? 1 : 0;
555
556 if (activate) {
557 if (!irqActive[int_id]) {
558 DPRINTF(GIC, "Gicv3Redistributor::write(): "
559 "int_id %d active set\n", int_id);
560 }
561
562 irqActive[int_id] = true;
563 }
564 }
565
566 break;
567
568 case GICR_ICACTIVER0: // Interrupt Clear-Active Register 0
569 for (int int_id = 0; int_id < 8 * size; int_id++) {
570 if (!distributor->DS && !is_secure_access) {
571 // RAZ/WI for non-secure accesses for secure interrupts
572 if (getIntGroup(int_id) != Gicv3::G1NS) {
573 continue;
574 }
575 }
576
577 bool clear = data & (1 << int_id) ? 1 : 0;
578
579 if (clear) {
580 if (irqActive[int_id]) {
581 DPRINTF(GIC, "Gicv3Redistributor::write(): "
582 "int_id %d active cleared\n", int_id);
583 }
584
585 irqActive[int_id] = false;
586 }
587 }
588
589 break;
590
591 case GICR_ICFGR1: { // PPI Configuration Register
592 int first_intid = Gicv3::SGI_MAX;
593
594 for (int i = 0, int_id = first_intid; i < 8 * size;
595 i = i + 2, int_id++) {
596 if (!distributor->DS && !is_secure_access) {
597 // RAZ/WI for non-secure accesses for secure interrupts
598 if (getIntGroup(int_id) != Gicv3::G1NS) {
599 continue;
600 }
601 }
602
603 irqConfig[int_id] = data & (0x2 << i) ?
604 Gicv3::INT_EDGE_TRIGGERED :
605 Gicv3::INT_LEVEL_SENSITIVE;
606 DPRINTF(GIC, "Gicv3Redistributor::write(): "
607 "int_id %d (PPI) config %d\n",
608 int_id, irqConfig[int_id]);
609 }
610
611 break;
612 }
613
614 case GICR_IGRPMODR0: { // Interrupt Group Modifier Register 0
615 if (distributor->DS) {
616 // RAZ/WI if secutiry disabled
617 } else {
618 for (int int_id = 0; int_id < 8 * size; int_id++) {
619 if (!is_secure_access) {
620 // RAZ/WI for non-secure accesses
621 continue;
622 }
623
624 irqGrpmod[int_id] = data & (1 << int_id);
625 }
626 }
627
628 break;
629 }
630
631 case GICR_NSACR: { // Non-secure Access Control Register
632 if (distributor->DS) {
633 // RAZ/WI
634 } else {
635 if (!is_secure_access) {
636 // RAZ/WI
637 } else {
638 for (int i = 0, int_id = 0; i < 8 * size;
639 i = i + 2, int_id++) {
640 irqNsacr[int_id] = (data >> i) & 0x3;
641 }
642 }
643 }
644
645 break;
646 }
647
648 case GICR_SETLPIR: // Set LPI Pending Register
649 setClrLPI(data, true);
650 break;
651
652 case GICR_CLRLPIR: // Clear LPI Pending Register
653 setClrLPI(data, false);
654 break;
655
656 case GICR_PROPBASER: { // Redistributor Properties Base Address Register
657 // OuterCache, bits [58:56]
658 // 000 Memory type defined in InnerCache field
659 // Physical_Address, bits [51:12]
660 // Bits [51:12] of the physical address containing the LPI
661 // Configuration table
662 // Shareability, bits [11:10]
663 // 00 Non-shareable
664 // InnerCache, bits [9:7]
665 // 000 Device-nGnRnE
666 // IDbits, bits [4:0]
667 // limited by GICD_TYPER.IDbits (= 0xf)
668 lpiConfigurationTablePtr = data & 0xFFFFFFFFFF000;
669 lpiIDBits = data & 0x1f;
670
671 // 0xf here matches the value of GICD_TYPER.IDbits.
672 // TODO - make GICD_TYPER.IDbits a parameter instead of a hardcoded
673 // value
674 if (lpiIDBits > 0xf) {
675 lpiIDBits = 0xf;
676 }
677
678 break;
679 }
680
681 // Redistributor LPI Pending Table Base Address Register
682 case GICR_PENDBASER:
683 // PTZ, bit [62]
684 // Pending Table Zero
685 // OuterCache, bits [58:56]
686 // 000 Memory type defined in InnerCache field
687 // Physical_Address, bits [51:16]
688 // Bits [51:16] of the physical address containing the LPI Pending
689 // table
690 // Shareability, bits [11:10]
691 // 00 Non-shareable
692 // InnerCache, bits [9:7]
693 // 000 Device-nGnRnE
694 lpiPendingTablePtr = data & 0xFFFFFFFFF0000;
695 break;
696
697 case GICR_INVLPIR: { // Redistributor Invalidate LPI Register
698 // Do nothing: no caching supported
699 break;
700 }
701
702 case GICR_INVALLR: { // Redistributor Invalidate All Register
703 // Do nothing: no caching supported
704 break;
705 }
706
707 default:
708 panic("Gicv3Redistributor::write(): invalid offset %#x\n", addr);
709 break;
710 }
711}
712
713void
714Gicv3Redistributor::sendPPInt(uint32_t int_id)
715{
716 assert((int_id >= Gicv3::SGI_MAX) &&
717 (int_id < Gicv3::SGI_MAX + Gicv3::PPI_MAX));
718 irqPending[int_id] = true;
719 DPRINTF(GIC, "Gicv3Redistributor::sendPPInt(): "
720 "int_id %d (PPI) pending bit set\n", int_id);
721 updateAndInformCPUInterface();
722}
723
724void
725Gicv3Redistributor::sendSGI(uint32_t int_id, Gicv3::GroupId group, bool ns)
726{
727 assert(int_id < Gicv3::SGI_MAX);
728 Gicv3::GroupId int_group = getIntGroup(int_id);
729
730 // asked for secure group 1
731 // configured as group 0
732 // send group 0
733 if (int_group == Gicv3::G0S && group == Gicv3::G1S) {
734 group = Gicv3::G0S;
735 }
736
737 if (group == Gicv3::G0S and int_group != Gicv3::G0S) {
738 return;
739 }
740
741 if (ns && distributor->DS == 0) {
742 int nsaccess = irqNsacr[int_id];
743
744 if ((int_group == Gicv3::G0S && nsaccess < 1) ||
745 (int_group == Gicv3::G1S && nsaccess < 2)) {
746 return;
747 }
748 }
749
750 irqPending[int_id] = true;
751 DPRINTF(GIC, "Gicv3ReDistributor::sendSGI(): "
752 "int_id %d (SGI) pending bit set\n", int_id);
753 updateAndInformCPUInterface();
754}
755
756Gicv3::IntStatus
757Gicv3Redistributor::intStatus(uint32_t int_id) const
758{
759 assert(int_id < Gicv3::SGI_MAX + Gicv3::PPI_MAX);
760
761 if (irqPending[int_id]) {
762 if (irqActive[int_id]) {
763 return Gicv3::INT_ACTIVE_PENDING;
764 }
765
766 return Gicv3::INT_PENDING;
767 } else if (irqActive[int_id]) {
768 return Gicv3::INT_ACTIVE;
769 } else {
770 return Gicv3::INT_INACTIVE;
771 }
772}
773
774/*
775 * Recalculate the highest priority pending interrupt after a
776 * change to redistributor state.
777 */
778void
779Gicv3Redistributor::update()
780{
781 bool new_hppi = false;
782
783 for (int int_id = 0; int_id < Gicv3::SGI_MAX + Gicv3::PPI_MAX; int_id++) {
784 Gicv3::GroupId int_group = getIntGroup(int_id);
785 bool group_enabled = distributor->groupEnabled(int_group);
786
787 if (irqPending[int_id] && irqEnabled[int_id] &&
788 !irqActive[int_id] && group_enabled) {
789 if ((irqPriority[int_id] < cpuInterface->hppi.prio) ||
790 /*
791 * Multiple pending ints with same priority.
792 * Implementation choice which one to signal.
793 * Our implementation selects the one with the lower id.
794 */
795 (irqPriority[int_id] == cpuInterface->hppi.prio &&
796 int_id < cpuInterface->hppi.intid)) {
797 cpuInterface->hppi.intid = int_id;
798 cpuInterface->hppi.prio = irqPriority[int_id];
799 cpuInterface->hppi.group = int_group;
800 new_hppi = true;
801 }
802 }
803 }
804
805 // Check LPIs
806 if (EnableLPIs) {
807 ThreadContext * tc = gic->getSystem()->getThreadContext(cpuId);
808
809 const uint32_t largest_lpi_id = 1 << (lpiIDBits + 1);
810 const uint32_t number_lpis = largest_lpi_id - SMALLEST_LPI_ID + 1;
811
812 uint8_t lpi_pending_table[largest_lpi_id / 8];
813 uint8_t lpi_config_table[number_lpis];
814
815 tc->getPhysProxy().readBlob(lpiPendingTablePtr,
816 (uint8_t *) lpi_pending_table,
817 sizeof(lpi_pending_table));
818
819 tc->getPhysProxy().readBlob(lpiConfigurationTablePtr,
820 (uint8_t*) lpi_config_table,
821 sizeof(lpi_config_table));
822
823 for (int lpi_id = SMALLEST_LPI_ID; lpi_id < largest_lpi_id;
824 lpi_id++) {
825 uint32_t lpi_pending_entry_byte = lpi_id / 8;
826 uint8_t lpi_pending_entry_bit_position = lpi_id % 8;
827 bool lpi_is_pending = lpi_pending_table[lpi_pending_entry_byte] &
828 1 << lpi_pending_entry_bit_position;
829 uint32_t lpi_configuration_entry_index = lpi_id - SMALLEST_LPI_ID;
830
831 LPIConfigurationTableEntry config_entry =
832 lpi_config_table[lpi_configuration_entry_index];
833
834 bool lpi_is_enable = config_entry.enable;
835
836 // LPIs are always Non-secure Group 1 interrupts,
837 // in a system where two Security states are enabled.
838 Gicv3::GroupId lpi_group = Gicv3::G1NS;
839 bool group_enabled = distributor->groupEnabled(lpi_group);
840
841 if (lpi_is_pending && lpi_is_enable && group_enabled) {
842 uint8_t lpi_priority = config_entry.priority << 2;
843
844 if ((lpi_priority < cpuInterface->hppi.prio) ||
845 (lpi_priority == cpuInterface->hppi.prio &&
846 lpi_id < cpuInterface->hppi.intid)) {
847 cpuInterface->hppi.intid = lpi_id;
848 cpuInterface->hppi.prio = lpi_priority;
849 cpuInterface->hppi.group = lpi_group;
850 new_hppi = true;
851 }
852 }
853 }
854 }
855
856 if (!new_hppi && cpuInterface->hppi.prio != 0xff &&
1/*
2 * Copyright (c) 2018 Metempsy Technology Consulting
3 * All rights reserved.
4 *
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions are
7 * met: redistributions of source code must retain the above copyright
8 * notice, this list of conditions and the following disclaimer;
9 * redistributions in binary form must reproduce the above copyright
10 * notice, this list of conditions and the following disclaimer in the
11 * documentation and/or other materials provided with the distribution;
12 * neither the name of the copyright holders nor the names of its
13 * contributors may be used to endorse or promote products derived from
14 * this software without specific prior written permission.
15 *
16 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
17 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
18 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
19 * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
20 * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
21 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
22 * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
23 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
24 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
25 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
26 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
27 *
28 * Authors: Jairo Balart
29 */
30
31#include "dev/arm/gic_v3_redistributor.hh"
32
33#include "arch/arm/utility.hh"
34#include "debug/GIC.hh"
35#include "dev/arm/gic_v3_cpu_interface.hh"
36#include "dev/arm/gic_v3_distributor.hh"
37#include "mem/fs_translating_port_proxy.hh"
38
39const AddrRange Gicv3Redistributor::GICR_IPRIORITYR(SGI_base + 0x0400,
40 SGI_base + 0x041f);
41
42Gicv3Redistributor::Gicv3Redistributor(Gicv3 * gic, uint32_t cpu_id)
43 : gic(gic),
44 distributor(nullptr),
45 cpuInterface(nullptr),
46 cpuId(cpu_id),
47 irqGroup(Gicv3::SGI_MAX + Gicv3::PPI_MAX),
48 irqEnabled(Gicv3::SGI_MAX + Gicv3::PPI_MAX),
49 irqPending(Gicv3::SGI_MAX + Gicv3::PPI_MAX),
50 irqActive(Gicv3::SGI_MAX + Gicv3::PPI_MAX),
51 irqPriority(Gicv3::SGI_MAX + Gicv3::PPI_MAX),
52 irqConfig(Gicv3::SGI_MAX + Gicv3::PPI_MAX),
53 irqGrpmod(Gicv3::SGI_MAX + Gicv3::PPI_MAX),
54 irqNsacr(Gicv3::SGI_MAX + Gicv3::PPI_MAX),
55 addrRangeSize(gic->params()->gicv4 ? 0x40000 : 0x20000)
56{
57}
58
59void
60Gicv3Redistributor::init()
61{
62 distributor = gic->getDistributor();
63 cpuInterface = gic->getCPUInterface(cpuId);
64}
65
66void
67Gicv3Redistributor::initState()
68{
69 reset();
70}
71
72void
73Gicv3Redistributor::reset()
74{
75 peInLowPowerState = true;
76 std::fill(irqGroup.begin(), irqGroup.end(), 0);
77 std::fill(irqEnabled.begin(), irqEnabled.end(), false);
78 std::fill(irqPending.begin(), irqPending.end(), false);
79 std::fill(irqActive.begin(), irqActive.end(), false);
80 std::fill(irqPriority.begin(), irqPriority.end(), 0);
81
82 // SGIs have edge-triggered behavior
83 for (uint32_t int_id = 0; int_id < Gicv3::SGI_MAX; int_id++) {
84 irqConfig[int_id] = Gicv3::INT_EDGE_TRIGGERED;
85 }
86
87 std::fill(irqGrpmod.begin(), irqGrpmod.end(), 0);
88 std::fill(irqNsacr.begin(), irqNsacr.end(), 0);
89 DPG1S = false;
90 DPG1NS = false;
91 DPG0 = false;
92 EnableLPIs = false;
93 lpiConfigurationTablePtr = 0;
94 lpiIDBits = 0;
95 lpiPendingTablePtr = 0;
96}
97
98uint64_t
99Gicv3Redistributor::read(Addr addr, size_t size, bool is_secure_access)
100{
101 if (GICR_IPRIORITYR.contains(addr)) { // Interrupt Priority Registers
102 uint64_t value = 0;
103 int first_intid = addr - GICR_IPRIORITYR.start();
104
105 for (int i = 0, int_id = first_intid; i < size; i++, int_id++) {
106 uint8_t prio = irqPriority[int_id];
107
108 if (!distributor->DS && !is_secure_access) {
109 if (getIntGroup(int_id) != Gicv3::G1NS) {
110 // RAZ/WI for non-secure accesses for secure interrupts
111 continue;
112 } else {
113 // NS view
114 prio = (prio << 1) & 0xff;
115 }
116 }
117
118 value |= prio << (i * 8);
119 }
120
121 return value;
122 }
123
124 switch (addr) {
125 case GICR_CTLR: { // Control Register
126 uint64_t value = 0;
127
128 if (DPG1S) {
129 value |= GICR_CTLR_DPG1S;
130 }
131
132 if (DPG1NS) {
133 value |= GICR_CTLR_DPG1NS;
134 }
135
136 if (DPG0) {
137 value |= GICR_CTLR_DPG0;
138 }
139
140 if (EnableLPIs) {
141 value |= GICR_CTLR_ENABLE_LPIS;
142 }
143
144 return value;
145 }
146
147 case GICR_IIDR: // Implementer Identification Register
148 //return 0x43b; // r0p0 GIC-500
149 return 0;
150
151 case GICR_TYPER: { // Type Register
152 /*
153 * Affinity_Value [63:32] == X
154 * (The identity of the PE associated with this Redistributor)
155 * CommonLPIAff [25:24] == 01
156 * (All Redistributors with the same Aff3 value must share an
157 * LPI Configuration table)
158 * Processor_Number [23:8] == X
159 * (A unique identifier for the PE)
160 * DPGS [5] == 1
161 * (GICR_CTLR.DPG* bits are supported)
162 * Last [4] == X
163 * (This Redistributor is the highest-numbered Redistributor in
164 * a series of contiguous Redistributor pages)
165 * DirectLPI [3] == 1
166 * (direct injection of LPIs supported)
167 * VLPIS [1] == 0
168 * (virtual LPIs not supported)
169 * PLPIS [0] == 1
170 * (physical LPIs supported)
171 */
172 uint64_t affinity = getAffinity();
173 int last = cpuId == (gic->getSystem()->numContexts() - 1);
174 return (affinity << 32) | (1 << 24) | (cpuId << 8) |
175 (1 << 5) | (last << 4) | (1 << 3) | (1 << 0);
176 }
177
178 case GICR_WAKER: // Wake Register
179 if (!distributor->DS && !is_secure_access) {
180 // RAZ/WI for non-secure accesses
181 return 0;
182 }
183
184 if (peInLowPowerState) {
185 return GICR_WAKER_ChildrenAsleep | GICR_WAKER_ProcessorSleep;
186 } else {
187 return 0;
188 }
189
190 case GICR_PIDR0: { // Peripheral ID0 Register
191 return 0x92; // Part number, bits[7:0]
192 }
193
194 case GICR_PIDR1: { // Peripheral ID1 Register
195 uint8_t des_0 = 0xB; // JEP106 identification code, bits[3:0]
196 uint8_t part_1 = 0x4; // Part number, bits[11:8]
197 return (des_0 << 4) | (part_1 << 0);
198 }
199
200 case GICR_PIDR2: { // Peripheral ID2 Register
201 uint8_t arch_rev = 0x3; // 0x3 GICv3
202 uint8_t jedec = 0x1; // JEP code
203 uint8_t des_1 = 0x3; // JEP106 identification code, bits[6:4]
204 return (arch_rev << 4) | (jedec << 3) | (des_1 << 0);
205 }
206
207 case GICR_PIDR3: // Peripheral ID3 Register
208 return 0x0; // Implementation defined
209
210 case GICR_PIDR4: { // Peripheral ID4 Register
211 uint8_t size = 0x4; // 64 KB software visible page
212 uint8_t des_2 = 0x4; // ARM implementation
213 return (size << 4) | (des_2 << 0);
214 }
215
216 case GICR_PIDR5: // Peripheral ID5 Register
217 case GICR_PIDR6: // Peripheral ID6 Register
218 case GICR_PIDR7: // Peripheral ID7 Register
219 return 0; // RES0
220
221 case GICR_IGROUPR0: { // Interrupt Group Register 0
222 uint64_t value = 0;
223
224 if (!distributor->DS && !is_secure_access) {
225 // RAZ/WI for non-secure accesses
226 return 0;
227 }
228
229 for (int int_id = 0; int_id < 8 * size; int_id++) {
230 value |= (irqGroup[int_id] << int_id);
231 }
232
233 return value;
234 }
235
236 case GICR_ISENABLER0: // Interrupt Set-Enable Register 0
237 case GICR_ICENABLER0: { // Interrupt Clear-Enable Register 0
238 uint64_t value = 0;
239
240 for (int int_id = 0; int_id < 8 * size; int_id++) {
241 if (!distributor->DS && !is_secure_access) {
242 // RAZ/WI for non-secure accesses for secure interrupts
243 if (getIntGroup(int_id) != Gicv3::G1NS) {
244 continue;
245 }
246 }
247
248 if (irqEnabled[int_id]) {
249 value |= (1 << int_id);
250 }
251 }
252
253 return value;
254 }
255
256 case GICR_ISPENDR0: // Interrupt Set-Pending Register 0
257 case GICR_ICPENDR0: { // Interrupt Clear-Pending Register 0
258 uint64_t value = 0;
259
260 for (int int_id = 0; int_id < 8 * size; int_id++) {
261 if (!distributor->DS && !is_secure_access) {
262 // RAZ/WI for non-secure accesses for secure interrupts
263 if (getIntGroup(int_id) != Gicv3::G1NS) {
264 continue;
265 }
266 }
267
268 value |= (irqPending[int_id] << int_id);
269 }
270
271 return value;
272 }
273
274 case GICR_ISACTIVER0: // Interrupt Set-Active Register 0
275 case GICR_ICACTIVER0: { // Interrupt Clear-Active Register 0
276 uint64_t value = 0;
277
278 for (int int_id = 0; int_id < 8 * size; int_id++) {
279 if (!distributor->DS && !is_secure_access) {
280 // RAZ/WI for non-secure accesses for secure interrupts
281 if (getIntGroup(int_id) != Gicv3::G1NS) {
282 continue;
283 }
284 }
285
286 value |= irqActive[int_id] << int_id;
287 }
288
289 return value;
290 }
291
292 case GICR_ICFGR0: // SGI Configuration Register
293 case GICR_ICFGR1: { // PPI Configuration Register
294 uint64_t value = 0;
295 uint32_t first_int_id = addr == GICR_ICFGR0 ? 0 : Gicv3::SGI_MAX;
296
297 for (int i = 0, int_id = first_int_id; i < 32;
298 i = i + 2, int_id++) {
299 if (!distributor->DS && !is_secure_access) {
300 // RAZ/WI for non-secure accesses for secure interrupts
301 if (getIntGroup(int_id) != Gicv3::G1NS) {
302 continue;
303 }
304 }
305
306 if (irqConfig[int_id] == Gicv3::INT_EDGE_TRIGGERED) {
307 value |= (0x2) << i;
308 }
309 }
310
311 return value;
312 }
313
314 case GICR_IGRPMODR0: { // Interrupt Group Modifier Register 0
315 uint64_t value = 0;
316
317 if (distributor->DS) {
318 value = 0;
319 } else {
320 if (!is_secure_access) {
321 // RAZ/WI for non-secure accesses
322 value = 0;
323 } else {
324 for (int int_id = 0; int_id < 8 * size; int_id++) {
325 value |= irqGrpmod[int_id] << int_id;
326 }
327 }
328 }
329
330 return value;
331 }
332
333 case GICR_NSACR: { // Non-secure Access Control Register
334 uint64_t value = 0;
335
336 if (distributor->DS) {
337 // RAZ/WI
338 value = 0;
339 } else {
340 if (!is_secure_access) {
341 // RAZ/WI
342 value = 0;
343 } else {
344 for (int i = 0, int_id = 0; i < 8 * size;
345 i = i + 2, int_id++) {
346 value |= irqNsacr[int_id] << i;
347 }
348 }
349 }
350
351 return value;
352 }
353
354 case GICR_PROPBASER: // Redistributor Properties Base Address Register
355 // OuterCache, bits [58:56]
356 // 000 Memory type defined in InnerCache field
357 // Physical_Address, bits [51:12]
358 // Bits [51:12] of the physical address containing the LPI
359 // Configuration table
360 // Shareability, bits [11:10]
361 // 00 Non-shareable
362 // InnerCache, bits [9:7]
363 // 000 Device-nGnRnE
364 // IDbits, bits [4:0]
365 // limited by GICD_TYPER.IDbits
366 return lpiConfigurationTablePtr | lpiIDBits;
367
368 // Redistributor LPI Pending Table Base Address Register
369 case GICR_PENDBASER:
370 // PTZ, bit [62]
371 // Pending Table Zero
372 // OuterCache, bits [58:56]
373 // 000 Memory type defined in InnerCache field
374 // Physical_Address, bits [51:16]
375 // Bits [51:16] of the physical address containing the LPI Pending
376 // table
377 // Shareability, bits [11:10]
378 // 00 Non-shareable
379 // InnerCache, bits [9:7]
380 // 000 Device-nGnRnE
381 return lpiPendingTablePtr;
382
383 // Redistributor Synchronize Register
384 case GICR_SYNCR:
385 return 0;
386
387 default:
388 panic("Gicv3Redistributor::read(): invalid offset %#x\n", addr);
389 break;
390 }
391}
392
393void
394Gicv3Redistributor::write(Addr addr, uint64_t data, size_t size,
395 bool is_secure_access)
396{
397 if (GICR_IPRIORITYR.contains(addr)) { // Interrupt Priority Registers
398 int first_intid = addr - GICR_IPRIORITYR.start();
399
400 for (int i = 0, int_id = first_intid; i < size; i++, int_id++) {
401 uint8_t prio = bits(data, (i + 1) * 8 - 1, (i * 8));
402
403 if (!distributor->DS && !is_secure_access) {
404 if (getIntGroup(int_id) != Gicv3::G1NS) {
405 // RAZ/WI for non-secure accesses for secure interrupts
406 continue;
407 } else {
408 // NS view
409 prio = 0x80 | (prio >> 1);
410 }
411 }
412
413 irqPriority[int_id] = prio;
414 DPRINTF(GIC, "Gicv3Redistributor::write(): "
415 "int_id %d priority %d\n", int_id, irqPriority[int_id]);
416 }
417
418 return;
419 }
420
421 switch (addr) {
422 case GICR_CTLR: {
423 // GICR_TYPER.LPIS is 0 so EnableLPIs is RES0
424 EnableLPIs = data & GICR_CTLR_ENABLE_LPIS;
425 DPG1S = data & GICR_CTLR_DPG1S;
426 DPG1NS = data & GICR_CTLR_DPG1NS;
427 DPG0 = data & GICR_CTLR_DPG0;
428 break;
429 }
430
431 case GICR_WAKER: // Wake Register
432 if (!distributor->DS && !is_secure_access) {
433 // RAZ/WI for non-secure accesses
434 return;
435 }
436
437 if (not peInLowPowerState and
438 (data & GICR_WAKER_ProcessorSleep)) {
439 DPRINTF(GIC, "Gicv3Redistributor::write(): "
440 "PE entering in low power state\n");
441 } else if (peInLowPowerState and
442 not(data & GICR_WAKER_ProcessorSleep)) {
443 DPRINTF(GIC, "Gicv3Redistributor::write(): powering up PE\n");
444 }
445
446 peInLowPowerState = data & GICR_WAKER_ProcessorSleep;
447 break;
448
449 case GICR_IGROUPR0: // Interrupt Group Register 0
450 if (!distributor->DS && !is_secure_access) {
451 // RAZ/WI for non-secure accesses
452 return;
453 }
454
455 for (int int_id = 0; int_id < 8 * size; int_id++) {
456 irqGroup[int_id] = data & (1 << int_id) ? 1 : 0;
457 DPRINTF(GIC, "Gicv3Redistributor::write(): "
458 "int_id %d group %d\n", int_id, irqGroup[int_id]);
459 }
460
461 break;
462
463 case GICR_ISENABLER0: // Interrupt Set-Enable Register 0
464 for (int int_id = 0; int_id < 8 * size; int_id++) {
465 if (!distributor->DS && !is_secure_access) {
466 // RAZ/WI for non-secure accesses for secure interrupts
467 if (getIntGroup(int_id) != Gicv3::G1NS) {
468 continue;
469 }
470 }
471
472 bool enable = data & (1 << int_id) ? 1 : 0;
473
474 if (enable) {
475 irqEnabled[int_id] = true;
476 }
477
478 DPRINTF(GIC, "Gicv3Redistributor::write(): "
479 "int_id %d enable %i\n", int_id, irqEnabled[int_id]);
480 }
481
482 break;
483
484 case GICR_ICENABLER0: // Interrupt Clear-Enable Register 0
485 for (int int_id = 0; int_id < 8 * size; int_id++) {
486 if (!distributor->DS && !is_secure_access) {
487 // RAZ/WI for non-secure accesses for secure interrupts
488 if (getIntGroup(int_id) != Gicv3::G1NS) {
489 continue;
490 }
491 }
492
493 bool disable = data & (1 << int_id) ? 1 : 0;
494
495 if (disable) {
496 irqEnabled[int_id] = false;
497 }
498
499 DPRINTF(GIC, "Gicv3Redistributor::write(): "
500 "int_id %d enable %i\n", int_id, irqEnabled[int_id]);
501 }
502
503 break;
504
505 case GICR_ISPENDR0: // Interrupt Set-Pending Register 0
506 for (int int_id = 0; int_id < 8 * size; int_id++) {
507 if (!distributor->DS && !is_secure_access) {
508 // RAZ/WI for non-secure accesses for secure interrupts
509 if (getIntGroup(int_id) != Gicv3::G1NS) {
510 continue;
511 }
512 }
513
514 bool pending = data & (1 << int_id) ? 1 : 0;
515
516 if (pending) {
517 DPRINTF(GIC, "Gicv3Redistributor::write() "
518 "(GICR_ISPENDR0): int_id %d (PPI) "
519 "pending bit set\n", int_id);
520 irqPending[int_id] = true;
521 }
522 }
523
524 updateAndInformCPUInterface();
525 break;
526
527 case GICR_ICPENDR0:// Interrupt Clear-Pending Register 0
528 for (int int_id = 0; int_id < 8 * size; int_id++) {
529 if (!distributor->DS && !is_secure_access) {
530 // RAZ/WI for non-secure accesses for secure interrupts
531 if (getIntGroup(int_id) != Gicv3::G1NS) {
532 continue;
533 }
534 }
535
536 bool clear = data & (1 << int_id) ? 1 : 0;
537
538 if (clear) {
539 irqPending[int_id] = false;
540 }
541 }
542
543 break;
544
545 case GICR_ISACTIVER0: // Interrupt Set-Active Register 0
546 for (int int_id = 0; int_id < 8 * size; int_id++) {
547 if (!distributor->DS && !is_secure_access) {
548 // RAZ/WI for non-secure accesses for secure interrupts
549 if (getIntGroup(int_id) != Gicv3::G1NS) {
550 continue;
551 }
552 }
553
554 bool activate = data & (1 << int_id) ? 1 : 0;
555
556 if (activate) {
557 if (!irqActive[int_id]) {
558 DPRINTF(GIC, "Gicv3Redistributor::write(): "
559 "int_id %d active set\n", int_id);
560 }
561
562 irqActive[int_id] = true;
563 }
564 }
565
566 break;
567
568 case GICR_ICACTIVER0: // Interrupt Clear-Active Register 0
569 for (int int_id = 0; int_id < 8 * size; int_id++) {
570 if (!distributor->DS && !is_secure_access) {
571 // RAZ/WI for non-secure accesses for secure interrupts
572 if (getIntGroup(int_id) != Gicv3::G1NS) {
573 continue;
574 }
575 }
576
577 bool clear = data & (1 << int_id) ? 1 : 0;
578
579 if (clear) {
580 if (irqActive[int_id]) {
581 DPRINTF(GIC, "Gicv3Redistributor::write(): "
582 "int_id %d active cleared\n", int_id);
583 }
584
585 irqActive[int_id] = false;
586 }
587 }
588
589 break;
590
591 case GICR_ICFGR1: { // PPI Configuration Register
592 int first_intid = Gicv3::SGI_MAX;
593
594 for (int i = 0, int_id = first_intid; i < 8 * size;
595 i = i + 2, int_id++) {
596 if (!distributor->DS && !is_secure_access) {
597 // RAZ/WI for non-secure accesses for secure interrupts
598 if (getIntGroup(int_id) != Gicv3::G1NS) {
599 continue;
600 }
601 }
602
603 irqConfig[int_id] = data & (0x2 << i) ?
604 Gicv3::INT_EDGE_TRIGGERED :
605 Gicv3::INT_LEVEL_SENSITIVE;
606 DPRINTF(GIC, "Gicv3Redistributor::write(): "
607 "int_id %d (PPI) config %d\n",
608 int_id, irqConfig[int_id]);
609 }
610
611 break;
612 }
613
614 case GICR_IGRPMODR0: { // Interrupt Group Modifier Register 0
615 if (distributor->DS) {
616 // RAZ/WI if secutiry disabled
617 } else {
618 for (int int_id = 0; int_id < 8 * size; int_id++) {
619 if (!is_secure_access) {
620 // RAZ/WI for non-secure accesses
621 continue;
622 }
623
624 irqGrpmod[int_id] = data & (1 << int_id);
625 }
626 }
627
628 break;
629 }
630
631 case GICR_NSACR: { // Non-secure Access Control Register
632 if (distributor->DS) {
633 // RAZ/WI
634 } else {
635 if (!is_secure_access) {
636 // RAZ/WI
637 } else {
638 for (int i = 0, int_id = 0; i < 8 * size;
639 i = i + 2, int_id++) {
640 irqNsacr[int_id] = (data >> i) & 0x3;
641 }
642 }
643 }
644
645 break;
646 }
647
648 case GICR_SETLPIR: // Set LPI Pending Register
649 setClrLPI(data, true);
650 break;
651
652 case GICR_CLRLPIR: // Clear LPI Pending Register
653 setClrLPI(data, false);
654 break;
655
656 case GICR_PROPBASER: { // Redistributor Properties Base Address Register
657 // OuterCache, bits [58:56]
658 // 000 Memory type defined in InnerCache field
659 // Physical_Address, bits [51:12]
660 // Bits [51:12] of the physical address containing the LPI
661 // Configuration table
662 // Shareability, bits [11:10]
663 // 00 Non-shareable
664 // InnerCache, bits [9:7]
665 // 000 Device-nGnRnE
666 // IDbits, bits [4:0]
667 // limited by GICD_TYPER.IDbits (= 0xf)
668 lpiConfigurationTablePtr = data & 0xFFFFFFFFFF000;
669 lpiIDBits = data & 0x1f;
670
671 // 0xf here matches the value of GICD_TYPER.IDbits.
672 // TODO - make GICD_TYPER.IDbits a parameter instead of a hardcoded
673 // value
674 if (lpiIDBits > 0xf) {
675 lpiIDBits = 0xf;
676 }
677
678 break;
679 }
680
681 // Redistributor LPI Pending Table Base Address Register
682 case GICR_PENDBASER:
683 // PTZ, bit [62]
684 // Pending Table Zero
685 // OuterCache, bits [58:56]
686 // 000 Memory type defined in InnerCache field
687 // Physical_Address, bits [51:16]
688 // Bits [51:16] of the physical address containing the LPI Pending
689 // table
690 // Shareability, bits [11:10]
691 // 00 Non-shareable
692 // InnerCache, bits [9:7]
693 // 000 Device-nGnRnE
694 lpiPendingTablePtr = data & 0xFFFFFFFFF0000;
695 break;
696
697 case GICR_INVLPIR: { // Redistributor Invalidate LPI Register
698 // Do nothing: no caching supported
699 break;
700 }
701
702 case GICR_INVALLR: { // Redistributor Invalidate All Register
703 // Do nothing: no caching supported
704 break;
705 }
706
707 default:
708 panic("Gicv3Redistributor::write(): invalid offset %#x\n", addr);
709 break;
710 }
711}
712
713void
714Gicv3Redistributor::sendPPInt(uint32_t int_id)
715{
716 assert((int_id >= Gicv3::SGI_MAX) &&
717 (int_id < Gicv3::SGI_MAX + Gicv3::PPI_MAX));
718 irqPending[int_id] = true;
719 DPRINTF(GIC, "Gicv3Redistributor::sendPPInt(): "
720 "int_id %d (PPI) pending bit set\n", int_id);
721 updateAndInformCPUInterface();
722}
723
724void
725Gicv3Redistributor::sendSGI(uint32_t int_id, Gicv3::GroupId group, bool ns)
726{
727 assert(int_id < Gicv3::SGI_MAX);
728 Gicv3::GroupId int_group = getIntGroup(int_id);
729
730 // asked for secure group 1
731 // configured as group 0
732 // send group 0
733 if (int_group == Gicv3::G0S && group == Gicv3::G1S) {
734 group = Gicv3::G0S;
735 }
736
737 if (group == Gicv3::G0S and int_group != Gicv3::G0S) {
738 return;
739 }
740
741 if (ns && distributor->DS == 0) {
742 int nsaccess = irqNsacr[int_id];
743
744 if ((int_group == Gicv3::G0S && nsaccess < 1) ||
745 (int_group == Gicv3::G1S && nsaccess < 2)) {
746 return;
747 }
748 }
749
750 irqPending[int_id] = true;
751 DPRINTF(GIC, "Gicv3ReDistributor::sendSGI(): "
752 "int_id %d (SGI) pending bit set\n", int_id);
753 updateAndInformCPUInterface();
754}
755
756Gicv3::IntStatus
757Gicv3Redistributor::intStatus(uint32_t int_id) const
758{
759 assert(int_id < Gicv3::SGI_MAX + Gicv3::PPI_MAX);
760
761 if (irqPending[int_id]) {
762 if (irqActive[int_id]) {
763 return Gicv3::INT_ACTIVE_PENDING;
764 }
765
766 return Gicv3::INT_PENDING;
767 } else if (irqActive[int_id]) {
768 return Gicv3::INT_ACTIVE;
769 } else {
770 return Gicv3::INT_INACTIVE;
771 }
772}
773
774/*
775 * Recalculate the highest priority pending interrupt after a
776 * change to redistributor state.
777 */
778void
779Gicv3Redistributor::update()
780{
781 bool new_hppi = false;
782
783 for (int int_id = 0; int_id < Gicv3::SGI_MAX + Gicv3::PPI_MAX; int_id++) {
784 Gicv3::GroupId int_group = getIntGroup(int_id);
785 bool group_enabled = distributor->groupEnabled(int_group);
786
787 if (irqPending[int_id] && irqEnabled[int_id] &&
788 !irqActive[int_id] && group_enabled) {
789 if ((irqPriority[int_id] < cpuInterface->hppi.prio) ||
790 /*
791 * Multiple pending ints with same priority.
792 * Implementation choice which one to signal.
793 * Our implementation selects the one with the lower id.
794 */
795 (irqPriority[int_id] == cpuInterface->hppi.prio &&
796 int_id < cpuInterface->hppi.intid)) {
797 cpuInterface->hppi.intid = int_id;
798 cpuInterface->hppi.prio = irqPriority[int_id];
799 cpuInterface->hppi.group = int_group;
800 new_hppi = true;
801 }
802 }
803 }
804
805 // Check LPIs
806 if (EnableLPIs) {
807 ThreadContext * tc = gic->getSystem()->getThreadContext(cpuId);
808
809 const uint32_t largest_lpi_id = 1 << (lpiIDBits + 1);
810 const uint32_t number_lpis = largest_lpi_id - SMALLEST_LPI_ID + 1;
811
812 uint8_t lpi_pending_table[largest_lpi_id / 8];
813 uint8_t lpi_config_table[number_lpis];
814
815 tc->getPhysProxy().readBlob(lpiPendingTablePtr,
816 (uint8_t *) lpi_pending_table,
817 sizeof(lpi_pending_table));
818
819 tc->getPhysProxy().readBlob(lpiConfigurationTablePtr,
820 (uint8_t*) lpi_config_table,
821 sizeof(lpi_config_table));
822
823 for (int lpi_id = SMALLEST_LPI_ID; lpi_id < largest_lpi_id;
824 lpi_id++) {
825 uint32_t lpi_pending_entry_byte = lpi_id / 8;
826 uint8_t lpi_pending_entry_bit_position = lpi_id % 8;
827 bool lpi_is_pending = lpi_pending_table[lpi_pending_entry_byte] &
828 1 << lpi_pending_entry_bit_position;
829 uint32_t lpi_configuration_entry_index = lpi_id - SMALLEST_LPI_ID;
830
831 LPIConfigurationTableEntry config_entry =
832 lpi_config_table[lpi_configuration_entry_index];
833
834 bool lpi_is_enable = config_entry.enable;
835
836 // LPIs are always Non-secure Group 1 interrupts,
837 // in a system where two Security states are enabled.
838 Gicv3::GroupId lpi_group = Gicv3::G1NS;
839 bool group_enabled = distributor->groupEnabled(lpi_group);
840
841 if (lpi_is_pending && lpi_is_enable && group_enabled) {
842 uint8_t lpi_priority = config_entry.priority << 2;
843
844 if ((lpi_priority < cpuInterface->hppi.prio) ||
845 (lpi_priority == cpuInterface->hppi.prio &&
846 lpi_id < cpuInterface->hppi.intid)) {
847 cpuInterface->hppi.intid = lpi_id;
848 cpuInterface->hppi.prio = lpi_priority;
849 cpuInterface->hppi.group = lpi_group;
850 new_hppi = true;
851 }
852 }
853 }
854 }
855
856 if (!new_hppi && cpuInterface->hppi.prio != 0xff &&
857 cpuInterface->hppi.intid < Gicv3::SGI_MAX + Gicv3::PPI_MAX) {
857 (cpuInterface->hppi.intid < Gicv3::SGI_MAX + Gicv3::PPI_MAX ||
858 cpuInterface->hppi.intid > SMALLEST_LPI_ID)) {
858 distributor->fullUpdate();
859 }
860}
861
862void
863Gicv3Redistributor::setClrLPI(uint64_t data, bool set)
864{
865 if (!EnableLPIs) {
866 // Writes to GICR_SETLPIR or GICR_CLRLPIR have not effect if
867 // GICR_CTLR.EnableLPIs == 0.
868 return;
869 }
870
871 uint32_t lpi_id = data & 0xffffffff;
872 uint32_t largest_lpi_id = 1 << (lpiIDBits + 1);
873
874 if (lpi_id > largest_lpi_id) {
875 // Writes to GICR_SETLPIR or GICR_CLRLPIR have not effect if
876 // pINTID value specifies an unimplemented LPI.
877 return;
878 }
879
880 Addr lpi_pending_entry_ptr = lpiPendingTablePtr + (lpi_id / 8);
881 uint8_t lpi_pending_entry;
882 ThreadContext * tc = gic->getSystem()->getThreadContext(cpuId);
883 tc->getPhysProxy().readBlob(lpi_pending_entry_ptr,
884 (uint8_t*) &lpi_pending_entry,
885 sizeof(lpi_pending_entry));
886 uint8_t lpi_pending_entry_bit_position = lpi_id % 8;
887 bool is_set = lpi_pending_entry & (1 << lpi_pending_entry_bit_position);
888
889 if (set) {
890 if (is_set) {
891 // Writes to GICR_SETLPIR have not effect if the pINTID field
892 // corresponds to an LPI that is already pending.
893 return;
894 }
895
896 lpi_pending_entry |= 1 << (lpi_pending_entry_bit_position);
897 } else {
898 if (!is_set) {
899 // Writes to GICR_SETLPIR have not effect if the pINTID field
900 // corresponds to an LPI that is not pending.
901 return;
902 }
903
904 lpi_pending_entry &= ~(1 << (lpi_pending_entry_bit_position));
905 }
906
907 tc->getPhysProxy().writeBlob(lpi_pending_entry_ptr,
908 (uint8_t*) &lpi_pending_entry,
909 sizeof(lpi_pending_entry));
910 updateAndInformCPUInterface();
911}
912
913void
914Gicv3Redistributor::updateAndInformCPUInterface()
915{
916 update();
917 cpuInterface->update();
918}
919
920Gicv3::GroupId
921Gicv3Redistributor::getIntGroup(int int_id) const
922{
923 assert(int_id < (Gicv3::SGI_MAX + Gicv3::PPI_MAX));
924
925 if (distributor->DS) {
926 if (irqGroup[int_id] == 0) {
927 return Gicv3::G0S;
928 } else {
929 return Gicv3::G1NS;
930 }
931 } else {
932 if (irqGrpmod[int_id] == 0 && irqGroup[int_id] == 0) {
933 return Gicv3::G0S;
934 } else if (irqGrpmod[int_id] == 0 && irqGroup[int_id] == 1) {
935 return Gicv3::G1NS;
936 } else if (irqGrpmod[int_id] == 1 && irqGroup[int_id] == 0) {
937 return Gicv3::G1S;
938 } else if (irqGrpmod[int_id] == 1 && irqGroup[int_id] == 1) {
939 return Gicv3::G1NS;
940 }
941 }
942
943 M5_UNREACHABLE;
944}
945
946void
947Gicv3Redistributor::activateIRQ(uint32_t int_id)
948{
949 irqPending[int_id] = false;
950 irqActive[int_id] = true;
951}
952
953void
954Gicv3Redistributor::deactivateIRQ(uint32_t int_id)
955{
956 irqActive[int_id] = false;
957}
958
959uint32_t
960Gicv3Redistributor::getAffinity() const
961{
962 ThreadContext * tc = gic->getSystem()->getThreadContext(cpuId);
963 uint64_t mpidr = getMPIDR(gic->getSystem(), tc);
964 /*
965 * Aff3 = MPIDR[39:32]
966 * (Note getMPIDR() returns uint32_t so Aff3 is always 0...)
967 * Aff2 = MPIDR[23:16]
968 * Aff1 = MPIDR[15:8]
969 * Aff0 = MPIDR[7:0]
970 * affinity = Aff3.Aff2.Aff1.Aff0
971 */
972 uint64_t affinity = ((mpidr & 0xff00000000) >> 8) | (mpidr & (0xffffff));
973 return affinity;
974}
975
976bool
977Gicv3Redistributor::canBeSelectedFor1toNInterrupt(Gicv3::GroupId group) const
978{
979 if (peInLowPowerState) {
980 return false;
981 }
982
983 if (!distributor->groupEnabled(group)) {
984 return false;
985 }
986
987 if ((group == Gicv3::G1S) && DPG1S) {
988 return false;
989 }
990
991 if ((group == Gicv3::G1NS) && DPG1NS) {
992 return false;
993 }
994
995 if ((group == Gicv3::G0S) && DPG0) {
996 return false;
997 }
998
999 return true;
1000}
1001
1002void
1003Gicv3Redistributor::serialize(CheckpointOut & cp) const
1004{
1005 SERIALIZE_SCALAR(peInLowPowerState);
1006 SERIALIZE_CONTAINER(irqGroup);
1007 SERIALIZE_CONTAINER(irqEnabled);
1008 SERIALIZE_CONTAINER(irqPending);
1009 SERIALIZE_CONTAINER(irqActive);
1010 SERIALIZE_CONTAINER(irqPriority);
1011 SERIALIZE_CONTAINER(irqConfig);
1012 SERIALIZE_CONTAINER(irqGrpmod);
1013 SERIALIZE_CONTAINER(irqNsacr);
1014 SERIALIZE_SCALAR(DPG1S);
1015 SERIALIZE_SCALAR(DPG1NS);
1016 SERIALIZE_SCALAR(DPG0);
1017 SERIALIZE_SCALAR(EnableLPIs);
1018 SERIALIZE_SCALAR(lpiConfigurationTablePtr);
1019 SERIALIZE_SCALAR(lpiIDBits);
1020 SERIALIZE_SCALAR(lpiPendingTablePtr);
1021}
1022
1023void
1024Gicv3Redistributor::unserialize(CheckpointIn & cp)
1025{
1026 UNSERIALIZE_SCALAR(peInLowPowerState);
1027 UNSERIALIZE_CONTAINER(irqGroup);
1028 UNSERIALIZE_CONTAINER(irqEnabled);
1029 UNSERIALIZE_CONTAINER(irqPending);
1030 UNSERIALIZE_CONTAINER(irqActive);
1031 UNSERIALIZE_CONTAINER(irqPriority);
1032 UNSERIALIZE_CONTAINER(irqConfig);
1033 UNSERIALIZE_CONTAINER(irqGrpmod);
1034 UNSERIALIZE_CONTAINER(irqNsacr);
1035 UNSERIALIZE_SCALAR(DPG1S);
1036 UNSERIALIZE_SCALAR(DPG1NS);
1037 UNSERIALIZE_SCALAR(DPG0);
1038 UNSERIALIZE_SCALAR(EnableLPIs);
1039 UNSERIALIZE_SCALAR(lpiConfigurationTablePtr);
1040 UNSERIALIZE_SCALAR(lpiIDBits);
1041 UNSERIALIZE_SCALAR(lpiPendingTablePtr);
1042}
859 distributor->fullUpdate();
860 }
861}
862
863void
864Gicv3Redistributor::setClrLPI(uint64_t data, bool set)
865{
866 if (!EnableLPIs) {
867 // Writes to GICR_SETLPIR or GICR_CLRLPIR have not effect if
868 // GICR_CTLR.EnableLPIs == 0.
869 return;
870 }
871
872 uint32_t lpi_id = data & 0xffffffff;
873 uint32_t largest_lpi_id = 1 << (lpiIDBits + 1);
874
875 if (lpi_id > largest_lpi_id) {
876 // Writes to GICR_SETLPIR or GICR_CLRLPIR have not effect if
877 // pINTID value specifies an unimplemented LPI.
878 return;
879 }
880
881 Addr lpi_pending_entry_ptr = lpiPendingTablePtr + (lpi_id / 8);
882 uint8_t lpi_pending_entry;
883 ThreadContext * tc = gic->getSystem()->getThreadContext(cpuId);
884 tc->getPhysProxy().readBlob(lpi_pending_entry_ptr,
885 (uint8_t*) &lpi_pending_entry,
886 sizeof(lpi_pending_entry));
887 uint8_t lpi_pending_entry_bit_position = lpi_id % 8;
888 bool is_set = lpi_pending_entry & (1 << lpi_pending_entry_bit_position);
889
890 if (set) {
891 if (is_set) {
892 // Writes to GICR_SETLPIR have not effect if the pINTID field
893 // corresponds to an LPI that is already pending.
894 return;
895 }
896
897 lpi_pending_entry |= 1 << (lpi_pending_entry_bit_position);
898 } else {
899 if (!is_set) {
900 // Writes to GICR_SETLPIR have not effect if the pINTID field
901 // corresponds to an LPI that is not pending.
902 return;
903 }
904
905 lpi_pending_entry &= ~(1 << (lpi_pending_entry_bit_position));
906 }
907
908 tc->getPhysProxy().writeBlob(lpi_pending_entry_ptr,
909 (uint8_t*) &lpi_pending_entry,
910 sizeof(lpi_pending_entry));
911 updateAndInformCPUInterface();
912}
913
914void
915Gicv3Redistributor::updateAndInformCPUInterface()
916{
917 update();
918 cpuInterface->update();
919}
920
921Gicv3::GroupId
922Gicv3Redistributor::getIntGroup(int int_id) const
923{
924 assert(int_id < (Gicv3::SGI_MAX + Gicv3::PPI_MAX));
925
926 if (distributor->DS) {
927 if (irqGroup[int_id] == 0) {
928 return Gicv3::G0S;
929 } else {
930 return Gicv3::G1NS;
931 }
932 } else {
933 if (irqGrpmod[int_id] == 0 && irqGroup[int_id] == 0) {
934 return Gicv3::G0S;
935 } else if (irqGrpmod[int_id] == 0 && irqGroup[int_id] == 1) {
936 return Gicv3::G1NS;
937 } else if (irqGrpmod[int_id] == 1 && irqGroup[int_id] == 0) {
938 return Gicv3::G1S;
939 } else if (irqGrpmod[int_id] == 1 && irqGroup[int_id] == 1) {
940 return Gicv3::G1NS;
941 }
942 }
943
944 M5_UNREACHABLE;
945}
946
947void
948Gicv3Redistributor::activateIRQ(uint32_t int_id)
949{
950 irqPending[int_id] = false;
951 irqActive[int_id] = true;
952}
953
954void
955Gicv3Redistributor::deactivateIRQ(uint32_t int_id)
956{
957 irqActive[int_id] = false;
958}
959
960uint32_t
961Gicv3Redistributor::getAffinity() const
962{
963 ThreadContext * tc = gic->getSystem()->getThreadContext(cpuId);
964 uint64_t mpidr = getMPIDR(gic->getSystem(), tc);
965 /*
966 * Aff3 = MPIDR[39:32]
967 * (Note getMPIDR() returns uint32_t so Aff3 is always 0...)
968 * Aff2 = MPIDR[23:16]
969 * Aff1 = MPIDR[15:8]
970 * Aff0 = MPIDR[7:0]
971 * affinity = Aff3.Aff2.Aff1.Aff0
972 */
973 uint64_t affinity = ((mpidr & 0xff00000000) >> 8) | (mpidr & (0xffffff));
974 return affinity;
975}
976
977bool
978Gicv3Redistributor::canBeSelectedFor1toNInterrupt(Gicv3::GroupId group) const
979{
980 if (peInLowPowerState) {
981 return false;
982 }
983
984 if (!distributor->groupEnabled(group)) {
985 return false;
986 }
987
988 if ((group == Gicv3::G1S) && DPG1S) {
989 return false;
990 }
991
992 if ((group == Gicv3::G1NS) && DPG1NS) {
993 return false;
994 }
995
996 if ((group == Gicv3::G0S) && DPG0) {
997 return false;
998 }
999
1000 return true;
1001}
1002
1003void
1004Gicv3Redistributor::serialize(CheckpointOut & cp) const
1005{
1006 SERIALIZE_SCALAR(peInLowPowerState);
1007 SERIALIZE_CONTAINER(irqGroup);
1008 SERIALIZE_CONTAINER(irqEnabled);
1009 SERIALIZE_CONTAINER(irqPending);
1010 SERIALIZE_CONTAINER(irqActive);
1011 SERIALIZE_CONTAINER(irqPriority);
1012 SERIALIZE_CONTAINER(irqConfig);
1013 SERIALIZE_CONTAINER(irqGrpmod);
1014 SERIALIZE_CONTAINER(irqNsacr);
1015 SERIALIZE_SCALAR(DPG1S);
1016 SERIALIZE_SCALAR(DPG1NS);
1017 SERIALIZE_SCALAR(DPG0);
1018 SERIALIZE_SCALAR(EnableLPIs);
1019 SERIALIZE_SCALAR(lpiConfigurationTablePtr);
1020 SERIALIZE_SCALAR(lpiIDBits);
1021 SERIALIZE_SCALAR(lpiPendingTablePtr);
1022}
1023
1024void
1025Gicv3Redistributor::unserialize(CheckpointIn & cp)
1026{
1027 UNSERIALIZE_SCALAR(peInLowPowerState);
1028 UNSERIALIZE_CONTAINER(irqGroup);
1029 UNSERIALIZE_CONTAINER(irqEnabled);
1030 UNSERIALIZE_CONTAINER(irqPending);
1031 UNSERIALIZE_CONTAINER(irqActive);
1032 UNSERIALIZE_CONTAINER(irqPriority);
1033 UNSERIALIZE_CONTAINER(irqConfig);
1034 UNSERIALIZE_CONTAINER(irqGrpmod);
1035 UNSERIALIZE_CONTAINER(irqNsacr);
1036 UNSERIALIZE_SCALAR(DPG1S);
1037 UNSERIALIZE_SCALAR(DPG1NS);
1038 UNSERIALIZE_SCALAR(DPG0);
1039 UNSERIALIZE_SCALAR(EnableLPIs);
1040 UNSERIALIZE_SCALAR(lpiConfigurationTablePtr);
1041 UNSERIALIZE_SCALAR(lpiIDBits);
1042 UNSERIALIZE_SCALAR(lpiPendingTablePtr);
1043}