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