Commit 8943633c authored by Paul Mackerras's avatar Paul Mackerras Committed by Avi Kivity

KVM: PPC: Work around POWER7 DABR corruption problem

It turns out that on POWER7, writing to the DABR can cause a corrupted
value to be written if the PMU is active and updating SDAR in continuous
sampling mode.  To work around this, we make sure that the PMU is inactive
and SDAR updates are disabled (via MMCRA) when we are context-switching
DABR.

When the guest sets DABR via the H_SET_DABR hypercall, we use a slightly
different workaround, which is to read back the DABR and write it again
if it got corrupted.

While we are at it, make it consistent that the saving and restoring
of the guest's non-volatile GPRs and the FPRs are done with the guest
setup of the PMU active.
Signed-off-by: default avatarPaul Mackerras <paulus@samba.org>
Signed-off-by: default avatarAlexander Graf <agraf@suse.de>
Signed-off-by: default avatarAvi Kivity <avi@redhat.com>
parent 7657f408
...@@ -68,19 +68,24 @@ END_FTR_SECTION_IFSET(CPU_FTR_ARCH_206) ...@@ -68,19 +68,24 @@ END_FTR_SECTION_IFSET(CPU_FTR_ARCH_206)
rotldi r10,r10,16 rotldi r10,r10,16
mtmsrd r10,1 mtmsrd r10,1
/* Save host PMU registers and load guest PMU registers */ /* Save host PMU registers */
/* R4 is live here (vcpu pointer) but not r3 or r5 */ /* R4 is live here (vcpu pointer) but not r3 or r5 */
li r3, 1 li r3, 1
sldi r3, r3, 31 /* MMCR0_FC (freeze counters) bit */ sldi r3, r3, 31 /* MMCR0_FC (freeze counters) bit */
mfspr r7, SPRN_MMCR0 /* save MMCR0 */ mfspr r7, SPRN_MMCR0 /* save MMCR0 */
mtspr SPRN_MMCR0, r3 /* freeze all counters, disable interrupts */ mtspr SPRN_MMCR0, r3 /* freeze all counters, disable interrupts */
mfspr r6, SPRN_MMCRA
BEGIN_FTR_SECTION
/* On P7, clear MMCRA in order to disable SDAR updates */
li r5, 0
mtspr SPRN_MMCRA, r5
END_FTR_SECTION_IFSET(CPU_FTR_ARCH_206)
isync isync
ld r3, PACALPPACAPTR(r13) /* is the host using the PMU? */ ld r3, PACALPPACAPTR(r13) /* is the host using the PMU? */
lbz r5, LPPACA_PMCINUSE(r3) lbz r5, LPPACA_PMCINUSE(r3)
cmpwi r5, 0 cmpwi r5, 0
beq 31f /* skip if not */ beq 31f /* skip if not */
mfspr r5, SPRN_MMCR1 mfspr r5, SPRN_MMCR1
mfspr r6, SPRN_MMCRA
std r7, HSTATE_MMCR(r13) std r7, HSTATE_MMCR(r13)
std r5, HSTATE_MMCR + 8(r13) std r5, HSTATE_MMCR + 8(r13)
std r6, HSTATE_MMCR + 16(r13) std r6, HSTATE_MMCR + 16(r13)
......
...@@ -159,24 +159,15 @@ kvmppc_hv_entry: ...@@ -159,24 +159,15 @@ kvmppc_hv_entry:
mflr r0 mflr r0
std r0, HSTATE_VMHANDLER(r13) std r0, HSTATE_VMHANDLER(r13)
ld r14, VCPU_GPR(r14)(r4) /* Set partition DABR */
ld r15, VCPU_GPR(r15)(r4) /* Do this before re-enabling PMU to avoid P7 DABR corruption bug */
ld r16, VCPU_GPR(r16)(r4) li r5,3
ld r17, VCPU_GPR(r17)(r4) ld r6,VCPU_DABR(r4)
ld r18, VCPU_GPR(r18)(r4) mtspr SPRN_DABRX,r5
ld r19, VCPU_GPR(r19)(r4) mtspr SPRN_DABR,r6
ld r20, VCPU_GPR(r20)(r4) BEGIN_FTR_SECTION
ld r21, VCPU_GPR(r21)(r4) isync
ld r22, VCPU_GPR(r22)(r4) END_FTR_SECTION_IFSET(CPU_FTR_ARCH_206)
ld r23, VCPU_GPR(r23)(r4)
ld r24, VCPU_GPR(r24)(r4)
ld r25, VCPU_GPR(r25)(r4)
ld r26, VCPU_GPR(r26)(r4)
ld r27, VCPU_GPR(r27)(r4)
ld r28, VCPU_GPR(r28)(r4)
ld r29, VCPU_GPR(r29)(r4)
ld r30, VCPU_GPR(r30)(r4)
ld r31, VCPU_GPR(r31)(r4)
/* Load guest PMU registers */ /* Load guest PMU registers */
/* R4 is live here (vcpu pointer) */ /* R4 is live here (vcpu pointer) */
...@@ -215,6 +206,25 @@ END_FTR_SECTION_IFSET(CPU_FTR_ARCH_201) ...@@ -215,6 +206,25 @@ END_FTR_SECTION_IFSET(CPU_FTR_ARCH_201)
/* Load up FP, VMX and VSX registers */ /* Load up FP, VMX and VSX registers */
bl kvmppc_load_fp bl kvmppc_load_fp
ld r14, VCPU_GPR(r14)(r4)
ld r15, VCPU_GPR(r15)(r4)
ld r16, VCPU_GPR(r16)(r4)
ld r17, VCPU_GPR(r17)(r4)
ld r18, VCPU_GPR(r18)(r4)
ld r19, VCPU_GPR(r19)(r4)
ld r20, VCPU_GPR(r20)(r4)
ld r21, VCPU_GPR(r21)(r4)
ld r22, VCPU_GPR(r22)(r4)
ld r23, VCPU_GPR(r23)(r4)
ld r24, VCPU_GPR(r24)(r4)
ld r25, VCPU_GPR(r25)(r4)
ld r26, VCPU_GPR(r26)(r4)
ld r27, VCPU_GPR(r27)(r4)
ld r28, VCPU_GPR(r28)(r4)
ld r29, VCPU_GPR(r29)(r4)
ld r30, VCPU_GPR(r30)(r4)
ld r31, VCPU_GPR(r31)(r4)
BEGIN_FTR_SECTION BEGIN_FTR_SECTION
/* Switch DSCR to guest value */ /* Switch DSCR to guest value */
ld r5, VCPU_DSCR(r4) ld r5, VCPU_DSCR(r4)
...@@ -256,12 +266,6 @@ END_FTR_SECTION_IFSET(CPU_FTR_ARCH_206) ...@@ -256,12 +266,6 @@ END_FTR_SECTION_IFSET(CPU_FTR_ARCH_206)
mtspr SPRN_DAR, r5 mtspr SPRN_DAR, r5
mtspr SPRN_DSISR, r6 mtspr SPRN_DSISR, r6
/* Set partition DABR */
li r5,3
ld r6,VCPU_DABR(r4)
mtspr SPRN_DABRX,r5
mtspr SPRN_DABR,r6
BEGIN_FTR_SECTION BEGIN_FTR_SECTION
/* Restore AMR and UAMOR, set AMOR to all 1s */ /* Restore AMR and UAMOR, set AMOR to all 1s */
ld r5,VCPU_AMR(r4) ld r5,VCPU_AMR(r4)
...@@ -955,12 +959,6 @@ BEGIN_FTR_SECTION ...@@ -955,12 +959,6 @@ BEGIN_FTR_SECTION
mtspr SPRN_AMR,r6 mtspr SPRN_AMR,r6
END_FTR_SECTION_IFSET(CPU_FTR_ARCH_206) END_FTR_SECTION_IFSET(CPU_FTR_ARCH_206)
/* Restore host DABR and DABRX */
ld r5,HSTATE_DABR(r13)
li r6,7
mtspr SPRN_DABR,r5
mtspr SPRN_DABRX,r6
/* Switch DSCR back to host value */ /* Switch DSCR back to host value */
BEGIN_FTR_SECTION BEGIN_FTR_SECTION
mfspr r8, SPRN_DSCR mfspr r8, SPRN_DSCR
...@@ -999,6 +997,10 @@ END_FTR_SECTION_IFSET(CPU_FTR_ARCH_206) ...@@ -999,6 +997,10 @@ END_FTR_SECTION_IFSET(CPU_FTR_ARCH_206)
std r5, VCPU_SPRG2(r9) std r5, VCPU_SPRG2(r9)
std r6, VCPU_SPRG3(r9) std r6, VCPU_SPRG3(r9)
/* save FP state */
mr r3, r9
bl .kvmppc_save_fp
/* Increment yield count if they have a VPA */ /* Increment yield count if they have a VPA */
ld r8, VCPU_VPA(r9) /* do they have a VPA? */ ld r8, VCPU_VPA(r9) /* do they have a VPA? */
cmpdi r8, 0 cmpdi r8, 0
...@@ -1013,6 +1015,12 @@ END_FTR_SECTION_IFSET(CPU_FTR_ARCH_206) ...@@ -1013,6 +1015,12 @@ END_FTR_SECTION_IFSET(CPU_FTR_ARCH_206)
sldi r3, r3, 31 /* MMCR0_FC (freeze counters) bit */ sldi r3, r3, 31 /* MMCR0_FC (freeze counters) bit */
mfspr r4, SPRN_MMCR0 /* save MMCR0 */ mfspr r4, SPRN_MMCR0 /* save MMCR0 */
mtspr SPRN_MMCR0, r3 /* freeze all counters, disable ints */ mtspr SPRN_MMCR0, r3 /* freeze all counters, disable ints */
mfspr r6, SPRN_MMCRA
BEGIN_FTR_SECTION
/* On P7, clear MMCRA in order to disable SDAR updates */
li r7, 0
mtspr SPRN_MMCRA, r7
END_FTR_SECTION_IFSET(CPU_FTR_ARCH_206)
isync isync
beq 21f /* if no VPA, save PMU stuff anyway */ beq 21f /* if no VPA, save PMU stuff anyway */
lbz r7, LPPACA_PMCINUSE(r8) lbz r7, LPPACA_PMCINUSE(r8)
...@@ -1021,7 +1029,6 @@ END_FTR_SECTION_IFSET(CPU_FTR_ARCH_206) ...@@ -1021,7 +1029,6 @@ END_FTR_SECTION_IFSET(CPU_FTR_ARCH_206)
std r3, VCPU_MMCR(r9) /* if not, set saved MMCR0 to FC */ std r3, VCPU_MMCR(r9) /* if not, set saved MMCR0 to FC */
b 22f b 22f
21: mfspr r5, SPRN_MMCR1 21: mfspr r5, SPRN_MMCR1
mfspr r6, SPRN_MMCRA
std r4, VCPU_MMCR(r9) std r4, VCPU_MMCR(r9)
std r5, VCPU_MMCR + 8(r9) std r5, VCPU_MMCR + 8(r9)
std r6, VCPU_MMCR + 16(r9) std r6, VCPU_MMCR + 16(r9)
...@@ -1046,17 +1053,20 @@ BEGIN_FTR_SECTION ...@@ -1046,17 +1053,20 @@ BEGIN_FTR_SECTION
stw r11, VCPU_PMC + 28(r9) stw r11, VCPU_PMC + 28(r9)
END_FTR_SECTION_IFSET(CPU_FTR_ARCH_201) END_FTR_SECTION_IFSET(CPU_FTR_ARCH_201)
22: 22:
/* save FP state */
mr r3, r9
bl .kvmppc_save_fp
/* Secondary threads go off to take a nap on POWER7 */ /* Secondary threads go off to take a nap on POWER7 */
BEGIN_FTR_SECTION BEGIN_FTR_SECTION
lwz r0,VCPU_PTID(r3) lwz r0,VCPU_PTID(r9)
cmpwi r0,0 cmpwi r0,0
bne secondary_nap bne secondary_nap
END_FTR_SECTION_IFSET(CPU_FTR_ARCH_206) END_FTR_SECTION_IFSET(CPU_FTR_ARCH_206)
/* Restore host DABR and DABRX */
ld r5,HSTATE_DABR(r13)
li r6,7
mtspr SPRN_DABR,r5
mtspr SPRN_DABRX,r6
/* /*
* Reload DEC. HDEC interrupts were disabled when * Reload DEC. HDEC interrupts were disabled when
* we reloaded the host's LPCR value. * we reloaded the host's LPCR value.
...@@ -1393,7 +1403,12 @@ bounce_ext_interrupt: ...@@ -1393,7 +1403,12 @@ bounce_ext_interrupt:
_GLOBAL(kvmppc_h_set_dabr) _GLOBAL(kvmppc_h_set_dabr)
std r4,VCPU_DABR(r3) std r4,VCPU_DABR(r3)
mtspr SPRN_DABR,r4 /* Work around P7 bug where DABR can get corrupted on mtspr */
1: mtspr SPRN_DABR,r4
mfspr r5, SPRN_DABR
cmpd r4, r5
bne 1b
isync
li r3,0 li r3,0
blr blr
...@@ -1615,8 +1630,8 @@ kvm_no_guest: ...@@ -1615,8 +1630,8 @@ kvm_no_guest:
* r3 = vcpu pointer * r3 = vcpu pointer
*/ */
_GLOBAL(kvmppc_save_fp) _GLOBAL(kvmppc_save_fp)
mfmsr r9 mfmsr r5
ori r8,r9,MSR_FP ori r8,r5,MSR_FP
#ifdef CONFIG_ALTIVEC #ifdef CONFIG_ALTIVEC
BEGIN_FTR_SECTION BEGIN_FTR_SECTION
oris r8,r8,MSR_VEC@h oris r8,r8,MSR_VEC@h
...@@ -1665,7 +1680,7 @@ END_FTR_SECTION_IFSET(CPU_FTR_ALTIVEC) ...@@ -1665,7 +1680,7 @@ END_FTR_SECTION_IFSET(CPU_FTR_ALTIVEC)
#endif #endif
mfspr r6,SPRN_VRSAVE mfspr r6,SPRN_VRSAVE
stw r6,VCPU_VRSAVE(r3) stw r6,VCPU_VRSAVE(r3)
mtmsrd r9 mtmsrd r5
isync isync
blr blr
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment