162306a36Sopenharmony_ci/* SPDX-License-Identifier: GPL-2.0 */ 262306a36Sopenharmony_ci/* 362306a36Sopenharmony_ci * Asm versions of Xen pv-ops, suitable for direct use. 462306a36Sopenharmony_ci * 562306a36Sopenharmony_ci * We only bother with direct forms (ie, vcpu in percpu data) of the 662306a36Sopenharmony_ci * operations here; the indirect forms are better handled in C. 762306a36Sopenharmony_ci */ 862306a36Sopenharmony_ci 962306a36Sopenharmony_ci#include <asm/errno.h> 1062306a36Sopenharmony_ci#include <asm/asm-offsets.h> 1162306a36Sopenharmony_ci#include <asm/percpu.h> 1262306a36Sopenharmony_ci#include <asm/processor-flags.h> 1362306a36Sopenharmony_ci#include <asm/segment.h> 1462306a36Sopenharmony_ci#include <asm/thread_info.h> 1562306a36Sopenharmony_ci#include <asm/asm.h> 1662306a36Sopenharmony_ci#include <asm/frame.h> 1762306a36Sopenharmony_ci#include <asm/unwind_hints.h> 1862306a36Sopenharmony_ci 1962306a36Sopenharmony_ci#include <xen/interface/xen.h> 2062306a36Sopenharmony_ci 2162306a36Sopenharmony_ci#include <linux/init.h> 2262306a36Sopenharmony_ci#include <linux/linkage.h> 2362306a36Sopenharmony_ci#include <../entry/calling.h> 2462306a36Sopenharmony_ci 2562306a36Sopenharmony_ci.pushsection .noinstr.text, "ax" 2662306a36Sopenharmony_ci/* 2762306a36Sopenharmony_ci * Disabling events is simply a matter of making the event mask 2862306a36Sopenharmony_ci * non-zero. 2962306a36Sopenharmony_ci */ 3062306a36Sopenharmony_ciSYM_FUNC_START(xen_irq_disable_direct) 3162306a36Sopenharmony_ci movb $1, PER_CPU_VAR(xen_vcpu_info) + XEN_vcpu_info_mask 3262306a36Sopenharmony_ci RET 3362306a36Sopenharmony_ciSYM_FUNC_END(xen_irq_disable_direct) 3462306a36Sopenharmony_ci 3562306a36Sopenharmony_ci/* 3662306a36Sopenharmony_ci * Force an event check by making a hypercall, but preserve regs 3762306a36Sopenharmony_ci * before making the call. 3862306a36Sopenharmony_ci */ 3962306a36Sopenharmony_ciSYM_FUNC_START(check_events) 4062306a36Sopenharmony_ci FRAME_BEGIN 4162306a36Sopenharmony_ci push %rax 4262306a36Sopenharmony_ci push %rcx 4362306a36Sopenharmony_ci push %rdx 4462306a36Sopenharmony_ci push %rsi 4562306a36Sopenharmony_ci push %rdi 4662306a36Sopenharmony_ci push %r8 4762306a36Sopenharmony_ci push %r9 4862306a36Sopenharmony_ci push %r10 4962306a36Sopenharmony_ci push %r11 5062306a36Sopenharmony_ci call xen_force_evtchn_callback 5162306a36Sopenharmony_ci pop %r11 5262306a36Sopenharmony_ci pop %r10 5362306a36Sopenharmony_ci pop %r9 5462306a36Sopenharmony_ci pop %r8 5562306a36Sopenharmony_ci pop %rdi 5662306a36Sopenharmony_ci pop %rsi 5762306a36Sopenharmony_ci pop %rdx 5862306a36Sopenharmony_ci pop %rcx 5962306a36Sopenharmony_ci pop %rax 6062306a36Sopenharmony_ci FRAME_END 6162306a36Sopenharmony_ci RET 6262306a36Sopenharmony_ciSYM_FUNC_END(check_events) 6362306a36Sopenharmony_ci 6462306a36Sopenharmony_ci/* 6562306a36Sopenharmony_ci * Enable events. This clears the event mask and tests the pending 6662306a36Sopenharmony_ci * event status with one and operation. If there are pending events, 6762306a36Sopenharmony_ci * then enter the hypervisor to get them handled. 6862306a36Sopenharmony_ci */ 6962306a36Sopenharmony_ciSYM_FUNC_START(xen_irq_enable_direct) 7062306a36Sopenharmony_ci FRAME_BEGIN 7162306a36Sopenharmony_ci /* Unmask events */ 7262306a36Sopenharmony_ci movb $0, PER_CPU_VAR(xen_vcpu_info) + XEN_vcpu_info_mask 7362306a36Sopenharmony_ci 7462306a36Sopenharmony_ci /* 7562306a36Sopenharmony_ci * Preempt here doesn't matter because that will deal with any 7662306a36Sopenharmony_ci * pending interrupts. The pending check may end up being run 7762306a36Sopenharmony_ci * on the wrong CPU, but that doesn't hurt. 7862306a36Sopenharmony_ci */ 7962306a36Sopenharmony_ci 8062306a36Sopenharmony_ci /* Test for pending */ 8162306a36Sopenharmony_ci testb $0xff, PER_CPU_VAR(xen_vcpu_info) + XEN_vcpu_info_pending 8262306a36Sopenharmony_ci jz 1f 8362306a36Sopenharmony_ci 8462306a36Sopenharmony_ci call check_events 8562306a36Sopenharmony_ci1: 8662306a36Sopenharmony_ci FRAME_END 8762306a36Sopenharmony_ci RET 8862306a36Sopenharmony_ciSYM_FUNC_END(xen_irq_enable_direct) 8962306a36Sopenharmony_ci 9062306a36Sopenharmony_ci/* 9162306a36Sopenharmony_ci * (xen_)save_fl is used to get the current interrupt enable status. 9262306a36Sopenharmony_ci * Callers expect the status to be in X86_EFLAGS_IF, and other bits 9362306a36Sopenharmony_ci * may be set in the return value. We take advantage of this by 9462306a36Sopenharmony_ci * making sure that X86_EFLAGS_IF has the right value (and other bits 9562306a36Sopenharmony_ci * in that byte are 0), but other bits in the return value are 9662306a36Sopenharmony_ci * undefined. We need to toggle the state of the bit, because Xen and 9762306a36Sopenharmony_ci * x86 use opposite senses (mask vs enable). 9862306a36Sopenharmony_ci */ 9962306a36Sopenharmony_ciSYM_FUNC_START(xen_save_fl_direct) 10062306a36Sopenharmony_ci testb $0xff, PER_CPU_VAR(xen_vcpu_info) + XEN_vcpu_info_mask 10162306a36Sopenharmony_ci setz %ah 10262306a36Sopenharmony_ci addb %ah, %ah 10362306a36Sopenharmony_ci RET 10462306a36Sopenharmony_ciSYM_FUNC_END(xen_save_fl_direct) 10562306a36Sopenharmony_ci 10662306a36Sopenharmony_ciSYM_FUNC_START(xen_read_cr2) 10762306a36Sopenharmony_ci FRAME_BEGIN 10862306a36Sopenharmony_ci _ASM_MOV PER_CPU_VAR(xen_vcpu), %_ASM_AX 10962306a36Sopenharmony_ci _ASM_MOV XEN_vcpu_info_arch_cr2(%_ASM_AX), %_ASM_AX 11062306a36Sopenharmony_ci FRAME_END 11162306a36Sopenharmony_ci RET 11262306a36Sopenharmony_ciSYM_FUNC_END(xen_read_cr2); 11362306a36Sopenharmony_ci 11462306a36Sopenharmony_ciSYM_FUNC_START(xen_read_cr2_direct) 11562306a36Sopenharmony_ci FRAME_BEGIN 11662306a36Sopenharmony_ci _ASM_MOV PER_CPU_VAR(xen_vcpu_info) + XEN_vcpu_info_arch_cr2, %_ASM_AX 11762306a36Sopenharmony_ci FRAME_END 11862306a36Sopenharmony_ci RET 11962306a36Sopenharmony_ciSYM_FUNC_END(xen_read_cr2_direct); 12062306a36Sopenharmony_ci.popsection 12162306a36Sopenharmony_ci 12262306a36Sopenharmony_ci.macro xen_pv_trap name 12362306a36Sopenharmony_ciSYM_CODE_START(xen_\name) 12462306a36Sopenharmony_ci UNWIND_HINT_ENTRY 12562306a36Sopenharmony_ci ENDBR 12662306a36Sopenharmony_ci pop %rcx 12762306a36Sopenharmony_ci pop %r11 12862306a36Sopenharmony_ci jmp \name 12962306a36Sopenharmony_ciSYM_CODE_END(xen_\name) 13062306a36Sopenharmony_ci_ASM_NOKPROBE(xen_\name) 13162306a36Sopenharmony_ci.endm 13262306a36Sopenharmony_ci 13362306a36Sopenharmony_cixen_pv_trap asm_exc_divide_error 13462306a36Sopenharmony_cixen_pv_trap asm_xenpv_exc_debug 13562306a36Sopenharmony_cixen_pv_trap asm_exc_int3 13662306a36Sopenharmony_cixen_pv_trap asm_xenpv_exc_nmi 13762306a36Sopenharmony_cixen_pv_trap asm_exc_overflow 13862306a36Sopenharmony_cixen_pv_trap asm_exc_bounds 13962306a36Sopenharmony_cixen_pv_trap asm_exc_invalid_op 14062306a36Sopenharmony_cixen_pv_trap asm_exc_device_not_available 14162306a36Sopenharmony_cixen_pv_trap asm_xenpv_exc_double_fault 14262306a36Sopenharmony_cixen_pv_trap asm_exc_coproc_segment_overrun 14362306a36Sopenharmony_cixen_pv_trap asm_exc_invalid_tss 14462306a36Sopenharmony_cixen_pv_trap asm_exc_segment_not_present 14562306a36Sopenharmony_cixen_pv_trap asm_exc_stack_segment 14662306a36Sopenharmony_cixen_pv_trap asm_exc_general_protection 14762306a36Sopenharmony_cixen_pv_trap asm_exc_page_fault 14862306a36Sopenharmony_cixen_pv_trap asm_exc_spurious_interrupt_bug 14962306a36Sopenharmony_cixen_pv_trap asm_exc_coprocessor_error 15062306a36Sopenharmony_cixen_pv_trap asm_exc_alignment_check 15162306a36Sopenharmony_ci#ifdef CONFIG_X86_CET 15262306a36Sopenharmony_cixen_pv_trap asm_exc_control_protection 15362306a36Sopenharmony_ci#endif 15462306a36Sopenharmony_ci#ifdef CONFIG_X86_MCE 15562306a36Sopenharmony_cixen_pv_trap asm_xenpv_exc_machine_check 15662306a36Sopenharmony_ci#endif /* CONFIG_X86_MCE */ 15762306a36Sopenharmony_cixen_pv_trap asm_exc_simd_coprocessor_error 15862306a36Sopenharmony_ci#ifdef CONFIG_IA32_EMULATION 15962306a36Sopenharmony_cixen_pv_trap asm_int80_emulation 16062306a36Sopenharmony_ci#endif 16162306a36Sopenharmony_cixen_pv_trap asm_exc_xen_unknown_trap 16262306a36Sopenharmony_cixen_pv_trap asm_exc_xen_hypervisor_callback 16362306a36Sopenharmony_ci 16462306a36Sopenharmony_ci __INIT 16562306a36Sopenharmony_ciSYM_CODE_START(xen_early_idt_handler_array) 16662306a36Sopenharmony_ci i = 0 16762306a36Sopenharmony_ci .rept NUM_EXCEPTION_VECTORS 16862306a36Sopenharmony_ci UNWIND_HINT_UNDEFINED 16962306a36Sopenharmony_ci ENDBR 17062306a36Sopenharmony_ci pop %rcx 17162306a36Sopenharmony_ci pop %r11 17262306a36Sopenharmony_ci jmp early_idt_handler_array + i*EARLY_IDT_HANDLER_SIZE 17362306a36Sopenharmony_ci i = i + 1 17462306a36Sopenharmony_ci .fill xen_early_idt_handler_array + i*XEN_EARLY_IDT_HANDLER_SIZE - ., 1, 0xcc 17562306a36Sopenharmony_ci .endr 17662306a36Sopenharmony_ciSYM_CODE_END(xen_early_idt_handler_array) 17762306a36Sopenharmony_ci __FINIT 17862306a36Sopenharmony_ci 17962306a36Sopenharmony_cihypercall_iret = hypercall_page + __HYPERVISOR_iret * 32 18062306a36Sopenharmony_ci/* 18162306a36Sopenharmony_ci * Xen64 iret frame: 18262306a36Sopenharmony_ci * 18362306a36Sopenharmony_ci * ss 18462306a36Sopenharmony_ci * rsp 18562306a36Sopenharmony_ci * rflags 18662306a36Sopenharmony_ci * cs 18762306a36Sopenharmony_ci * rip <-- standard iret frame 18862306a36Sopenharmony_ci * 18962306a36Sopenharmony_ci * flags 19062306a36Sopenharmony_ci * 19162306a36Sopenharmony_ci * rcx } 19262306a36Sopenharmony_ci * r11 }<-- pushed by hypercall page 19362306a36Sopenharmony_ci * rsp->rax } 19462306a36Sopenharmony_ci */ 19562306a36Sopenharmony_ciSYM_CODE_START(xen_iret) 19662306a36Sopenharmony_ci UNWIND_HINT_UNDEFINED 19762306a36Sopenharmony_ci ANNOTATE_NOENDBR 19862306a36Sopenharmony_ci pushq $0 19962306a36Sopenharmony_ci jmp hypercall_iret 20062306a36Sopenharmony_ciSYM_CODE_END(xen_iret) 20162306a36Sopenharmony_ci 20262306a36Sopenharmony_ci/* 20362306a36Sopenharmony_ci * XEN pv doesn't use trampoline stack, PER_CPU_VAR(cpu_tss_rw + TSS_sp0) is 20462306a36Sopenharmony_ci * also the kernel stack. Reusing swapgs_restore_regs_and_return_to_usermode() 20562306a36Sopenharmony_ci * in XEN pv would cause %rsp to move up to the top of the kernel stack and 20662306a36Sopenharmony_ci * leave the IRET frame below %rsp, which is dangerous to be corrupted if #NMI 20762306a36Sopenharmony_ci * interrupts. And swapgs_restore_regs_and_return_to_usermode() pushing the IRET 20862306a36Sopenharmony_ci * frame at the same address is useless. 20962306a36Sopenharmony_ci */ 21062306a36Sopenharmony_ciSYM_CODE_START(xenpv_restore_regs_and_return_to_usermode) 21162306a36Sopenharmony_ci UNWIND_HINT_REGS 21262306a36Sopenharmony_ci POP_REGS 21362306a36Sopenharmony_ci 21462306a36Sopenharmony_ci /* stackleak_erase() can work safely on the kernel stack. */ 21562306a36Sopenharmony_ci STACKLEAK_ERASE_NOCLOBBER 21662306a36Sopenharmony_ci 21762306a36Sopenharmony_ci addq $8, %rsp /* skip regs->orig_ax */ 21862306a36Sopenharmony_ci jmp xen_iret 21962306a36Sopenharmony_ciSYM_CODE_END(xenpv_restore_regs_and_return_to_usermode) 22062306a36Sopenharmony_ci 22162306a36Sopenharmony_ci/* 22262306a36Sopenharmony_ci * Xen handles syscall callbacks much like ordinary exceptions, which 22362306a36Sopenharmony_ci * means we have: 22462306a36Sopenharmony_ci * - kernel gs 22562306a36Sopenharmony_ci * - kernel rsp 22662306a36Sopenharmony_ci * - an iret-like stack frame on the stack (including rcx and r11): 22762306a36Sopenharmony_ci * ss 22862306a36Sopenharmony_ci * rsp 22962306a36Sopenharmony_ci * rflags 23062306a36Sopenharmony_ci * cs 23162306a36Sopenharmony_ci * rip 23262306a36Sopenharmony_ci * r11 23362306a36Sopenharmony_ci * rsp->rcx 23462306a36Sopenharmony_ci */ 23562306a36Sopenharmony_ci 23662306a36Sopenharmony_ci/* Normal 64-bit system call target */ 23762306a36Sopenharmony_ciSYM_CODE_START(xen_entry_SYSCALL_64) 23862306a36Sopenharmony_ci UNWIND_HINT_ENTRY 23962306a36Sopenharmony_ci ENDBR 24062306a36Sopenharmony_ci popq %rcx 24162306a36Sopenharmony_ci popq %r11 24262306a36Sopenharmony_ci 24362306a36Sopenharmony_ci /* 24462306a36Sopenharmony_ci * Neither Xen nor the kernel really knows what the old SS and 24562306a36Sopenharmony_ci * CS were. The kernel expects __USER_DS and __USER_CS, so 24662306a36Sopenharmony_ci * report those values even though Xen will guess its own values. 24762306a36Sopenharmony_ci */ 24862306a36Sopenharmony_ci movq $__USER_DS, 4*8(%rsp) 24962306a36Sopenharmony_ci movq $__USER_CS, 1*8(%rsp) 25062306a36Sopenharmony_ci 25162306a36Sopenharmony_ci jmp entry_SYSCALL_64_after_hwframe 25262306a36Sopenharmony_ciSYM_CODE_END(xen_entry_SYSCALL_64) 25362306a36Sopenharmony_ci 25462306a36Sopenharmony_ci#ifdef CONFIG_IA32_EMULATION 25562306a36Sopenharmony_ci 25662306a36Sopenharmony_ci/* 32-bit compat syscall target */ 25762306a36Sopenharmony_ciSYM_CODE_START(xen_entry_SYSCALL_compat) 25862306a36Sopenharmony_ci UNWIND_HINT_ENTRY 25962306a36Sopenharmony_ci ENDBR 26062306a36Sopenharmony_ci popq %rcx 26162306a36Sopenharmony_ci popq %r11 26262306a36Sopenharmony_ci 26362306a36Sopenharmony_ci /* 26462306a36Sopenharmony_ci * Neither Xen nor the kernel really knows what the old SS and 26562306a36Sopenharmony_ci * CS were. The kernel expects __USER_DS and __USER32_CS, so 26662306a36Sopenharmony_ci * report those values even though Xen will guess its own values. 26762306a36Sopenharmony_ci */ 26862306a36Sopenharmony_ci movq $__USER_DS, 4*8(%rsp) 26962306a36Sopenharmony_ci movq $__USER32_CS, 1*8(%rsp) 27062306a36Sopenharmony_ci 27162306a36Sopenharmony_ci jmp entry_SYSCALL_compat_after_hwframe 27262306a36Sopenharmony_ciSYM_CODE_END(xen_entry_SYSCALL_compat) 27362306a36Sopenharmony_ci 27462306a36Sopenharmony_ci/* 32-bit compat sysenter target */ 27562306a36Sopenharmony_ciSYM_CODE_START(xen_entry_SYSENTER_compat) 27662306a36Sopenharmony_ci UNWIND_HINT_ENTRY 27762306a36Sopenharmony_ci ENDBR 27862306a36Sopenharmony_ci /* 27962306a36Sopenharmony_ci * NB: Xen is polite and clears TF from EFLAGS for us. This means 28062306a36Sopenharmony_ci * that we don't need to guard against single step exceptions here. 28162306a36Sopenharmony_ci */ 28262306a36Sopenharmony_ci popq %rcx 28362306a36Sopenharmony_ci popq %r11 28462306a36Sopenharmony_ci 28562306a36Sopenharmony_ci /* 28662306a36Sopenharmony_ci * Neither Xen nor the kernel really knows what the old SS and 28762306a36Sopenharmony_ci * CS were. The kernel expects __USER_DS and __USER32_CS, so 28862306a36Sopenharmony_ci * report those values even though Xen will guess its own values. 28962306a36Sopenharmony_ci */ 29062306a36Sopenharmony_ci movq $__USER_DS, 4*8(%rsp) 29162306a36Sopenharmony_ci movq $__USER32_CS, 1*8(%rsp) 29262306a36Sopenharmony_ci 29362306a36Sopenharmony_ci jmp entry_SYSENTER_compat_after_hwframe 29462306a36Sopenharmony_ciSYM_CODE_END(xen_entry_SYSENTER_compat) 29562306a36Sopenharmony_ci 29662306a36Sopenharmony_ci#else /* !CONFIG_IA32_EMULATION */ 29762306a36Sopenharmony_ci 29862306a36Sopenharmony_ciSYM_CODE_START(xen_entry_SYSCALL_compat) 29962306a36Sopenharmony_ciSYM_CODE_START(xen_entry_SYSENTER_compat) 30062306a36Sopenharmony_ci UNWIND_HINT_ENTRY 30162306a36Sopenharmony_ci ENDBR 30262306a36Sopenharmony_ci lea 16(%rsp), %rsp /* strip %rcx, %r11 */ 30362306a36Sopenharmony_ci mov $-ENOSYS, %rax 30462306a36Sopenharmony_ci pushq $0 30562306a36Sopenharmony_ci jmp hypercall_iret 30662306a36Sopenharmony_ciSYM_CODE_END(xen_entry_SYSENTER_compat) 30762306a36Sopenharmony_ciSYM_CODE_END(xen_entry_SYSCALL_compat) 30862306a36Sopenharmony_ci 30962306a36Sopenharmony_ci#endif /* CONFIG_IA32_EMULATION */ 310