gic.cc revision 12100
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{
5711461Sandreas.sandberg@arm.com    kdev.setAttr<uint64_t>(
5811461Sandreas.sandberg@arm.com        KVM_DEV_ARM_VGIC_GRP_ADDR, KVM_VGIC_V2_ADDR_TYPE_DIST, dist_addr);
5911461Sandreas.sandberg@arm.com    kdev.setAttr<uint64_t>(
6011461Sandreas.sandberg@arm.com        KVM_DEV_ARM_VGIC_GRP_ADDR, KVM_VGIC_V2_ADDR_TYPE_CPU, cpu_addr);
6111462Sandreas.sandberg@arm.com
6211462Sandreas.sandberg@arm.com    kdev.setAttr<uint32_t>(KVM_DEV_ARM_VGIC_GRP_NR_IRQS, 0, it_lines);
6311461Sandreas.sandberg@arm.com}
6411461Sandreas.sandberg@arm.com
6511461Sandreas.sandberg@arm.comKvmKernelGicV2::~KvmKernelGicV2()
6611461Sandreas.sandberg@arm.com{
6711461Sandreas.sandberg@arm.com}
6811461Sandreas.sandberg@arm.com
6911461Sandreas.sandberg@arm.comvoid
7011461Sandreas.sandberg@arm.comKvmKernelGicV2::setSPI(unsigned spi)
7111461Sandreas.sandberg@arm.com{
7211461Sandreas.sandberg@arm.com    setIntState(KVM_ARM_IRQ_TYPE_SPI, 0, spi, true);
7311461Sandreas.sandberg@arm.com}
7411461Sandreas.sandberg@arm.com
7511461Sandreas.sandberg@arm.comvoid
7611461Sandreas.sandberg@arm.comKvmKernelGicV2::clearSPI(unsigned spi)
7711461Sandreas.sandberg@arm.com{
7811461Sandreas.sandberg@arm.com    setIntState(KVM_ARM_IRQ_TYPE_SPI, 0, spi, false);
7911461Sandreas.sandberg@arm.com}
8011461Sandreas.sandberg@arm.com
8111461Sandreas.sandberg@arm.comvoid
8211461Sandreas.sandberg@arm.comKvmKernelGicV2::setPPI(unsigned vcpu, unsigned ppi)
8311461Sandreas.sandberg@arm.com{
8411461Sandreas.sandberg@arm.com    setIntState(KVM_ARM_IRQ_TYPE_PPI, vcpu, ppi, true);
8511461Sandreas.sandberg@arm.com}
8611461Sandreas.sandberg@arm.com
8711461Sandreas.sandberg@arm.comvoid
8811461Sandreas.sandberg@arm.comKvmKernelGicV2::clearPPI(unsigned vcpu, unsigned ppi)
8911461Sandreas.sandberg@arm.com{
9011461Sandreas.sandberg@arm.com    setIntState(KVM_ARM_IRQ_TYPE_PPI, vcpu, ppi, false);
9111461Sandreas.sandberg@arm.com}
9211461Sandreas.sandberg@arm.com
9311461Sandreas.sandberg@arm.comvoid
9411461Sandreas.sandberg@arm.comKvmKernelGicV2::setIntState(unsigned type, unsigned vcpu, unsigned irq,
9511461Sandreas.sandberg@arm.com                            bool high)
9611461Sandreas.sandberg@arm.com{
9711461Sandreas.sandberg@arm.com    assert(type <= KVM_ARM_IRQ_TYPE_MASK);
9811461Sandreas.sandberg@arm.com    assert(vcpu <= KVM_ARM_IRQ_VCPU_MASK);
9911461Sandreas.sandberg@arm.com    assert(irq <= KVM_ARM_IRQ_NUM_MASK);
10011461Sandreas.sandberg@arm.com    const uint32_t line(
10111461Sandreas.sandberg@arm.com        (type << KVM_ARM_IRQ_TYPE_SHIFT) |
10211461Sandreas.sandberg@arm.com        (vcpu << KVM_ARM_IRQ_VCPU_SHIFT) |
10311461Sandreas.sandberg@arm.com        (irq << KVM_ARM_IRQ_NUM_SHIFT));
10411461Sandreas.sandberg@arm.com
10511461Sandreas.sandberg@arm.com    vm.setIRQLine(line, high);
10611461Sandreas.sandberg@arm.com}
10711461Sandreas.sandberg@arm.com
10811943SCurtis.Dunham@arm.comuint32_t
10911943SCurtis.Dunham@arm.comKvmKernelGicV2::getGicReg(unsigned group, unsigned vcpu, unsigned offset)
11011943SCurtis.Dunham@arm.com{
11111943SCurtis.Dunham@arm.com    uint64_t reg;
11211943SCurtis.Dunham@arm.com
11311943SCurtis.Dunham@arm.com    assert(vcpu <= KVM_ARM_IRQ_VCPU_MASK);
11411943SCurtis.Dunham@arm.com    const uint32_t attr(
11511943SCurtis.Dunham@arm.com        (vcpu << KVM_DEV_ARM_VGIC_CPUID_SHIFT) |
11611943SCurtis.Dunham@arm.com        (offset << KVM_DEV_ARM_VGIC_OFFSET_SHIFT));
11711943SCurtis.Dunham@arm.com
11811943SCurtis.Dunham@arm.com    kdev.getAttrPtr(group, attr, &reg);
11911943SCurtis.Dunham@arm.com    return (uint32_t) reg;
12011943SCurtis.Dunham@arm.com}
12111943SCurtis.Dunham@arm.com
12211943SCurtis.Dunham@arm.comvoid
12311943SCurtis.Dunham@arm.comKvmKernelGicV2::setGicReg(unsigned group, unsigned vcpu, unsigned offset,
12411943SCurtis.Dunham@arm.com                          unsigned value)
12511943SCurtis.Dunham@arm.com{
12611943SCurtis.Dunham@arm.com    uint64_t reg = value;
12711943SCurtis.Dunham@arm.com
12811943SCurtis.Dunham@arm.com    assert(vcpu <= KVM_ARM_IRQ_VCPU_MASK);
12911943SCurtis.Dunham@arm.com    const uint32_t attr(
13011943SCurtis.Dunham@arm.com        (vcpu << KVM_DEV_ARM_VGIC_CPUID_SHIFT) |
13111943SCurtis.Dunham@arm.com        (offset << KVM_DEV_ARM_VGIC_OFFSET_SHIFT));
13211943SCurtis.Dunham@arm.com
13311943SCurtis.Dunham@arm.com    kdev.setAttrPtr(group, attr, &reg);
13411943SCurtis.Dunham@arm.com}
13511943SCurtis.Dunham@arm.com
13611943SCurtis.Dunham@arm.comuint32_t
13711943SCurtis.Dunham@arm.comKvmKernelGicV2::readDistributor(ContextID ctx, Addr daddr)
13811943SCurtis.Dunham@arm.com{
13911943SCurtis.Dunham@arm.com    auto vcpu = vm.contextIdToVCpuId(ctx);
14011943SCurtis.Dunham@arm.com    return getGicReg(KVM_DEV_ARM_VGIC_GRP_DIST_REGS, vcpu, daddr);
14111943SCurtis.Dunham@arm.com}
14211943SCurtis.Dunham@arm.com
14311943SCurtis.Dunham@arm.comuint32_t
14411943SCurtis.Dunham@arm.comKvmKernelGicV2::readCpu(ContextID ctx, Addr daddr)
14511943SCurtis.Dunham@arm.com{
14611943SCurtis.Dunham@arm.com    auto vcpu = vm.contextIdToVCpuId(ctx);
14711943SCurtis.Dunham@arm.com    return getGicReg(KVM_DEV_ARM_VGIC_GRP_CPU_REGS, vcpu, daddr);
14811943SCurtis.Dunham@arm.com}
14911943SCurtis.Dunham@arm.com
15011943SCurtis.Dunham@arm.comvoid
15111943SCurtis.Dunham@arm.comKvmKernelGicV2::writeDistributor(ContextID ctx, Addr daddr, uint32_t data)
15211943SCurtis.Dunham@arm.com{
15311943SCurtis.Dunham@arm.com    auto vcpu = vm.contextIdToVCpuId(ctx);
15411943SCurtis.Dunham@arm.com    setGicReg(KVM_DEV_ARM_VGIC_GRP_DIST_REGS, vcpu, daddr, data);
15511943SCurtis.Dunham@arm.com}
15611943SCurtis.Dunham@arm.com
15711943SCurtis.Dunham@arm.comvoid
15811943SCurtis.Dunham@arm.comKvmKernelGicV2::writeCpu(ContextID ctx, Addr daddr, uint32_t data)
15911943SCurtis.Dunham@arm.com{
16011943SCurtis.Dunham@arm.com    auto vcpu = vm.contextIdToVCpuId(ctx);
16111943SCurtis.Dunham@arm.com    setGicReg(KVM_DEV_ARM_VGIC_GRP_CPU_REGS, vcpu, daddr, data);
16211943SCurtis.Dunham@arm.com}
16311943SCurtis.Dunham@arm.com
16411943SCurtis.Dunham@arm.com
16511461Sandreas.sandberg@arm.com
16611840SCurtis.Dunham@arm.comMuxingKvmGic::MuxingKvmGic(const MuxingKvmGicParams *p)
16711840SCurtis.Dunham@arm.com    : Pl390(p),
16811840SCurtis.Dunham@arm.com      system(*p->system),
16911840SCurtis.Dunham@arm.com      kernelGic(nullptr),
17011840SCurtis.Dunham@arm.com      usingKvm(false)
17111840SCurtis.Dunham@arm.com{
17211840SCurtis.Dunham@arm.com    if (auto vm = system.getKvmVM()) {
17311840SCurtis.Dunham@arm.com        kernelGic = new KvmKernelGicV2(*vm, p->cpu_addr, p->dist_addr,
17411840SCurtis.Dunham@arm.com                                       p->it_lines);
17511840SCurtis.Dunham@arm.com    }
17611840SCurtis.Dunham@arm.com}
17711840SCurtis.Dunham@arm.com
17811840SCurtis.Dunham@arm.comMuxingKvmGic::~MuxingKvmGic()
17911840SCurtis.Dunham@arm.com{
18011840SCurtis.Dunham@arm.com}
18111840SCurtis.Dunham@arm.com
18211840SCurtis.Dunham@arm.comvoid
18311943SCurtis.Dunham@arm.comMuxingKvmGic::loadState(CheckpointIn &cp)
18411943SCurtis.Dunham@arm.com{
18511943SCurtis.Dunham@arm.com    Pl390::loadState(cp);
18611943SCurtis.Dunham@arm.com}
18711943SCurtis.Dunham@arm.com
18811943SCurtis.Dunham@arm.comvoid
18911840SCurtis.Dunham@arm.comMuxingKvmGic::startup()
19011840SCurtis.Dunham@arm.com{
19111943SCurtis.Dunham@arm.com    Pl390::startup();
19212100SCurtis.Dunham@arm.com    usingKvm = (kernelGic != nullptr) && system.validKvmEnvironment();
19311943SCurtis.Dunham@arm.com    if (usingKvm)
19411943SCurtis.Dunham@arm.com        fromPl390ToKvm();
19511943SCurtis.Dunham@arm.com}
19611943SCurtis.Dunham@arm.com
19711943SCurtis.Dunham@arm.comDrainState
19811943SCurtis.Dunham@arm.comMuxingKvmGic::drain()
19911943SCurtis.Dunham@arm.com{
20011943SCurtis.Dunham@arm.com    if (usingKvm)
20111943SCurtis.Dunham@arm.com        fromKvmToPl390();
20211943SCurtis.Dunham@arm.com    return Pl390::drain();
20311840SCurtis.Dunham@arm.com}
20411840SCurtis.Dunham@arm.com
20511840SCurtis.Dunham@arm.comvoid
20611840SCurtis.Dunham@arm.comMuxingKvmGic::drainResume()
20711840SCurtis.Dunham@arm.com{
20811943SCurtis.Dunham@arm.com    Pl390::drainResume();
20912100SCurtis.Dunham@arm.com    bool use_kvm = (kernelGic != nullptr) && system.validKvmEnvironment();
21011840SCurtis.Dunham@arm.com    if (use_kvm != usingKvm) {
21111943SCurtis.Dunham@arm.com        // Should only occur due to CPU switches
21211840SCurtis.Dunham@arm.com        if (use_kvm) // from simulation to KVM emulation
21311840SCurtis.Dunham@arm.com            fromPl390ToKvm();
21411943SCurtis.Dunham@arm.com        // otherwise, drain() already sync'd the state back to the Pl390
21511840SCurtis.Dunham@arm.com
21611840SCurtis.Dunham@arm.com        usingKvm = use_kvm;
21711840SCurtis.Dunham@arm.com    }
21811840SCurtis.Dunham@arm.com}
21911840SCurtis.Dunham@arm.com
22011840SCurtis.Dunham@arm.comvoid
22111840SCurtis.Dunham@arm.comMuxingKvmGic::serialize(CheckpointOut &cp) const
22211840SCurtis.Dunham@arm.com{
22311943SCurtis.Dunham@arm.com    // drain() already ensured Pl390 updated with KvmGic state if necessary
22411943SCurtis.Dunham@arm.com    Pl390::serialize(cp);
22511840SCurtis.Dunham@arm.com}
22611840SCurtis.Dunham@arm.com
22711840SCurtis.Dunham@arm.comvoid
22811840SCurtis.Dunham@arm.comMuxingKvmGic::unserialize(CheckpointIn &cp)
22911840SCurtis.Dunham@arm.com{
23011943SCurtis.Dunham@arm.com    Pl390::unserialize(cp);
23111840SCurtis.Dunham@arm.com}
23211840SCurtis.Dunham@arm.com
23311840SCurtis.Dunham@arm.comTick
23411840SCurtis.Dunham@arm.comMuxingKvmGic::read(PacketPtr pkt)
23511840SCurtis.Dunham@arm.com{
23611840SCurtis.Dunham@arm.com    if (!usingKvm)
23711840SCurtis.Dunham@arm.com        return Pl390::read(pkt);
23811840SCurtis.Dunham@arm.com
23911840SCurtis.Dunham@arm.com    panic("MuxingKvmGic: PIO from gem5 is currently unsupported\n");
24011840SCurtis.Dunham@arm.com}
24111840SCurtis.Dunham@arm.com
24211840SCurtis.Dunham@arm.comTick
24311840SCurtis.Dunham@arm.comMuxingKvmGic::write(PacketPtr pkt)
24411840SCurtis.Dunham@arm.com{
24511840SCurtis.Dunham@arm.com    if (!usingKvm)
24611840SCurtis.Dunham@arm.com        return Pl390::write(pkt);
24711840SCurtis.Dunham@arm.com
24811840SCurtis.Dunham@arm.com    panic("MuxingKvmGic: PIO from gem5 is currently unsupported\n");
24911840SCurtis.Dunham@arm.com}
25011840SCurtis.Dunham@arm.com
25111840SCurtis.Dunham@arm.comvoid
25211840SCurtis.Dunham@arm.comMuxingKvmGic::sendInt(uint32_t num)
25311840SCurtis.Dunham@arm.com{
25411840SCurtis.Dunham@arm.com    if (!usingKvm)
25511840SCurtis.Dunham@arm.com        return Pl390::sendInt(num);
25611840SCurtis.Dunham@arm.com
25711840SCurtis.Dunham@arm.com    DPRINTF(Interrupt, "Set SPI %d\n", num);
25811840SCurtis.Dunham@arm.com    kernelGic->setSPI(num);
25911840SCurtis.Dunham@arm.com}
26011840SCurtis.Dunham@arm.com
26111840SCurtis.Dunham@arm.comvoid
26211840SCurtis.Dunham@arm.comMuxingKvmGic::clearInt(uint32_t num)
26311840SCurtis.Dunham@arm.com{
26411840SCurtis.Dunham@arm.com    if (!usingKvm)
26511840SCurtis.Dunham@arm.com        return Pl390::clearInt(num);
26611840SCurtis.Dunham@arm.com
26711840SCurtis.Dunham@arm.com    DPRINTF(Interrupt, "Clear SPI %d\n", num);
26811840SCurtis.Dunham@arm.com    kernelGic->clearSPI(num);
26911840SCurtis.Dunham@arm.com}
27011840SCurtis.Dunham@arm.com
27111840SCurtis.Dunham@arm.comvoid
27211840SCurtis.Dunham@arm.comMuxingKvmGic::sendPPInt(uint32_t num, uint32_t cpu)
27311840SCurtis.Dunham@arm.com{
27411840SCurtis.Dunham@arm.com    if (!usingKvm)
27511840SCurtis.Dunham@arm.com        return Pl390::sendPPInt(num, cpu);
27611840SCurtis.Dunham@arm.com    DPRINTF(Interrupt, "Set PPI %d:%d\n", cpu, num);
27711840SCurtis.Dunham@arm.com    kernelGic->setPPI(cpu, num);
27811840SCurtis.Dunham@arm.com}
27911840SCurtis.Dunham@arm.com
28011840SCurtis.Dunham@arm.comvoid
28111840SCurtis.Dunham@arm.comMuxingKvmGic::clearPPInt(uint32_t num, uint32_t cpu)
28211840SCurtis.Dunham@arm.com{
28311840SCurtis.Dunham@arm.com    if (!usingKvm)
28411840SCurtis.Dunham@arm.com        return Pl390::clearPPInt(num, cpu);
28511840SCurtis.Dunham@arm.com
28611840SCurtis.Dunham@arm.com    DPRINTF(Interrupt, "Clear PPI %d:%d\n", cpu, num);
28711840SCurtis.Dunham@arm.com    kernelGic->clearPPI(cpu, num);
28811840SCurtis.Dunham@arm.com}
28911840SCurtis.Dunham@arm.com
29011840SCurtis.Dunham@arm.comvoid
29111943SCurtis.Dunham@arm.comMuxingKvmGic::copyDistRegister(BaseGicRegisters* from, BaseGicRegisters* to,
29211943SCurtis.Dunham@arm.com                               ContextID ctx, Addr daddr)
29311943SCurtis.Dunham@arm.com{
29411943SCurtis.Dunham@arm.com    auto val = from->readDistributor(ctx, daddr);
29511943SCurtis.Dunham@arm.com    DPRINTF(GIC, "copy dist 0x%x 0x%08x\n", daddr, val);
29611943SCurtis.Dunham@arm.com    to->writeDistributor(ctx, daddr, val);
29711943SCurtis.Dunham@arm.com}
29811943SCurtis.Dunham@arm.com
29911943SCurtis.Dunham@arm.comvoid
30011943SCurtis.Dunham@arm.comMuxingKvmGic::copyCpuRegister(BaseGicRegisters* from, BaseGicRegisters* to,
30111943SCurtis.Dunham@arm.com                               ContextID ctx, Addr daddr)
30211943SCurtis.Dunham@arm.com{
30311943SCurtis.Dunham@arm.com    auto val = from->readCpu(ctx, daddr);
30411943SCurtis.Dunham@arm.com    DPRINTF(GIC, "copy cpu  0x%x 0x%08x\n", daddr, val);
30511943SCurtis.Dunham@arm.com    to->writeCpu(ctx, daddr, val);
30611943SCurtis.Dunham@arm.com}
30711943SCurtis.Dunham@arm.com
30811943SCurtis.Dunham@arm.comvoid
30911943SCurtis.Dunham@arm.comMuxingKvmGic::copyBankedDistRange(BaseGicRegisters* from, BaseGicRegisters* to,
31011943SCurtis.Dunham@arm.com                                  Addr daddr, size_t size)
31111943SCurtis.Dunham@arm.com{
31211943SCurtis.Dunham@arm.com    for (int ctx = 0; ctx < system._numContexts; ++ctx)
31311943SCurtis.Dunham@arm.com        for (auto a = daddr; a < daddr + size; a += 4)
31411943SCurtis.Dunham@arm.com            copyDistRegister(from, to, ctx, a);
31511943SCurtis.Dunham@arm.com}
31611943SCurtis.Dunham@arm.com
31711943SCurtis.Dunham@arm.comvoid
31811943SCurtis.Dunham@arm.comMuxingKvmGic::clearBankedDistRange(BaseGicRegisters* to,
31911943SCurtis.Dunham@arm.com                                   Addr daddr, size_t size)
32011943SCurtis.Dunham@arm.com{
32111943SCurtis.Dunham@arm.com    for (int ctx = 0; ctx < system._numContexts; ++ctx)
32211943SCurtis.Dunham@arm.com        for (auto a = daddr; a < daddr + size; a += 4)
32311943SCurtis.Dunham@arm.com            to->writeDistributor(ctx, a, 0xFFFFFFFF);
32411943SCurtis.Dunham@arm.com}
32511943SCurtis.Dunham@arm.com
32611943SCurtis.Dunham@arm.comvoid
32711943SCurtis.Dunham@arm.comMuxingKvmGic::copyDistRange(BaseGicRegisters* from, BaseGicRegisters* to,
32811943SCurtis.Dunham@arm.com                            Addr daddr, size_t size)
32911943SCurtis.Dunham@arm.com{
33011943SCurtis.Dunham@arm.com    for (auto a = daddr; a < daddr + size; a += 4)
33111943SCurtis.Dunham@arm.com        copyDistRegister(from, to, 0, a);
33211943SCurtis.Dunham@arm.com}
33311943SCurtis.Dunham@arm.com
33411943SCurtis.Dunham@arm.comvoid
33511943SCurtis.Dunham@arm.comMuxingKvmGic::clearDistRange(BaseGicRegisters* to,
33611943SCurtis.Dunham@arm.com                             Addr daddr, size_t size)
33711943SCurtis.Dunham@arm.com{
33811943SCurtis.Dunham@arm.com    for (auto a = daddr; a < daddr + size; a += 4)
33911943SCurtis.Dunham@arm.com        to->writeDistributor(0, a, 0xFFFFFFFF);
34011943SCurtis.Dunham@arm.com}
34111943SCurtis.Dunham@arm.com
34211943SCurtis.Dunham@arm.comvoid
34311943SCurtis.Dunham@arm.comMuxingKvmGic::copyGicState(BaseGicRegisters* from, BaseGicRegisters* to)
34411943SCurtis.Dunham@arm.com{
34511943SCurtis.Dunham@arm.com    Addr set, clear;
34611943SCurtis.Dunham@arm.com    size_t size;
34711943SCurtis.Dunham@arm.com
34811943SCurtis.Dunham@arm.com    /// CPU state (GICC_*)
34911943SCurtis.Dunham@arm.com    // Copy CPU Interface Control Register (CTLR),
35011943SCurtis.Dunham@arm.com    //      Interrupt Priority Mask Register (PMR), and
35111943SCurtis.Dunham@arm.com    //      Binary Point Register (BPR)
35211943SCurtis.Dunham@arm.com    for (int ctx = 0; ctx < system._numContexts; ++ctx) {
35311943SCurtis.Dunham@arm.com        copyCpuRegister(from, to, ctx, GICC_CTLR);
35411943SCurtis.Dunham@arm.com        copyCpuRegister(from, to, ctx, GICC_PMR);
35511943SCurtis.Dunham@arm.com        copyCpuRegister(from, to, ctx, GICC_BPR);
35611943SCurtis.Dunham@arm.com    }
35711943SCurtis.Dunham@arm.com
35811943SCurtis.Dunham@arm.com
35911943SCurtis.Dunham@arm.com    /// Distributor state (GICD_*)
36011943SCurtis.Dunham@arm.com    // Copy Distributor Control Register (CTLR)
36111943SCurtis.Dunham@arm.com    copyDistRegister(from, to, 0, GICD_CTLR);
36211943SCurtis.Dunham@arm.com
36311943SCurtis.Dunham@arm.com    // Copy interrupt-enabled statuses (I[CS]ENABLERn; R0 is per-CPU banked)
36411943SCurtis.Dunham@arm.com    set   = Pl390::GICD_ISENABLER.start();
36511943SCurtis.Dunham@arm.com    clear = Pl390::GICD_ICENABLER.start();
36611943SCurtis.Dunham@arm.com    size  = Pl390::itLines / 8;
36711943SCurtis.Dunham@arm.com    clearBankedDistRange(to, clear, 4);
36811943SCurtis.Dunham@arm.com    copyBankedDistRange(from, to, set, 4);
36911943SCurtis.Dunham@arm.com
37011943SCurtis.Dunham@arm.com    set += 4, clear += 4, size -= 4;
37111943SCurtis.Dunham@arm.com    clearDistRange(to, clear, size);
37211943SCurtis.Dunham@arm.com    copyDistRange(from, to, set, size);
37311943SCurtis.Dunham@arm.com
37411943SCurtis.Dunham@arm.com    // Copy pending interrupts (I[CS]PENDRn; R0 is per-CPU banked)
37511943SCurtis.Dunham@arm.com    set   = Pl390::GICD_ISPENDR.start();
37611943SCurtis.Dunham@arm.com    clear = Pl390::GICD_ICPENDR.start();
37711943SCurtis.Dunham@arm.com    size  = Pl390::itLines / 8;
37811943SCurtis.Dunham@arm.com    clearBankedDistRange(to, clear, 4);
37911943SCurtis.Dunham@arm.com    copyBankedDistRange(from, to, set, 4);
38011943SCurtis.Dunham@arm.com
38111943SCurtis.Dunham@arm.com    set += 4, clear += 4, size -= 4;
38211943SCurtis.Dunham@arm.com    clearDistRange(to, clear, size);
38311943SCurtis.Dunham@arm.com    copyDistRange(from, to, set, size);
38411943SCurtis.Dunham@arm.com
38511943SCurtis.Dunham@arm.com    // Copy active interrupts (I[CS]ACTIVERn; R0 is per-CPU banked)
38611943SCurtis.Dunham@arm.com    set   = Pl390::GICD_ISACTIVER.start();
38711943SCurtis.Dunham@arm.com    clear = Pl390::GICD_ICACTIVER.start();
38811943SCurtis.Dunham@arm.com    size  = Pl390::itLines / 8;
38911943SCurtis.Dunham@arm.com    clearBankedDistRange(to, clear, 4);
39011943SCurtis.Dunham@arm.com    copyBankedDistRange(from, to, set, 4);
39111943SCurtis.Dunham@arm.com
39211943SCurtis.Dunham@arm.com    set += 4, clear += 4, size -= 4;
39311943SCurtis.Dunham@arm.com    clearDistRange(to, clear, size);
39411943SCurtis.Dunham@arm.com    copyDistRange(from, to, set, size);
39511943SCurtis.Dunham@arm.com
39611943SCurtis.Dunham@arm.com    // Copy interrupt priorities (IPRIORITYRn; R0-7 are per-CPU banked)
39711943SCurtis.Dunham@arm.com    set   = Pl390::GICD_IPRIORITYR.start();
39811943SCurtis.Dunham@arm.com    copyBankedDistRange(from, to, set, 32);
39911943SCurtis.Dunham@arm.com
40011943SCurtis.Dunham@arm.com    set += 32;
40111943SCurtis.Dunham@arm.com    size = Pl390::itLines - 32;
40211943SCurtis.Dunham@arm.com    copyDistRange(from, to, set, size);
40311943SCurtis.Dunham@arm.com
40411943SCurtis.Dunham@arm.com    // Copy interrupt processor target regs (ITARGETRn; R0-7 are read-only)
40511943SCurtis.Dunham@arm.com    set = Pl390::GICD_ITARGETSR.start() + 32;
40611943SCurtis.Dunham@arm.com    size = Pl390::itLines - 32;
40711943SCurtis.Dunham@arm.com    copyDistRange(from, to, set, size);
40811943SCurtis.Dunham@arm.com
40911943SCurtis.Dunham@arm.com    // Copy interrupt configuration registers (ICFGRn)
41011943SCurtis.Dunham@arm.com    set = Pl390::GICD_ICFGR.start();
41111943SCurtis.Dunham@arm.com    size = Pl390::itLines / 4;
41211943SCurtis.Dunham@arm.com    copyDistRange(from, to, set, size);
41311943SCurtis.Dunham@arm.com}
41411943SCurtis.Dunham@arm.com
41511943SCurtis.Dunham@arm.comvoid
41611840SCurtis.Dunham@arm.comMuxingKvmGic::fromPl390ToKvm()
41711840SCurtis.Dunham@arm.com{
41811943SCurtis.Dunham@arm.com    copyGicState(static_cast<Pl390*>(this), kernelGic);
41911840SCurtis.Dunham@arm.com}
42011840SCurtis.Dunham@arm.com
42111840SCurtis.Dunham@arm.comvoid
42211840SCurtis.Dunham@arm.comMuxingKvmGic::fromKvmToPl390()
42311840SCurtis.Dunham@arm.com{
42411943SCurtis.Dunham@arm.com    copyGicState(kernelGic, static_cast<Pl390*>(this));
42511943SCurtis.Dunham@arm.com
42611943SCurtis.Dunham@arm.com    // the values read for the Interrupt Priority Mask Register (PMR)
42711943SCurtis.Dunham@arm.com    // have been shifted by three bits due to its having been emulated by
42811943SCurtis.Dunham@arm.com    // a VGIC with only 5 PMR bits in its VMCR register.  Presently the
42911943SCurtis.Dunham@arm.com    // Linux kernel does not repair this inaccuracy, so we correct it here.
43011943SCurtis.Dunham@arm.com    for (int cpu = 0; cpu < system._numContexts; ++cpu) {
43111943SCurtis.Dunham@arm.com       cpuPriority[cpu] <<= 3;
43211943SCurtis.Dunham@arm.com       assert((cpuPriority[cpu] & ~0xff) == 0);
43311943SCurtis.Dunham@arm.com    }
43411840SCurtis.Dunham@arm.com}
43511840SCurtis.Dunham@arm.com
43611840SCurtis.Dunham@arm.comMuxingKvmGic *
43711840SCurtis.Dunham@arm.comMuxingKvmGicParams::create()
43811840SCurtis.Dunham@arm.com{
43911840SCurtis.Dunham@arm.com    return new MuxingKvmGic(this);
44011840SCurtis.Dunham@arm.com}
441