110859Sandreas.sandberg@arm.com/*
211840SCurtis.Dunham@arm.com * Copyright (c) 2015-2017 ARM Limited
310859Sandreas.sandberg@arm.com * All rights reserved
410859Sandreas.sandberg@arm.com *
510859Sandreas.sandberg@arm.com * The license below extends only to copyright in the software and shall
610859Sandreas.sandberg@arm.com * not be construed as granting a license to any other intellectual
710859Sandreas.sandberg@arm.com * property including but not limited to intellectual property relating
810859Sandreas.sandberg@arm.com * to a hardware implementation of the functionality of the software
910859Sandreas.sandberg@arm.com * licensed hereunder.  You may use the software subject to the license
1010859Sandreas.sandberg@arm.com * terms below provided that you ensure that this notice is replicated
1110859Sandreas.sandberg@arm.com * unmodified and in its entirety in all distributions of the software,
1210859Sandreas.sandberg@arm.com * modified or unmodified, in source code or in binary form.
1310859Sandreas.sandberg@arm.com *
1410859Sandreas.sandberg@arm.com * Redistribution and use in source and binary forms, with or without
1510859Sandreas.sandberg@arm.com * modification, are permitted provided that the following conditions are
1610859Sandreas.sandberg@arm.com * met: redistributions of source code must retain the above copyright
1710859Sandreas.sandberg@arm.com * notice, this list of conditions and the following disclaimer;
1810859Sandreas.sandberg@arm.com * redistributions in binary form must reproduce the above copyright
1910859Sandreas.sandberg@arm.com * notice, this list of conditions and the following disclaimer in the
2010859Sandreas.sandberg@arm.com * documentation and/or other materials provided with the distribution;
2110859Sandreas.sandberg@arm.com * neither the name of the copyright holders nor the names of its
2210859Sandreas.sandberg@arm.com * contributors may be used to endorse or promote products derived from
2310859Sandreas.sandberg@arm.com * this software without specific prior written permission.
2410859Sandreas.sandberg@arm.com *
2510859Sandreas.sandberg@arm.com * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
2610859Sandreas.sandberg@arm.com * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
2710859Sandreas.sandberg@arm.com * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
2810859Sandreas.sandberg@arm.com * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
2910859Sandreas.sandberg@arm.com * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
3010859Sandreas.sandberg@arm.com * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
3110859Sandreas.sandberg@arm.com * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
3210859Sandreas.sandberg@arm.com * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
3310859Sandreas.sandberg@arm.com * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
3410859Sandreas.sandberg@arm.com * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
3510859Sandreas.sandberg@arm.com * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
3610859Sandreas.sandberg@arm.com *
3710859Sandreas.sandberg@arm.com * Authors: Andreas Sandberg
3811840SCurtis.Dunham@arm.com *          Curtis Dunham
3910859Sandreas.sandberg@arm.com */
4010859Sandreas.sandberg@arm.com
4110859Sandreas.sandberg@arm.com#include "arch/arm/kvm/gic.hh"
4210859Sandreas.sandberg@arm.com
4310859Sandreas.sandberg@arm.com#include <linux/kvm.h>
4410859Sandreas.sandberg@arm.com
4511840SCurtis.Dunham@arm.com#include "arch/arm/kvm/base_cpu.hh"
4611943SCurtis.Dunham@arm.com#include "debug/GIC.hh"
4710859Sandreas.sandberg@arm.com#include "debug/Interrupt.hh"
4811840SCurtis.Dunham@arm.com#include "params/MuxingKvmGic.hh"
4910859Sandreas.sandberg@arm.com
5011462Sandreas.sandberg@arm.comKvmKernelGicV2::KvmKernelGicV2(KvmVM &_vm, Addr cpu_addr, Addr dist_addr,
5111462Sandreas.sandberg@arm.com                               unsigned it_lines)
5211461Sandreas.sandberg@arm.com    : cpuRange(RangeSize(cpu_addr, KVM_VGIC_V2_CPU_SIZE)),
5311461Sandreas.sandberg@arm.com      distRange(RangeSize(dist_addr, KVM_VGIC_V2_DIST_SIZE)),
5411461Sandreas.sandberg@arm.com      vm(_vm),
5511461Sandreas.sandberg@arm.com      kdev(vm.createDevice(KVM_DEV_TYPE_ARM_VGIC_V2))
5611461Sandreas.sandberg@arm.com{
5712111Sandreas.sandberg@arm.com    // Tell the VM that we will emulate the GIC in the kernel. This
5812111Sandreas.sandberg@arm.com    // disables IRQ and FIQ handling in the KVM CPU model.
5912111Sandreas.sandberg@arm.com    vm.enableKernelIRQChip();
6012111Sandreas.sandberg@arm.com
6111461Sandreas.sandberg@arm.com    kdev.setAttr<uint64_t>(
6211461Sandreas.sandberg@arm.com        KVM_DEV_ARM_VGIC_GRP_ADDR, KVM_VGIC_V2_ADDR_TYPE_DIST, dist_addr);
6311461Sandreas.sandberg@arm.com    kdev.setAttr<uint64_t>(
6411461Sandreas.sandberg@arm.com        KVM_DEV_ARM_VGIC_GRP_ADDR, KVM_VGIC_V2_ADDR_TYPE_CPU, cpu_addr);
6511462Sandreas.sandberg@arm.com
6611462Sandreas.sandberg@arm.com    kdev.setAttr<uint32_t>(KVM_DEV_ARM_VGIC_GRP_NR_IRQS, 0, it_lines);
6711461Sandreas.sandberg@arm.com}
6811461Sandreas.sandberg@arm.com
6911461Sandreas.sandberg@arm.comKvmKernelGicV2::~KvmKernelGicV2()
7011461Sandreas.sandberg@arm.com{
7111461Sandreas.sandberg@arm.com}
7211461Sandreas.sandberg@arm.com
7311461Sandreas.sandberg@arm.comvoid
7411461Sandreas.sandberg@arm.comKvmKernelGicV2::setSPI(unsigned spi)
7511461Sandreas.sandberg@arm.com{
7611461Sandreas.sandberg@arm.com    setIntState(KVM_ARM_IRQ_TYPE_SPI, 0, spi, true);
7711461Sandreas.sandberg@arm.com}
7811461Sandreas.sandberg@arm.com
7911461Sandreas.sandberg@arm.comvoid
8011461Sandreas.sandberg@arm.comKvmKernelGicV2::clearSPI(unsigned spi)
8111461Sandreas.sandberg@arm.com{
8211461Sandreas.sandberg@arm.com    setIntState(KVM_ARM_IRQ_TYPE_SPI, 0, spi, false);
8311461Sandreas.sandberg@arm.com}
8411461Sandreas.sandberg@arm.com
8511461Sandreas.sandberg@arm.comvoid
8611461Sandreas.sandberg@arm.comKvmKernelGicV2::setPPI(unsigned vcpu, unsigned ppi)
8711461Sandreas.sandberg@arm.com{
8811461Sandreas.sandberg@arm.com    setIntState(KVM_ARM_IRQ_TYPE_PPI, vcpu, ppi, true);
8911461Sandreas.sandberg@arm.com}
9011461Sandreas.sandberg@arm.com
9111461Sandreas.sandberg@arm.comvoid
9211461Sandreas.sandberg@arm.comKvmKernelGicV2::clearPPI(unsigned vcpu, unsigned ppi)
9311461Sandreas.sandberg@arm.com{
9411461Sandreas.sandberg@arm.com    setIntState(KVM_ARM_IRQ_TYPE_PPI, vcpu, ppi, false);
9511461Sandreas.sandberg@arm.com}
9611461Sandreas.sandberg@arm.com
9711461Sandreas.sandberg@arm.comvoid
9811461Sandreas.sandberg@arm.comKvmKernelGicV2::setIntState(unsigned type, unsigned vcpu, unsigned irq,
9911461Sandreas.sandberg@arm.com                            bool high)
10011461Sandreas.sandberg@arm.com{
10111461Sandreas.sandberg@arm.com    assert(type <= KVM_ARM_IRQ_TYPE_MASK);
10211461Sandreas.sandberg@arm.com    assert(vcpu <= KVM_ARM_IRQ_VCPU_MASK);
10311461Sandreas.sandberg@arm.com    assert(irq <= KVM_ARM_IRQ_NUM_MASK);
10411461Sandreas.sandberg@arm.com    const uint32_t line(
10511461Sandreas.sandberg@arm.com        (type << KVM_ARM_IRQ_TYPE_SHIFT) |
10611461Sandreas.sandberg@arm.com        (vcpu << KVM_ARM_IRQ_VCPU_SHIFT) |
10711461Sandreas.sandberg@arm.com        (irq << KVM_ARM_IRQ_NUM_SHIFT));
10811461Sandreas.sandberg@arm.com
10911461Sandreas.sandberg@arm.com    vm.setIRQLine(line, high);
11011461Sandreas.sandberg@arm.com}
11111461Sandreas.sandberg@arm.com
11211943SCurtis.Dunham@arm.comuint32_t
11311943SCurtis.Dunham@arm.comKvmKernelGicV2::getGicReg(unsigned group, unsigned vcpu, unsigned offset)
11411943SCurtis.Dunham@arm.com{
11511943SCurtis.Dunham@arm.com    uint64_t reg;
11611943SCurtis.Dunham@arm.com
11711943SCurtis.Dunham@arm.com    assert(vcpu <= KVM_ARM_IRQ_VCPU_MASK);
11811943SCurtis.Dunham@arm.com    const uint32_t attr(
11911943SCurtis.Dunham@arm.com        (vcpu << KVM_DEV_ARM_VGIC_CPUID_SHIFT) |
12011943SCurtis.Dunham@arm.com        (offset << KVM_DEV_ARM_VGIC_OFFSET_SHIFT));
12111943SCurtis.Dunham@arm.com
12211943SCurtis.Dunham@arm.com    kdev.getAttrPtr(group, attr, &reg);
12311943SCurtis.Dunham@arm.com    return (uint32_t) reg;
12411943SCurtis.Dunham@arm.com}
12511943SCurtis.Dunham@arm.com
12611943SCurtis.Dunham@arm.comvoid
12711943SCurtis.Dunham@arm.comKvmKernelGicV2::setGicReg(unsigned group, unsigned vcpu, unsigned offset,
12811943SCurtis.Dunham@arm.com                          unsigned value)
12911943SCurtis.Dunham@arm.com{
13011943SCurtis.Dunham@arm.com    uint64_t reg = value;
13111943SCurtis.Dunham@arm.com
13211943SCurtis.Dunham@arm.com    assert(vcpu <= KVM_ARM_IRQ_VCPU_MASK);
13311943SCurtis.Dunham@arm.com    const uint32_t attr(
13411943SCurtis.Dunham@arm.com        (vcpu << KVM_DEV_ARM_VGIC_CPUID_SHIFT) |
13511943SCurtis.Dunham@arm.com        (offset << KVM_DEV_ARM_VGIC_OFFSET_SHIFT));
13611943SCurtis.Dunham@arm.com
13711943SCurtis.Dunham@arm.com    kdev.setAttrPtr(group, attr, &reg);
13811943SCurtis.Dunham@arm.com}
13911943SCurtis.Dunham@arm.com
14011943SCurtis.Dunham@arm.comuint32_t
14111943SCurtis.Dunham@arm.comKvmKernelGicV2::readDistributor(ContextID ctx, Addr daddr)
14211943SCurtis.Dunham@arm.com{
14311943SCurtis.Dunham@arm.com    auto vcpu = vm.contextIdToVCpuId(ctx);
14411943SCurtis.Dunham@arm.com    return getGicReg(KVM_DEV_ARM_VGIC_GRP_DIST_REGS, vcpu, daddr);
14511943SCurtis.Dunham@arm.com}
14611943SCurtis.Dunham@arm.com
14711943SCurtis.Dunham@arm.comuint32_t
14811943SCurtis.Dunham@arm.comKvmKernelGicV2::readCpu(ContextID ctx, Addr daddr)
14911943SCurtis.Dunham@arm.com{
15011943SCurtis.Dunham@arm.com    auto vcpu = vm.contextIdToVCpuId(ctx);
15111943SCurtis.Dunham@arm.com    return getGicReg(KVM_DEV_ARM_VGIC_GRP_CPU_REGS, vcpu, daddr);
15211943SCurtis.Dunham@arm.com}
15311943SCurtis.Dunham@arm.com
15411943SCurtis.Dunham@arm.comvoid
15511943SCurtis.Dunham@arm.comKvmKernelGicV2::writeDistributor(ContextID ctx, Addr daddr, uint32_t data)
15611943SCurtis.Dunham@arm.com{
15711943SCurtis.Dunham@arm.com    auto vcpu = vm.contextIdToVCpuId(ctx);
15811943SCurtis.Dunham@arm.com    setGicReg(KVM_DEV_ARM_VGIC_GRP_DIST_REGS, vcpu, daddr, data);
15911943SCurtis.Dunham@arm.com}
16011943SCurtis.Dunham@arm.com
16111943SCurtis.Dunham@arm.comvoid
16211943SCurtis.Dunham@arm.comKvmKernelGicV2::writeCpu(ContextID ctx, Addr daddr, uint32_t data)
16311943SCurtis.Dunham@arm.com{
16411943SCurtis.Dunham@arm.com    auto vcpu = vm.contextIdToVCpuId(ctx);
16511943SCurtis.Dunham@arm.com    setGicReg(KVM_DEV_ARM_VGIC_GRP_CPU_REGS, vcpu, daddr, data);
16611943SCurtis.Dunham@arm.com}
16711943SCurtis.Dunham@arm.com
16811943SCurtis.Dunham@arm.com
16911461Sandreas.sandberg@arm.com
17011840SCurtis.Dunham@arm.comMuxingKvmGic::MuxingKvmGic(const MuxingKvmGicParams *p)
17113014Sciro.santilli@arm.com    : GicV2(p),
17211840SCurtis.Dunham@arm.com      system(*p->system),
17311840SCurtis.Dunham@arm.com      kernelGic(nullptr),
17411840SCurtis.Dunham@arm.com      usingKvm(false)
17511840SCurtis.Dunham@arm.com{
17611840SCurtis.Dunham@arm.com    if (auto vm = system.getKvmVM()) {
17711840SCurtis.Dunham@arm.com        kernelGic = new KvmKernelGicV2(*vm, p->cpu_addr, p->dist_addr,
17811840SCurtis.Dunham@arm.com                                       p->it_lines);
17911840SCurtis.Dunham@arm.com    }
18011840SCurtis.Dunham@arm.com}
18111840SCurtis.Dunham@arm.com
18211840SCurtis.Dunham@arm.comMuxingKvmGic::~MuxingKvmGic()
18311840SCurtis.Dunham@arm.com{
18411840SCurtis.Dunham@arm.com}
18511840SCurtis.Dunham@arm.com
18611840SCurtis.Dunham@arm.comvoid
18711840SCurtis.Dunham@arm.comMuxingKvmGic::startup()
18811840SCurtis.Dunham@arm.com{
18913014Sciro.santilli@arm.com    GicV2::startup();
19012100SCurtis.Dunham@arm.com    usingKvm = (kernelGic != nullptr) && system.validKvmEnvironment();
19111943SCurtis.Dunham@arm.com    if (usingKvm)
19213014Sciro.santilli@arm.com        fromGicV2ToKvm();
19311943SCurtis.Dunham@arm.com}
19411943SCurtis.Dunham@arm.com
19511943SCurtis.Dunham@arm.comDrainState
19611943SCurtis.Dunham@arm.comMuxingKvmGic::drain()
19711943SCurtis.Dunham@arm.com{
19811943SCurtis.Dunham@arm.com    if (usingKvm)
19913014Sciro.santilli@arm.com        fromKvmToGicV2();
20013014Sciro.santilli@arm.com    return GicV2::drain();
20111840SCurtis.Dunham@arm.com}
20211840SCurtis.Dunham@arm.com
20311840SCurtis.Dunham@arm.comvoid
20411840SCurtis.Dunham@arm.comMuxingKvmGic::drainResume()
20511840SCurtis.Dunham@arm.com{
20613014Sciro.santilli@arm.com    GicV2::drainResume();
20712100SCurtis.Dunham@arm.com    bool use_kvm = (kernelGic != nullptr) && system.validKvmEnvironment();
20811840SCurtis.Dunham@arm.com    if (use_kvm != usingKvm) {
20911943SCurtis.Dunham@arm.com        // Should only occur due to CPU switches
21011840SCurtis.Dunham@arm.com        if (use_kvm) // from simulation to KVM emulation
21113014Sciro.santilli@arm.com            fromGicV2ToKvm();
21213014Sciro.santilli@arm.com        // otherwise, drain() already sync'd the state back to the GicV2
21311840SCurtis.Dunham@arm.com
21411840SCurtis.Dunham@arm.com        usingKvm = use_kvm;
21511840SCurtis.Dunham@arm.com    }
21611840SCurtis.Dunham@arm.com}
21711840SCurtis.Dunham@arm.com
21811840SCurtis.Dunham@arm.comTick
21911840SCurtis.Dunham@arm.comMuxingKvmGic::read(PacketPtr pkt)
22011840SCurtis.Dunham@arm.com{
22111840SCurtis.Dunham@arm.com    if (!usingKvm)
22213014Sciro.santilli@arm.com        return GicV2::read(pkt);
22311840SCurtis.Dunham@arm.com
22411840SCurtis.Dunham@arm.com    panic("MuxingKvmGic: PIO from gem5 is currently unsupported\n");
22511840SCurtis.Dunham@arm.com}
22611840SCurtis.Dunham@arm.com
22711840SCurtis.Dunham@arm.comTick
22811840SCurtis.Dunham@arm.comMuxingKvmGic::write(PacketPtr pkt)
22911840SCurtis.Dunham@arm.com{
23011840SCurtis.Dunham@arm.com    if (!usingKvm)
23113014Sciro.santilli@arm.com        return GicV2::write(pkt);
23211840SCurtis.Dunham@arm.com
23311840SCurtis.Dunham@arm.com    panic("MuxingKvmGic: PIO from gem5 is currently unsupported\n");
23411840SCurtis.Dunham@arm.com}
23511840SCurtis.Dunham@arm.com
23611840SCurtis.Dunham@arm.comvoid
23711840SCurtis.Dunham@arm.comMuxingKvmGic::sendInt(uint32_t num)
23811840SCurtis.Dunham@arm.com{
23911840SCurtis.Dunham@arm.com    if (!usingKvm)
24013014Sciro.santilli@arm.com        return GicV2::sendInt(num);
24111840SCurtis.Dunham@arm.com
24211840SCurtis.Dunham@arm.com    DPRINTF(Interrupt, "Set SPI %d\n", num);
24311840SCurtis.Dunham@arm.com    kernelGic->setSPI(num);
24411840SCurtis.Dunham@arm.com}
24511840SCurtis.Dunham@arm.com
24611840SCurtis.Dunham@arm.comvoid
24711840SCurtis.Dunham@arm.comMuxingKvmGic::clearInt(uint32_t num)
24811840SCurtis.Dunham@arm.com{
24911840SCurtis.Dunham@arm.com    if (!usingKvm)
25013014Sciro.santilli@arm.com        return GicV2::clearInt(num);
25111840SCurtis.Dunham@arm.com
25211840SCurtis.Dunham@arm.com    DPRINTF(Interrupt, "Clear SPI %d\n", num);
25311840SCurtis.Dunham@arm.com    kernelGic->clearSPI(num);
25411840SCurtis.Dunham@arm.com}
25511840SCurtis.Dunham@arm.com
25611840SCurtis.Dunham@arm.comvoid
25711840SCurtis.Dunham@arm.comMuxingKvmGic::sendPPInt(uint32_t num, uint32_t cpu)
25811840SCurtis.Dunham@arm.com{
25911840SCurtis.Dunham@arm.com    if (!usingKvm)
26013014Sciro.santilli@arm.com        return GicV2::sendPPInt(num, cpu);
26111840SCurtis.Dunham@arm.com    DPRINTF(Interrupt, "Set PPI %d:%d\n", cpu, num);
26211840SCurtis.Dunham@arm.com    kernelGic->setPPI(cpu, num);
26311840SCurtis.Dunham@arm.com}
26411840SCurtis.Dunham@arm.com
26511840SCurtis.Dunham@arm.comvoid
26611840SCurtis.Dunham@arm.comMuxingKvmGic::clearPPInt(uint32_t num, uint32_t cpu)
26711840SCurtis.Dunham@arm.com{
26811840SCurtis.Dunham@arm.com    if (!usingKvm)
26913014Sciro.santilli@arm.com        return GicV2::clearPPInt(num, cpu);
27011840SCurtis.Dunham@arm.com
27111840SCurtis.Dunham@arm.com    DPRINTF(Interrupt, "Clear PPI %d:%d\n", cpu, num);
27211840SCurtis.Dunham@arm.com    kernelGic->clearPPI(cpu, num);
27311840SCurtis.Dunham@arm.com}
27411840SCurtis.Dunham@arm.com
27511840SCurtis.Dunham@arm.comvoid
27612112SCurtis.Dunham@arm.comMuxingKvmGic::updateIntState(int hint)
27712112SCurtis.Dunham@arm.com{
27813014Sciro.santilli@arm.com    // During Kvm->GicV2 state transfer, writes to the GicV2 will call
27912112SCurtis.Dunham@arm.com    // updateIntState() which can post an interrupt.  Since we're only
28013014Sciro.santilli@arm.com    // using the GicV2 model for holding state in this circumstance, we
28113014Sciro.santilli@arm.com    // short-circuit this behavior, as the GicV2 is not actually active.
28212112SCurtis.Dunham@arm.com    if (!usingKvm)
28313014Sciro.santilli@arm.com        return GicV2::updateIntState(hint);
28412112SCurtis.Dunham@arm.com}
28512112SCurtis.Dunham@arm.com
28612112SCurtis.Dunham@arm.comvoid
28711943SCurtis.Dunham@arm.comMuxingKvmGic::copyDistRegister(BaseGicRegisters* from, BaseGicRegisters* to,
28811943SCurtis.Dunham@arm.com                               ContextID ctx, Addr daddr)
28911943SCurtis.Dunham@arm.com{
29011943SCurtis.Dunham@arm.com    auto val = from->readDistributor(ctx, daddr);
29111943SCurtis.Dunham@arm.com    DPRINTF(GIC, "copy dist 0x%x 0x%08x\n", daddr, val);
29211943SCurtis.Dunham@arm.com    to->writeDistributor(ctx, daddr, val);
29311943SCurtis.Dunham@arm.com}
29411943SCurtis.Dunham@arm.com
29511943SCurtis.Dunham@arm.comvoid
29611943SCurtis.Dunham@arm.comMuxingKvmGic::copyCpuRegister(BaseGicRegisters* from, BaseGicRegisters* to,
29711943SCurtis.Dunham@arm.com                               ContextID ctx, Addr daddr)
29811943SCurtis.Dunham@arm.com{
29911943SCurtis.Dunham@arm.com    auto val = from->readCpu(ctx, daddr);
30011943SCurtis.Dunham@arm.com    DPRINTF(GIC, "copy cpu  0x%x 0x%08x\n", daddr, val);
30111943SCurtis.Dunham@arm.com    to->writeCpu(ctx, daddr, val);
30211943SCurtis.Dunham@arm.com}
30311943SCurtis.Dunham@arm.com
30411943SCurtis.Dunham@arm.comvoid
30511943SCurtis.Dunham@arm.comMuxingKvmGic::copyBankedDistRange(BaseGicRegisters* from, BaseGicRegisters* to,
30611943SCurtis.Dunham@arm.com                                  Addr daddr, size_t size)
30711943SCurtis.Dunham@arm.com{
30812515Sgiacomo.travaglini@arm.com    for (int ctx = 0; ctx < system.numContexts(); ++ctx)
30911943SCurtis.Dunham@arm.com        for (auto a = daddr; a < daddr + size; a += 4)
31011943SCurtis.Dunham@arm.com            copyDistRegister(from, to, ctx, a);
31111943SCurtis.Dunham@arm.com}
31211943SCurtis.Dunham@arm.com
31311943SCurtis.Dunham@arm.comvoid
31411943SCurtis.Dunham@arm.comMuxingKvmGic::clearBankedDistRange(BaseGicRegisters* to,
31511943SCurtis.Dunham@arm.com                                   Addr daddr, size_t size)
31611943SCurtis.Dunham@arm.com{
31712515Sgiacomo.travaglini@arm.com    for (int ctx = 0; ctx < system.numContexts(); ++ctx)
31811943SCurtis.Dunham@arm.com        for (auto a = daddr; a < daddr + size; a += 4)
31911943SCurtis.Dunham@arm.com            to->writeDistributor(ctx, a, 0xFFFFFFFF);
32011943SCurtis.Dunham@arm.com}
32111943SCurtis.Dunham@arm.com
32211943SCurtis.Dunham@arm.comvoid
32311943SCurtis.Dunham@arm.comMuxingKvmGic::copyDistRange(BaseGicRegisters* from, BaseGicRegisters* to,
32411943SCurtis.Dunham@arm.com                            Addr daddr, size_t size)
32511943SCurtis.Dunham@arm.com{
32611943SCurtis.Dunham@arm.com    for (auto a = daddr; a < daddr + size; a += 4)
32711943SCurtis.Dunham@arm.com        copyDistRegister(from, to, 0, a);
32811943SCurtis.Dunham@arm.com}
32911943SCurtis.Dunham@arm.com
33011943SCurtis.Dunham@arm.comvoid
33111943SCurtis.Dunham@arm.comMuxingKvmGic::clearDistRange(BaseGicRegisters* to,
33211943SCurtis.Dunham@arm.com                             Addr daddr, size_t size)
33311943SCurtis.Dunham@arm.com{
33411943SCurtis.Dunham@arm.com    for (auto a = daddr; a < daddr + size; a += 4)
33511943SCurtis.Dunham@arm.com        to->writeDistributor(0, a, 0xFFFFFFFF);
33611943SCurtis.Dunham@arm.com}
33711943SCurtis.Dunham@arm.com
33811943SCurtis.Dunham@arm.comvoid
33911943SCurtis.Dunham@arm.comMuxingKvmGic::copyGicState(BaseGicRegisters* from, BaseGicRegisters* to)
34011943SCurtis.Dunham@arm.com{
34111943SCurtis.Dunham@arm.com    Addr set, clear;
34211943SCurtis.Dunham@arm.com    size_t size;
34311943SCurtis.Dunham@arm.com
34411943SCurtis.Dunham@arm.com    /// CPU state (GICC_*)
34511943SCurtis.Dunham@arm.com    // Copy CPU Interface Control Register (CTLR),
34611943SCurtis.Dunham@arm.com    //      Interrupt Priority Mask Register (PMR), and
34711943SCurtis.Dunham@arm.com    //      Binary Point Register (BPR)
34812515Sgiacomo.travaglini@arm.com    for (int ctx = 0; ctx < system.numContexts(); ++ctx) {
34911943SCurtis.Dunham@arm.com        copyCpuRegister(from, to, ctx, GICC_CTLR);
35011943SCurtis.Dunham@arm.com        copyCpuRegister(from, to, ctx, GICC_PMR);
35111943SCurtis.Dunham@arm.com        copyCpuRegister(from, to, ctx, GICC_BPR);
35211943SCurtis.Dunham@arm.com    }
35311943SCurtis.Dunham@arm.com
35411943SCurtis.Dunham@arm.com
35511943SCurtis.Dunham@arm.com    /// Distributor state (GICD_*)
35611943SCurtis.Dunham@arm.com    // Copy Distributor Control Register (CTLR)
35711943SCurtis.Dunham@arm.com    copyDistRegister(from, to, 0, GICD_CTLR);
35811943SCurtis.Dunham@arm.com
35911943SCurtis.Dunham@arm.com    // Copy interrupt-enabled statuses (I[CS]ENABLERn; R0 is per-CPU banked)
36013014Sciro.santilli@arm.com    set   = GicV2::GICD_ISENABLER.start();
36113014Sciro.santilli@arm.com    clear = GicV2::GICD_ICENABLER.start();
36213014Sciro.santilli@arm.com    size  = GicV2::itLines / 8;
36311943SCurtis.Dunham@arm.com    clearBankedDistRange(to, clear, 4);
36411943SCurtis.Dunham@arm.com    copyBankedDistRange(from, to, set, 4);
36511943SCurtis.Dunham@arm.com
36611943SCurtis.Dunham@arm.com    set += 4, clear += 4, size -= 4;
36711943SCurtis.Dunham@arm.com    clearDistRange(to, clear, size);
36811943SCurtis.Dunham@arm.com    copyDistRange(from, to, set, size);
36911943SCurtis.Dunham@arm.com
37011943SCurtis.Dunham@arm.com    // Copy pending interrupts (I[CS]PENDRn; R0 is per-CPU banked)
37113014Sciro.santilli@arm.com    set   = GicV2::GICD_ISPENDR.start();
37213014Sciro.santilli@arm.com    clear = GicV2::GICD_ICPENDR.start();
37313014Sciro.santilli@arm.com    size  = GicV2::itLines / 8;
37411943SCurtis.Dunham@arm.com    clearBankedDistRange(to, clear, 4);
37511943SCurtis.Dunham@arm.com    copyBankedDistRange(from, to, set, 4);
37611943SCurtis.Dunham@arm.com
37711943SCurtis.Dunham@arm.com    set += 4, clear += 4, size -= 4;
37811943SCurtis.Dunham@arm.com    clearDistRange(to, clear, size);
37911943SCurtis.Dunham@arm.com    copyDistRange(from, to, set, size);
38011943SCurtis.Dunham@arm.com
38111943SCurtis.Dunham@arm.com    // Copy active interrupts (I[CS]ACTIVERn; R0 is per-CPU banked)
38213014Sciro.santilli@arm.com    set   = GicV2::GICD_ISACTIVER.start();
38313014Sciro.santilli@arm.com    clear = GicV2::GICD_ICACTIVER.start();
38413014Sciro.santilli@arm.com    size  = GicV2::itLines / 8;
38511943SCurtis.Dunham@arm.com    clearBankedDistRange(to, clear, 4);
38611943SCurtis.Dunham@arm.com    copyBankedDistRange(from, to, set, 4);
38711943SCurtis.Dunham@arm.com
38811943SCurtis.Dunham@arm.com    set += 4, clear += 4, size -= 4;
38911943SCurtis.Dunham@arm.com    clearDistRange(to, clear, size);
39011943SCurtis.Dunham@arm.com    copyDistRange(from, to, set, size);
39111943SCurtis.Dunham@arm.com
39211943SCurtis.Dunham@arm.com    // Copy interrupt priorities (IPRIORITYRn; R0-7 are per-CPU banked)
39313014Sciro.santilli@arm.com    set   = GicV2::GICD_IPRIORITYR.start();
39411943SCurtis.Dunham@arm.com    copyBankedDistRange(from, to, set, 32);
39511943SCurtis.Dunham@arm.com
39611943SCurtis.Dunham@arm.com    set += 32;
39713014Sciro.santilli@arm.com    size = GicV2::itLines - 32;
39811943SCurtis.Dunham@arm.com    copyDistRange(from, to, set, size);
39911943SCurtis.Dunham@arm.com
40011943SCurtis.Dunham@arm.com    // Copy interrupt processor target regs (ITARGETRn; R0-7 are read-only)
40113014Sciro.santilli@arm.com    set = GicV2::GICD_ITARGETSR.start() + 32;
40213014Sciro.santilli@arm.com    size = GicV2::itLines - 32;
40311943SCurtis.Dunham@arm.com    copyDistRange(from, to, set, size);
40411943SCurtis.Dunham@arm.com
40511943SCurtis.Dunham@arm.com    // Copy interrupt configuration registers (ICFGRn)
40613014Sciro.santilli@arm.com    set = GicV2::GICD_ICFGR.start();
40713014Sciro.santilli@arm.com    size = GicV2::itLines / 4;
40811943SCurtis.Dunham@arm.com    copyDistRange(from, to, set, size);
40911943SCurtis.Dunham@arm.com}
41011943SCurtis.Dunham@arm.com
41111943SCurtis.Dunham@arm.comvoid
41213014Sciro.santilli@arm.comMuxingKvmGic::fromGicV2ToKvm()
41311840SCurtis.Dunham@arm.com{
41413014Sciro.santilli@arm.com    copyGicState(static_cast<GicV2*>(this), kernelGic);
41511840SCurtis.Dunham@arm.com}
41611840SCurtis.Dunham@arm.com
41711840SCurtis.Dunham@arm.comvoid
41813014Sciro.santilli@arm.comMuxingKvmGic::fromKvmToGicV2()
41911840SCurtis.Dunham@arm.com{
42013014Sciro.santilli@arm.com    copyGicState(kernelGic, static_cast<GicV2*>(this));
42111943SCurtis.Dunham@arm.com
42211943SCurtis.Dunham@arm.com    // the values read for the Interrupt Priority Mask Register (PMR)
42311943SCurtis.Dunham@arm.com    // have been shifted by three bits due to its having been emulated by
42411943SCurtis.Dunham@arm.com    // a VGIC with only 5 PMR bits in its VMCR register.  Presently the
42511943SCurtis.Dunham@arm.com    // Linux kernel does not repair this inaccuracy, so we correct it here.
42612515Sgiacomo.travaglini@arm.com    for (int cpu = 0; cpu < system.numContexts(); ++cpu) {
42711943SCurtis.Dunham@arm.com       cpuPriority[cpu] <<= 3;
42811943SCurtis.Dunham@arm.com       assert((cpuPriority[cpu] & ~0xff) == 0);
42911943SCurtis.Dunham@arm.com    }
43011840SCurtis.Dunham@arm.com}
43111840SCurtis.Dunham@arm.com
43211840SCurtis.Dunham@arm.comMuxingKvmGic *
43311840SCurtis.Dunham@arm.comMuxingKvmGicParams::create()
43411840SCurtis.Dunham@arm.com{
43511840SCurtis.Dunham@arm.com    return new MuxingKvmGic(this);
43611840SCurtis.Dunham@arm.com}
437