| /* SPDX-License-Identifier: GPL-2.0 */ |
| /* |
| * Asm versions of Xen pv-ops, suitable for direct use. |
| * |
| * We only bother with direct forms (ie, vcpu in pda) of the |
| * operations here; the indirect forms are better handled in C. |
| */ |
| |
| #include <asm/errno.h> |
| #include <asm/percpu.h> |
| #include <asm/processor-flags.h> |
| #include <asm/segment.h> |
| #include <asm/asm-offsets.h> |
| #include <asm/thread_info.h> |
| #include <asm/asm.h> |
| |
| #include <xen/interface/xen.h> |
| |
| #include <linux/init.h> |
| #include <linux/linkage.h> |
| |
| .macro xen_pv_trap name |
| ENTRY(xen_\name) |
| pop %rcx |
| pop %r11 |
| jmp \name |
| END(xen_\name) |
| _ASM_NOKPROBE(xen_\name) |
| .endm |
| |
| xen_pv_trap divide_error |
| xen_pv_trap debug |
| xen_pv_trap xendebug |
| xen_pv_trap int3 |
| xen_pv_trap xennmi |
| xen_pv_trap overflow |
| xen_pv_trap bounds |
| xen_pv_trap invalid_op |
| xen_pv_trap device_not_available |
| xen_pv_trap double_fault |
| xen_pv_trap coprocessor_segment_overrun |
| xen_pv_trap invalid_TSS |
| xen_pv_trap segment_not_present |
| xen_pv_trap stack_segment |
| xen_pv_trap general_protection |
| xen_pv_trap page_fault |
| xen_pv_trap spurious_interrupt_bug |
| xen_pv_trap coprocessor_error |
| xen_pv_trap alignment_check |
| #ifdef CONFIG_X86_MCE |
| xen_pv_trap machine_check |
| #endif /* CONFIG_X86_MCE */ |
| xen_pv_trap simd_coprocessor_error |
| #ifdef CONFIG_IA32_EMULATION |
| xen_pv_trap entry_INT80_compat |
| #endif |
| xen_pv_trap hypervisor_callback |
| |
| __INIT |
| ENTRY(xen_early_idt_handler_array) |
| i = 0 |
| .rept NUM_EXCEPTION_VECTORS |
| pop %rcx |
| pop %r11 |
| jmp early_idt_handler_array + i*EARLY_IDT_HANDLER_SIZE |
| i = i + 1 |
| .fill xen_early_idt_handler_array + i*XEN_EARLY_IDT_HANDLER_SIZE - ., 1, 0xcc |
| .endr |
| END(xen_early_idt_handler_array) |
| __FINIT |
| |
| hypercall_iret = hypercall_page + __HYPERVISOR_iret * 32 |
| /* |
| * Xen64 iret frame: |
| * |
| * ss |
| * rsp |
| * rflags |
| * cs |
| * rip <-- standard iret frame |
| * |
| * flags |
| * |
| * rcx } |
| * r11 }<-- pushed by hypercall page |
| * rsp->rax } |
| */ |
| ENTRY(xen_iret) |
| pushq $0 |
| jmp hypercall_iret |
| |
| ENTRY(xen_sysret64) |
| /* |
| * We're already on the usermode stack at this point, but |
| * still with the kernel gs, so we can easily switch back. |
| * |
| * tss.sp2 is scratch space. |
| */ |
| movq %rsp, PER_CPU_VAR(cpu_tss_rw + TSS_sp2) |
| movq PER_CPU_VAR(cpu_current_top_of_stack), %rsp |
| |
| pushq $__USER_DS |
| pushq PER_CPU_VAR(cpu_tss_rw + TSS_sp2) |
| pushq %r11 |
| pushq $__USER_CS |
| pushq %rcx |
| |
| pushq $VGCF_in_syscall |
| jmp hypercall_iret |
| |
| /* |
| * Xen handles syscall callbacks much like ordinary exceptions, which |
| * means we have: |
| * - kernel gs |
| * - kernel rsp |
| * - an iret-like stack frame on the stack (including rcx and r11): |
| * ss |
| * rsp |
| * rflags |
| * cs |
| * rip |
| * r11 |
| * rsp->rcx |
| */ |
| |
| /* Normal 64-bit system call target */ |
| ENTRY(xen_syscall_target) |
| popq %rcx |
| popq %r11 |
| |
| /* |
| * Neither Xen nor the kernel really knows what the old SS and |
| * CS were. The kernel expects __USER_DS and __USER_CS, so |
| * report those values even though Xen will guess its own values. |
| */ |
| movq $__USER_DS, 4*8(%rsp) |
| movq $__USER_CS, 1*8(%rsp) |
| |
| jmp entry_SYSCALL_64_after_hwframe |
| ENDPROC(xen_syscall_target) |
| |
| #ifdef CONFIG_IA32_EMULATION |
| |
| /* 32-bit compat syscall target */ |
| ENTRY(xen_syscall32_target) |
| popq %rcx |
| popq %r11 |
| |
| /* |
| * Neither Xen nor the kernel really knows what the old SS and |
| * CS were. The kernel expects __USER32_DS and __USER32_CS, so |
| * report those values even though Xen will guess its own values. |
| */ |
| movq $__USER32_DS, 4*8(%rsp) |
| movq $__USER32_CS, 1*8(%rsp) |
| |
| jmp entry_SYSCALL_compat_after_hwframe |
| ENDPROC(xen_syscall32_target) |
| |
| /* 32-bit compat sysenter target */ |
| ENTRY(xen_sysenter_target) |
| mov 0*8(%rsp), %rcx |
| mov 1*8(%rsp), %r11 |
| mov 5*8(%rsp), %rsp |
| jmp entry_SYSENTER_compat |
| ENDPROC(xen_sysenter_target) |
| |
| #else /* !CONFIG_IA32_EMULATION */ |
| |
| ENTRY(xen_syscall32_target) |
| ENTRY(xen_sysenter_target) |
| lea 16(%rsp), %rsp /* strip %rcx, %r11 */ |
| mov $-ENOSYS, %rax |
| pushq $0 |
| jmp hypercall_iret |
| ENDPROC(xen_syscall32_target) |
| ENDPROC(xen_sysenter_target) |
| |
| #endif /* CONFIG_IA32_EMULATION */ |