diff options
Diffstat (limited to 'arch/powerpc/kvm/book3s.c')
-rw-r--r-- | arch/powerpc/kvm/book3s.c | 18 |
1 files changed, 16 insertions, 2 deletions
diff --git a/arch/powerpc/kvm/book3s.c b/arch/powerpc/kvm/book3s.c index 5cb5f0d9381f..d6227ff0ceae 100644 --- a/arch/powerpc/kvm/book3s.c +++ b/arch/powerpc/kvm/book3s.c | |||
@@ -251,14 +251,28 @@ int kvmppc_book3s_irqprio_deliver(struct kvm_vcpu *vcpu, unsigned int priority) | |||
251 | int deliver = 1; | 251 | int deliver = 1; |
252 | int vec = 0; | 252 | int vec = 0; |
253 | ulong flags = 0ULL; | 253 | ulong flags = 0ULL; |
254 | ulong crit_raw = vcpu->arch.shared->critical; | ||
255 | ulong crit_r1 = kvmppc_get_gpr(vcpu, 1); | ||
256 | bool crit; | ||
257 | |||
258 | /* Truncate crit indicators in 32 bit mode */ | ||
259 | if (!(vcpu->arch.shared->msr & MSR_SF)) { | ||
260 | crit_raw &= 0xffffffff; | ||
261 | crit_r1 &= 0xffffffff; | ||
262 | } | ||
263 | |||
264 | /* Critical section when crit == r1 */ | ||
265 | crit = (crit_raw == crit_r1); | ||
266 | /* ... and we're in supervisor mode */ | ||
267 | crit = crit && !(vcpu->arch.shared->msr & MSR_PR); | ||
254 | 268 | ||
255 | switch (priority) { | 269 | switch (priority) { |
256 | case BOOK3S_IRQPRIO_DECREMENTER: | 270 | case BOOK3S_IRQPRIO_DECREMENTER: |
257 | deliver = vcpu->arch.shared->msr & MSR_EE; | 271 | deliver = (vcpu->arch.shared->msr & MSR_EE) && !crit; |
258 | vec = BOOK3S_INTERRUPT_DECREMENTER; | 272 | vec = BOOK3S_INTERRUPT_DECREMENTER; |
259 | break; | 273 | break; |
260 | case BOOK3S_IRQPRIO_EXTERNAL: | 274 | case BOOK3S_IRQPRIO_EXTERNAL: |
261 | deliver = vcpu->arch.shared->msr & MSR_EE; | 275 | deliver = (vcpu->arch.shared->msr & MSR_EE) && !crit; |
262 | vec = BOOK3S_INTERRUPT_EXTERNAL; | 276 | vec = BOOK3S_INTERRUPT_EXTERNAL; |
263 | break; | 277 | break; |
264 | case BOOK3S_IRQPRIO_SYSTEM_RESET: | 278 | case BOOK3S_IRQPRIO_SYSTEM_RESET: |