aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorChristoffer Dall <christoffer.dall@linaro.org>2015-10-16 06:41:21 -0400
committerChristoffer Dall <christoffer.dall@linaro.org>2015-10-20 12:04:54 -0400
commitcff9211eb1a1f58ce7f5a2d596b617928fd4be0e (patch)
treebe0d29ce87e62ad6281e75646e0da3c7e01d3a7a
parent4a5d69b73948d0e03cd38d77dc11edb2e707165f (diff)
arm/arm64: KVM: Fix arch timer behavior for disabled interrupts
We have an interesting issue when the guest disables the timer interrupt on the VGIC, which happens when turning VCPUs off using PSCI, for example. The problem is that because the guest disables the virtual interrupt at the VGIC level, we never inject interrupts to the guest and therefore never mark the interrupt as active on the physical distributor. The host also never takes the timer interrupt (we only use the timer device to trigger a guest exit and everything else is done in software), so the interrupt does not become active through normal means. The result is that we keep entering the guest with a programmed timer that will always fire as soon as we context switch the hardware timer state and run the guest, preventing forward progress for the VCPU. Since the active state on the physical distributor is really part of the timer logic, it is the job of our virtual arch timer driver to manage this state. The timer->map->active boolean field indicates whether we have signalled this interrupt to the vgic and if that interrupt is still pending or active. As long as that is the case, the hardware doesn't have to generate physical interrupts and therefore we mark the interrupt as active on the physical distributor. We also have to restore the pending state of an interrupt that was queued to an LR but was retired from the LR for some reason, while remaining pending in the LR. Cc: Marc Zyngier <marc.zyngier@arm.com> Reported-by: Lorenzo Pieralisi <lorenzo.pieralisi@arm.com> Signed-off-by: Christoffer Dall <christoffer.dall@linaro.org>
-rw-r--r--virt/kvm/arm/arch_timer.c19
-rw-r--r--virt/kvm/arm/vgic.c43
2 files changed, 30 insertions, 32 deletions
diff --git a/virt/kvm/arm/arch_timer.c b/virt/kvm/arm/arch_timer.c
index 48c6e1ac6827..b9d3a32cbc04 100644
--- a/virt/kvm/arm/arch_timer.c
+++ b/virt/kvm/arm/arch_timer.c
@@ -137,6 +137,8 @@ bool kvm_timer_should_fire(struct kvm_vcpu *vcpu)
137void kvm_timer_flush_hwstate(struct kvm_vcpu *vcpu) 137void kvm_timer_flush_hwstate(struct kvm_vcpu *vcpu)
138{ 138{
139 struct arch_timer_cpu *timer = &vcpu->arch.timer_cpu; 139 struct arch_timer_cpu *timer = &vcpu->arch.timer_cpu;
140 bool phys_active;
141 int ret;
140 142
141 /* 143 /*
142 * We're about to run this vcpu again, so there is no need to 144 * We're about to run this vcpu again, so there is no need to
@@ -151,6 +153,23 @@ void kvm_timer_flush_hwstate(struct kvm_vcpu *vcpu)
151 */ 153 */
152 if (kvm_timer_should_fire(vcpu)) 154 if (kvm_timer_should_fire(vcpu))
153 kvm_timer_inject_irq(vcpu); 155 kvm_timer_inject_irq(vcpu);
156
157 /*
158 * We keep track of whether the edge-triggered interrupt has been
159 * signalled to the vgic/guest, and if so, we mask the interrupt and
160 * the physical distributor to prevent the timer from raising a
161 * physical interrupt whenever we run a guest, preventing forward
162 * VCPU progress.
163 */
164 if (kvm_vgic_get_phys_irq_active(timer->map))
165 phys_active = true;
166 else
167 phys_active = false;
168
169 ret = irq_set_irqchip_state(timer->map->irq,
170 IRQCHIP_STATE_ACTIVE,
171 phys_active);
172 WARN_ON(ret);
154} 173}
155 174
156/** 175/**
diff --git a/virt/kvm/arm/vgic.c b/virt/kvm/arm/vgic.c
index 596455a394af..ea21bc273542 100644
--- a/virt/kvm/arm/vgic.c
+++ b/virt/kvm/arm/vgic.c
@@ -1092,6 +1092,15 @@ static void vgic_retire_lr(int lr_nr, int irq, struct kvm_vcpu *vcpu)
1092 struct vgic_cpu *vgic_cpu = &vcpu->arch.vgic_cpu; 1092 struct vgic_cpu *vgic_cpu = &vcpu->arch.vgic_cpu;
1093 struct vgic_lr vlr = vgic_get_lr(vcpu, lr_nr); 1093 struct vgic_lr vlr = vgic_get_lr(vcpu, lr_nr);
1094 1094
1095 /*
1096 * We must transfer the pending state back to the distributor before
1097 * retiring the LR, otherwise we may loose edge-triggered interrupts.
1098 */
1099 if (vlr.state & LR_STATE_PENDING) {
1100 vgic_dist_irq_set_pending(vcpu, irq);
1101 vlr.hwirq = 0;
1102 }
1103
1095 vlr.state = 0; 1104 vlr.state = 0;
1096 vgic_set_lr(vcpu, lr_nr, vlr); 1105 vgic_set_lr(vcpu, lr_nr, vlr);
1097 clear_bit(lr_nr, vgic_cpu->lr_used); 1106 clear_bit(lr_nr, vgic_cpu->lr_used);
@@ -1241,7 +1250,7 @@ static void __kvm_vgic_flush_hwstate(struct kvm_vcpu *vcpu)
1241 struct vgic_cpu *vgic_cpu = &vcpu->arch.vgic_cpu; 1250 struct vgic_cpu *vgic_cpu = &vcpu->arch.vgic_cpu;
1242 struct vgic_dist *dist = &vcpu->kvm->arch.vgic; 1251 struct vgic_dist *dist = &vcpu->kvm->arch.vgic;
1243 unsigned long *pa_percpu, *pa_shared; 1252 unsigned long *pa_percpu, *pa_shared;
1244 int i, vcpu_id, lr, ret; 1253 int i, vcpu_id;
1245 int overflow = 0; 1254 int overflow = 0;
1246 int nr_shared = vgic_nr_shared_irqs(dist); 1255 int nr_shared = vgic_nr_shared_irqs(dist);
1247 1256
@@ -1296,31 +1305,6 @@ epilog:
1296 */ 1305 */
1297 clear_bit(vcpu_id, dist->irq_pending_on_cpu); 1306 clear_bit(vcpu_id, dist->irq_pending_on_cpu);
1298 } 1307 }
1299
1300 for (lr = 0; lr < vgic->nr_lr; lr++) {
1301 struct vgic_lr vlr;
1302
1303 if (!test_bit(lr, vgic_cpu->lr_used))
1304 continue;
1305
1306 vlr = vgic_get_lr(vcpu, lr);
1307
1308 /*
1309 * If we have a mapping, and the virtual interrupt is
1310 * presented to the guest (as pending or active), then we must
1311 * set the state to active in the physical world. See
1312 * Documentation/virtual/kvm/arm/vgic-mapped-irqs.txt.
1313 */
1314 if (vlr.state & LR_HW) {
1315 struct irq_phys_map *map;
1316 map = vgic_irq_map_search(vcpu, vlr.irq);
1317
1318 ret = irq_set_irqchip_state(map->irq,
1319 IRQCHIP_STATE_ACTIVE,
1320 true);
1321 WARN_ON(ret);
1322 }
1323 }
1324} 1308}
1325 1309
1326static bool vgic_process_maintenance(struct kvm_vcpu *vcpu) 1310static bool vgic_process_maintenance(struct kvm_vcpu *vcpu)
@@ -1430,13 +1414,8 @@ static int vgic_sync_hwirq(struct kvm_vcpu *vcpu, struct vgic_lr vlr)
1430 1414
1431 WARN_ON(ret); 1415 WARN_ON(ret);
1432 1416
1433 if (map->active) { 1417 if (map->active)
1434 ret = irq_set_irqchip_state(map->irq,
1435 IRQCHIP_STATE_ACTIVE,
1436 false);
1437 WARN_ON(ret);
1438 return 0; 1418 return 0;
1439 }
1440 1419
1441 return 1; 1420 return 1;
1442} 1421}