Skip to content

Commit 6204aea

Browse files
author
Peter Zijlstra
committed
KVM: x86: Introduce EM_ASM_1
Replace fastops with C based stubs. There are a bunch of problems with the current fastop infrastructure, most all related to their special calling convention, which bypasses the normal C-ABI. There are two immediate problems with this at present: - it relies on RET preserving EFLAGS; whereas C-ABI does not. - it circumvents compiler based control-flow-integrity checking because its all asm magic. The first is a problem for some mitigations where the x86_indirect_return_thunk needs to include non-trivial work that clobbers EFLAGS (eg. the Skylake call depth tracking thing). The second is a problem because it presents a 'naked' indirect call on kCFI builds, making it a prime target for control flow hijacking. Additionally, given that a large chunk of virtual machine performance relies on absolutely avoiding vmexit these days, this emulation stuff just isn't that critical for performance anymore. As such, replace the fastop calls with normal C functions using the 'execute' member. As noted by Paolo: this code was performance critical for pre-Westmere (2010) and only when running big real mode code. Signed-off-by: Peter Zijlstra (Intel) <peterz@infradead.org> Acked-by: Sean Christopherson <seanjc@google.com> Link: https://lkml.kernel.org/r/20250714103439.773781574@infradead.org
1 parent 0cb6f1e commit 6204aea

1 file changed

Lines changed: 58 additions & 13 deletions

File tree

arch/x86/kvm/emulate.c

Lines changed: 58 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -267,11 +267,56 @@ static void invalidate_registers(struct x86_emulate_ctxt *ctxt)
267267
X86_EFLAGS_PF|X86_EFLAGS_CF)
268268

269269
#ifdef CONFIG_X86_64
270-
#define ON64(x) x
270+
#define ON64(x...) x
271271
#else
272-
#define ON64(x)
272+
#define ON64(x...)
273273
#endif
274274

275+
#define EM_ASM_START(op) \
276+
static int em_##op(struct x86_emulate_ctxt *ctxt) \
277+
{ \
278+
unsigned long flags = (ctxt->eflags & EFLAGS_MASK) | X86_EFLAGS_IF; \
279+
int bytes = 1, ok = 1; \
280+
if (!(ctxt->d & ByteOp)) \
281+
bytes = ctxt->dst.bytes; \
282+
switch (bytes) {
283+
284+
#define __EM_ASM(str) \
285+
asm("push %[flags]; popf \n\t" \
286+
"10: " str \
287+
"pushf; pop %[flags] \n\t" \
288+
"11: \n\t" \
289+
: "+a" (ctxt->dst.val), \
290+
"+d" (ctxt->src.val), \
291+
[flags] "+D" (flags), \
292+
"+S" (ok) \
293+
: "c" (ctxt->src2.val))
294+
295+
#define __EM_ASM_1(op, dst) \
296+
__EM_ASM(#op " %%" #dst " \n\t")
297+
298+
#define __EM_ASM_1_EX(op, dst) \
299+
__EM_ASM(#op " %%" #dst " \n\t" \
300+
_ASM_EXTABLE_TYPE_REG(10b, 11f, EX_TYPE_ZERO_REG, %%esi))
301+
302+
#define __EM_ASM_2(op, dst, src) \
303+
__EM_ASM(#op " %%" #src ", %%" #dst " \n\t")
304+
305+
#define EM_ASM_END \
306+
} \
307+
ctxt->eflags = (ctxt->eflags & ~EFLAGS_MASK) | (flags & EFLAGS_MASK); \
308+
return !ok ? emulate_de(ctxt) : X86EMUL_CONTINUE; \
309+
}
310+
311+
/* 1-operand, using "a" (dst) */
312+
#define EM_ASM_1(op) \
313+
EM_ASM_START(op) \
314+
case 1: __EM_ASM_1(op##b, al); break; \
315+
case 2: __EM_ASM_1(op##w, ax); break; \
316+
case 4: __EM_ASM_1(op##l, eax); break; \
317+
ON64(case 8: __EM_ASM_1(op##q, rax); break;) \
318+
EM_ASM_END
319+
275320
/*
276321
* fastop functions have a special calling convention:
277322
*
@@ -1002,10 +1047,10 @@ FASTOP3WCL(shrd);
10021047

10031048
FASTOP2W(imul);
10041049

1005-
FASTOP1(not);
1006-
FASTOP1(neg);
1007-
FASTOP1(inc);
1008-
FASTOP1(dec);
1050+
EM_ASM_1(not);
1051+
EM_ASM_1(neg);
1052+
EM_ASM_1(inc);
1053+
EM_ASM_1(dec);
10091054

10101055
FASTOP2CL(rol);
10111056
FASTOP2CL(ror);
@@ -4021,23 +4066,23 @@ static const struct opcode group2[] = {
40214066
static const struct opcode group3[] = {
40224067
F(DstMem | SrcImm | NoWrite, em_test),
40234068
F(DstMem | SrcImm | NoWrite, em_test),
4024-
F(DstMem | SrcNone | Lock, em_not),
4025-
F(DstMem | SrcNone | Lock, em_neg),
4069+
I(DstMem | SrcNone | Lock, em_not),
4070+
I(DstMem | SrcNone | Lock, em_neg),
40264071
F(DstXacc | Src2Mem, em_mul_ex),
40274072
F(DstXacc | Src2Mem, em_imul_ex),
40284073
F(DstXacc | Src2Mem, em_div_ex),
40294074
F(DstXacc | Src2Mem, em_idiv_ex),
40304075
};
40314076

40324077
static const struct opcode group4[] = {
4033-
F(ByteOp | DstMem | SrcNone | Lock, em_inc),
4034-
F(ByteOp | DstMem | SrcNone | Lock, em_dec),
4078+
I(ByteOp | DstMem | SrcNone | Lock, em_inc),
4079+
I(ByteOp | DstMem | SrcNone | Lock, em_dec),
40354080
N, N, N, N, N, N,
40364081
};
40374082

40384083
static const struct opcode group5[] = {
4039-
F(DstMem | SrcNone | Lock, em_inc),
4040-
F(DstMem | SrcNone | Lock, em_dec),
4084+
I(DstMem | SrcNone | Lock, em_inc),
4085+
I(DstMem | SrcNone | Lock, em_dec),
40414086
I(SrcMem | NearBranch | IsBranch, em_call_near_abs),
40424087
I(SrcMemFAddr | ImplicitOps | IsBranch, em_call_far),
40434088
I(SrcMem | NearBranch | IsBranch, em_jmp_abs),
@@ -4237,7 +4282,7 @@ static const struct opcode opcode_table[256] = {
42374282
/* 0x38 - 0x3F */
42384283
F6ALU(NoWrite, em_cmp), N, N,
42394284
/* 0x40 - 0x4F */
4240-
X8(F(DstReg, em_inc)), X8(F(DstReg, em_dec)),
4285+
X8(I(DstReg, em_inc)), X8(I(DstReg, em_dec)),
42414286
/* 0x50 - 0x57 */
42424287
X8(I(SrcReg | Stack, em_push)),
42434288
/* 0x58 - 0x5F */

0 commit comments

Comments
 (0)