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: Michael Neuling <mikey@neuling.org> Signed-off-by: Paul Mackerras <paulus@samba.org> Acked-by: Scott Wood <scottwood@freescale.com>
This commit is contained in:
Родитель
7505258c5f
Коммит
e4e3812150
|
@ -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
|
||||
|
|
|
@ -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__ */
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
|
||||
/*
|
||||
|
|
|
@ -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
|
||||
|
|
Загрузка…
Ссылка в новой задаче