/* SPDX-License-Identifier: GPL-2.0 */1/*2* The actual FRED entry points.3*/45#include <linux/export.h>6#include <linux/kvm_types.h>78#include <asm/asm.h>9#include <asm/fred.h>10#include <asm/segment.h>1112#include "calling.h"1314.code6415.section .noinstr.text, "ax"1617.macro FRED_ENTER18UNWIND_HINT_END_OF_STACK19ANNOTATE_NOENDBR20PUSH_AND_CLEAR_REGS21movq %rsp, %rdi /* %rdi -> pt_regs */22.endm2324.macro FRED_EXIT25UNWIND_HINT_REGS26POP_REGS27.endm2829/*30* The new RIP value that FRED event delivery establishes is31* IA32_FRED_CONFIG & ~FFFH for events that occur in ring 3.32* Thus the FRED ring 3 entry point must be 4K page aligned.33*/34.align 40963536SYM_CODE_START_NOALIGN(asm_fred_entrypoint_user)37FRED_ENTER38call fred_entry_from_user39SYM_INNER_LABEL(asm_fred_exit_user, SYM_L_GLOBAL)40FRED_EXIT411: ERETU4243_ASM_EXTABLE_TYPE(1b, asm_fred_entrypoint_user, EX_TYPE_ERETU)44SYM_CODE_END(asm_fred_entrypoint_user)4546/*47* The new RIP value that FRED event delivery establishes is48* (IA32_FRED_CONFIG & ~FFFH) + 256 for events that occur in49* ring 0, i.e., asm_fred_entrypoint_user + 256.50*/51.org asm_fred_entrypoint_user + 256, 0xcc52SYM_CODE_START_NOALIGN(asm_fred_entrypoint_kernel)53FRED_ENTER54call fred_entry_from_kernel55FRED_EXIT56ERETS57SYM_CODE_END(asm_fred_entrypoint_kernel)5859#if IS_ENABLED(CONFIG_KVM_INTEL)60SYM_FUNC_START(asm_fred_entry_from_kvm)61ANNOTATE_NOENDBR62push %rbp63mov %rsp, %rbp6465UNWIND_HINT_SAVE6667/*68* Both IRQ and NMI from VMX can be handled on current task stack69* because there is no need to protect from reentrancy and the call70* stack leading to this helper is effectively constant and shallow71* (relatively speaking). Do the same when FRED is active, i.e., no72* need to check current stack level for a stack switch.73*74* Emulate the FRED-defined redzone and stack alignment.75*/76sub $(FRED_CONFIG_REDZONE_AMOUNT << 6), %rsp77and $FRED_STACK_FRAME_RSP_MASK, %rsp7879/*80* Start to push a FRED stack frame, which is always 64 bytes:81*82* +--------+-----------------+83* | Bytes | Usage |84* +--------+-----------------+85* | 63:56 | Reserved |86* | 55:48 | Event Data |87* | 47:40 | SS + Event Info |88* | 39:32 | RSP |89* | 31:24 | RFLAGS |90* | 23:16 | CS + Aux Info |91* | 15:8 | RIP |92* | 7:0 | Error Code |93* +--------+-----------------+94*/95push $0 /* Reserved, must be 0 */96push $0 /* Event data, 0 for IRQ/NMI */97push %rdi /* fred_ss handed in by the caller */98push %rbp99pushf100push $__KERNEL_CS101102/*103* Unlike the IDT event delivery, FRED _always_ pushes an error code104* after pushing the return RIP, thus the CALL instruction CANNOT be105* used here to push the return RIP, otherwise there is no chance to106* push an error code before invoking the IRQ/NMI handler.107*108* Use LEA to get the return RIP and push it, then push an error code.109*/110lea 1f(%rip), %rax111push %rax /* Return RIP */112push $0 /* Error code, 0 for IRQ/NMI */113114PUSH_AND_CLEAR_REGS clear_callee=0 unwind_hint=0115116movq %rsp, %rdi /* %rdi -> pt_regs */117/*118* At this point: {rdi, rsi, rdx, rcx, r8, r9}, {r10, r11}, {rax, rdx}119* are clobbered, which corresponds to: arguments, extra caller-saved120* and return. All registers a C function is allowed to clobber.121*122* Notably, the callee-saved registers: {rbx, r12, r13, r14, r15}123* are untouched, with the exception of rbp, which carries the stack124* frame and will be restored before exit.125*126* Further calling another C function will not alter this state.127*/128call __fred_entry_from_kvm /* Call the C entry point */129130/*131* When FRED, use ERETS to potentially clear NMIs, otherwise simply132* restore the stack pointer.133*/134ALTERNATIVE "nop; nop; mov %rbp, %rsp", \135__stringify(add $C_PTREGS_SIZE, %rsp; ERETS), \136X86_FEATURE_FRED1371381: /*139* Objtool doesn't understand ERETS, and the cfi register state is140* different from initial_func_cfi due to PUSH_REGS. Tell it the state141* is similar to where UNWIND_HINT_SAVE is.142*/143UNWIND_HINT_RESTORE144145pop %rbp146RET147148SYM_FUNC_END(asm_fred_entry_from_kvm)149EXPORT_SYMBOL_FOR_KVM(asm_fred_entry_from_kvm);150#endif151152153