KVM: PPC: Book3S HV: Add transactional memory support
authorMichael Neuling <mikey@neuling.org>
Mon, 24 Mar 2014 23:47:02 +0000 (10:47 +1100)
committerPaul Mackerras <paulus@samba.org>
Sat, 29 Mar 2014 08:58:02 +0000 (19:58 +1100)
This adds saving of the transactional memory (TM) checkpointed state
on guest entry and exit.  We only do this if we see that the guest has
an active transaction.

It also adds emulation of the TM state changes when delivering IRQs
into the guest.  According to the architecture, if we are
transactional when an IRQ occurs, the TM state is changed to
suspended, otherwise it's left unchanged.

Signed-off-by: Michael Neuling <mikey@neuling.org>
Signed-off-by: Paul Mackerras <paulus@samba.org>
Acked-by: Scott Wood <scottwood@freescale.com>
arch/powerpc/include/asm/reg.h
arch/powerpc/include/asm/tm.h
arch/powerpc/kvm/book3s_64_mmu_hv.c
arch/powerpc/kvm/book3s_hv_rmhandlers.S

index 6ba8d4af3999b8b700659ad5949905bf4bfe405c..af21e876837e21ab86c49b796fe5376e9cd044c0 100644 (file)
 #define SPRN_ACOP      0x1F    /* Available Coprocessor Register */
 #define SPRN_TFIAR     0x81    /* Transaction Failure Inst Addr   */
 #define SPRN_TEXASR    0x82    /* Transaction EXception & Summary */
+#define   TEXASR_FS    __MASK(63-36)   /* Transaction Failure Summary */
 #define SPRN_TEXASRU   0x83    /* ''      ''      ''    Upper 32  */
 #define SPRN_TFHAR     0x80    /* Transaction Failure Handler Addr */
 #define SPRN_CTRLF     0x088
index 9dfbc34bdbf5e7e86eda005d4e974f5fe3ebd12a..386a3efd34972509fe5c329b9712cf74baf96345 100644 (file)
@@ -7,6 +7,8 @@
 
 #include <uapi/asm/tm.h>
 
+#ifndef __ASSEMBLY__
+
 #ifdef CONFIG_PPC_TRANSACTIONAL_MEM
 extern void do_load_up_transact_fpu(struct thread_struct *thread);
 extern void do_load_up_transact_altivec(struct thread_struct *thread);
