2e670358ec
In IRQ/NMI induced VM exits, KVM VMX needs to execute the respective handlers, which requires the software to create a FRED stack frame, and use it to invoke the handlers. Add fred_irq_entry_from_kvm() for this job. Export fred_entry_from_kvm() because VMX can be compiled as a module. Suggested-by: Sean Christopherson <seanjc@google.com> Suggested-by: Thomas Gleixner <tglx@linutronix.de> Signed-off-by: Xin Li <xin3.li@intel.com> Signed-off-by: Thomas Gleixner <tglx@linutronix.de> Signed-off-by: Borislav Petkov (AMD) <bp@alien8.de> Tested-by: Shan Kang <shan.kang@intel.com> Link: https://lore.kernel.org/r/20231205105030.8698-32-xin3.li@intel.com
132 lines
3.4 KiB
ArmAsm
132 lines
3.4 KiB
ArmAsm
/* SPDX-License-Identifier: GPL-2.0 */
|
|
/*
|
|
* The actual FRED entry points.
|
|
*/
|
|
|
|
#include <linux/export.h>
|
|
|
|
#include <asm/asm.h>
|
|
#include <asm/fred.h>
|
|
#include <asm/segment.h>
|
|
|
|
#include "calling.h"
|
|
|
|
.code64
|
|
.section .noinstr.text, "ax"
|
|
|
|
.macro FRED_ENTER
|
|
UNWIND_HINT_END_OF_STACK
|
|
ENDBR
|
|
PUSH_AND_CLEAR_REGS
|
|
movq %rsp, %rdi /* %rdi -> pt_regs */
|
|
.endm
|
|
|
|
.macro FRED_EXIT
|
|
UNWIND_HINT_REGS
|
|
POP_REGS
|
|
.endm
|
|
|
|
/*
|
|
* The new RIP value that FRED event delivery establishes is
|
|
* IA32_FRED_CONFIG & ~FFFH for events that occur in ring 3.
|
|
* Thus the FRED ring 3 entry point must be 4K page aligned.
|
|
*/
|
|
.align 4096
|
|
|
|
SYM_CODE_START_NOALIGN(asm_fred_entrypoint_user)
|
|
FRED_ENTER
|
|
call fred_entry_from_user
|
|
SYM_INNER_LABEL(asm_fred_exit_user, SYM_L_GLOBAL)
|
|
FRED_EXIT
|
|
1: ERETU
|
|
|
|
_ASM_EXTABLE_TYPE(1b, asm_fred_entrypoint_user, EX_TYPE_ERETU)
|
|
SYM_CODE_END(asm_fred_entrypoint_user)
|
|
|
|
/*
|
|
* The new RIP value that FRED event delivery establishes is
|
|
* (IA32_FRED_CONFIG & ~FFFH) + 256 for events that occur in
|
|
* ring 0, i.e., asm_fred_entrypoint_user + 256.
|
|
*/
|
|
.org asm_fred_entrypoint_user + 256, 0xcc
|
|
SYM_CODE_START_NOALIGN(asm_fred_entrypoint_kernel)
|
|
FRED_ENTER
|
|
call fred_entry_from_kernel
|
|
FRED_EXIT
|
|
ERETS
|
|
SYM_CODE_END(asm_fred_entrypoint_kernel)
|
|
|
|
#if IS_ENABLED(CONFIG_KVM_INTEL)
|
|
SYM_FUNC_START(asm_fred_entry_from_kvm)
|
|
push %rbp
|
|
mov %rsp, %rbp
|
|
|
|
UNWIND_HINT_SAVE
|
|
|
|
/*
|
|
* Both IRQ and NMI from VMX can be handled on current task stack
|
|
* because there is no need to protect from reentrancy and the call
|
|
* stack leading to this helper is effectively constant and shallow
|
|
* (relatively speaking). Do the same when FRED is active, i.e., no
|
|
* need to check current stack level for a stack switch.
|
|
*
|
|
* Emulate the FRED-defined redzone and stack alignment.
|
|
*/
|
|
sub $(FRED_CONFIG_REDZONE_AMOUNT << 6), %rsp
|
|
and $FRED_STACK_FRAME_RSP_MASK, %rsp
|
|
|
|
/*
|
|
* Start to push a FRED stack frame, which is always 64 bytes:
|
|
*
|
|
* +--------+-----------------+
|
|
* | Bytes | Usage |
|
|
* +--------+-----------------+
|
|
* | 63:56 | Reserved |
|
|
* | 55:48 | Event Data |
|
|
* | 47:40 | SS + Event Info |
|
|
* | 39:32 | RSP |
|
|
* | 31:24 | RFLAGS |
|
|
* | 23:16 | CS + Aux Info |
|
|
* | 15:8 | RIP |
|
|
* | 7:0 | Error Code |
|
|
* +--------+-----------------+
|
|
*/
|
|
push $0 /* Reserved, must be 0 */
|
|
push $0 /* Event data, 0 for IRQ/NMI */
|
|
push %rdi /* fred_ss handed in by the caller */
|
|
push %rbp
|
|
pushf
|
|
mov $__KERNEL_CS, %rax
|
|
push %rax
|
|
|
|
/*
|
|
* Unlike the IDT event delivery, FRED _always_ pushes an error code
|
|
* after pushing the return RIP, thus the CALL instruction CANNOT be
|
|
* used here to push the return RIP, otherwise there is no chance to
|
|
* push an error code before invoking the IRQ/NMI handler.
|
|
*
|
|
* Use LEA to get the return RIP and push it, then push an error code.
|
|
*/
|
|
lea 1f(%rip), %rax
|
|
push %rax /* Return RIP */
|
|
push $0 /* Error code, 0 for IRQ/NMI */
|
|
|
|
PUSH_AND_CLEAR_REGS clear_bp=0 unwind_hint=0
|
|
movq %rsp, %rdi /* %rdi -> pt_regs */
|
|
call __fred_entry_from_kvm /* Call the C entry point */
|
|
POP_REGS
|
|
ERETS
|
|
1:
|
|
/*
|
|
* Objtool doesn't understand what ERETS does, this hint tells it that
|
|
* yes, we'll reach here and with what stack state. A save/restore pair
|
|
* isn't strictly needed, but it's the simplest form.
|
|
*/
|
|
UNWIND_HINT_RESTORE
|
|
pop %rbp
|
|
RET
|
|
|
|
SYM_FUNC_END(asm_fred_entry_from_kvm)
|
|
EXPORT_SYMBOL_GPL(asm_fred_entry_from_kvm);
|
|
#endif
|