Skip to content

Commit 0b5e7a1

Browse files
committed
KVM: VMX: Make vmread_error_trampoline() uncallable from C code
Declare vmread_error_trampoline() as an opaque symbol so that it cannot be called from C code, at least not without some serious fudging. The trampoline always passes parameters on the stack so that the inline VMREAD sequence doesn't need to clobber registers. regparm(0) was originally added to document the stack behavior, but it ended up being confusing because regparm(0) is a nop for 64-bit targets. Opportunustically wrap the trampoline and its declaration in #ifdeffery to make it even harder to invoke incorrectly, to document why it exists, and so that it's not left behind if/when CONFIG_CC_HAS_ASM_GOTO_OUTPUT is true for all supported toolchains. No functional change intended. Cc: Uros Bizjak <[email protected]> Signed-off-by: Sean Christopherson <[email protected]> Link: https://lore.kernel.org/r/[email protected]
1 parent 4a8fd4a commit 0b5e7a1

File tree

2 files changed

+18
-2
lines changed

2 files changed

+18
-2
lines changed

arch/x86/kvm/vmx/vmenter.S

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -269,6 +269,7 @@ SYM_FUNC_END(__vmx_vcpu_run)
269269

270270
.section .text, "ax"
271271

272+
#ifndef CONFIG_CC_HAS_ASM_GOTO_OUTPUT
272273
/**
273274
* vmread_error_trampoline - Trampoline from inline asm to vmread_error()
274275
* @field: VMCS field encoding that failed
@@ -317,6 +318,7 @@ SYM_FUNC_START(vmread_error_trampoline)
317318

318319
RET
319320
SYM_FUNC_END(vmread_error_trampoline)
321+
#endif
320322

321323
SYM_FUNC_START(vmx_do_interrupt_nmi_irqoff)
322324
/*

arch/x86/kvm/vmx/vmx_ops.h

Lines changed: 16 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -11,14 +11,28 @@
1111
#include "../x86.h"
1212

1313
void vmread_error(unsigned long field, bool fault);
14-
__attribute__((regparm(0))) void vmread_error_trampoline(unsigned long field,
15-
bool fault);
1614
void vmwrite_error(unsigned long field, unsigned long value);
1715
void vmclear_error(struct vmcs *vmcs, u64 phys_addr);
1816
void vmptrld_error(struct vmcs *vmcs, u64 phys_addr);
1917
void invvpid_error(unsigned long ext, u16 vpid, gva_t gva);
2018
void invept_error(unsigned long ext, u64 eptp, gpa_t gpa);
2119

20+
#ifndef CONFIG_CC_HAS_ASM_GOTO_OUTPUT
21+
/*
22+
* The VMREAD error trampoline _always_ uses the stack to pass parameters, even
23+
* for 64-bit targets. Preserving all registers allows the VMREAD inline asm
24+
* blob to avoid clobbering GPRs, which in turn allows the compiler to better
25+
* optimize sequences of VMREADs.
26+
*
27+
* Declare the trampoline as an opaque label as it's not safe to call from C
28+
* code; there is no way to tell the compiler to pass params on the stack for
29+
* 64-bit targets.
30+
*
31+
* void vmread_error_trampoline(unsigned long field, bool fault);
32+
*/
33+
extern unsigned long vmread_error_trampoline;
34+
#endif
35+
2236
static __always_inline void vmcs_check16(unsigned long field)
2337
{
2438
BUILD_BUG_ON_MSG(__builtin_constant_p(field) && ((field) & 0x6001) == 0x2000,

0 commit comments

Comments
 (0)