diff options
author | Alexander Graf <agraf@suse.de> | 2012-04-27 10:33:35 -0400 |
---|---|---|
committer | Alexander Graf <agraf@suse.de> | 2012-05-16 09:02:10 -0400 |
commit | 56e13dbae3eddb1648e6e94ae251c83cdc8304e0 (patch) | |
tree | d9e7df8e8bf1917e82711e9437673535f40c8f55 /arch | |
parent | 7ef4e985d54bad2773f260da38530f858a9a8491 (diff) |
KVM: PPC: Fix PR KVM on POWER7 bare metal
When running on a system that is HV capable, some interrupts use HSRR
SPRs instead of the normal SRR SPRs. These are also used in the Linux
handlers to jump back to code after an interrupt got processed.
Unfortunately, in our "jump back to the real host handler after we've
done the context switch" code, we were only setting the SRR SPRs,
rendering Linux to jump back to some invalid IP after it's processed
the interrupt.
This fixes random crashes on p7 opal mode with PR KVM for me.
Signed-off-by: Alexander Graf <agraf@suse.de>
Diffstat (limited to 'arch')
-rw-r--r-- | arch/powerpc/kvm/book3s_segment.S | 35 |
1 files changed, 22 insertions, 13 deletions
diff --git a/arch/powerpc/kvm/book3s_segment.S b/arch/powerpc/kvm/book3s_segment.S index 012fc9281213..87cfc1def241 100644 --- a/arch/powerpc/kvm/book3s_segment.S +++ b/arch/powerpc/kvm/book3s_segment.S | |||
@@ -197,6 +197,7 @@ kvmppc_interrupt: | |||
197 | /* Save guest PC and MSR */ | 197 | /* Save guest PC and MSR */ |
198 | #ifdef CONFIG_PPC64 | 198 | #ifdef CONFIG_PPC64 |
199 | BEGIN_FTR_SECTION | 199 | BEGIN_FTR_SECTION |
200 | mr r10, r12 | ||
200 | andi. r0,r12,0x2 | 201 | andi. r0,r12,0x2 |
201 | beq 1f | 202 | beq 1f |
202 | mfspr r3,SPRN_HSRR0 | 203 | mfspr r3,SPRN_HSRR0 |
@@ -322,23 +323,17 @@ no_dcbz32_off: | |||
322 | * Having set up SRR0/1 with the address where we want | 323 | * Having set up SRR0/1 with the address where we want |
323 | * to continue with relocation on (potentially in module | 324 | * to continue with relocation on (potentially in module |
324 | * space), we either just go straight there with rfi[d], | 325 | * space), we either just go straight there with rfi[d], |
325 | * or we jump to an interrupt handler with bctr if there | 326 | * or we jump to an interrupt handler if there is an |
326 | * is an interrupt to be handled first. In the latter | 327 | * interrupt to be handled first. In the latter case, |
327 | * case, the rfi[d] at the end of the interrupt handler | 328 | * the rfi[d] at the end of the interrupt handler will |
328 | * will get us back to where we want to continue. | 329 | * get us back to where we want to continue. |
329 | */ | 330 | */ |
330 | 331 | ||
331 | cmpwi r12, BOOK3S_INTERRUPT_EXTERNAL | ||
332 | beq 1f | ||
333 | cmpwi r12, BOOK3S_INTERRUPT_DECREMENTER | ||
334 | beq 1f | ||
335 | cmpwi r12, BOOK3S_INTERRUPT_PERFMON | ||
336 | 1: mtctr r12 | ||
337 | |||
338 | /* Register usage at this point: | 332 | /* Register usage at this point: |
339 | * | 333 | * |
340 | * R1 = host R1 | 334 | * R1 = host R1 |
341 | * R2 = host R2 | 335 | * R2 = host R2 |
336 | * R10 = raw exit handler id | ||
342 | * R12 = exit handler id | 337 | * R12 = exit handler id |
343 | * R13 = shadow vcpu (32-bit) or PACA (64-bit) | 338 | * R13 = shadow vcpu (32-bit) or PACA (64-bit) |
344 | * SVCPU.* = guest * | 339 | * SVCPU.* = guest * |
@@ -348,12 +343,26 @@ no_dcbz32_off: | |||
348 | PPC_LL r6, HSTATE_HOST_MSR(r13) | 343 | PPC_LL r6, HSTATE_HOST_MSR(r13) |
349 | PPC_LL r8, HSTATE_VMHANDLER(r13) | 344 | PPC_LL r8, HSTATE_VMHANDLER(r13) |
350 | 345 | ||
351 | /* Restore host msr -> SRR1 */ | 346 | #ifdef CONFIG_PPC64 |
347 | BEGIN_FTR_SECTION | ||
348 | andi. r0,r10,0x2 | ||
349 | beq 1f | ||
350 | mtspr SPRN_HSRR1, r6 | ||
351 | mtspr SPRN_HSRR0, r8 | ||
352 | END_FTR_SECTION_IFSET(CPU_FTR_HVMODE) | ||
353 | #endif | ||
354 | 1: /* Restore host msr -> SRR1 */ | ||
352 | mtsrr1 r6 | 355 | mtsrr1 r6 |
353 | /* Load highmem handler address */ | 356 | /* Load highmem handler address */ |
354 | mtsrr0 r8 | 357 | mtsrr0 r8 |
355 | 358 | ||
356 | /* RFI into the highmem handler, or jump to interrupt handler */ | 359 | /* RFI into the highmem handler, or jump to interrupt handler */ |
357 | beqctr | 360 | cmpwi r12, BOOK3S_INTERRUPT_EXTERNAL |
361 | beqa BOOK3S_INTERRUPT_EXTERNAL | ||
362 | cmpwi r12, BOOK3S_INTERRUPT_DECREMENTER | ||
363 | beqa BOOK3S_INTERRUPT_DECREMENTER | ||
364 | cmpwi r12, BOOK3S_INTERRUPT_PERFMON | ||
365 | beqa BOOK3S_INTERRUPT_PERFMON | ||
366 | |||
358 | RFI | 367 | RFI |
359 | kvmppc_handler_trampoline_exit_end: | 368 | kvmppc_handler_trampoline_exit_end: |