1 // SPDX-License-Identifier: GPL-2.0-only
3 * Copyright 2017 Paul Mackerras, IBM Corp. <paulus@au1.ibm.com>
6 #include <linux/kvm_host.h>
8 #include <asm/kvm_ppc.h>
9 #include <asm/kvm_book3s.h>
10 #include <asm/kvm_book3s_64.h>
12 #include <asm/ppc-opcode.h>
14 static void emulate_tx_failure(struct kvm_vcpu
*vcpu
, u64 failure_cause
)
17 u64 msr
= vcpu
->arch
.shregs
.msr
;
19 tfiar
= vcpu
->arch
.regs
.nip
& ~0x3ull
;
20 texasr
= (failure_cause
<< 56) | TEXASR_ABORT
| TEXASR_FS
| TEXASR_EXACT
;
21 if (MSR_TM_SUSPENDED(vcpu
->arch
.shregs
.msr
))
22 texasr
|= TEXASR_SUSP
;
27 vcpu
->arch
.tfiar
= tfiar
;
28 /* Preserve ROT and TL fields of existing TEXASR */
29 vcpu
->arch
.texasr
= (vcpu
->arch
.texasr
& 0x3ffffff) | texasr
;
33 * This gets called on a softpatch interrupt on POWER9 DD2.2 processors.
34 * We expect to find a TM-related instruction to be emulated. The
35 * instruction image is in vcpu->arch.emul_inst. If the guest was in
36 * TM suspended or transactional state, the checkpointed state has been
37 * reclaimed and is in the vcpu struct. The CPU is in virtual mode in
40 int kvmhv_p9_tm_emulation(struct kvm_vcpu
*vcpu
)
42 u32 instr
= vcpu
->arch
.emul_inst
;
43 u64 msr
= vcpu
->arch
.shregs
.msr
;
47 switch (instr
& 0xfc0007ff) {
49 /* XXX do we need to check for PR=0 here? */
50 newmsr
= vcpu
->arch
.shregs
.srr1
;
51 /* should only get here for Sx -> T1 transition */
52 WARN_ON_ONCE(!(MSR_TM_SUSPENDED(msr
) &&
53 MSR_TM_TRANSACTIONAL(newmsr
) &&
55 newmsr
= sanitize_msr(newmsr
);
56 vcpu
->arch
.shregs
.msr
= newmsr
;
57 vcpu
->arch
.cfar
= vcpu
->arch
.regs
.nip
- 4;
58 vcpu
->arch
.regs
.nip
= vcpu
->arch
.shregs
.srr0
;
62 if ((msr
& MSR_PR
) && (vcpu
->arch
.vcore
->pcr
& PCR_ARCH_206
)) {
63 /* generate an illegal instruction interrupt */
64 kvmppc_core_queue_program(vcpu
, SRR1_PROGILL
);
67 /* check EBB facility is available */
68 if (!(vcpu
->arch
.hfscr
& HFSCR_EBB
)) {
69 /* generate an illegal instruction interrupt */
70 kvmppc_core_queue_program(vcpu
, SRR1_PROGILL
);
73 if ((msr
& MSR_PR
) && !(vcpu
->arch
.fscr
& FSCR_EBB
)) {
74 /* generate a facility unavailable interrupt */
75 vcpu
->arch
.fscr
= (vcpu
->arch
.fscr
& ~(0xffull
<< 56)) |
76 ((u64
)FSCR_EBB_LG
<< 56);
77 kvmppc_book3s_queue_irqprio(vcpu
, BOOK3S_INTERRUPT_FAC_UNAVAIL
);
80 bescr
= vcpu
->arch
.bescr
;
81 /* expect to see a S->T transition requested */
82 WARN_ON_ONCE(!(MSR_TM_SUSPENDED(msr
) &&
83 ((bescr
>> 30) & 3) == 2));
85 if (instr
& (1 << 11))
87 vcpu
->arch
.bescr
= bescr
;
88 msr
= (msr
& ~MSR_TS_MASK
) | MSR_TS_T
;
89 vcpu
->arch
.shregs
.msr
= msr
;
90 vcpu
->arch
.cfar
= vcpu
->arch
.regs
.nip
- 4;
91 vcpu
->arch
.regs
.nip
= vcpu
->arch
.ebbrr
;
95 /* XXX do we need to check for PR=0 here? */
96 rs
= (instr
>> 21) & 0x1f;
97 newmsr
= kvmppc_get_gpr(vcpu
, rs
);
98 /* check this is a Sx -> T1 transition */
99 WARN_ON_ONCE(!(MSR_TM_SUSPENDED(msr
) &&
100 MSR_TM_TRANSACTIONAL(newmsr
) &&
102 /* mtmsrd doesn't change LE */
103 newmsr
= (newmsr
& ~MSR_LE
) | (msr
& MSR_LE
);
104 newmsr
= sanitize_msr(newmsr
);
105 vcpu
->arch
.shregs
.msr
= newmsr
;
109 /* check for PR=1 and arch 2.06 bit set in PCR */
110 if ((msr
& MSR_PR
) && (vcpu
->arch
.vcore
->pcr
& PCR_ARCH_206
)) {
111 /* generate an illegal instruction interrupt */
112 kvmppc_core_queue_program(vcpu
, SRR1_PROGILL
);
115 /* check for TM disabled in the HFSCR or MSR */
116 if (!(vcpu
->arch
.hfscr
& HFSCR_TM
)) {
117 /* generate an illegal instruction interrupt */
118 kvmppc_core_queue_program(vcpu
, SRR1_PROGILL
);
121 if (!(msr
& MSR_TM
)) {
122 /* generate a facility unavailable interrupt */
123 vcpu
->arch
.fscr
= (vcpu
->arch
.fscr
& ~(0xffull
<< 56)) |
124 ((u64
)FSCR_TM_LG
<< 56);
125 kvmppc_book3s_queue_irqprio(vcpu
,
126 BOOK3S_INTERRUPT_FAC_UNAVAIL
);
129 /* Set CR0 to indicate previous transactional state */
130 vcpu
->arch
.regs
.ccr
= (vcpu
->arch
.regs
.ccr
& 0x0fffffff) |
131 (((msr
& MSR_TS_MASK
) >> MSR_TS_S_LG
) << 29);
132 /* L=1 => tresume, L=0 => tsuspend */
133 if (instr
& (1 << 21)) {
134 if (MSR_TM_SUSPENDED(msr
))
135 msr
= (msr
& ~MSR_TS_MASK
) | MSR_TS_T
;
137 if (MSR_TM_TRANSACTIONAL(msr
))
138 msr
= (msr
& ~MSR_TS_MASK
) | MSR_TS_S
;
140 vcpu
->arch
.shregs
.msr
= msr
;
143 case PPC_INST_TRECLAIM
:
144 /* check for TM disabled in the HFSCR or MSR */
145 if (!(vcpu
->arch
.hfscr
& HFSCR_TM
)) {
146 /* generate an illegal instruction interrupt */
147 kvmppc_core_queue_program(vcpu
, SRR1_PROGILL
);
150 if (!(msr
& MSR_TM
)) {
151 /* generate a facility unavailable interrupt */
152 vcpu
->arch
.fscr
= (vcpu
->arch
.fscr
& ~(0xffull
<< 56)) |
153 ((u64
)FSCR_TM_LG
<< 56);
154 kvmppc_book3s_queue_irqprio(vcpu
,
155 BOOK3S_INTERRUPT_FAC_UNAVAIL
);
158 /* If no transaction active, generate TM bad thing */
159 if (!MSR_TM_ACTIVE(msr
)) {
160 kvmppc_core_queue_program(vcpu
, SRR1_PROGTM
);
163 /* If failure was not previously recorded, recompute TEXASR */
164 if (!(vcpu
->arch
.orig_texasr
& TEXASR_FS
)) {
165 ra
= (instr
>> 16) & 0x1f;
167 ra
= kvmppc_get_gpr(vcpu
, ra
) & 0xff;
168 emulate_tx_failure(vcpu
, ra
);
171 copy_from_checkpoint(vcpu
);
173 /* Set CR0 to indicate previous transactional state */
174 vcpu
->arch
.regs
.ccr
= (vcpu
->arch
.regs
.ccr
& 0x0fffffff) |
175 (((msr
& MSR_TS_MASK
) >> MSR_TS_S_LG
) << 29);
176 vcpu
->arch
.shregs
.msr
&= ~MSR_TS_MASK
;
179 case PPC_INST_TRECHKPT
:
180 /* XXX do we need to check for PR=0 here? */
181 /* check for TM disabled in the HFSCR or MSR */
182 if (!(vcpu
->arch
.hfscr
& HFSCR_TM
)) {
183 /* generate an illegal instruction interrupt */
184 kvmppc_core_queue_program(vcpu
, SRR1_PROGILL
);
187 if (!(msr
& MSR_TM
)) {
188 /* generate a facility unavailable interrupt */
189 vcpu
->arch
.fscr
= (vcpu
->arch
.fscr
& ~(0xffull
<< 56)) |
190 ((u64
)FSCR_TM_LG
<< 56);
191 kvmppc_book3s_queue_irqprio(vcpu
,
192 BOOK3S_INTERRUPT_FAC_UNAVAIL
);
195 /* If transaction active or TEXASR[FS] = 0, bad thing */
196 if (MSR_TM_ACTIVE(msr
) || !(vcpu
->arch
.texasr
& TEXASR_FS
)) {
197 kvmppc_core_queue_program(vcpu
, SRR1_PROGTM
);
201 copy_to_checkpoint(vcpu
);
203 /* Set CR0 to indicate previous transactional state */
204 vcpu
->arch
.regs
.ccr
= (vcpu
->arch
.regs
.ccr
& 0x0fffffff) |
205 (((msr
& MSR_TS_MASK
) >> MSR_TS_S_LG
) << 29);
206 vcpu
->arch
.shregs
.msr
= msr
| MSR_TS_S
;
210 /* What should we do here? We didn't recognize the instruction */