Merge tag 'kvm-arm-for-v4.12' of git://git.kernel.org/pub/scm/linux/kernel/git/kvmarm/kvmarm into HEAD
KVM/ARM Changes for v4.12. Changes include: - Using the common sysreg definitions between KVM and arm64 - Improved hyp-stub implementation with support for kexec and kdump on the 32-bit side - Proper PMU exception handling - Performance improvements of our GIC handling - Support for irqchip in userspace with in-kernel arch-timers and PMU support - A fix for a race condition in our PSCI code Conflicts: Documentation/virtual/kvm/api.txt include/uapi/linux/kvm.h
This commit is contained in:
+98
-26
@@ -184,28 +184,47 @@ bool kvm_timer_should_fire(struct arch_timer_context *timer_ctx)
|
||||
return cval <= now;
|
||||
}
|
||||
|
||||
/*
|
||||
* Reflect the timer output level into the kvm_run structure
|
||||
*/
|
||||
void kvm_timer_update_run(struct kvm_vcpu *vcpu)
|
||||
{
|
||||
struct arch_timer_context *vtimer = vcpu_vtimer(vcpu);
|
||||
struct arch_timer_context *ptimer = vcpu_ptimer(vcpu);
|
||||
struct kvm_sync_regs *regs = &vcpu->run->s.regs;
|
||||
|
||||
/* Populate the device bitmap with the timer states */
|
||||
regs->device_irq_level &= ~(KVM_ARM_DEV_EL1_VTIMER |
|
||||
KVM_ARM_DEV_EL1_PTIMER);
|
||||
if (vtimer->irq.level)
|
||||
regs->device_irq_level |= KVM_ARM_DEV_EL1_VTIMER;
|
||||
if (ptimer->irq.level)
|
||||
regs->device_irq_level |= KVM_ARM_DEV_EL1_PTIMER;
|
||||
}
|
||||
|
||||
static void kvm_timer_update_irq(struct kvm_vcpu *vcpu, bool new_level,
|
||||
struct arch_timer_context *timer_ctx)
|
||||
{
|
||||
int ret;
|
||||
|
||||
BUG_ON(!vgic_initialized(vcpu->kvm));
|
||||
|
||||
timer_ctx->active_cleared_last = false;
|
||||
timer_ctx->irq.level = new_level;
|
||||
trace_kvm_timer_update_irq(vcpu->vcpu_id, timer_ctx->irq.irq,
|
||||
timer_ctx->irq.level);
|
||||
|
||||
ret = kvm_vgic_inject_irq(vcpu->kvm, vcpu->vcpu_id, timer_ctx->irq.irq,
|
||||
timer_ctx->irq.level);
|
||||
WARN_ON(ret);
|
||||
if (likely(irqchip_in_kernel(vcpu->kvm))) {
|
||||
ret = kvm_vgic_inject_irq(vcpu->kvm, vcpu->vcpu_id,
|
||||
timer_ctx->irq.irq,
|
||||
timer_ctx->irq.level);
|
||||
WARN_ON(ret);
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* Check if there was a change in the timer state (should we raise or lower
|
||||
* the line level to the GIC).
|
||||
*/
|
||||
static int kvm_timer_update_state(struct kvm_vcpu *vcpu)
|
||||
static void kvm_timer_update_state(struct kvm_vcpu *vcpu)
|
||||
{
|
||||
struct arch_timer_cpu *timer = &vcpu->arch.timer_cpu;
|
||||
struct arch_timer_context *vtimer = vcpu_vtimer(vcpu);
|
||||
@@ -217,16 +236,14 @@ static int kvm_timer_update_state(struct kvm_vcpu *vcpu)
|
||||
* because the guest would never see the interrupt. Instead wait
|
||||
* until we call this function from kvm_timer_flush_hwstate.
|
||||
*/
|
||||
if (!vgic_initialized(vcpu->kvm) || !timer->enabled)
|
||||
return -ENODEV;
|
||||
if (unlikely(!timer->enabled))
|
||||
return;
|
||||
|
||||
if (kvm_timer_should_fire(vtimer) != vtimer->irq.level)
|
||||
kvm_timer_update_irq(vcpu, !vtimer->irq.level, vtimer);
|
||||
|
||||
if (kvm_timer_should_fire(ptimer) != ptimer->irq.level)
|
||||
kvm_timer_update_irq(vcpu, !ptimer->irq.level, ptimer);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* Schedule the background timer for the emulated timer. */
|
||||
@@ -286,25 +303,12 @@ void kvm_timer_unschedule(struct kvm_vcpu *vcpu)
|
||||
timer_disarm(timer);
|
||||
}
|
||||
|
||||
/**
|
||||
* kvm_timer_flush_hwstate - prepare to move the virt timer to the cpu
|
||||
* @vcpu: The vcpu pointer
|
||||
*
|
||||
* Check if the virtual timer has expired while we were running in the host,
|
||||
* and inject an interrupt if that was the case.
|
||||
*/
|
||||
void kvm_timer_flush_hwstate(struct kvm_vcpu *vcpu)
|
||||
static void kvm_timer_flush_hwstate_vgic(struct kvm_vcpu *vcpu)
|
||||
{
|
||||
struct arch_timer_context *vtimer = vcpu_vtimer(vcpu);
|
||||
bool phys_active;
|
||||
int ret;
|
||||
|
||||
if (kvm_timer_update_state(vcpu))
|
||||
return;
|
||||
|
||||
/* Set the background timer for the physical timer emulation. */
|
||||
kvm_timer_emulate(vcpu, vcpu_ptimer(vcpu));
|
||||
|
||||
/*
|
||||
* If we enter the guest with the virtual input level to the VGIC
|
||||
* asserted, then we have already told the VGIC what we need to, and
|
||||
@@ -356,11 +360,72 @@ void kvm_timer_flush_hwstate(struct kvm_vcpu *vcpu)
|
||||
vtimer->active_cleared_last = !phys_active;
|
||||
}
|
||||
|
||||
bool kvm_timer_should_notify_user(struct kvm_vcpu *vcpu)
|
||||
{
|
||||
struct arch_timer_context *vtimer = vcpu_vtimer(vcpu);
|
||||
struct arch_timer_context *ptimer = vcpu_ptimer(vcpu);
|
||||
struct kvm_sync_regs *sregs = &vcpu->run->s.regs;
|
||||
bool vlevel, plevel;
|
||||
|
||||
if (likely(irqchip_in_kernel(vcpu->kvm)))
|
||||
return false;
|
||||
|
||||
vlevel = sregs->device_irq_level & KVM_ARM_DEV_EL1_VTIMER;
|
||||
plevel = sregs->device_irq_level & KVM_ARM_DEV_EL1_PTIMER;
|
||||
|
||||
return vtimer->irq.level != vlevel ||
|
||||
ptimer->irq.level != plevel;
|
||||
}
|
||||
|
||||
static void kvm_timer_flush_hwstate_user(struct kvm_vcpu *vcpu)
|
||||
{
|
||||
struct arch_timer_context *vtimer = vcpu_vtimer(vcpu);
|
||||
|
||||
/*
|
||||
* To prevent continuously exiting from the guest, we mask the
|
||||
* physical interrupt such that the guest can make forward progress.
|
||||
* Once we detect the output level being deasserted, we unmask the
|
||||
* interrupt again so that we exit from the guest when the timer
|
||||
* fires.
|
||||
*/
|
||||
if (vtimer->irq.level)
|
||||
disable_percpu_irq(host_vtimer_irq);
|
||||
else
|
||||
enable_percpu_irq(host_vtimer_irq, 0);
|
||||
}
|
||||
|
||||
/**
|
||||
* kvm_timer_flush_hwstate - prepare timers before running the vcpu
|
||||
* @vcpu: The vcpu pointer
|
||||
*
|
||||
* Check if the virtual timer has expired while we were running in the host,
|
||||
* and inject an interrupt if that was the case, making sure the timer is
|
||||
* masked or disabled on the host so that we keep executing. Also schedule a
|
||||
* software timer for the physical timer if it is enabled.
|
||||
*/
|
||||
void kvm_timer_flush_hwstate(struct kvm_vcpu *vcpu)
|
||||
{
|
||||
struct arch_timer_cpu *timer = &vcpu->arch.timer_cpu;
|
||||
|
||||
if (unlikely(!timer->enabled))
|
||||
return;
|
||||
|
||||
kvm_timer_update_state(vcpu);
|
||||
|
||||
/* Set the background timer for the physical timer emulation. */
|
||||
kvm_timer_emulate(vcpu, vcpu_ptimer(vcpu));
|
||||
|
||||
if (unlikely(!irqchip_in_kernel(vcpu->kvm)))
|
||||
kvm_timer_flush_hwstate_user(vcpu);
|
||||
else
|
||||
kvm_timer_flush_hwstate_vgic(vcpu);
|
||||
}
|
||||
|
||||
/**
|
||||
* kvm_timer_sync_hwstate - sync timer state from cpu
|
||||
* @vcpu: The vcpu pointer
|
||||
*
|
||||
* Check if the virtual timer has expired while we were running in the guest,
|
||||
* Check if any of the timers have expired while we were running in the guest,
|
||||
* and inject an interrupt if that was the case.
|
||||
*/
|
||||
void kvm_timer_sync_hwstate(struct kvm_vcpu *vcpu)
|
||||
@@ -560,6 +625,13 @@ int kvm_timer_enable(struct kvm_vcpu *vcpu)
|
||||
if (timer->enabled)
|
||||
return 0;
|
||||
|
||||
/* Without a VGIC we do not map virtual IRQs to physical IRQs */
|
||||
if (!irqchip_in_kernel(vcpu->kvm))
|
||||
goto no_vgic;
|
||||
|
||||
if (!vgic_initialized(vcpu->kvm))
|
||||
return -ENODEV;
|
||||
|
||||
/*
|
||||
* Find the physical IRQ number corresponding to the host_vtimer_irq
|
||||
*/
|
||||
@@ -583,8 +655,8 @@ int kvm_timer_enable(struct kvm_vcpu *vcpu)
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
no_vgic:
|
||||
timer->enabled = 1;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
@@ -22,49 +22,6 @@
|
||||
#include <asm/kvm_emulate.h>
|
||||
#include <asm/kvm_hyp.h>
|
||||
|
||||
static void __hyp_text save_maint_int_state(struct kvm_vcpu *vcpu,
|
||||
void __iomem *base)
|
||||
{
|
||||
struct vgic_v2_cpu_if *cpu_if = &vcpu->arch.vgic_cpu.vgic_v2;
|
||||
int nr_lr = (kern_hyp_va(&kvm_vgic_global_state))->nr_lr;
|
||||
u32 eisr0, eisr1;
|
||||
int i;
|
||||
bool expect_mi;
|
||||
|
||||
expect_mi = !!(cpu_if->vgic_hcr & GICH_HCR_UIE);
|
||||
|
||||
for (i = 0; i < nr_lr; i++) {
|
||||
if (!(vcpu->arch.vgic_cpu.live_lrs & (1UL << i)))
|
||||
continue;
|
||||
|
||||
expect_mi |= (!(cpu_if->vgic_lr[i] & GICH_LR_HW) &&
|
||||
(cpu_if->vgic_lr[i] & GICH_LR_EOI));
|
||||
}
|
||||
|
||||
if (expect_mi) {
|
||||
cpu_if->vgic_misr = readl_relaxed(base + GICH_MISR);
|
||||
|
||||
if (cpu_if->vgic_misr & GICH_MISR_EOI) {
|
||||
eisr0 = readl_relaxed(base + GICH_EISR0);
|
||||
if (unlikely(nr_lr > 32))
|
||||
eisr1 = readl_relaxed(base + GICH_EISR1);
|
||||
else
|
||||
eisr1 = 0;
|
||||
} else {
|
||||
eisr0 = eisr1 = 0;
|
||||
}
|
||||
} else {
|
||||
cpu_if->vgic_misr = 0;
|
||||
eisr0 = eisr1 = 0;
|
||||
}
|
||||
|
||||
#ifdef CONFIG_CPU_BIG_ENDIAN
|
||||
cpu_if->vgic_eisr = ((u64)eisr0 << 32) | eisr1;
|
||||
#else
|
||||
cpu_if->vgic_eisr = ((u64)eisr1 << 32) | eisr0;
|
||||
#endif
|
||||
}
|
||||
|
||||
static void __hyp_text save_elrsr(struct kvm_vcpu *vcpu, void __iomem *base)
|
||||
{
|
||||
struct vgic_v2_cpu_if *cpu_if = &vcpu->arch.vgic_cpu.vgic_v2;
|
||||
@@ -87,13 +44,10 @@ static void __hyp_text save_elrsr(struct kvm_vcpu *vcpu, void __iomem *base)
|
||||
static void __hyp_text save_lrs(struct kvm_vcpu *vcpu, void __iomem *base)
|
||||
{
|
||||
struct vgic_v2_cpu_if *cpu_if = &vcpu->arch.vgic_cpu.vgic_v2;
|
||||
int nr_lr = (kern_hyp_va(&kvm_vgic_global_state))->nr_lr;
|
||||
int i;
|
||||
u64 used_lrs = vcpu->arch.vgic_cpu.used_lrs;
|
||||
|
||||
for (i = 0; i < nr_lr; i++) {
|
||||
if (!(vcpu->arch.vgic_cpu.live_lrs & (1UL << i)))
|
||||
continue;
|
||||
|
||||
for (i = 0; i < used_lrs; i++) {
|
||||
if (cpu_if->vgic_elrsr & (1UL << i))
|
||||
cpu_if->vgic_lr[i] &= ~GICH_LR_STATE;
|
||||
else
|
||||
@@ -110,26 +64,20 @@ void __hyp_text __vgic_v2_save_state(struct kvm_vcpu *vcpu)
|
||||
struct vgic_v2_cpu_if *cpu_if = &vcpu->arch.vgic_cpu.vgic_v2;
|
||||
struct vgic_dist *vgic = &kvm->arch.vgic;
|
||||
void __iomem *base = kern_hyp_va(vgic->vctrl_base);
|
||||
u64 used_lrs = vcpu->arch.vgic_cpu.used_lrs;
|
||||
|
||||
if (!base)
|
||||
return;
|
||||
|
||||
cpu_if->vgic_vmcr = readl_relaxed(base + GICH_VMCR);
|
||||
|
||||
if (vcpu->arch.vgic_cpu.live_lrs) {
|
||||
if (used_lrs) {
|
||||
cpu_if->vgic_apr = readl_relaxed(base + GICH_APR);
|
||||
|
||||
save_maint_int_state(vcpu, base);
|
||||
save_elrsr(vcpu, base);
|
||||
save_lrs(vcpu, base);
|
||||
|
||||
writel_relaxed(0, base + GICH_HCR);
|
||||
|
||||
vcpu->arch.vgic_cpu.live_lrs = 0;
|
||||
} else {
|
||||
cpu_if->vgic_eisr = 0;
|
||||
cpu_if->vgic_elrsr = ~0UL;
|
||||
cpu_if->vgic_misr = 0;
|
||||
cpu_if->vgic_apr = 0;
|
||||
}
|
||||
}
|
||||
@@ -141,32 +89,20 @@ void __hyp_text __vgic_v2_restore_state(struct kvm_vcpu *vcpu)
|
||||
struct vgic_v2_cpu_if *cpu_if = &vcpu->arch.vgic_cpu.vgic_v2;
|
||||
struct vgic_dist *vgic = &kvm->arch.vgic;
|
||||
void __iomem *base = kern_hyp_va(vgic->vctrl_base);
|
||||
int nr_lr = (kern_hyp_va(&kvm_vgic_global_state))->nr_lr;
|
||||
int i;
|
||||
u64 live_lrs = 0;
|
||||
u64 used_lrs = vcpu->arch.vgic_cpu.used_lrs;
|
||||
|
||||
if (!base)
|
||||
return;
|
||||
|
||||
|
||||
for (i = 0; i < nr_lr; i++)
|
||||
if (cpu_if->vgic_lr[i] & GICH_LR_STATE)
|
||||
live_lrs |= 1UL << i;
|
||||
|
||||
if (live_lrs) {
|
||||
if (used_lrs) {
|
||||
writel_relaxed(cpu_if->vgic_hcr, base + GICH_HCR);
|
||||
writel_relaxed(cpu_if->vgic_apr, base + GICH_APR);
|
||||
for (i = 0; i < nr_lr; i++) {
|
||||
if (!(live_lrs & (1UL << i)))
|
||||
continue;
|
||||
|
||||
for (i = 0; i < used_lrs; i++) {
|
||||
writel_relaxed(cpu_if->vgic_lr[i],
|
||||
base + GICH_LR0 + (i * 4));
|
||||
}
|
||||
}
|
||||
|
||||
writel_relaxed(cpu_if->vgic_vmcr, base + GICH_VMCR);
|
||||
vcpu->arch.vgic_cpu.live_lrs = live_lrs;
|
||||
}
|
||||
|
||||
#ifdef CONFIG_ARM64
|
||||
|
||||
@@ -118,66 +118,32 @@ static void __hyp_text __gic_v3_set_lr(u64 val, int lr)
|
||||
}
|
||||
}
|
||||
|
||||
static void __hyp_text save_maint_int_state(struct kvm_vcpu *vcpu, int nr_lr)
|
||||
{
|
||||
struct vgic_v3_cpu_if *cpu_if = &vcpu->arch.vgic_cpu.vgic_v3;
|
||||
int i;
|
||||
bool expect_mi;
|
||||
|
||||
expect_mi = !!(cpu_if->vgic_hcr & ICH_HCR_UIE);
|
||||
|
||||
for (i = 0; i < nr_lr; i++) {
|
||||
if (!(vcpu->arch.vgic_cpu.live_lrs & (1UL << i)))
|
||||
continue;
|
||||
|
||||
expect_mi |= (!(cpu_if->vgic_lr[i] & ICH_LR_HW) &&
|
||||
(cpu_if->vgic_lr[i] & ICH_LR_EOI));
|
||||
}
|
||||
|
||||
if (expect_mi) {
|
||||
cpu_if->vgic_misr = read_gicreg(ICH_MISR_EL2);
|
||||
|
||||
if (cpu_if->vgic_misr & ICH_MISR_EOI)
|
||||
cpu_if->vgic_eisr = read_gicreg(ICH_EISR_EL2);
|
||||
else
|
||||
cpu_if->vgic_eisr = 0;
|
||||
} else {
|
||||
cpu_if->vgic_misr = 0;
|
||||
cpu_if->vgic_eisr = 0;
|
||||
}
|
||||
}
|
||||
|
||||
void __hyp_text __vgic_v3_save_state(struct kvm_vcpu *vcpu)
|
||||
{
|
||||
struct vgic_v3_cpu_if *cpu_if = &vcpu->arch.vgic_cpu.vgic_v3;
|
||||
u64 used_lrs = vcpu->arch.vgic_cpu.used_lrs;
|
||||
u64 val;
|
||||
|
||||
/*
|
||||
* Make sure stores to the GIC via the memory mapped interface
|
||||
* are now visible to the system register interface.
|
||||
*/
|
||||
if (!cpu_if->vgic_sre)
|
||||
if (!cpu_if->vgic_sre) {
|
||||
dsb(st);
|
||||
cpu_if->vgic_vmcr = read_gicreg(ICH_VMCR_EL2);
|
||||
}
|
||||
|
||||
cpu_if->vgic_vmcr = read_gicreg(ICH_VMCR_EL2);
|
||||
|
||||
if (vcpu->arch.vgic_cpu.live_lrs) {
|
||||
if (used_lrs) {
|
||||
int i;
|
||||
u32 max_lr_idx, nr_pri_bits;
|
||||
u32 nr_pri_bits;
|
||||
|
||||
cpu_if->vgic_elrsr = read_gicreg(ICH_ELSR_EL2);
|
||||
|
||||
write_gicreg(0, ICH_HCR_EL2);
|
||||
val = read_gicreg(ICH_VTR_EL2);
|
||||
max_lr_idx = vtr_to_max_lr_idx(val);
|
||||
nr_pri_bits = vtr_to_nr_pri_bits(val);
|
||||
|
||||
save_maint_int_state(vcpu, max_lr_idx + 1);
|
||||
|
||||
for (i = 0; i <= max_lr_idx; i++) {
|
||||
if (!(vcpu->arch.vgic_cpu.live_lrs & (1UL << i)))
|
||||
continue;
|
||||
|
||||
for (i = 0; i < used_lrs; i++) {
|
||||
if (cpu_if->vgic_elrsr & (1 << i))
|
||||
cpu_if->vgic_lr[i] &= ~ICH_LR_STATE;
|
||||
else
|
||||
@@ -205,11 +171,7 @@ void __hyp_text __vgic_v3_save_state(struct kvm_vcpu *vcpu)
|
||||
default:
|
||||
cpu_if->vgic_ap1r[0] = read_gicreg(ICH_AP1R0_EL2);
|
||||
}
|
||||
|
||||
vcpu->arch.vgic_cpu.live_lrs = 0;
|
||||
} else {
|
||||
cpu_if->vgic_misr = 0;
|
||||
cpu_if->vgic_eisr = 0;
|
||||
cpu_if->vgic_elrsr = 0xffff;
|
||||
cpu_if->vgic_ap0r[0] = 0;
|
||||
cpu_if->vgic_ap0r[1] = 0;
|
||||
@@ -234,9 +196,9 @@ void __hyp_text __vgic_v3_save_state(struct kvm_vcpu *vcpu)
|
||||
void __hyp_text __vgic_v3_restore_state(struct kvm_vcpu *vcpu)
|
||||
{
|
||||
struct vgic_v3_cpu_if *cpu_if = &vcpu->arch.vgic_cpu.vgic_v3;
|
||||
u64 used_lrs = vcpu->arch.vgic_cpu.used_lrs;
|
||||
u64 val;
|
||||
u32 max_lr_idx, nr_pri_bits;
|
||||
u16 live_lrs = 0;
|
||||
u32 nr_pri_bits;
|
||||
int i;
|
||||
|
||||
/*
|
||||
@@ -245,25 +207,19 @@ void __hyp_text __vgic_v3_restore_state(struct kvm_vcpu *vcpu)
|
||||
* delivered as a FIQ to the guest, with potentially fatal
|
||||
* consequences. So we must make sure that ICC_SRE_EL1 has
|
||||
* been actually programmed with the value we want before
|
||||
* starting to mess with the rest of the GIC.
|
||||
* starting to mess with the rest of the GIC, and VMCR_EL2 in
|
||||
* particular.
|
||||
*/
|
||||
if (!cpu_if->vgic_sre) {
|
||||
write_gicreg(0, ICC_SRE_EL1);
|
||||
isb();
|
||||
write_gicreg(cpu_if->vgic_vmcr, ICH_VMCR_EL2);
|
||||
}
|
||||
|
||||
val = read_gicreg(ICH_VTR_EL2);
|
||||
max_lr_idx = vtr_to_max_lr_idx(val);
|
||||
nr_pri_bits = vtr_to_nr_pri_bits(val);
|
||||
|
||||
for (i = 0; i <= max_lr_idx; i++) {
|
||||
if (cpu_if->vgic_lr[i] & ICH_LR_STATE)
|
||||
live_lrs |= (1 << i);
|
||||
}
|
||||
|
||||
write_gicreg(cpu_if->vgic_vmcr, ICH_VMCR_EL2);
|
||||
|
||||
if (live_lrs) {
|
||||
if (used_lrs) {
|
||||
write_gicreg(cpu_if->vgic_hcr, ICH_HCR_EL2);
|
||||
|
||||
switch (nr_pri_bits) {
|
||||
@@ -286,12 +242,8 @@ void __hyp_text __vgic_v3_restore_state(struct kvm_vcpu *vcpu)
|
||||
write_gicreg(cpu_if->vgic_ap1r[0], ICH_AP1R0_EL2);
|
||||
}
|
||||
|
||||
for (i = 0; i <= max_lr_idx; i++) {
|
||||
if (!(live_lrs & (1 << i)))
|
||||
continue;
|
||||
|
||||
for (i = 0; i < used_lrs; i++)
|
||||
__gic_v3_set_lr(cpu_if->vgic_lr[i], i);
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
@@ -303,7 +255,6 @@ void __hyp_text __vgic_v3_restore_state(struct kvm_vcpu *vcpu)
|
||||
isb();
|
||||
dsb(sy);
|
||||
}
|
||||
vcpu->arch.vgic_cpu.live_lrs = live_lrs;
|
||||
|
||||
/*
|
||||
* Prevent the guest from touching the GIC system registers if
|
||||
@@ -326,3 +277,13 @@ u64 __hyp_text __vgic_v3_get_ich_vtr_el2(void)
|
||||
{
|
||||
return read_gicreg(ICH_VTR_EL2);
|
||||
}
|
||||
|
||||
u64 __hyp_text __vgic_v3_read_vmcr(void)
|
||||
{
|
||||
return read_gicreg(ICH_VMCR_EL2);
|
||||
}
|
||||
|
||||
void __hyp_text __vgic_v3_write_vmcr(u32 vmcr)
|
||||
{
|
||||
write_gicreg(vmcr, ICH_VMCR_EL2);
|
||||
}
|
||||
|
||||
+35
-4
@@ -230,13 +230,44 @@ static void kvm_pmu_update_state(struct kvm_vcpu *vcpu)
|
||||
return;
|
||||
|
||||
overflow = !!kvm_pmu_overflow_status(vcpu);
|
||||
if (pmu->irq_level != overflow) {
|
||||
pmu->irq_level = overflow;
|
||||
kvm_vgic_inject_irq(vcpu->kvm, vcpu->vcpu_id,
|
||||
pmu->irq_num, overflow);
|
||||
if (pmu->irq_level == overflow)
|
||||
return;
|
||||
|
||||
pmu->irq_level = overflow;
|
||||
|
||||
if (likely(irqchip_in_kernel(vcpu->kvm))) {
|
||||
int ret;
|
||||
ret = kvm_vgic_inject_irq(vcpu->kvm, vcpu->vcpu_id,
|
||||
pmu->irq_num, overflow);
|
||||
WARN_ON(ret);
|
||||
}
|
||||
}
|
||||
|
||||
bool kvm_pmu_should_notify_user(struct kvm_vcpu *vcpu)
|
||||
{
|
||||
struct kvm_pmu *pmu = &vcpu->arch.pmu;
|
||||
struct kvm_sync_regs *sregs = &vcpu->run->s.regs;
|
||||
bool run_level = sregs->device_irq_level & KVM_ARM_DEV_PMU;
|
||||
|
||||
if (likely(irqchip_in_kernel(vcpu->kvm)))
|
||||
return false;
|
||||
|
||||
return pmu->irq_level != run_level;
|
||||
}
|
||||
|
||||
/*
|
||||
* Reflect the PMU overflow interrupt output level into the kvm_run structure
|
||||
*/
|
||||
void kvm_pmu_update_run(struct kvm_vcpu *vcpu)
|
||||
{
|
||||
struct kvm_sync_regs *regs = &vcpu->run->s.regs;
|
||||
|
||||
/* Populate the timer bitmap for user space */
|
||||
regs->device_irq_level &= ~KVM_ARM_DEV_PMU;
|
||||
if (vcpu->arch.pmu.irq_level)
|
||||
regs->device_irq_level |= KVM_ARM_DEV_PMU;
|
||||
}
|
||||
|
||||
/**
|
||||
* kvm_pmu_flush_hwstate - flush pmu state to cpu
|
||||
* @vcpu: The vcpu pointer
|
||||
|
||||
@@ -24,7 +24,12 @@
|
||||
|
||||
/*
|
||||
* Initialization rules: there are multiple stages to the vgic
|
||||
* initialization, both for the distributor and the CPU interfaces.
|
||||
* initialization, both for the distributor and the CPU interfaces. The basic
|
||||
* idea is that even though the VGIC is not functional or not requested from
|
||||
* user space, the critical path of the run loop can still call VGIC functions
|
||||
* that just won't do anything, without them having to check additional
|
||||
* initialization flags to ensure they don't look at uninitialized data
|
||||
* structures.
|
||||
*
|
||||
* Distributor:
|
||||
*
|
||||
@@ -39,23 +44,67 @@
|
||||
*
|
||||
* CPU Interface:
|
||||
*
|
||||
* - kvm_vgic_cpu_early_init(): initialization of static data that
|
||||
* - kvm_vgic_vcpu_early_init(): initialization of static data that
|
||||
* doesn't depend on any sizing information or emulation type. No
|
||||
* allocation is allowed there.
|
||||
*/
|
||||
|
||||
/* EARLY INIT */
|
||||
|
||||
/*
|
||||
* Those 2 functions should not be needed anymore but they
|
||||
* still are called from arm.c
|
||||
/**
|
||||
* kvm_vgic_early_init() - Initialize static VGIC VCPU data structures
|
||||
* @kvm: The VM whose VGIC districutor should be initialized
|
||||
*
|
||||
* Only do initialization of static structures that don't require any
|
||||
* allocation or sizing information from userspace. vgic_init() called
|
||||
* kvm_vgic_dist_init() which takes care of the rest.
|
||||
*/
|
||||
void kvm_vgic_early_init(struct kvm *kvm)
|
||||
{
|
||||
struct vgic_dist *dist = &kvm->arch.vgic;
|
||||
|
||||
INIT_LIST_HEAD(&dist->lpi_list_head);
|
||||
spin_lock_init(&dist->lpi_list_lock);
|
||||
}
|
||||
|
||||
/**
|
||||
* kvm_vgic_vcpu_early_init() - Initialize static VGIC VCPU data structures
|
||||
* @vcpu: The VCPU whose VGIC data structures whould be initialized
|
||||
*
|
||||
* Only do initialization, but do not actually enable the VGIC CPU interface
|
||||
* yet.
|
||||
*/
|
||||
void kvm_vgic_vcpu_early_init(struct kvm_vcpu *vcpu)
|
||||
{
|
||||
struct vgic_cpu *vgic_cpu = &vcpu->arch.vgic_cpu;
|
||||
int i;
|
||||
|
||||
INIT_LIST_HEAD(&vgic_cpu->ap_list_head);
|
||||
spin_lock_init(&vgic_cpu->ap_list_lock);
|
||||
|
||||
/*
|
||||
* Enable and configure all SGIs to be edge-triggered and
|
||||
* configure all PPIs as level-triggered.
|
||||
*/
|
||||
for (i = 0; i < VGIC_NR_PRIVATE_IRQS; i++) {
|
||||
struct vgic_irq *irq = &vgic_cpu->private_irqs[i];
|
||||
|
||||
INIT_LIST_HEAD(&irq->ap_list);
|
||||
spin_lock_init(&irq->irq_lock);
|
||||
irq->intid = i;
|
||||
irq->vcpu = NULL;
|
||||
irq->target_vcpu = vcpu;
|
||||
irq->targets = 1U << vcpu->vcpu_id;
|
||||
kref_init(&irq->refcount);
|
||||
if (vgic_irq_is_sgi(i)) {
|
||||
/* SGIs */
|
||||
irq->enabled = 1;
|
||||
irq->config = VGIC_CONFIG_EDGE;
|
||||
} else {
|
||||
/* PPIs */
|
||||
irq->config = VGIC_CONFIG_LEVEL;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* CREATION */
|
||||
@@ -148,9 +197,6 @@ static int kvm_vgic_dist_init(struct kvm *kvm, unsigned int nr_spis)
|
||||
struct kvm_vcpu *vcpu0 = kvm_get_vcpu(kvm, 0);
|
||||
int i;
|
||||
|
||||
INIT_LIST_HEAD(&dist->lpi_list_head);
|
||||
spin_lock_init(&dist->lpi_list_lock);
|
||||
|
||||
dist->spis = kcalloc(nr_spis, sizeof(struct vgic_irq), GFP_KERNEL);
|
||||
if (!dist->spis)
|
||||
return -ENOMEM;
|
||||
@@ -181,41 +227,11 @@ static int kvm_vgic_dist_init(struct kvm *kvm, unsigned int nr_spis)
|
||||
}
|
||||
|
||||
/**
|
||||
* kvm_vgic_vcpu_init: initialize the vcpu data structures and
|
||||
* enable the VCPU interface
|
||||
* @vcpu: the VCPU which's VGIC should be initialized
|
||||
* kvm_vgic_vcpu_init() - Enable the VCPU interface
|
||||
* @vcpu: the VCPU which's VGIC should be enabled
|
||||
*/
|
||||
static void kvm_vgic_vcpu_init(struct kvm_vcpu *vcpu)
|
||||
{
|
||||
struct vgic_cpu *vgic_cpu = &vcpu->arch.vgic_cpu;
|
||||
int i;
|
||||
|
||||
INIT_LIST_HEAD(&vgic_cpu->ap_list_head);
|
||||
spin_lock_init(&vgic_cpu->ap_list_lock);
|
||||
|
||||
/*
|
||||
* Enable and configure all SGIs to be edge-triggered and
|
||||
* configure all PPIs as level-triggered.
|
||||
*/
|
||||
for (i = 0; i < VGIC_NR_PRIVATE_IRQS; i++) {
|
||||
struct vgic_irq *irq = &vgic_cpu->private_irqs[i];
|
||||
|
||||
INIT_LIST_HEAD(&irq->ap_list);
|
||||
spin_lock_init(&irq->irq_lock);
|
||||
irq->intid = i;
|
||||
irq->vcpu = NULL;
|
||||
irq->target_vcpu = vcpu;
|
||||
irq->targets = 1U << vcpu->vcpu_id;
|
||||
kref_init(&irq->refcount);
|
||||
if (vgic_irq_is_sgi(i)) {
|
||||
/* SGIs */
|
||||
irq->enabled = 1;
|
||||
irq->config = VGIC_CONFIG_EDGE;
|
||||
} else {
|
||||
/* PPIs */
|
||||
irq->config = VGIC_CONFIG_LEVEL;
|
||||
}
|
||||
}
|
||||
if (kvm_vgic_global_state.type == VGIC_V2)
|
||||
vgic_v2_enable(vcpu);
|
||||
else
|
||||
@@ -262,6 +278,18 @@ int vgic_init(struct kvm *kvm)
|
||||
vgic_debug_init(kvm);
|
||||
|
||||
dist->initialized = true;
|
||||
|
||||
/*
|
||||
* If we're initializing GICv2 on-demand when first running the VCPU
|
||||
* then we need to load the VGIC state onto the CPU. We can detect
|
||||
* this easily by checking if we are in between vcpu_load and vcpu_put
|
||||
* when we just initialized the VGIC.
|
||||
*/
|
||||
preempt_disable();
|
||||
vcpu = kvm_arm_get_running_vcpu();
|
||||
if (vcpu)
|
||||
kvm_vgic_load(vcpu);
|
||||
preempt_enable();
|
||||
out:
|
||||
return ret;
|
||||
}
|
||||
|
||||
+40
-52
@@ -22,54 +22,6 @@
|
||||
|
||||
#include "vgic.h"
|
||||
|
||||
/*
|
||||
* Call this function to convert a u64 value to an unsigned long * bitmask
|
||||
* in a way that works on both 32-bit and 64-bit LE and BE platforms.
|
||||
*
|
||||
* Warning: Calling this function may modify *val.
|
||||
*/
|
||||
static unsigned long *u64_to_bitmask(u64 *val)
|
||||
{
|
||||
#if defined(CONFIG_CPU_BIG_ENDIAN) && BITS_PER_LONG == 32
|
||||
*val = (*val >> 32) | (*val << 32);
|
||||
#endif
|
||||
return (unsigned long *)val;
|
||||
}
|
||||
|
||||
void vgic_v2_process_maintenance(struct kvm_vcpu *vcpu)
|
||||
{
|
||||
struct vgic_v2_cpu_if *cpuif = &vcpu->arch.vgic_cpu.vgic_v2;
|
||||
|
||||
if (cpuif->vgic_misr & GICH_MISR_EOI) {
|
||||
u64 eisr = cpuif->vgic_eisr;
|
||||
unsigned long *eisr_bmap = u64_to_bitmask(&eisr);
|
||||
int lr;
|
||||
|
||||
for_each_set_bit(lr, eisr_bmap, kvm_vgic_global_state.nr_lr) {
|
||||
u32 intid = cpuif->vgic_lr[lr] & GICH_LR_VIRTUALID;
|
||||
|
||||
WARN_ON(cpuif->vgic_lr[lr] & GICH_LR_STATE);
|
||||
|
||||
/* Only SPIs require notification */
|
||||
if (vgic_valid_spi(vcpu->kvm, intid))
|
||||
kvm_notify_acked_irq(vcpu->kvm, 0,
|
||||
intid - VGIC_NR_PRIVATE_IRQS);
|
||||
}
|
||||
}
|
||||
|
||||
/* check and disable underflow maintenance IRQ */
|
||||
cpuif->vgic_hcr &= ~GICH_HCR_UIE;
|
||||
|
||||
/*
|
||||
* In the next iterations of the vcpu loop, if we sync the
|
||||
* vgic state after flushing it, but before entering the guest
|
||||
* (this happens for pending signals and vmid rollovers), then
|
||||
* make sure we don't pick up any old maintenance interrupts
|
||||
* here.
|
||||
*/
|
||||
cpuif->vgic_eisr = 0;
|
||||
}
|
||||
|
||||
void vgic_v2_set_underflow(struct kvm_vcpu *vcpu)
|
||||
{
|
||||
struct vgic_v2_cpu_if *cpuif = &vcpu->arch.vgic_cpu.vgic_v2;
|
||||
@@ -77,6 +29,12 @@ void vgic_v2_set_underflow(struct kvm_vcpu *vcpu)
|
||||
cpuif->vgic_hcr |= GICH_HCR_UIE;
|
||||
}
|
||||
|
||||
static bool lr_signals_eoi_mi(u32 lr_val)
|
||||
{
|
||||
return !(lr_val & GICH_LR_STATE) && (lr_val & GICH_LR_EOI) &&
|
||||
!(lr_val & GICH_LR_HW);
|
||||
}
|
||||
|
||||
/*
|
||||
* transfer the content of the LRs back into the corresponding ap_list:
|
||||
* - active bit is transferred as is
|
||||
@@ -86,14 +44,22 @@ void vgic_v2_set_underflow(struct kvm_vcpu *vcpu)
|
||||
*/
|
||||
void vgic_v2_fold_lr_state(struct kvm_vcpu *vcpu)
|
||||
{
|
||||
struct vgic_v2_cpu_if *cpuif = &vcpu->arch.vgic_cpu.vgic_v2;
|
||||
struct vgic_cpu *vgic_cpu = &vcpu->arch.vgic_cpu;
|
||||
struct vgic_v2_cpu_if *cpuif = &vgic_cpu->vgic_v2;
|
||||
int lr;
|
||||
|
||||
for (lr = 0; lr < vcpu->arch.vgic_cpu.used_lrs; lr++) {
|
||||
cpuif->vgic_hcr &= ~GICH_HCR_UIE;
|
||||
|
||||
for (lr = 0; lr < vgic_cpu->used_lrs; lr++) {
|
||||
u32 val = cpuif->vgic_lr[lr];
|
||||
u32 intid = val & GICH_LR_VIRTUALID;
|
||||
struct vgic_irq *irq;
|
||||
|
||||
/* Notify fds when the guest EOI'ed a level-triggered SPI */
|
||||
if (lr_signals_eoi_mi(val) && vgic_valid_spi(vcpu->kvm, intid))
|
||||
kvm_notify_acked_irq(vcpu->kvm, 0,
|
||||
intid - VGIC_NR_PRIVATE_IRQS);
|
||||
|
||||
irq = vgic_get_irq(vcpu->kvm, vcpu, intid);
|
||||
|
||||
spin_lock(&irq->irq_lock);
|
||||
@@ -126,6 +92,8 @@ void vgic_v2_fold_lr_state(struct kvm_vcpu *vcpu)
|
||||
spin_unlock(&irq->irq_lock);
|
||||
vgic_put_irq(vcpu->kvm, irq);
|
||||
}
|
||||
|
||||
vgic_cpu->used_lrs = 0;
|
||||
}
|
||||
|
||||
/*
|
||||
@@ -184,6 +152,7 @@ void vgic_v2_clear_lr(struct kvm_vcpu *vcpu, int lr)
|
||||
|
||||
void vgic_v2_set_vmcr(struct kvm_vcpu *vcpu, struct vgic_vmcr *vmcrp)
|
||||
{
|
||||
struct vgic_v2_cpu_if *cpu_if = &vcpu->arch.vgic_cpu.vgic_v2;
|
||||
u32 vmcr;
|
||||
|
||||
vmcr = (vmcrp->ctlr << GICH_VMCR_CTRL_SHIFT) & GICH_VMCR_CTRL_MASK;
|
||||
@@ -194,12 +163,15 @@ void vgic_v2_set_vmcr(struct kvm_vcpu *vcpu, struct vgic_vmcr *vmcrp)
|
||||
vmcr |= (vmcrp->pmr << GICH_VMCR_PRIMASK_SHIFT) &
|
||||
GICH_VMCR_PRIMASK_MASK;
|
||||
|
||||
vcpu->arch.vgic_cpu.vgic_v2.vgic_vmcr = vmcr;
|
||||
cpu_if->vgic_vmcr = vmcr;
|
||||
}
|
||||
|
||||
void vgic_v2_get_vmcr(struct kvm_vcpu *vcpu, struct vgic_vmcr *vmcrp)
|
||||
{
|
||||
u32 vmcr = vcpu->arch.vgic_cpu.vgic_v2.vgic_vmcr;
|
||||
struct vgic_v2_cpu_if *cpu_if = &vcpu->arch.vgic_cpu.vgic_v2;
|
||||
u32 vmcr;
|
||||
|
||||
vmcr = cpu_if->vgic_vmcr;
|
||||
|
||||
vmcrp->ctlr = (vmcr & GICH_VMCR_CTRL_MASK) >>
|
||||
GICH_VMCR_CTRL_SHIFT;
|
||||
@@ -375,3 +347,19 @@ out:
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
void vgic_v2_load(struct kvm_vcpu *vcpu)
|
||||
{
|
||||
struct vgic_v2_cpu_if *cpu_if = &vcpu->arch.vgic_cpu.vgic_v2;
|
||||
struct vgic_dist *vgic = &vcpu->kvm->arch.vgic;
|
||||
|
||||
writel_relaxed(cpu_if->vgic_vmcr, vgic->vctrl_base + GICH_VMCR);
|
||||
}
|
||||
|
||||
void vgic_v2_put(struct kvm_vcpu *vcpu)
|
||||
{
|
||||
struct vgic_v2_cpu_if *cpu_if = &vcpu->arch.vgic_cpu.vgic_v2;
|
||||
struct vgic_dist *vgic = &vcpu->kvm->arch.vgic;
|
||||
|
||||
cpu_if->vgic_vmcr = readl_relaxed(vgic->vctrl_base + GICH_VMCR);
|
||||
}
|
||||
|
||||
+46
-43
@@ -21,45 +21,6 @@
|
||||
|
||||
#include "vgic.h"
|
||||
|
||||
void vgic_v3_process_maintenance(struct kvm_vcpu *vcpu)
|
||||
{
|
||||
struct vgic_v3_cpu_if *cpuif = &vcpu->arch.vgic_cpu.vgic_v3;
|
||||
u32 model = vcpu->kvm->arch.vgic.vgic_model;
|
||||
|
||||
if (cpuif->vgic_misr & ICH_MISR_EOI) {
|
||||
unsigned long eisr_bmap = cpuif->vgic_eisr;
|
||||
int lr;
|
||||
|
||||
for_each_set_bit(lr, &eisr_bmap, kvm_vgic_global_state.nr_lr) {
|
||||
u32 intid;
|
||||
u64 val = cpuif->vgic_lr[lr];
|
||||
|
||||
if (model == KVM_DEV_TYPE_ARM_VGIC_V3)
|
||||
intid = val & ICH_LR_VIRTUAL_ID_MASK;
|
||||
else
|
||||
intid = val & GICH_LR_VIRTUALID;
|
||||
|
||||
WARN_ON(cpuif->vgic_lr[lr] & ICH_LR_STATE);
|
||||
|
||||
/* Only SPIs require notification */
|
||||
if (vgic_valid_spi(vcpu->kvm, intid))
|
||||
kvm_notify_acked_irq(vcpu->kvm, 0,
|
||||
intid - VGIC_NR_PRIVATE_IRQS);
|
||||
}
|
||||
|
||||
/*
|
||||
* In the next iterations of the vcpu loop, if we sync
|
||||
* the vgic state after flushing it, but before
|
||||
* entering the guest (this happens for pending
|
||||
* signals and vmid rollovers), then make sure we
|
||||
* don't pick up any old maintenance interrupts here.
|
||||
*/
|
||||
cpuif->vgic_eisr = 0;
|
||||
}
|
||||
|
||||
cpuif->vgic_hcr &= ~ICH_HCR_UIE;
|
||||
}
|
||||
|
||||
void vgic_v3_set_underflow(struct kvm_vcpu *vcpu)
|
||||
{
|
||||
struct vgic_v3_cpu_if *cpuif = &vcpu->arch.vgic_cpu.vgic_v3;
|
||||
@@ -67,13 +28,22 @@ void vgic_v3_set_underflow(struct kvm_vcpu *vcpu)
|
||||
cpuif->vgic_hcr |= ICH_HCR_UIE;
|
||||
}
|
||||
|
||||
static bool lr_signals_eoi_mi(u64 lr_val)
|
||||
{
|
||||
return !(lr_val & ICH_LR_STATE) && (lr_val & ICH_LR_EOI) &&
|
||||
!(lr_val & ICH_LR_HW);
|
||||
}
|
||||
|
||||
void vgic_v3_fold_lr_state(struct kvm_vcpu *vcpu)
|
||||
{
|
||||
struct vgic_v3_cpu_if *cpuif = &vcpu->arch.vgic_cpu.vgic_v3;
|
||||
struct vgic_cpu *vgic_cpu = &vcpu->arch.vgic_cpu;
|
||||
struct vgic_v3_cpu_if *cpuif = &vgic_cpu->vgic_v3;
|
||||
u32 model = vcpu->kvm->arch.vgic.vgic_model;
|
||||
int lr;
|
||||
|
||||
for (lr = 0; lr < vcpu->arch.vgic_cpu.used_lrs; lr++) {
|
||||
cpuif->vgic_hcr &= ~ICH_HCR_UIE;
|
||||
|
||||
for (lr = 0; lr < vgic_cpu->used_lrs; lr++) {
|
||||
u64 val = cpuif->vgic_lr[lr];
|
||||
u32 intid;
|
||||
struct vgic_irq *irq;
|
||||
@@ -82,6 +52,12 @@ void vgic_v3_fold_lr_state(struct kvm_vcpu *vcpu)
|
||||
intid = val & ICH_LR_VIRTUAL_ID_MASK;
|
||||
else
|
||||
intid = val & GICH_LR_VIRTUALID;
|
||||
|
||||
/* Notify fds when the guest EOI'ed a level-triggered IRQ */
|
||||
if (lr_signals_eoi_mi(val) && vgic_valid_spi(vcpu->kvm, intid))
|
||||
kvm_notify_acked_irq(vcpu->kvm, 0,
|
||||
intid - VGIC_NR_PRIVATE_IRQS);
|
||||
|
||||
irq = vgic_get_irq(vcpu->kvm, vcpu, intid);
|
||||
if (!irq) /* An LPI could have been unmapped. */
|
||||
continue;
|
||||
@@ -117,6 +93,8 @@ void vgic_v3_fold_lr_state(struct kvm_vcpu *vcpu)
|
||||
spin_unlock(&irq->irq_lock);
|
||||
vgic_put_irq(vcpu->kvm, irq);
|
||||
}
|
||||
|
||||
vgic_cpu->used_lrs = 0;
|
||||
}
|
||||
|
||||
/* Requires the irq to be locked already */
|
||||
@@ -173,6 +151,7 @@ void vgic_v3_clear_lr(struct kvm_vcpu *vcpu, int lr)
|
||||
|
||||
void vgic_v3_set_vmcr(struct kvm_vcpu *vcpu, struct vgic_vmcr *vmcrp)
|
||||
{
|
||||
struct vgic_v3_cpu_if *cpu_if = &vcpu->arch.vgic_cpu.vgic_v3;
|
||||
u32 vmcr;
|
||||
|
||||
/*
|
||||
@@ -188,12 +167,15 @@ void vgic_v3_set_vmcr(struct kvm_vcpu *vcpu, struct vgic_vmcr *vmcrp)
|
||||
vmcr |= (vmcrp->grpen0 << ICH_VMCR_ENG0_SHIFT) & ICH_VMCR_ENG0_MASK;
|
||||
vmcr |= (vmcrp->grpen1 << ICH_VMCR_ENG1_SHIFT) & ICH_VMCR_ENG1_MASK;
|
||||
|
||||
vcpu->arch.vgic_cpu.vgic_v3.vgic_vmcr = vmcr;
|
||||
cpu_if->vgic_vmcr = vmcr;
|
||||
}
|
||||
|
||||
void vgic_v3_get_vmcr(struct kvm_vcpu *vcpu, struct vgic_vmcr *vmcrp)
|
||||
{
|
||||
u32 vmcr = vcpu->arch.vgic_cpu.vgic_v3.vgic_vmcr;
|
||||
struct vgic_v3_cpu_if *cpu_if = &vcpu->arch.vgic_cpu.vgic_v3;
|
||||
u32 vmcr;
|
||||
|
||||
vmcr = cpu_if->vgic_vmcr;
|
||||
|
||||
/*
|
||||
* Ignore the FIQen bit, because GIC emulation always implies
|
||||
@@ -386,3 +368,24 @@ int vgic_v3_probe(const struct gic_kvm_info *info)
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
void vgic_v3_load(struct kvm_vcpu *vcpu)
|
||||
{
|
||||
struct vgic_v3_cpu_if *cpu_if = &vcpu->arch.vgic_cpu.vgic_v3;
|
||||
|
||||
/*
|
||||
* If dealing with a GICv2 emulation on GICv3, VMCR_EL2.VFIQen
|
||||
* is dependent on ICC_SRE_EL1.SRE, and we have to perform the
|
||||
* VMCR_EL2 save/restore in the world switch.
|
||||
*/
|
||||
if (likely(cpu_if->vgic_sre))
|
||||
kvm_call_hyp(__vgic_v3_write_vmcr, cpu_if->vgic_vmcr);
|
||||
}
|
||||
|
||||
void vgic_v3_put(struct kvm_vcpu *vcpu)
|
||||
{
|
||||
struct vgic_v3_cpu_if *cpu_if = &vcpu->arch.vgic_cpu.vgic_v3;
|
||||
|
||||
if (likely(cpu_if->vgic_sre))
|
||||
cpu_if->vgic_vmcr = kvm_call_hyp(__vgic_v3_read_vmcr);
|
||||
}
|
||||
|
||||
+44
-16
@@ -527,14 +527,6 @@ retry:
|
||||
spin_unlock(&vgic_cpu->ap_list_lock);
|
||||
}
|
||||
|
||||
static inline void vgic_process_maintenance_interrupt(struct kvm_vcpu *vcpu)
|
||||
{
|
||||
if (kvm_vgic_global_state.type == VGIC_V2)
|
||||
vgic_v2_process_maintenance(vcpu);
|
||||
else
|
||||
vgic_v3_process_maintenance(vcpu);
|
||||
}
|
||||
|
||||
static inline void vgic_fold_lr_state(struct kvm_vcpu *vcpu)
|
||||
{
|
||||
if (kvm_vgic_global_state.type == VGIC_V2)
|
||||
@@ -601,10 +593,8 @@ static void vgic_flush_lr_state(struct kvm_vcpu *vcpu)
|
||||
|
||||
DEBUG_SPINLOCK_BUG_ON(!spin_is_locked(&vgic_cpu->ap_list_lock));
|
||||
|
||||
if (compute_ap_list_depth(vcpu) > kvm_vgic_global_state.nr_lr) {
|
||||
vgic_set_underflow(vcpu);
|
||||
if (compute_ap_list_depth(vcpu) > kvm_vgic_global_state.nr_lr)
|
||||
vgic_sort_ap_list(vcpu);
|
||||
}
|
||||
|
||||
list_for_each_entry(irq, &vgic_cpu->ap_list_head, ap_list) {
|
||||
spin_lock(&irq->irq_lock);
|
||||
@@ -623,8 +613,12 @@ static void vgic_flush_lr_state(struct kvm_vcpu *vcpu)
|
||||
next:
|
||||
spin_unlock(&irq->irq_lock);
|
||||
|
||||
if (count == kvm_vgic_global_state.nr_lr)
|
||||
if (count == kvm_vgic_global_state.nr_lr) {
|
||||
if (!list_is_last(&irq->ap_list,
|
||||
&vgic_cpu->ap_list_head))
|
||||
vgic_set_underflow(vcpu);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
vcpu->arch.vgic_cpu.used_lrs = count;
|
||||
@@ -637,18 +631,30 @@ next:
|
||||
/* Sync back the hardware VGIC state into our emulation after a guest's run. */
|
||||
void kvm_vgic_sync_hwstate(struct kvm_vcpu *vcpu)
|
||||
{
|
||||
if (unlikely(!vgic_initialized(vcpu->kvm)))
|
||||
struct vgic_cpu *vgic_cpu = &vcpu->arch.vgic_cpu;
|
||||
|
||||
/* An empty ap_list_head implies used_lrs == 0 */
|
||||
if (list_empty(&vcpu->arch.vgic_cpu.ap_list_head))
|
||||
return;
|
||||
|
||||
vgic_process_maintenance_interrupt(vcpu);
|
||||
vgic_fold_lr_state(vcpu);
|
||||
if (vgic_cpu->used_lrs)
|
||||
vgic_fold_lr_state(vcpu);
|
||||
vgic_prune_ap_list(vcpu);
|
||||
}
|
||||
|
||||
/* Flush our emulation state into the GIC hardware before entering the guest. */
|
||||
void kvm_vgic_flush_hwstate(struct kvm_vcpu *vcpu)
|
||||
{
|
||||
if (unlikely(!vgic_initialized(vcpu->kvm)))
|
||||
/*
|
||||
* If there are no virtual interrupts active or pending for this
|
||||
* VCPU, then there is no work to do and we can bail out without
|
||||
* taking any lock. There is a potential race with someone injecting
|
||||
* interrupts to the VCPU, but it is a benign race as the VCPU will
|
||||
* either observe the new interrupt before or after doing this check,
|
||||
* and introducing additional synchronization mechanism doesn't change
|
||||
* this.
|
||||
*/
|
||||
if (list_empty(&vcpu->arch.vgic_cpu.ap_list_head))
|
||||
return;
|
||||
|
||||
spin_lock(&vcpu->arch.vgic_cpu.ap_list_lock);
|
||||
@@ -656,6 +662,28 @@ void kvm_vgic_flush_hwstate(struct kvm_vcpu *vcpu)
|
||||
spin_unlock(&vcpu->arch.vgic_cpu.ap_list_lock);
|
||||
}
|
||||
|
||||
void kvm_vgic_load(struct kvm_vcpu *vcpu)
|
||||
{
|
||||
if (unlikely(!vgic_initialized(vcpu->kvm)))
|
||||
return;
|
||||
|
||||
if (kvm_vgic_global_state.type == VGIC_V2)
|
||||
vgic_v2_load(vcpu);
|
||||
else
|
||||
vgic_v3_load(vcpu);
|
||||
}
|
||||
|
||||
void kvm_vgic_put(struct kvm_vcpu *vcpu)
|
||||
{
|
||||
if (unlikely(!vgic_initialized(vcpu->kvm)))
|
||||
return;
|
||||
|
||||
if (kvm_vgic_global_state.type == VGIC_V2)
|
||||
vgic_v2_put(vcpu);
|
||||
else
|
||||
vgic_v3_put(vcpu);
|
||||
}
|
||||
|
||||
int kvm_vgic_vcpu_pending_irq(struct kvm_vcpu *vcpu)
|
||||
{
|
||||
struct vgic_cpu *vgic_cpu = &vcpu->arch.vgic_cpu;
|
||||
|
||||
@@ -112,7 +112,6 @@ void vgic_kick_vcpus(struct kvm *kvm);
|
||||
int vgic_check_ioaddr(struct kvm *kvm, phys_addr_t *ioaddr,
|
||||
phys_addr_t addr, phys_addr_t alignment);
|
||||
|
||||
void vgic_v2_process_maintenance(struct kvm_vcpu *vcpu);
|
||||
void vgic_v2_fold_lr_state(struct kvm_vcpu *vcpu);
|
||||
void vgic_v2_populate_lr(struct kvm_vcpu *vcpu, struct vgic_irq *irq, int lr);
|
||||
void vgic_v2_clear_lr(struct kvm_vcpu *vcpu, int lr);
|
||||
@@ -130,6 +129,9 @@ int vgic_v2_map_resources(struct kvm *kvm);
|
||||
int vgic_register_dist_iodev(struct kvm *kvm, gpa_t dist_base_address,
|
||||
enum vgic_type);
|
||||
|
||||
void vgic_v2_load(struct kvm_vcpu *vcpu);
|
||||
void vgic_v2_put(struct kvm_vcpu *vcpu);
|
||||
|
||||
static inline void vgic_get_irq_kref(struct vgic_irq *irq)
|
||||
{
|
||||
if (irq->intid < VGIC_MIN_LPI)
|
||||
@@ -138,7 +140,6 @@ static inline void vgic_get_irq_kref(struct vgic_irq *irq)
|
||||
kref_get(&irq->refcount);
|
||||
}
|
||||
|
||||
void vgic_v3_process_maintenance(struct kvm_vcpu *vcpu);
|
||||
void vgic_v3_fold_lr_state(struct kvm_vcpu *vcpu);
|
||||
void vgic_v3_populate_lr(struct kvm_vcpu *vcpu, struct vgic_irq *irq, int lr);
|
||||
void vgic_v3_clear_lr(struct kvm_vcpu *vcpu, int lr);
|
||||
@@ -150,6 +151,9 @@ int vgic_v3_probe(const struct gic_kvm_info *info);
|
||||
int vgic_v3_map_resources(struct kvm *kvm);
|
||||
int vgic_register_redist_iodevs(struct kvm *kvm, gpa_t dist_base_address);
|
||||
|
||||
void vgic_v3_load(struct kvm_vcpu *vcpu);
|
||||
void vgic_v3_put(struct kvm_vcpu *vcpu);
|
||||
|
||||
int vgic_register_its_iodevs(struct kvm *kvm);
|
||||
bool vgic_has_its(struct kvm *kvm);
|
||||
int kvm_vgic_register_its_device(void);
|
||||
|
||||
Reference in New Issue
Block a user