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