From d5e78923505b18cd5af6a7a2996605569fb2e4b9 Mon Sep 17 00:00:00 2001 From: Andreas Sandberg Date: Wed, 27 Apr 2016 15:34:31 +0100 Subject: [PATCH] kvm, arm: Refactor KVM GIC device Factor out the kernel device wrapper from the KvmGIC and put it in a separate class. This will simplify a future kernel/gem5 hybrid GIC. Signed-off-by: Andreas Sandberg Reviewed-by: Radhika Jagtap Reviewed-by: Nikos Nikoleris --- src/arch/arm/kvm/gic.cc | 94 +++++++++++++++++++++----------- src/arch/arm/kvm/gic.hh | 115 ++++++++++++++++++++++++++++++++-------- 2 files changed, 158 insertions(+), 51 deletions(-) diff --git a/src/arch/arm/kvm/gic.cc b/src/arch/arm/kvm/gic.cc index a0e0e7899..bed13ec2c 100644 --- a/src/arch/arm/kvm/gic.cc +++ b/src/arch/arm/kvm/gic.cc @@ -1,5 +1,5 @@ /* - * Copyright (c) 2015 ARM Limited + * Copyright (c) 2015-2016 ARM Limited * All rights reserved * * The license below extends only to copyright in the software and shall @@ -44,21 +44,69 @@ #include "debug/Interrupt.hh" #include "params/KvmGic.hh" + +KvmKernelGicV2::KvmKernelGicV2(KvmVM &_vm, Addr cpu_addr, Addr dist_addr) + : cpuRange(RangeSize(cpu_addr, KVM_VGIC_V2_CPU_SIZE)), + distRange(RangeSize(dist_addr, KVM_VGIC_V2_DIST_SIZE)), + vm(_vm), + kdev(vm.createDevice(KVM_DEV_TYPE_ARM_VGIC_V2)) +{ + kdev.setAttr( + KVM_DEV_ARM_VGIC_GRP_ADDR, KVM_VGIC_V2_ADDR_TYPE_DIST, dist_addr); + kdev.setAttr( + KVM_DEV_ARM_VGIC_GRP_ADDR, KVM_VGIC_V2_ADDR_TYPE_CPU, cpu_addr); +} + +KvmKernelGicV2::~KvmKernelGicV2() +{ +} + +void +KvmKernelGicV2::setSPI(unsigned spi) +{ + setIntState(KVM_ARM_IRQ_TYPE_SPI, 0, spi, true); +} + +void +KvmKernelGicV2::clearSPI(unsigned spi) +{ + setIntState(KVM_ARM_IRQ_TYPE_SPI, 0, spi, false); +} + +void +KvmKernelGicV2::setPPI(unsigned vcpu, unsigned ppi) +{ + setIntState(KVM_ARM_IRQ_TYPE_PPI, vcpu, ppi, true); +} + +void +KvmKernelGicV2::clearPPI(unsigned vcpu, unsigned ppi) +{ + setIntState(KVM_ARM_IRQ_TYPE_PPI, vcpu, ppi, false); +} + +void +KvmKernelGicV2::setIntState(unsigned type, unsigned vcpu, unsigned irq, + bool high) +{ + assert(type <= KVM_ARM_IRQ_TYPE_MASK); + assert(vcpu <= KVM_ARM_IRQ_VCPU_MASK); + assert(irq <= KVM_ARM_IRQ_NUM_MASK); + const uint32_t line( + (type << KVM_ARM_IRQ_TYPE_SHIFT) | + (vcpu << KVM_ARM_IRQ_VCPU_SHIFT) | + (irq << KVM_ARM_IRQ_NUM_SHIFT)); + + vm.setIRQLine(line, high); +} + + KvmGic::KvmGic(const KvmGicParams *p) : BaseGic(p), system(*p->system), - vm(*p->kvmVM), - kdev(vm.createDevice(KVM_DEV_TYPE_ARM_VGIC_V2)), - distRange(RangeSize(p->dist_addr, KVM_VGIC_V2_DIST_SIZE)), - cpuRange(RangeSize(p->cpu_addr, KVM_VGIC_V2_CPU_SIZE)), - addrRanges{distRange, cpuRange} + kernelGic(*p->kvmVM, p->cpu_addr, p->dist_addr), + addrRanges{kernelGic.distRange, kernelGic.cpuRange} { - kdev.setAttr( - KVM_DEV_ARM_VGIC_GRP_ADDR, KVM_VGIC_V2_ADDR_TYPE_DIST, - p->dist_addr); - kdev.setAttr( - KVM_DEV_ARM_VGIC_GRP_ADDR, KVM_VGIC_V2_ADDR_TYPE_CPU, - p->cpu_addr); } KvmGic::~KvmGic() @@ -93,28 +141,28 @@ void KvmGic::sendInt(uint32_t num) { DPRINTF(Interrupt, "Set SPI %d\n", num); - setIntState(KVM_ARM_IRQ_TYPE_SPI, 0, num, true); + kernelGic.setSPI(num); } void KvmGic::clearInt(uint32_t num) { DPRINTF(Interrupt, "Clear SPI %d\n", num); - setIntState(KVM_ARM_IRQ_TYPE_SPI, 0, num, false); + kernelGic.clearSPI(num); } void KvmGic::sendPPInt(uint32_t num, uint32_t cpu) { DPRINTF(Interrupt, "Set PPI %d:%d\n", cpu, num); - setIntState(KVM_ARM_IRQ_TYPE_PPI, cpu, num, true); + kernelGic.setPPI(cpu, num); } void KvmGic::clearPPInt(uint32_t num, uint32_t cpu) { DPRINTF(Interrupt, "Clear PPI %d:%d\n", cpu, num); - setIntState(KVM_ARM_IRQ_TYPE_PPI, cpu, num, false); + kernelGic.clearPPI(cpu, num); } void @@ -126,20 +174,6 @@ KvmGic::verifyMemoryMode() const } } -void -KvmGic::setIntState(uint8_t type, uint8_t vcpu, uint16_t irq, bool high) -{ - assert(type < KVM_ARM_IRQ_TYPE_MASK); - assert(vcpu < KVM_ARM_IRQ_VCPU_MASK); - assert(irq < KVM_ARM_IRQ_NUM_MASK); - const uint32_t line( - (type << KVM_ARM_IRQ_TYPE_SHIFT) | - (vcpu << KVM_ARM_IRQ_VCPU_SHIFT) | - (irq << KVM_ARM_IRQ_NUM_SHIFT)); - - vm.setIRQLine(line, high); -} - KvmGic * KvmGicParams::create() diff --git a/src/arch/arm/kvm/gic.hh b/src/arch/arm/kvm/gic.hh index f6360858b..77a7b5e53 100644 --- a/src/arch/arm/kvm/gic.hh +++ b/src/arch/arm/kvm/gic.hh @@ -1,5 +1,5 @@ /* - * Copyright (c) 2015 ARM Limited + * Copyright (c) 2015-2016 ARM Limited * All rights reserved * * The license below extends only to copyright in the software and shall @@ -46,7 +46,95 @@ #include "dev/arm/base_gic.hh" #include "dev/platform.hh" -class KvmGicParams; +/** + * KVM in-kernel GIC abstraction + * + * This class defines a high-level interface to the KVM in-kernel GIC + * model. It exposes an API that is similar to that of + * software-emulated GIC models in gem5. + */ +class KvmKernelGicV2 +{ + public: + /** + * Instantiate a KVM in-kernel GIC model. + * + * This constructor instantiates an in-kernel GIC model and wires + * it up to the virtual memory system. + * + * @param vm KVM VM representing this system + * @param cpu_addr GIC CPU interface base address + * @param dist_addr GIC distributor base address + */ + KvmKernelGicV2(KvmVM &vm, Addr cpu_addr, Addr dist_addr); + virtual ~KvmKernelGicV2(); + + KvmKernelGicV2(const KvmKernelGicV2 &other) = delete; + KvmKernelGicV2(const KvmKernelGicV2 &&other) = delete; + KvmKernelGicV2 &operator=(const KvmKernelGicV2 &&rhs) = delete; + KvmKernelGicV2 &operator=(const KvmKernelGicV2 &rhs) = delete; + + public: + /** + * @{ + * @name In-kernel GIC API + */ + + /** + * Raise a shared peripheral interrupt + * + * @param spi SPI number + */ + void setSPI(unsigned spi); + /** + * Clear a shared peripheral interrupt + * + * @param spi SPI number + */ + void clearSPI(unsigned spi); + + /** + * Raise a private peripheral interrupt + * + * @param vcpu KVM virtual CPU number + * @parma ppi PPI interrupt number + */ + void setPPI(unsigned vcpu, unsigned ppi); + + /** + * Clear a private peripheral interrupt + * + * @param vcpu KVM virtual CPU number + * @parma ppi PPI interrupt number + */ + void clearPPI(unsigned vcpu, unsigned ppi); + + /** Address range for the CPU interfaces */ + const AddrRange cpuRange; + /** Address range for the distributor interface */ + const AddrRange distRange; + + /* @} */ + + protected: + /** + * Update the kernel's VGIC interrupt state + * + * @param type Interrupt type (KVM_ARM_IRQ_TYPE_PPI/KVM_ARM_IRQ_TYPE_SPI) + * @param vcpu CPU id within KVM (ignored for SPIs) + * @param irq Interrupt number + * @param high True to signal an interrupt, false to clear it. + */ + void setIntState(unsigned type, unsigned vcpu, unsigned irq, bool high); + + /** KVM VM in the parent system */ + KvmVM &vm; + + /** Kernel interface to the GIC */ + KvmDevice kdev; +}; + +struct KvmGicParams; /** * In-kernel GIC model. @@ -80,7 +168,7 @@ class KvmGic : public BaseGic void drainResume() override { verifyMemoryMode(); } void serialize(CheckpointOut &cp) const override; - void unserialize(CheckpointIn &cp) override; + void unserialize(CheckpointIn &cp) override; public: // PioDevice AddrRangeList getAddrRanges() const { return addrRanges; } @@ -105,27 +193,12 @@ class KvmGic : public BaseGic */ void verifyMemoryMode() const; - /** - * Update the kernel's VGIC interrupt state - * - * @param type Interrupt type (KVM_ARM_IRQ_TYPE_PPI/KVM_ARM_IRQ_TYPE_SPI) - * @param vcpu CPU id within KVM (ignored for SPIs) - * @param irq Interrupt number - * @param high True to signal an interrupt, false to clear it. - */ - void setIntState(uint8_t type, uint8_t vcpu, uint16_t irq, bool high); - /** System this interrupt controller belongs to */ System &system; - /** VM for this system */ - KvmVM &vm; - /** Kernel interface to the GIC */ - KvmDevice kdev; - /** Address range for the distributor interface */ - const AddrRange distRange; - /** Address range for the CPU interfaces */ - const AddrRange cpuRange; + /** Kernel GIC device */ + KvmKernelGicV2 kernelGic; + /** Union of all memory */ const AddrRangeList addrRanges; }; -- 2.30.2