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 <andreas.sandberg@arm.com> Reviewed-by: Radhika Jagtap <radhika.jagtap@arm.com> Reviewed-by: Nikos Nikoleris <nikos.nikoleris@arm.com>
This commit is contained in:
parent
6d74892b38
commit
d5e7892350
2 changed files with 158 additions and 51 deletions
|
@ -1,5 +1,5 @@
|
||||||
/*
|
/*
|
||||||
* Copyright (c) 2015 ARM Limited
|
* Copyright (c) 2015-2016 ARM Limited
|
||||||
* All rights reserved
|
* All rights reserved
|
||||||
*
|
*
|
||||||
* The license below extends only to copyright in the software and shall
|
* The license below extends only to copyright in the software and shall
|
||||||
|
@ -44,21 +44,69 @@
|
||||||
#include "debug/Interrupt.hh"
|
#include "debug/Interrupt.hh"
|
||||||
#include "params/KvmGic.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<uint64_t>(
|
||||||
|
KVM_DEV_ARM_VGIC_GRP_ADDR, KVM_VGIC_V2_ADDR_TYPE_DIST, dist_addr);
|
||||||
|
kdev.setAttr<uint64_t>(
|
||||||
|
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)
|
KvmGic::KvmGic(const KvmGicParams *p)
|
||||||
: BaseGic(p),
|
: BaseGic(p),
|
||||||
system(*p->system),
|
system(*p->system),
|
||||||
vm(*p->kvmVM),
|
kernelGic(*p->kvmVM, p->cpu_addr, p->dist_addr),
|
||||||
kdev(vm.createDevice(KVM_DEV_TYPE_ARM_VGIC_V2)),
|
addrRanges{kernelGic.distRange, kernelGic.cpuRange}
|
||||||
distRange(RangeSize(p->dist_addr, KVM_VGIC_V2_DIST_SIZE)),
|
|
||||||
cpuRange(RangeSize(p->cpu_addr, KVM_VGIC_V2_CPU_SIZE)),
|
|
||||||
addrRanges{distRange, cpuRange}
|
|
||||||
{
|
{
|
||||||
kdev.setAttr<uint64_t>(
|
|
||||||
KVM_DEV_ARM_VGIC_GRP_ADDR, KVM_VGIC_V2_ADDR_TYPE_DIST,
|
|
||||||
p->dist_addr);
|
|
||||||
kdev.setAttr<uint64_t>(
|
|
||||||
KVM_DEV_ARM_VGIC_GRP_ADDR, KVM_VGIC_V2_ADDR_TYPE_CPU,
|
|
||||||
p->cpu_addr);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
KvmGic::~KvmGic()
|
KvmGic::~KvmGic()
|
||||||
|
@ -93,28 +141,28 @@ void
|
||||||
KvmGic::sendInt(uint32_t num)
|
KvmGic::sendInt(uint32_t num)
|
||||||
{
|
{
|
||||||
DPRINTF(Interrupt, "Set SPI %d\n", num);
|
DPRINTF(Interrupt, "Set SPI %d\n", num);
|
||||||
setIntState(KVM_ARM_IRQ_TYPE_SPI, 0, num, true);
|
kernelGic.setSPI(num);
|
||||||
}
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
KvmGic::clearInt(uint32_t num)
|
KvmGic::clearInt(uint32_t num)
|
||||||
{
|
{
|
||||||
DPRINTF(Interrupt, "Clear SPI %d\n", num);
|
DPRINTF(Interrupt, "Clear SPI %d\n", num);
|
||||||
setIntState(KVM_ARM_IRQ_TYPE_SPI, 0, num, false);
|
kernelGic.clearSPI(num);
|
||||||
}
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
KvmGic::sendPPInt(uint32_t num, uint32_t cpu)
|
KvmGic::sendPPInt(uint32_t num, uint32_t cpu)
|
||||||
{
|
{
|
||||||
DPRINTF(Interrupt, "Set PPI %d:%d\n", cpu, num);
|
DPRINTF(Interrupt, "Set PPI %d:%d\n", cpu, num);
|
||||||
setIntState(KVM_ARM_IRQ_TYPE_PPI, cpu, num, true);
|
kernelGic.setPPI(cpu, num);
|
||||||
}
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
KvmGic::clearPPInt(uint32_t num, uint32_t cpu)
|
KvmGic::clearPPInt(uint32_t num, uint32_t cpu)
|
||||||
{
|
{
|
||||||
DPRINTF(Interrupt, "Clear PPI %d:%d\n", cpu, num);
|
DPRINTF(Interrupt, "Clear PPI %d:%d\n", cpu, num);
|
||||||
setIntState(KVM_ARM_IRQ_TYPE_PPI, cpu, num, false);
|
kernelGic.clearPPI(cpu, num);
|
||||||
}
|
}
|
||||||
|
|
||||||
void
|
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 *
|
KvmGic *
|
||||||
KvmGicParams::create()
|
KvmGicParams::create()
|
||||||
|
|
|
@ -1,5 +1,5 @@
|
||||||
/*
|
/*
|
||||||
* Copyright (c) 2015 ARM Limited
|
* Copyright (c) 2015-2016 ARM Limited
|
||||||
* All rights reserved
|
* All rights reserved
|
||||||
*
|
*
|
||||||
* The license below extends only to copyright in the software and shall
|
* The license below extends only to copyright in the software and shall
|
||||||
|
@ -46,7 +46,95 @@
|
||||||
#include "dev/arm/base_gic.hh"
|
#include "dev/arm/base_gic.hh"
|
||||||
#include "dev/platform.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.
|
* In-kernel GIC model.
|
||||||
|
@ -80,7 +168,7 @@ class KvmGic : public BaseGic
|
||||||
void drainResume() override { verifyMemoryMode(); }
|
void drainResume() override { verifyMemoryMode(); }
|
||||||
|
|
||||||
void serialize(CheckpointOut &cp) const override;
|
void serialize(CheckpointOut &cp) const override;
|
||||||
void unserialize(CheckpointIn &cp) override;
|
void unserialize(CheckpointIn &cp) override;
|
||||||
|
|
||||||
public: // PioDevice
|
public: // PioDevice
|
||||||
AddrRangeList getAddrRanges() const { return addrRanges; }
|
AddrRangeList getAddrRanges() const { return addrRanges; }
|
||||||
|
@ -105,27 +193,12 @@ class KvmGic : public BaseGic
|
||||||
*/
|
*/
|
||||||
void verifyMemoryMode() const;
|
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 this interrupt controller belongs to */
|
||||||
System &system;
|
System &system;
|
||||||
/** VM for this system */
|
|
||||||
KvmVM &vm;
|
|
||||||
/** Kernel interface to the GIC */
|
|
||||||
KvmDevice kdev;
|
|
||||||
|
|
||||||
/** Address range for the distributor interface */
|
/** Kernel GIC device */
|
||||||
const AddrRange distRange;
|
KvmKernelGicV2 kernelGic;
|
||||||
/** Address range for the CPU interfaces */
|
|
||||||
const AddrRange cpuRange;
|
|
||||||
/** Union of all memory */
|
/** Union of all memory */
|
||||||
const AddrRangeList addrRanges;
|
const AddrRangeList addrRanges;
|
||||||
};
|
};
|
||||||
|
|
Loading…
Reference in a new issue