/* SPDX-License-Identifier: GPL-2.0 */1/*2* The actual FRED entry points.3*/45#include <linux/export.h>67#include <asm/asm.h>8#include <asm/fred.h>9#include <asm/segment.h>1011#include "calling.h"1213.code6414.section .noinstr.text, "ax"1516.macro FRED_ENTER17UNWIND_HINT_END_OF_STACK18ENDBR19PUSH_AND_CLEAR_REGS20movq %rsp, %rdi /* %rdi -> pt_regs */21.endm2223.macro FRED_EXIT24UNWIND_HINT_REGS25POP_REGS26.endm2728/*29* The new RIP value that FRED event delivery establishes is30* IA32_FRED_CONFIG & ~FFFH for events that occur in ring 3.31* Thus the FRED ring 3 entry point must be 4K page aligned.32*/33.align 40963435SYM_CODE_START_NOALIGN(asm_fred_entrypoint_user)36FRED_ENTER37call fred_entry_from_user38SYM_INNER_LABEL(asm_fred_exit_user, SYM_L_GLOBAL)39FRED_EXIT401: ERETU4142_ASM_EXTABLE_TYPE(1b, asm_fred_entrypoint_user, EX_TYPE_ERETU)43SYM_CODE_END(asm_fred_entrypoint_user)4445/*46* The new RIP value that FRED event delivery establishes is47* (IA32_FRED_CONFIG & ~FFFH) + 256 for events that occur in48* ring 0, i.e., asm_fred_entrypoint_user + 256.49*/50.org asm_fred_entrypoint_user + 256, 0xcc51SYM_CODE_START_NOALIGN(asm_fred_entrypoint_kernel)52FRED_ENTER53call fred_entry_from_kernel54FRED_EXIT55ERETS56SYM_CODE_END(asm_fred_entrypoint_kernel)5758#if IS_ENABLED(CONFIG_KVM_INTEL)59SYM_FUNC_START(asm_fred_entry_from_kvm)60ANNOTATE_NOENDBR61push %rbp62mov %rsp, %rbp6364UNWIND_HINT_SAVE6566/*67* Both IRQ and NMI from VMX can be handled on current task stack68* because there is no need to protect from reentrancy and the call69* stack leading to this helper is effectively constant and shallow70* (relatively speaking). Do the same when FRED is active, i.e., no71* need to check current stack level for a stack switch.72*73* Emulate the FRED-defined redzone and stack alignment.74*/75sub $(FRED_CONFIG_REDZONE_AMOUNT << 6), %rsp76and $FRED_STACK_FRAME_RSP_MASK, %rsp7778/*79* Start to push a FRED stack frame, which is always 64 bytes:80*81* +--------+-----------------+82* | Bytes | Usage |83* +--------+-----------------+84* | 63:56 | Reserved |85* | 55:48 | Event Data |86* | 47:40 | SS + Event Info |87* | 39:32 | RSP |88* | 31:24 | RFLAGS |89* | 23:16 | CS + Aux Info |90* | 15:8 | RIP |91* | 7:0 | Error Code |92* +--------+-----------------+93*/94push $0 /* Reserved, must be 0 */95push $0 /* Event data, 0 for IRQ/NMI */96push %rdi /* fred_ss handed in by the caller */97push %rbp98pushf99mov $__KERNEL_CS, %rax100push %rax101102/*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_bp=0 unwind_hint=0115movq %rsp, %rdi /* %rdi -> pt_regs */116call __fred_entry_from_kvm /* Call the C entry point */117POP_REGS118ERETS1191:120/*121* Objtool doesn't understand what ERETS does, this hint tells it that122* yes, we'll reach here and with what stack state. A save/restore pair123* isn't strictly needed, but it's the simplest form.124*/125UNWIND_HINT_RESTORE126pop %rbp127RET128129SYM_FUNC_END(asm_fred_entry_from_kvm)130EXPORT_SYMBOL_GPL(asm_fred_entry_from_kvm);131#endif132133134