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