@@ -20,3 +22,5 @@ extern void tm_recheckpoint(struct thread_struct *thread,
 extern void tm_abort(uint8_t cause);
 extern void tm_save_sprs(struct thread_struct *thread);
 extern void tm_restore_sprs(struct thread_struct *thread);
+
+#endif /* __ASSEMBLY__ */
index 303ece75b8e4aa5b798381b4cf782a3dde8b79f6..fb25ebc0af0ce212469180eee027615bd20ea631 100644 (file)
@@ -262,7 +262,14 @@ int kvmppc_mmu_hv_init(void)
 
 static void kvmppc_mmu_book3s_64_hv_reset_msr(struct kvm_vcpu *vcpu)
 {
-       kvmppc_set_msr(vcpu, vcpu->arch.intr_msr);
+       unsigned long msr = vcpu->arch.intr_msr;
+
+       /* If transactional, change to suspend mode on IRQ delivery */
+       if (MSR_TM_TRANSACTIONAL(vcpu->arch.shregs.msr))
+               msr |= MSR_TS_S;
+       else
+               msr |= vcpu->arch.shregs.msr & MSR_TS_MASK;
+       kvmppc_set_msr(vcpu, msr);
 }
 
 /*
index 7c5788c735c9b560a6f5f7410773d5b12b1009bd..61190ddd9f3bc20b5d3d073f0681dd8f52fd2a85 100644 (file)
@@ -28,6 +28,9 @@
 #include <asm/exception-64s.h>
 #include <asm/kvm_book3s_asm.h>
 #include <asm/mmu-hash64.h>
+#include <asm/tm.h>
+
+#define VCPU_GPRS_TM(reg) (((reg) * ULONG_SIZE) + VCPU_GPR_TM)
 
 #ifdef __LITTLE_ENDIAN__
 #error Need to fix lppaca and SLB shadow accesses in little endian mode
@@ -597,6 +600,116 @@ BEGIN_FTR_SECTION
  END_FTR_SECTION_NESTED(CPU_FTR_ARCH_206, CPU_FTR_ARCH_206, 89)
 END_FTR_SECTION_IFCLR(CPU_FTR_ARCH_207S)
 
+#ifdef CONFIG_PPC_TRANSACTIONAL_MEM
+BEGIN_FTR_SECTION
+       b       skip_tm
+END_FTR_SECTION_IFCLR(CPU_FTR_TM)
+
+       /* Turn on TM/FP/VSX/VMX so we can restore them. */
+       mfmsr   r5
+       li      r6, MSR_TM >> 32
+       sldi    r6, r6, 32
+       or      r5, r5, r6
+       ori     r5, r5, MSR_FP
+       oris    r5, r5, (MSR_VEC | MSR_VSX)@h
+       mtmsrd  r5
+
+       /*
+        * The user may change these outside of a transaction, so they must
+        * always be context switched.
+        */
+       ld      r5, VCPU_TFHAR(r4)
+       ld      r6, VCPU_TFIAR(r4)
+       ld      r7, VCPU_TEXASR(r4)
+       mtspr   SPRN_TFHAR, r5
+       mtspr   SPRN_TFIAR, r6
+       mtspr   SPRN_TEXASR, r7
+
+       ld      r5, VCPU_MSR(r4)
+       rldicl. r5, r5, 64 - MSR_TS_S_LG, 62
+       beq     skip_tm /* TM not active in guest */
+
+       /* Make sure the failure summary is set, otherwise we'll program check
+        * when we trechkpt.  It's possible that this might have been not set
+        * on a kvmppc_set_one_reg() call but we shouldn't let this crash the
+        * host.
+        */
+       oris    r7, r7, (TEXASR_FS)@h
+       mtspr   SPRN_TEXASR, r7
+
+       /*
+        * We need to load up the checkpointed state for the guest.
+        * We need to do this early as it will blow away any GPRs, VSRs and
+        * some SPRs.
+        */
+
+       mr      r31, r4
+       addi    r3, r31, VCPU_FPRS_TM
+       bl      .load_fp_state
+       addi    r3, r31, VCPU_VRS_TM
+       bl      .load_vr_state
+       mr      r4, r31
+       lwz     r7, VCPU_VRSAVE_TM(r4)
+       mtspr   SPRN_VRSAVE, r7
+
+       ld      r5, VCPU_LR_TM(r4)
+       lwz     r6, VCPU_CR_TM(r4)
+       ld      r7, VCPU_CTR_TM(r4)
+       ld      r8, VCPU_AMR_TM(r4)
+       ld      r9, VCPU_TAR_TM(r4)
+       mtlr    r5
+       mtcr    r6
+       mtctr   r7
+       mtspr   SPRN_AMR, r8
+       mtspr   SPRN_TAR, r9
+
+       /*
+        * Load up PPR and DSCR values but don't put them in the actual SPRs
+        * till the last moment to avoid running with userspace PPR and DSCR for
+        * too long.
+        */
+       ld      r29, VCPU_DSCR_TM(r4)
+       ld      r30, VCPU_PPR_TM(r4)
+
+       std     r2, PACATMSCRATCH(r13) /* Save TOC */
+
+       /* Clear the MSR RI since r1, r13 are all going to be foobar. */
+       li      r5, 0
+       mtmsrd  r5, 1
+
+       /* Load GPRs r0-r28 */
+       reg = 0
+       .rept   29
+       ld      reg, VCPU_GPRS_TM(reg)(r31)
+       reg = reg + 1
+       .endr
+
+       mtspr   SPRN_DSCR, r29
+       mtspr   SPRN_PPR, r30
+
+       /* Load final GPRs */
+       ld      29, VCPU_GPRS_TM(29)(r31)
+       ld      30, VCPU_GPRS_TM(30)(r31)
+       ld      31, VCPU_GPRS_TM(31)(r31)
+
+       /* TM checkpointed state is now setup.  All GPRs are now volatile. */
+       TRECHKPT
+
+       /* Now let's get back the state we need. */
+       HMT_MEDIUM
+       GET_PACA(r13)
+       ld      r29, HSTATE_DSCR(r13)
+       mtspr   SPRN_DSCR, r29
+       ld      r4, HSTATE_KVM_VCPU(r13)
+       ld      r1, HSTATE_HOST_R1(r13)
+       ld      r2, PACATMSCRATCH(r13)
+
+       /* Set the MSR RI since we have our registers back. */
+       li      r5, MSR_RI
+       mtmsrd  r5, 1
+skip_tm:
+#endif
+
        /* Load guest PMU registers */
        /* R4 is live here (vcpu pointer) */
        li      r3, 1
@@ -704,14 +817,6 @@ END_FTR_SECTION_IFCLR(CPU_FTR_ARCH_207S)
        ld      r6, VCPU_VTB(r4)
        mtspr   SPRN_IC, r5
        mtspr   SPRN_VTB, r6
-#ifdef CONFIG_PPC_TRANSACTIONAL_MEM
-       ld      r5, VCPU_TFHAR(r4)
-       ld      r6, VCPU_TFIAR(r4)
-       ld      r7, VCPU_TEXASR(r4)
-       mtspr   SPRN_TFHAR, r5
-       mtspr   SPRN_TFIAR, r6
-       mtspr   SPRN_TEXASR, r7
-#endif
        ld      r8, VCPU_EBBHR(r4)
        mtspr   SPRN_EBBHR, r8
        ld      r5, VCPU_EBBRR(r4)
@@ -817,7 +922,8 @@ END_FTR_SECTION_IFSET(CPU_FTR_ARCH_206)
 12:    mtspr   SPRN_SRR0, r10
        mr      r10,r0
        mtspr   SPRN_SRR1, r11
-       ld      r11, VCPU_INTR_MSR(r4)
+       mr      r9, r4
+       bl      kvmppc_msr_interrupt
 5:
 
 /*
@@ -1103,12 +1209,6 @@ END_FTR_SECTION_IFCLR(CPU_FTR_ARCH_201)
 BEGIN_FTR_SECTION
        b       8f
 END_FTR_SECTION_IFCLR(CPU_FTR_ARCH_207S)
-       /* Turn on TM so we can access TFHAR/TFIAR/TEXASR */
-       mfmsr   r8
-       li      r0, 1
-       rldimi  r8, r0, MSR_TM_LG, 63-MSR_TM_LG
-       mtmsrd  r8
-
        /* Save POWER8-specific registers */
        mfspr   r5, SPRN_IAMR
        mfspr   r6, SPRN_PSPB
@@ -1122,14 +1222,6 @@ END_FTR_SECTION_IFCLR(CPU_FTR_ARCH_207S)
        std     r5, VCPU_IC(r9)
        std     r6, VCPU_VTB(r9)
        std     r7, VCPU_TAR(r9)
-#ifdef CONFIG_PPC_TRANSACTIONAL_MEM
-       mfspr   r5, SPRN_TFHAR
-       mfspr   r6, SPRN_TFIAR
-       mfspr   r7, SPRN_TEXASR
-       std     r5, VCPU_TFHAR(r9)
-       std     r6, VCPU_TFIAR(r9)
-       std     r7, VCPU_TEXASR(r9)
-#endif
        mfspr   r8, SPRN_EBBHR
        std     r8, VCPU_EBBHR(r9)
        mfspr   r5, SPRN_EBBRR
@@ -1557,7 +1649,7 @@ kvmppc_hdsi:
        mtspr   SPRN_SRR0, r10
        mtspr   SPRN_SRR1, r11
        li      r10, BOOK3S_INTERRUPT_DATA_STORAGE
-       ld      r11, VCPU_INTR_MSR(r9)
+       bl      kvmppc_msr_interrupt
 fast_interrupt_c_return:
 6:     ld      r7, VCPU_CTR(r9)
        lwz     r8, VCPU_XER(r9)
@@ -1626,7 +1718,7 @@ kvmppc_hisi:
 1:     mtspr   SPRN_SRR0, r10
        mtspr   SPRN_SRR1, r11
        li      r10, BOOK3S_INTERRUPT_INST_STORAGE
-       ld      r11, VCPU_INTR_MSR(r9)
+       bl      kvmppc_msr_interrupt
        b       fast_interrupt_c_return
 
 3:     ld      r6, VCPU_KVM(r9)        /* not relocated, use VRMA */
@@ -1669,7 +1761,7 @@ sc_1_fast_return:
        mtspr   SPRN_SRR0,r10
        mtspr   SPRN_SRR1,r11
        li      r10, BOOK3S_INTERRUPT_SYSCALL
-       ld      r11, VCPU_INTR_MSR(r9)
+       bl      kvmppc_msr_interrupt
        mr      r4,r9
        b       fast_guest_return
 
@@ -1997,7 +2089,7 @@ machine_check_realmode:
        beq     mc_cont
        /* If not, deliver a machine check.  SRR0/1 are already set */
        li      r10, BOOK3S_INTERRUPT_MACHINE_CHECK
-       ld      r11, VCPU_INTR_MSR(r9)
+       bl      kvmppc_msr_interrupt
        b       fast_interrupt_c_return
 
 /*
@@ -2138,8 +2230,6 @@ END_FTR_SECTION_IFSET(CPU_FTR_ALTIVEC)
        mfspr   r6,SPRN_VRSAVE
        stw     r6,VCPU_VRSAVE(r31)
        mtlr    r30
-       mtmsrd  r5
-       isync
        blr
 
 /*
@@ -2186,3 +2276,20 @@ END_FTR_SECTION_IFSET(CPU_FTR_ALTIVEC)
  */
 kvmppc_bad_host_intr:
        b       .
+
+/*
+ * This mimics the MSR transition on IRQ delivery.  The new guest MSR is taken
+ * from VCPU_INTR_MSR and is modified based on the required TM state changes.
+ *   r11 has the guest MSR value (in/out)
+ *   r9 has a vcpu pointer (in)
+ *   r0 is used as a scratch register
+ */
+kvmppc_msr_interrupt:
+       rldicl  r0, r11, 64 - MSR_TS_S_LG, 62
+       cmpwi   r0, 2 /* Check if we are in transactional state..  */
+       ld      r11, VCPU_INTR_MSR(r9)
+       bne     1f
+       /* ... if transactional, change to suspended */
+       li      r0, 1
+1:     rldimi  r11, r0, MSR_TS_S_LG, 63 - MSR_TS_T_LG
+       blr