KVM: arm/arm64: vgic-new: Add CTLR, TYPER and IIDR handlers
Those three registers are v2 emulation specific, so their implementation lives entirely in vgic-mmio-v2.c. Also they are handled in one function, as their implementation is pretty simple. When the guest enables the distributor, we kick all VCPUs to get potentially pending interrupts serviced. Signed-off-by: Marc Zyngier <marc.zyngier@arm.com> Signed-off-by: Andre Przywara <andre.przywara@arm.com> Reviewed-by: Christoffer Dall <christoffer.dall@linaro.org>
This commit is contained in:
parent
fb848db396
commit
2b0cda8789
|
@ -33,6 +33,7 @@
|
||||||
|
|
||||||
#define GIC_DIST_CTRL 0x000
|
#define GIC_DIST_CTRL 0x000
|
||||||
#define GIC_DIST_CTR 0x004
|
#define GIC_DIST_CTR 0x004
|
||||||
|
#define GIC_DIST_IIDR 0x008
|
||||||
#define GIC_DIST_IGROUP 0x080
|
#define GIC_DIST_IGROUP 0x080
|
||||||
#define GIC_DIST_ENABLE_SET 0x100
|
#define GIC_DIST_ENABLE_SET 0x100
|
||||||
#define GIC_DIST_ENABLE_CLEAR 0x180
|
#define GIC_DIST_ENABLE_CLEAR 0x180
|
||||||
|
|
|
@ -20,9 +20,53 @@
|
||||||
#include "vgic.h"
|
#include "vgic.h"
|
||||||
#include "vgic-mmio.h"
|
#include "vgic-mmio.h"
|
||||||
|
|
||||||
|
static unsigned long vgic_mmio_read_v2_misc(struct kvm_vcpu *vcpu,
|
||||||
|
gpa_t addr, unsigned int len)
|
||||||
|
{
|
||||||
|
u32 value;
|
||||||
|
|
||||||
|
switch (addr & 0x0c) {
|
||||||
|
case GIC_DIST_CTRL:
|
||||||
|
value = vcpu->kvm->arch.vgic.enabled ? GICD_ENABLE : 0;
|
||||||
|
break;
|
||||||
|
case GIC_DIST_CTR:
|
||||||
|
value = vcpu->kvm->arch.vgic.nr_spis + VGIC_NR_PRIVATE_IRQS;
|
||||||
|
value = (value >> 5) - 1;
|
||||||
|
value |= (atomic_read(&vcpu->kvm->online_vcpus) - 1) << 5;
|
||||||
|
break;
|
||||||
|
case GIC_DIST_IIDR:
|
||||||
|
value = (PRODUCT_ID_KVM << 24) | (IMPLEMENTER_ARM << 0);
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
return value;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void vgic_mmio_write_v2_misc(struct kvm_vcpu *vcpu,
|
||||||
|
gpa_t addr, unsigned int len,
|
||||||
|
unsigned long val)
|
||||||
|
{
|
||||||
|
struct vgic_dist *dist = &vcpu->kvm->arch.vgic;
|
||||||
|
bool was_enabled = dist->enabled;
|
||||||
|
|
||||||
|
switch (addr & 0x0c) {
|
||||||
|
case GIC_DIST_CTRL:
|
||||||
|
dist->enabled = val & GICD_ENABLE;
|
||||||
|
if (!was_enabled && dist->enabled)
|
||||||
|
vgic_kick_vcpus(vcpu->kvm);
|
||||||
|
break;
|
||||||
|
case GIC_DIST_CTR:
|
||||||
|
case GIC_DIST_IIDR:
|
||||||
|
/* Nothing to do */
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
static const struct vgic_register_region vgic_v2_dist_registers[] = {
|
static const struct vgic_register_region vgic_v2_dist_registers[] = {
|
||||||
REGISTER_DESC_WITH_LENGTH(GIC_DIST_CTRL,
|
REGISTER_DESC_WITH_LENGTH(GIC_DIST_CTRL,
|
||||||
vgic_mmio_read_raz, vgic_mmio_write_wi, 12,
|
vgic_mmio_read_v2_misc, vgic_mmio_write_v2_misc, 12,
|
||||||
VGIC_ACCESS_32bit),
|
VGIC_ACCESS_32bit),
|
||||||
REGISTER_DESC_WITH_BITS_PER_IRQ(GIC_DIST_IGROUP,
|
REGISTER_DESC_WITH_BITS_PER_IRQ(GIC_DIST_IGROUP,
|
||||||
vgic_mmio_read_rao, vgic_mmio_write_wi, 1,
|
vgic_mmio_read_rao, vgic_mmio_write_wi, 1,
|
||||||
|
|
|
@ -545,3 +545,18 @@ int kvm_vgic_vcpu_pending_irq(struct kvm_vcpu *vcpu)
|
||||||
|
|
||||||
return pending;
|
return pending;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void vgic_kick_vcpus(struct kvm *kvm)
|
||||||
|
{
|
||||||
|
struct kvm_vcpu *vcpu;
|
||||||
|
int c;
|
||||||
|
|
||||||
|
/*
|
||||||
|
* We've injected an interrupt, time to find out who deserves
|
||||||
|
* a good kick...
|
||||||
|
*/
|
||||||
|
kvm_for_each_vcpu(c, vcpu, kvm) {
|
||||||
|
if (kvm_vgic_vcpu_pending_irq(vcpu))
|
||||||
|
kvm_vcpu_kick(vcpu);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
|
@ -16,11 +16,15 @@
|
||||||
#ifndef __KVM_ARM_VGIC_NEW_H__
|
#ifndef __KVM_ARM_VGIC_NEW_H__
|
||||||
#define __KVM_ARM_VGIC_NEW_H__
|
#define __KVM_ARM_VGIC_NEW_H__
|
||||||
|
|
||||||
|
#define PRODUCT_ID_KVM 0x4b /* ASCII code K */
|
||||||
|
#define IMPLEMENTER_ARM 0x43b
|
||||||
|
|
||||||
#define vgic_irq_is_sgi(intid) ((intid) < VGIC_NR_SGIS)
|
#define vgic_irq_is_sgi(intid) ((intid) < VGIC_NR_SGIS)
|
||||||
|
|
||||||
struct vgic_irq *vgic_get_irq(struct kvm *kvm, struct kvm_vcpu *vcpu,
|
struct vgic_irq *vgic_get_irq(struct kvm *kvm, struct kvm_vcpu *vcpu,
|
||||||
u32 intid);
|
u32 intid);
|
||||||
bool vgic_queue_irq_unlock(struct kvm *kvm, struct vgic_irq *irq);
|
bool vgic_queue_irq_unlock(struct kvm *kvm, struct vgic_irq *irq);
|
||||||
|
void vgic_kick_vcpus(struct kvm *kvm);
|
||||||
|
|
||||||
void vgic_v2_process_maintenance(struct kvm_vcpu *vcpu);
|
void vgic_v2_process_maintenance(struct kvm_vcpu *vcpu);
|
||||||
void vgic_v2_fold_lr_state(struct kvm_vcpu *vcpu);
|
void vgic_v2_fold_lr_state(struct kvm_vcpu *vcpu);
|
||||||
|
|
Loading…
Reference in a new issue