/* SPDX-License-Identifier: GPL-2.0 */ /* * The actual FRED entry points. */ #include #include #include #include #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