diff options
author | Christoffer Dall <christoffer.dall@linaro.org> | 2014-12-12 15:19:23 -0500 |
---|---|---|
committer | Christoffer Dall <christoffer.dall@linaro.org> | 2014-12-15 05:50:42 -0500 |
commit | 05971120fca43e0357789a14b3386bb56eef2201 (patch) | |
tree | e839f7efda57e1d53fa69c90315df4d0775716bf | |
parent | ca7d9c829d419c06e450afa5f785d58198c37caa (diff) |
arm/arm64: KVM: Require in-kernel vgic for the arch timers
It is curently possible to run a VM with architected timers support
without creating an in-kernel VGIC, which will result in interrupts from
the virtual timer going nowhere.
To address this issue, move the architected timers initialization to the
time when we run a VCPU for the first time, and then only initialize
(and enable) the architected timers if we have a properly created and
initialized in-kernel VGIC.
When injecting interrupts from the virtual timer to the vgic, the
current setup should ensure that this never calls an on-demand init of
the VGIC, which is the only call path that could return an error from
kvm_vgic_inject_irq(), so capture the return value and raise a warning
if there's an error there.
We also change the kvm_timer_init() function from returning an int to be
a void function, since the function always succeeds.
Reviewed-by: Marc Zyngier <marc.zyngier@arm.com>
Signed-off-by: Christoffer Dall <christoffer.dall@linaro.org>
-rw-r--r-- | arch/arm/kvm/arm.c | 13 | ||||
-rw-r--r-- | include/kvm/arm_arch_timer.h | 10 | ||||
-rw-r--r-- | virt/kvm/arm/arch_timer.c | 30 |
3 files changed, 37 insertions, 16 deletions
diff --git a/arch/arm/kvm/arm.c b/arch/arm/kvm/arm.c index 66f37c4cdf13..2d6d91001062 100644 --- a/arch/arm/kvm/arm.c +++ b/arch/arm/kvm/arm.c | |||
@@ -425,6 +425,7 @@ static void update_vttbr(struct kvm *kvm) | |||
425 | 425 | ||
426 | static int kvm_vcpu_first_run_init(struct kvm_vcpu *vcpu) | 426 | static int kvm_vcpu_first_run_init(struct kvm_vcpu *vcpu) |
427 | { | 427 | { |
428 | struct kvm *kvm = vcpu->kvm; | ||
428 | int ret; | 429 | int ret; |
429 | 430 | ||
430 | if (likely(vcpu->arch.has_run_once)) | 431 | if (likely(vcpu->arch.has_run_once)) |
@@ -436,12 +437,20 @@ static int kvm_vcpu_first_run_init(struct kvm_vcpu *vcpu) | |||
436 | * Map the VGIC hardware resources before running a vcpu the first | 437 | * Map the VGIC hardware resources before running a vcpu the first |
437 | * time on this VM. | 438 | * time on this VM. |
438 | */ | 439 | */ |
439 | if (unlikely(!vgic_ready(vcpu->kvm))) { | 440 | if (unlikely(!vgic_ready(kvm))) { |
440 | ret = kvm_vgic_map_resources(vcpu->kvm); | 441 | ret = kvm_vgic_map_resources(kvm); |
441 | if (ret) | 442 | if (ret) |
442 | return ret; | 443 | return ret; |
443 | } | 444 | } |
444 | 445 | ||
446 | /* | ||
447 | * Enable the arch timers only if we have an in-kernel VGIC | ||
448 | * and it has been properly initialized, since we cannot handle | ||
449 | * interrupts from the virtual timer with a userspace gic. | ||
450 | */ | ||
451 | if (irqchip_in_kernel(kvm) && vgic_initialized(kvm)) | ||
452 | kvm_timer_enable(kvm); | ||
453 | |||
445 | return 0; | 454 | return 0; |
446 | } | 455 | } |
447 | 456 | ||
diff --git a/include/kvm/arm_arch_timer.h b/include/kvm/arm_arch_timer.h index ad9db6045b2f..b3f45a578344 100644 --- a/include/kvm/arm_arch_timer.h +++ b/include/kvm/arm_arch_timer.h | |||
@@ -60,7 +60,8 @@ struct arch_timer_cpu { | |||
60 | 60 | ||
61 | #ifdef CONFIG_KVM_ARM_TIMER | 61 | #ifdef CONFIG_KVM_ARM_TIMER |
62 | int kvm_timer_hyp_init(void); | 62 | int kvm_timer_hyp_init(void); |
63 | int kvm_timer_init(struct kvm *kvm); | 63 | void kvm_timer_enable(struct kvm *kvm); |
64 | void kvm_timer_init(struct kvm *kvm); | ||
64 | void kvm_timer_vcpu_reset(struct kvm_vcpu *vcpu, | 65 | void kvm_timer_vcpu_reset(struct kvm_vcpu *vcpu, |
65 | const struct kvm_irq_level *irq); | 66 | const struct kvm_irq_level *irq); |
66 | void kvm_timer_vcpu_init(struct kvm_vcpu *vcpu); | 67 | void kvm_timer_vcpu_init(struct kvm_vcpu *vcpu); |
@@ -77,11 +78,8 @@ static inline int kvm_timer_hyp_init(void) | |||
77 | return 0; | 78 | return 0; |
78 | }; | 79 | }; |
79 | 80 | ||
80 | static inline int kvm_timer_init(struct kvm *kvm) | 81 | static inline void kvm_timer_enable(struct kvm *kvm) {} |
81 | { | 82 | static inline void kvm_timer_init(struct kvm *kvm) {} |
82 | return 0; | ||
83 | } | ||
84 | |||
85 | static inline void kvm_timer_vcpu_reset(struct kvm_vcpu *vcpu, | 83 | static inline void kvm_timer_vcpu_reset(struct kvm_vcpu *vcpu, |
86 | const struct kvm_irq_level *irq) {} | 84 | const struct kvm_irq_level *irq) {} |
87 | static inline void kvm_timer_vcpu_init(struct kvm_vcpu *vcpu) {} | 85 | static inline void kvm_timer_vcpu_init(struct kvm_vcpu *vcpu) {} |
diff --git a/virt/kvm/arm/arch_timer.c b/virt/kvm/arm/arch_timer.c index 22fa819a9b6a..1c0772b340d8 100644 --- a/virt/kvm/arm/arch_timer.c +++ b/virt/kvm/arm/arch_timer.c | |||
@@ -61,12 +61,14 @@ static void timer_disarm(struct arch_timer_cpu *timer) | |||
61 | 61 | ||
62 | static void kvm_timer_inject_irq(struct kvm_vcpu *vcpu) | 62 | static void kvm_timer_inject_irq(struct kvm_vcpu *vcpu) |
63 | { | 63 | { |
64 | int ret; | ||
64 | struct arch_timer_cpu *timer = &vcpu->arch.timer_cpu; | 65 | struct arch_timer_cpu *timer = &vcpu->arch.timer_cpu; |
65 | 66 | ||
66 | timer->cntv_ctl |= ARCH_TIMER_CTRL_IT_MASK; | 67 | timer->cntv_ctl |= ARCH_TIMER_CTRL_IT_MASK; |
67 | kvm_vgic_inject_irq(vcpu->kvm, vcpu->vcpu_id, | 68 | ret = kvm_vgic_inject_irq(vcpu->kvm, vcpu->vcpu_id, |
68 | timer->irq->irq, | 69 | timer->irq->irq, |
69 | timer->irq->level); | 70 | timer->irq->level); |
71 | WARN_ON(ret); | ||
70 | } | 72 | } |
71 | 73 | ||
72 | static irqreturn_t kvm_arch_timer_handler(int irq, void *dev_id) | 74 | static irqreturn_t kvm_arch_timer_handler(int irq, void *dev_id) |
@@ -307,12 +309,24 @@ void kvm_timer_vcpu_terminate(struct kvm_vcpu *vcpu) | |||
307 | timer_disarm(timer); | 309 | timer_disarm(timer); |
308 | } | 310 | } |
309 | 311 | ||
310 | int kvm_timer_init(struct kvm *kvm) | 312 | void kvm_timer_enable(struct kvm *kvm) |
311 | { | 313 | { |
312 | if (timecounter && wqueue) { | 314 | if (kvm->arch.timer.enabled) |
313 | kvm->arch.timer.cntvoff = kvm_phys_timer_read(); | 315 | return; |
316 | |||
317 | /* | ||
318 | * There is a potential race here between VCPUs starting for the first | ||
319 | * time, which may be enabling the timer multiple times. That doesn't | ||
320 | * hurt though, because we're just setting a variable to the same | ||
321 | * variable that it already was. The important thing is that all | ||
322 | * VCPUs have the enabled variable set, before entering the guest, if | ||
323 | * the arch timers are enabled. | ||
324 | */ | ||
325 | if (timecounter && wqueue) | ||
314 | kvm->arch.timer.enabled = 1; | 326 | kvm->arch.timer.enabled = 1; |
315 | } | 327 | } |
316 | 328 | ||
317 | return 0; | 329 | void kvm_timer_init(struct kvm *kvm) |
330 | { | ||
331 | kvm->arch.timer.cntvoff = kvm_phys_timer_read(); | ||
318 | } | 332 | } |