diff options
Diffstat (limited to 'src/dev/arm/gic_v3_redistributor.cc')
-rw-r--r-- | src/dev/arm/gic_v3_redistributor.cc | 834 |
1 files changed, 834 insertions, 0 deletions
diff --git a/src/dev/arm/gic_v3_redistributor.cc b/src/dev/arm/gic_v3_redistributor.cc new file mode 100644 index 000000000..ec1e388c7 --- /dev/null +++ b/src/dev/arm/gic_v3_redistributor.cc @@ -0,0 +1,834 @@ +/* + * Copyright (c) 2018 Metempsy Technology Consulting + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are + * met: redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer; + * redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution; + * neither the name of the copyright holders nor the names of its + * contributors may be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * Authors: Jairo Balart + */ + +#include "dev/arm/gic_v3_redistributor.hh" + +#include "arch/arm/utility.hh" +#include "debug/GIC.hh" +#include "dev/arm/gic_v3_cpu_interface.hh" +#include "dev/arm/gic_v3_distributor.hh" + +const AddrRange Gicv3Redistributor::GICR_IPRIORITYR(SGI_base + 0x0400, + SGI_base + 0x041f); + +Gicv3Redistributor::Gicv3Redistributor(Gicv3 * gic, uint32_t cpu_id) + : gic(gic), + distributor(nullptr), + cpuInterface(nullptr), + cpuId(cpu_id), + irqGroup(Gicv3::SGI_MAX + Gicv3::PPI_MAX), + irqEnabled(Gicv3::SGI_MAX + Gicv3::PPI_MAX), + irqPending(Gicv3::SGI_MAX + Gicv3::PPI_MAX), + irqActive(Gicv3::SGI_MAX + Gicv3::PPI_MAX), + irqPriority(Gicv3::SGI_MAX + Gicv3::PPI_MAX), + irqConfig(Gicv3::SGI_MAX + Gicv3::PPI_MAX), + irqGrpmod(Gicv3::SGI_MAX + Gicv3::PPI_MAX), + irqNsacr(Gicv3::SGI_MAX + Gicv3::PPI_MAX) +{ +} + +Gicv3Redistributor::~Gicv3Redistributor() +{ +} + +void +Gicv3Redistributor::init() +{ + distributor = gic->getDistributor(); + cpuInterface = gic->getCPUInterface(cpuId); +} + +void +Gicv3Redistributor::initState() +{ + reset(); +} + +void +Gicv3Redistributor::reset() +{ + peInLowPowerState = true; + std::fill(irqGroup.begin(), irqGroup.end(), 0); + std::fill(irqEnabled.begin(), irqEnabled.end(), false); + std::fill(irqPending.begin(), irqPending.end(), false); + std::fill(irqActive.begin(), irqActive.end(), false); + std::fill(irqPriority.begin(), irqPriority.end(), 0); + + // SGIs have edge-triggered behavior + for (uint32_t int_id = 0; int_id < Gicv3::SGI_MAX; int_id++) { + irqConfig[int_id] = Gicv3::INT_EDGE_TRIGGERED; + } + + std::fill(irqGrpmod.begin(), irqGrpmod.end(), 0); + std::fill(irqNsacr.begin(), irqNsacr.end(), 0); + DPG1S = false; + DPG1NS = false; + DPG0 = false; +} + +uint64_t +Gicv3Redistributor::read(Addr addr, size_t size, bool is_secure_access) +{ + if (GICR_IPRIORITYR.contains(addr)) { // Interrupt Priority Registers + uint64_t value = 0; + int first_intid = addr - GICR_IPRIORITYR.start(); + + for (int i = 0, int_id = first_intid; i < size; i++, int_id++) { + uint8_t prio = irqPriority[int_id]; + + if (!distributor->DS && !is_secure_access) { + if (getIntGroup(int_id) != Gicv3::G1NS) { + // RAZ/WI for non-secure accesses for secure interrupts + continue; + } else { + // NS view + prio = (prio << 1) & 0xff; + } + } + + value |= prio << (i * 8); + } + + return value; + } + + switch (addr) { + case GICR_CTLR: { // Control Register + uint64_t value = 0; + + if (DPG1S) { + value |= GICR_CTLR_DPG1S; + } + + if (DPG1NS) { + value |= GICR_CTLR_DPG1NS; + } + + if (DPG0) { + value |= GICR_CTLR_DPG0; + } + + return value; + } + + case GICR_IIDR: // Implementer Identification Register + //return 0x43b; // r0p0 GIC-500 + return 0; + + case GICR_TYPER: { // Type Register + /* + * Affinity_Value [63:32] == X + * (The identity of the PE associated with this Redistributor) + * CommonLPIAff [25:24] == 01 + * (All Redistributors with the same Aff3 value must share an + * LPI Configuration table) + * Processor_Number [23:8] == X + * (A unique identifier for the PE) + * DPGS [5] == 1 + * (GICR_CTLR.DPG* bits are supported) + * Last [4] == X + * (This Redistributor is the highest-numbered Redistributor in + * a series of contiguous Redistributor pages) + * DirectLPI [3] == 0 + * (direct injection of LPIs not supported) + * VLPIS [1] == 0 + * (virtual LPIs not supported) + * PLPIS [0] == 0 + * (physical LPIs not supported) + */ + uint64_t affinity = getAffinity(); + int last = cpuId == (gic->getSystem()->numContexts() - 1); + return (affinity << 32) | (1 << 24) | (cpuId << 8) | + (1 << 5) | (last << 4); + } + + case GICR_WAKER: // Wake Register + if (!distributor->DS && !is_secure_access) { + // RAZ/WI for non-secure accesses + return 0; + } + + if (peInLowPowerState) { + return GICR_WAKER_ChildrenAsleep | GICR_WAKER_ProcessorSleep; + } else { + return 0; + } + + case GICR_PIDR0: { // Peripheral ID0 Register + uint8_t part_0 = 0x92; // Part number, bits[7:0] + return part_0; + } + + case GICR_PIDR1: { // Peripheral ID1 Register + uint8_t des_0 = 0xB; // JEP106 identification code, bits[3:0] + uint8_t part_1 = 0x4; // Part number, bits[11:8] + return (des_0 << 4) | (part_1 << 0); + } + + case GICR_PIDR2: { // Peripheral ID2 Register + uint8_t arch_rev = 0x3; // 0x3 GICv3 + uint8_t jedec = 0x1; // JEP code + uint8_t des_1 = 0x3; // JEP106 identification code, bits[6:4] + return (arch_rev << 4) | (jedec << 3) | (des_1 << 0); + } + + case GICR_PIDR3: // Peripheral ID3 Register + return 0x0; // Implementation defined + + case GICR_PIDR4: { // Peripheral ID4 Register + uint8_t size = 0x4; // 64 KB software visible page + uint8_t des_2 = 0x4; // ARM implementation + return (size << 4) | (des_2 << 0); + } + + case GICR_PIDR5: // Peripheral ID5 Register + case GICR_PIDR6: // Peripheral ID6 Register + case GICR_PIDR7: // Peripheral ID7 Register + return 0; // RES0 + + case GICR_IGROUPR0: { // Interrupt Group Register 0 + uint64_t value = 0; + + if (!distributor->DS && !is_secure_access) { + // RAZ/WI for non-secure accesses + return 0; + } + + for (int int_id = 0; int_id < 8 * size; int_id++) { + value |= (irqGroup[int_id] << int_id); + } + + return value; + } + + case GICR_ISENABLER0: // Interrupt Set-Enable Register 0 + case GICR_ICENABLER0: { // Interrupt Clear-Enable Register 0 + uint64_t value = 0; + + for (int int_id = 0; int_id < 8 * size; int_id++) { + if (!distributor->DS && !is_secure_access) { + // RAZ/WI for non-secure accesses for secure interrupts + if (getIntGroup(int_id) != Gicv3::G1NS) { + continue; + } + } + + if (irqEnabled[int_id]) { + value |= (1 << int_id); + } + } + + return value; + } + + case GICR_ISPENDR0: // Interrupt Set-Pending Register 0 + case GICR_ICPENDR0: { // Interrupt Clear-Pending Register 0 + uint64_t value = 0; + + for (int int_id = 0; int_id < 8 * size; int_id++) { + if (!distributor->DS && !is_secure_access) { + // RAZ/WI for non-secure accesses for secure interrupts + if (getIntGroup(int_id) != Gicv3::G1NS) { + continue; + } + } + + value |= (irqPending[int_id] << int_id); + } + + return value; + } + + case GICR_ISACTIVER0: // Interrupt Set-Active Register 0 + case GICR_ICACTIVER0: { // Interrupt Clear-Active Register 0 + uint64_t value = 0; + + for (int int_id = 0; int_id < 8 * size; int_id++) { + if (!distributor->DS && !is_secure_access) { + // RAZ/WI for non-secure accesses for secure interrupts + if (getIntGroup(int_id) != Gicv3::G1NS) { + continue; + } + } + + value |= irqActive[int_id] << int_id; + } + + return value; + } + + case GICR_ICFGR0: // SGI Configuration Register + case GICR_ICFGR1: { // PPI Configuration Register + uint64_t value = 0; + uint32_t first_int_id = addr == GICR_ICFGR0 ? 0 : Gicv3::SGI_MAX; + + for (int i = 0, int_id = first_int_id; i < 32; + i = i + 2, int_id++) { + if (!distributor->DS && !is_secure_access) { + // RAZ/WI for non-secure accesses for secure interrupts + if (getIntGroup(int_id) != Gicv3::G1NS) { + continue; + } + } + + if (irqConfig[int_id] == Gicv3::INT_EDGE_TRIGGERED) { + value |= (0x2) << i; + } + } + + return value; + } + + case GICR_IGRPMODR0: { // Interrupt Group Modifier Register 0 + uint64_t value = 0; + + if (distributor->DS) { + value = 0; + } else { + if (!is_secure_access) { + // RAZ/WI for non-secure accesses + value = 0; + } else { + for (int int_id = 0; int_id < 8 * size; int_id++) { + value |= irqGrpmod[int_id] << int_id; + } + } + } + + return value; + } + + case GICR_NSACR: { // Non-secure Access Control Register + uint64_t value = 0; + + if (distributor->DS) { + // RAZ/WI + value = 0; + } else { + if (!is_secure_access) { + // RAZ/WI + value = 0; + } else { + for (int i = 0, int_id = 0; i < 8 * size; + i = i + 2, int_id++) { + value |= irqNsacr[int_id] << i; + } + } + } + + return value; + } + + default: + panic("Gicv3Redistributor::read(): invalid offset %#x\n", addr); + break; + } +} + +void +Gicv3Redistributor::write(Addr addr, uint64_t data, size_t size, + bool is_secure_access) +{ + if (GICR_IPRIORITYR.contains(addr)) { // Interrupt Priority Registers + int first_intid = addr - GICR_IPRIORITYR.start(); + + for (int i = 0, int_id = first_intid; i < size; i++, int_id++) { + uint8_t prio = bits(data, (i + 1) * 8 - 1, (i * 8)); + + if (!distributor->DS && !is_secure_access) { + if (getIntGroup(int_id) != Gicv3::G1NS) { + // RAZ/WI for non-secure accesses for secure interrupts + continue; + } else { + // NS view + prio = 0x80 | (prio >> 1); + } + } + + irqPriority[int_id] = prio; + DPRINTF(GIC, "Gicv3Redistributor::write(): " + "int_id %d priority %d\n", int_id, irqPriority[int_id]); + } + + return; + } + + switch (addr) { + case GICR_CTLR: { + // GICR_TYPER.LPIS is 0 so Enable_LPIs is RES0 + DPG1S = data & GICR_CTLR_DPG1S; + DPG1NS = data & GICR_CTLR_DPG1NS; + DPG0 = data & GICR_CTLR_DPG0; + break; + } + + case GICR_WAKER: // Wake Register + if (!distributor->DS && !is_secure_access) { + // RAZ/WI for non-secure accesses + return; + } + + if (not peInLowPowerState and + (data & GICR_WAKER_ProcessorSleep)) { + DPRINTF(GIC, "Gicv3Redistributor::write(): " + "PE entering in low power state\n"); + } else if (peInLowPowerState and + not(data & GICR_WAKER_ProcessorSleep)) { + DPRINTF(GIC, "Gicv3Redistributor::write(): powering up PE\n"); + } + + peInLowPowerState = data & GICR_WAKER_ProcessorSleep; + break; + + case GICR_IGROUPR0: // Interrupt Group Register 0 + if (!distributor->DS && !is_secure_access) { + // RAZ/WI for non-secure accesses + return; + } + + for (int int_id = 0; int_id < 8 * size; int_id++) { + irqGroup[int_id] = data & (1 << int_id) ? 1 : 0; + DPRINTF(GIC, "Gicv3Redistributor::write(): " + "int_id %d group %d\n", int_id, irqGroup[int_id]); + } + + break; + + case GICR_ISENABLER0: // Interrupt Set-Enable Register 0 + for (int int_id = 0; int_id < 8 * size; int_id++) { + if (!distributor->DS && !is_secure_access) { + // RAZ/WI for non-secure accesses for secure interrupts + if (getIntGroup(int_id) != Gicv3::G1NS) { + continue; + } + } + + bool enable = data & (1 << int_id) ? 1 : 0; + + if (enable) { + irqEnabled[int_id] = true; + } + + DPRINTF(GIC, "Gicv3Redistributor::write(): " + "int_id %d enable %i\n", int_id, irqEnabled[int_id]); + } + + break; + + case GICR_ICENABLER0: // Interrupt Clear-Enable Register 0 + for (int int_id = 0; int_id < 8 * size; int_id++) { + if (!distributor->DS && !is_secure_access) { + // RAZ/WI for non-secure accesses for secure interrupts + if (getIntGroup(int_id) != Gicv3::G1NS) { + continue; + } + } + + bool disable = data & (1 << int_id) ? 1 : 0; + + if (disable) { + irqEnabled[int_id] = false; + } + + DPRINTF(GIC, "Gicv3Redistributor::write(): " + "int_id %d enable %i\n", int_id, irqEnabled[int_id]); + } + + break; + + case GICR_ISPENDR0: // Interrupt Set-Pending Register 0 + for (int int_id = 0; int_id < 8 * size; int_id++) { + if (!distributor->DS && !is_secure_access) { + // RAZ/WI for non-secure accesses for secure interrupts + if (getIntGroup(int_id) != Gicv3::G1NS) { + continue; + } + } + + bool pending = data & (1 << int_id) ? 1 : 0; + + if (pending) { + DPRINTF(GIC, "Gicv3Redistributor::write() " + "(GICR_ISPENDR0): int_id %d (PPI) " + "pending bit set\n", int_id); + irqPending[int_id] = true; + } + } + + updateAndInformCPUInterface(); + break; + + case GICR_ICPENDR0:// Interrupt Clear-Pending Register 0 + for (int int_id = 0; int_id < 8 * size; int_id++) { + if (!distributor->DS && !is_secure_access) { + // RAZ/WI for non-secure accesses for secure interrupts + if (getIntGroup(int_id) != Gicv3::G1NS) { + continue; + } + } + + bool clear = data & (1 << int_id) ? 1 : 0; + + if (clear) { + irqPending[int_id] = false; + } + } + + break; + + case GICR_ISACTIVER0: // Interrupt Set-Active Register 0 + for (int int_id = 0; int_id < 8 * size; int_id++) { + if (!distributor->DS && !is_secure_access) { + // RAZ/WI for non-secure accesses for secure interrupts + if (getIntGroup(int_id) != Gicv3::G1NS) { + continue; + } + } + + bool activate = data & (1 << int_id) ? 1 : 0; + + if (activate) { + if (!irqActive[int_id]) { + DPRINTF(GIC, "Gicv3Redistributor::write(): " + "int_id %d active set\n", int_id); + } + + irqActive[int_id] = true; + } + } + + break; + + case GICR_ICACTIVER0: // Interrupt Clear-Active Register 0 + for (int int_id = 0; int_id < 8 * size; int_id++) { + if (!distributor->DS && !is_secure_access) { + // RAZ/WI for non-secure accesses for secure interrupts + if (getIntGroup(int_id) != Gicv3::G1NS) { + continue; + } + } + + bool clear = data & (1 << int_id) ? 1 : 0; + + if (clear) { + if (irqActive[int_id]) { + DPRINTF(GIC, "Gicv3Redistributor::write(): " + "int_id %d active cleared\n", int_id); + } + + irqActive[int_id] = false; + } + } + + break; + + case GICR_ICFGR1: { // PPI Configuration Register + int first_intid = Gicv3::SGI_MAX; + + for (int i = 0, int_id = first_intid; i < 8 * size; + i = i + 2, int_id++) { + if (!distributor->DS && !is_secure_access) { + // RAZ/WI for non-secure accesses for secure interrupts + if (getIntGroup(int_id) != Gicv3::G1NS) { + continue; + } + } + + irqConfig[int_id] = data & (0x2 << i) + ? Gicv3::INT_EDGE_TRIGGERED : + Gicv3::INT_LEVEL_SENSITIVE; + DPRINTF(GIC, "Gicv3Redistributor::write(): " + "int_id %d (PPI) config %d\n", + int_id, irqConfig[int_id]); + } + + break; + } + + case GICR_IGRPMODR0: { // Interrupt Group Modifier Register 0 + if (distributor->DS) { + // RAZ/WI if secutiry disabled + } else { + for (int int_id = 0; int_id < 8 * size; int_id++) { + if (!is_secure_access) { + // RAZ/WI for non-secure accesses + continue; + } + + irqGrpmod[int_id] = data & (1 << int_id); + } + } + + break; + } + + case GICR_NSACR: { // Non-secure Access Control Register + if (distributor->DS) { + // RAZ/WI + } else { + if (!is_secure_access) { + // RAZ/WI + } else { + for (int i = 0, int_id = 0; i < 8 * size; + i = i + 2, int_id++) { + irqNsacr[int_id] = (data >> i) & 0x3; + } + } + } + + break; + } + + default: + panic("Gicv3Redistributor::write(): invalid offset %#x\n", addr); + break; + } +} + +void +Gicv3Redistributor::sendPPInt(uint32_t int_id) +{ + assert((int_id >= Gicv3::SGI_MAX) && + (int_id < Gicv3::SGI_MAX + Gicv3::PPI_MAX)); + irqPending[int_id] = true; + DPRINTF(GIC, "Gicv3Redistributor::sendPPInt(): " + "int_id %d (PPI) pending bit set\n", int_id); + updateAndInformCPUInterface(); +} + +void +Gicv3Redistributor::sendSGI(uint32_t int_id, Gicv3::GroupId group, bool ns) +{ + assert(int_id < Gicv3::SGI_MAX); + Gicv3::GroupId int_group = getIntGroup(int_id); + + // asked for secure group 1 + // configured as group 0 + // send group 0 + if (int_group == Gicv3::G0S && group == Gicv3::G1S) { + group = Gicv3::G0S; + } + + if (group == Gicv3::G0S and int_group != Gicv3::G0S) { + return; + } + + if (ns && distributor->DS == 0) { + int nsaccess = irqNsacr[int_id]; + + if ((int_group == Gicv3::G0S && nsaccess < 1) || + (int_group == Gicv3::G1S && nsaccess < 2)) { + return; + } + } + + irqPending[int_id] = true; + DPRINTF(GIC, "Gicv3ReDistributor::sendSGI(): " + "int_id %d (SGI) pending bit set\n", int_id); + updateAndInformCPUInterface(); +} + +Gicv3::IntStatus +Gicv3Redistributor::intStatus(uint32_t int_id) +{ + assert(int_id < Gicv3::SGI_MAX + Gicv3::PPI_MAX); + + if (irqPending[int_id]) { + if (irqActive[int_id]) { + return Gicv3::INT_ACTIVE_PENDING; + } + + return Gicv3::INT_PENDING; + } else if (irqActive[int_id]) { + return Gicv3::INT_ACTIVE; + } else { + return Gicv3::INT_INACTIVE; + } +} + +/* + * Recalculate the highest priority pending interrupt after a + * change to redistributor state. + */ +void +Gicv3Redistributor::update() +{ + bool new_hppi = false; + + for (int int_id = 0; int_id < Gicv3::SGI_MAX + Gicv3::PPI_MAX; int_id++) { + Gicv3::GroupId int_group = getIntGroup(int_id); + bool group_enabled = distributor->groupEnabled(int_group); + + if (irqPending[int_id] && irqEnabled[int_id] && + !irqActive[int_id] && group_enabled) { + if ((irqPriority[int_id] < cpuInterface->hppi.prio) || + /* + * Multiple pending ints with same priority. + * Implementation choice which one to signal. + * Our implementation selects the one with the lower id. + */ + (irqPriority[int_id] == cpuInterface->hppi.prio && + int_id < cpuInterface->hppi.intid)) { + cpuInterface->hppi.intid = int_id; + cpuInterface->hppi.prio = irqPriority[int_id]; + cpuInterface->hppi.group = int_group; + new_hppi = true; + } + } + } + + if (!new_hppi && cpuInterface->hppi.prio != 0xff && + cpuInterface->hppi.intid < Gicv3::SGI_MAX + Gicv3::PPI_MAX) { + distributor->fullUpdate(); + } +} + +void +Gicv3Redistributor::updateAndInformCPUInterface() +{ + update(); + cpuInterface->update(); +} + +Gicv3::GroupId +Gicv3Redistributor::getIntGroup(int int_id) +{ + assert(int_id < (Gicv3::SGI_MAX + Gicv3::PPI_MAX)); + + if (distributor->DS) { + if (irqGroup[int_id] == 0) { + return Gicv3::G0S; + } else { + return Gicv3::G1NS; + } + } else { + if (irqGrpmod[int_id] == 0 && irqGroup[int_id] == 0) { + return Gicv3::G0S; + } else if (irqGrpmod[int_id] == 0 && irqGroup[int_id] == 1) { + return Gicv3::G1NS; + } else if (irqGrpmod[int_id] == 1 && irqGroup[int_id] == 0) { + return Gicv3::G1S; + } else if (irqGrpmod[int_id] == 1 && irqGroup[int_id] == 1) { + return Gicv3::G1NS; + } + } + + M5_UNREACHABLE; +} + +void +Gicv3Redistributor::activateIRQ(uint32_t int_id) +{ + irqPending[int_id] = false; + irqActive[int_id] = true; +} + +void +Gicv3Redistributor::deactivateIRQ(uint32_t int_id) +{ + irqActive[int_id] = false; +} + +uint32_t +Gicv3Redistributor::getAffinity() +{ + ThreadContext * tc = gic->getSystem()->getThreadContext(cpuId); + uint64_t mpidr = getMPIDR(gic->getSystem(), tc); + /* + * Aff3 = MPIDR[39:32] + * (Note getMPIDR() returns uint32_t so Aff3 is always 0...) + * Aff2 = MPIDR[23:16] + * Aff1 = MPIDR[15:8] + * Aff0 = MPIDR[7:0] + * affinity = Aff3.Aff2.Aff1.Aff0 + */ + uint64_t affinity = ((mpidr & 0xff00000000) >> 8) | (mpidr & (0xffffff)); + return affinity; +} + +bool +Gicv3Redistributor::canBeSelectedFor1toNInterrupt(Gicv3::GroupId group) +{ + if (peInLowPowerState) { + return false; + } + + if (!distributor->groupEnabled(group)) { + return false; + } + + if ((group == Gicv3::G1S) && DPG1S) { + return false; + } + + if ((group == Gicv3::G1NS) && DPG1NS) { + return false; + } + + if ((group == Gicv3::G0S) && DPG0) { + return false; + } + + return true; +} + +void +Gicv3Redistributor::serialize(CheckpointOut & cp) const +{ + SERIALIZE_SCALAR(peInLowPowerState); + SERIALIZE_CONTAINER(irqGroup); + SERIALIZE_CONTAINER(irqEnabled); + SERIALIZE_CONTAINER(irqPending); + SERIALIZE_CONTAINER(irqActive); + SERIALIZE_CONTAINER(irqPriority); + SERIALIZE_CONTAINER(irqConfig); + SERIALIZE_CONTAINER(irqGrpmod); + SERIALIZE_CONTAINER(irqNsacr); + SERIALIZE_SCALAR(DPG1S); + SERIALIZE_SCALAR(DPG1NS); + SERIALIZE_SCALAR(DPG0); +} + +void +Gicv3Redistributor::unserialize(CheckpointIn & cp) +{ + UNSERIALIZE_SCALAR(peInLowPowerState); + UNSERIALIZE_CONTAINER(irqGroup); + UNSERIALIZE_CONTAINER(irqEnabled); + UNSERIALIZE_CONTAINER(irqPending); + UNSERIALIZE_CONTAINER(irqActive); + UNSERIALIZE_CONTAINER(irqPriority); + UNSERIALIZE_CONTAINER(irqConfig); + UNSERIALIZE_CONTAINER(irqGrpmod); + UNSERIALIZE_CONTAINER(irqNsacr); + UNSERIALIZE_SCALAR(DPG1S); + UNSERIALIZE_SCALAR(DPG1NS); + UNSERIALIZE_SCALAR(DPG0); +} |