Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit e4e38121 authored by Michael Neuling's avatar Michael Neuling Committed by Paul Mackerras
Browse files

KVM: PPC: Book3S HV: Add transactional memory support



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: default avatarMichael Neuling <mikey@neuling.org>
Signed-off-by: default avatarPaul Mackerras <paulus@samba.org>
Acked-by: default avatarScott Wood <scottwood@freescale.com>
parent 7505258c
Loading
Loading
Loading
Loading
+1 −0
Original line number Diff line number Diff line
@@ -213,6 +213,7 @@
#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
+4 −0
Original line number Diff line number Diff line
@@ -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__ */
+8 −1
Original line number Diff line number Diff line
@@ -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);
}

/*
+136 −29
Original line number Diff line number Diff line
@@ -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