Эх сурвалжийг харах

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>
Alexander Graf 13 жил өмнө
parent
commit
56e13dbae3

+ 22 - 13
arch/powerpc/kvm/book3s_segment.S

@@ -197,6 +197,7 @@ kvmppc_interrupt:
 	/* Save guest PC and MSR */
 	/* Save guest PC and MSR */
 #ifdef CONFIG_PPC64
 #ifdef CONFIG_PPC64
 BEGIN_FTR_SECTION
 BEGIN_FTR_SECTION
+	mr	r10, r12
 	andi.	r0,r12,0x2
 	andi.	r0,r12,0x2
 	beq	1f
 	beq	1f
 	mfspr	r3,SPRN_HSRR0
 	mfspr	r3,SPRN_HSRR0
@@ -322,23 +323,17 @@ no_dcbz32_off:
 	 * Having set up SRR0/1 with the address where we want
 	 * Having set up SRR0/1 with the address where we want
 	 * to continue with relocation on (potentially in module
 	 * to continue with relocation on (potentially in module
 	 * space), we either just go straight there with rfi[d],
 	 * space), we either just go straight there with rfi[d],
-	 * or we jump to an interrupt handler with bctr if there
-	 * is an interrupt to be handled first.  In the latter
-	 * case, the rfi[d] at the end of the interrupt handler
-	 * will get us back to where we want to continue.
+	 * or we jump to an interrupt handler if there is an
+	 * interrupt to be handled first.  In the latter case,
+	 * the rfi[d] at the end of the interrupt handler will
+	 * get us back to where we want to continue.
 	 */
 	 */
 
 
-	cmpwi	r12, BOOK3S_INTERRUPT_EXTERNAL
-	beq	1f
-	cmpwi	r12, BOOK3S_INTERRUPT_DECREMENTER
-	beq	1f
-	cmpwi	r12, BOOK3S_INTERRUPT_PERFMON
-1:	mtctr	r12
-
 	/* Register usage at this point:
 	/* Register usage at this point:
 	 *
 	 *
 	 * R1       = host R1
 	 * R1       = host R1
 	 * R2       = host R2
 	 * R2       = host R2
+	 * R10      = raw exit handler id
 	 * R12      = exit handler id
 	 * R12      = exit handler id
 	 * R13      = shadow vcpu (32-bit) or PACA (64-bit)
 	 * R13      = shadow vcpu (32-bit) or PACA (64-bit)
 	 * SVCPU.*  = guest *
 	 * SVCPU.*  = guest *
@@ -348,12 +343,26 @@ no_dcbz32_off:
 	PPC_LL	r6, HSTATE_HOST_MSR(r13)
 	PPC_LL	r6, HSTATE_HOST_MSR(r13)
 	PPC_LL	r8, HSTATE_VMHANDLER(r13)
 	PPC_LL	r8, HSTATE_VMHANDLER(r13)
 
 
-	/* Restore host msr -> SRR1 */
+#ifdef CONFIG_PPC64
+BEGIN_FTR_SECTION
+	andi.	r0,r10,0x2
+	beq	1f
+	mtspr	SPRN_HSRR1, r6
+	mtspr	SPRN_HSRR0, r8
+END_FTR_SECTION_IFSET(CPU_FTR_HVMODE)
+#endif
+1:	/* Restore host msr -> SRR1 */
 	mtsrr1	r6
 	mtsrr1	r6
 	/* Load highmem handler address */
 	/* Load highmem handler address */
 	mtsrr0	r8
 	mtsrr0	r8
 
 
 	/* RFI into the highmem handler, or jump to interrupt handler */
 	/* RFI into the highmem handler, or jump to interrupt handler */
-	beqctr
+	cmpwi	r12, BOOK3S_INTERRUPT_EXTERNAL
+	beqa	BOOK3S_INTERRUPT_EXTERNAL
+	cmpwi	r12, BOOK3S_INTERRUPT_DECREMENTER
+	beqa	BOOK3S_INTERRUPT_DECREMENTER
+	cmpwi	r12, BOOK3S_INTERRUPT_PERFMON
+	beqa	BOOK3S_INTERRUPT_PERFMON
+
 	RFI
 	RFI
 kvmppc_handler_trampoline_exit_end:
 kvmppc_handler_trampoline_exit_end: