mirror of
https://git.kernel.org/pub/scm/linux/kernel/git/stable/linux.git
synced 2025-01-04 04:06:26 +00:00
b4845bb638
Add generic hypercall functions usable for all normal (i.e. not iret) hypercalls. Depending on the guest type and the processor vendor different functions need to be used due to the to be used instruction for entering the hypervisor: - PV guests need to use syscall - HVM/PVH guests on Intel need to use vmcall - HVM/PVH guests on AMD and Hygon need to use vmmcall As PVH guests need to issue hypercalls very early during boot, there is a 4th hypercall function needed for HVM/PVH which can be used on Intel and AMD processors. It will check the vendor type and then set the Intel or AMD specific function to use via static_call(). This is part of XSA-466 / CVE-2024-53241. Reported-by: Andrew Cooper <andrew.cooper3@citrix.com> Signed-off-by: Juergen Gross <jgross@suse.com> Co-developed-by: Peter Zijlstra <peterz@infradead.org>
210 lines
4.9 KiB
ArmAsm
210 lines
4.9 KiB
ArmAsm
/* SPDX-License-Identifier: GPL-2.0 */
|
|
/* Xen-specific pieces of head.S, intended to be included in the right
|
|
place in head.S */
|
|
|
|
#ifdef CONFIG_XEN
|
|
|
|
#include <linux/elfnote.h>
|
|
#include <linux/init.h>
|
|
#include <linux/instrumentation.h>
|
|
|
|
#include <asm/boot.h>
|
|
#include <asm/asm.h>
|
|
#include <asm/frame.h>
|
|
#include <asm/msr.h>
|
|
#include <asm/page_types.h>
|
|
#include <asm/percpu.h>
|
|
#include <asm/unwind_hints.h>
|
|
|
|
#include <xen/interface/elfnote.h>
|
|
#include <xen/interface/features.h>
|
|
#include <xen/interface/xen.h>
|
|
#include <xen/interface/xen-mca.h>
|
|
#include <asm/xen/interface.h>
|
|
|
|
.pushsection .noinstr.text, "ax"
|
|
.balign PAGE_SIZE
|
|
SYM_CODE_START(hypercall_page)
|
|
.rept (PAGE_SIZE / 32)
|
|
UNWIND_HINT_FUNC
|
|
ANNOTATE_NOENDBR
|
|
ANNOTATE_UNRET_SAFE
|
|
ret
|
|
/*
|
|
* Xen will write the hypercall page, and sort out ENDBR.
|
|
*/
|
|
.skip 31, 0xcc
|
|
.endr
|
|
|
|
#define HYPERCALL(n) \
|
|
.equ xen_hypercall_##n, hypercall_page + __HYPERVISOR_##n * 32; \
|
|
.type xen_hypercall_##n, @function; .size xen_hypercall_##n, 32
|
|
#include <asm/xen-hypercalls.h>
|
|
#undef HYPERCALL
|
|
SYM_CODE_END(hypercall_page)
|
|
.popsection
|
|
|
|
#ifdef CONFIG_XEN_PV
|
|
__INIT
|
|
SYM_CODE_START(startup_xen)
|
|
UNWIND_HINT_END_OF_STACK
|
|
ANNOTATE_NOENDBR
|
|
cld
|
|
|
|
leaq __top_init_kernel_stack(%rip), %rsp
|
|
|
|
/* Set up %gs.
|
|
*
|
|
* The base of %gs always points to fixed_percpu_data. If the
|
|
* stack protector canary is enabled, it is located at %gs:40.
|
|
* Note that, on SMP, the boot cpu uses init data section until
|
|
* the per cpu areas are set up.
|
|
*/
|
|
movl $MSR_GS_BASE,%ecx
|
|
movq $INIT_PER_CPU_VAR(fixed_percpu_data),%rax
|
|
cdq
|
|
wrmsr
|
|
|
|
mov %rsi, %rdi
|
|
call xen_start_kernel
|
|
SYM_CODE_END(startup_xen)
|
|
__FINIT
|
|
|
|
#ifdef CONFIG_XEN_PV_SMP
|
|
.pushsection .text
|
|
SYM_CODE_START(asm_cpu_bringup_and_idle)
|
|
UNWIND_HINT_END_OF_STACK
|
|
ENDBR
|
|
|
|
call cpu_bringup_and_idle
|
|
SYM_CODE_END(asm_cpu_bringup_and_idle)
|
|
|
|
SYM_CODE_START(xen_cpu_bringup_again)
|
|
UNWIND_HINT_FUNC
|
|
mov %rdi, %rsp
|
|
UNWIND_HINT_REGS
|
|
call cpu_bringup_and_idle
|
|
SYM_CODE_END(xen_cpu_bringup_again)
|
|
.popsection
|
|
#endif
|
|
#endif
|
|
|
|
.pushsection .noinstr.text, "ax"
|
|
/*
|
|
* Xen hypercall interface to the hypervisor.
|
|
*
|
|
* Input:
|
|
* %eax: hypercall number
|
|
* 32-bit:
|
|
* %ebx, %ecx, %edx, %esi, %edi: args 1..5 for the hypercall
|
|
* 64-bit:
|
|
* %rdi, %rsi, %rdx, %r10, %r8: args 1..5 for the hypercall
|
|
* Output: %[er]ax
|
|
*/
|
|
SYM_FUNC_START(xen_hypercall_hvm)
|
|
ENDBR
|
|
FRAME_BEGIN
|
|
/* Save all relevant registers (caller save and arguments). */
|
|
#ifdef CONFIG_X86_32
|
|
push %eax
|
|
push %ebx
|
|
push %ecx
|
|
push %edx
|
|
push %esi
|
|
push %edi
|
|
#else
|
|
push %rax
|
|
push %rcx
|
|
push %rdx
|
|
push %rdi
|
|
push %rsi
|
|
push %r11
|
|
push %r10
|
|
push %r9
|
|
push %r8
|
|
#ifdef CONFIG_FRAME_POINTER
|
|
pushq $0 /* Dummy push for stack alignment. */
|
|
#endif
|
|
#endif
|
|
/* Set the vendor specific function. */
|
|
call __xen_hypercall_setfunc
|
|
/* Set ZF = 1 if AMD, Restore saved registers. */
|
|
#ifdef CONFIG_X86_32
|
|
lea xen_hypercall_amd, %ebx
|
|
cmp %eax, %ebx
|
|
pop %edi
|
|
pop %esi
|
|
pop %edx
|
|
pop %ecx
|
|
pop %ebx
|
|
pop %eax
|
|
#else
|
|
lea xen_hypercall_amd(%rip), %rbx
|
|
cmp %rax, %rbx
|
|
#ifdef CONFIG_FRAME_POINTER
|
|
pop %rax /* Dummy pop. */
|
|
#endif
|
|
pop %r8
|
|
pop %r9
|
|
pop %r10
|
|
pop %r11
|
|
pop %rsi
|
|
pop %rdi
|
|
pop %rdx
|
|
pop %rcx
|
|
pop %rax
|
|
#endif
|
|
/* Use correct hypercall function. */
|
|
jz xen_hypercall_amd
|
|
jmp xen_hypercall_intel
|
|
SYM_FUNC_END(xen_hypercall_hvm)
|
|
|
|
SYM_FUNC_START(xen_hypercall_amd)
|
|
vmmcall
|
|
RET
|
|
SYM_FUNC_END(xen_hypercall_amd)
|
|
|
|
SYM_FUNC_START(xen_hypercall_intel)
|
|
vmcall
|
|
RET
|
|
SYM_FUNC_END(xen_hypercall_intel)
|
|
.popsection
|
|
|
|
ELFNOTE(Xen, XEN_ELFNOTE_GUEST_OS, .asciz "linux")
|
|
ELFNOTE(Xen, XEN_ELFNOTE_GUEST_VERSION, .asciz "2.6")
|
|
ELFNOTE(Xen, XEN_ELFNOTE_XEN_VERSION, .asciz "xen-3.0")
|
|
#ifdef CONFIG_XEN_PV
|
|
ELFNOTE(Xen, XEN_ELFNOTE_VIRT_BASE, _ASM_PTR __START_KERNEL_map)
|
|
/* Map the p2m table to a 512GB-aligned user address. */
|
|
ELFNOTE(Xen, XEN_ELFNOTE_INIT_P2M, .quad (PUD_SIZE * PTRS_PER_PUD))
|
|
ELFNOTE(Xen, XEN_ELFNOTE_ENTRY, .globl xen_elfnote_entry;
|
|
xen_elfnote_entry: _ASM_PTR xen_elfnote_entry_value - .)
|
|
ELFNOTE(Xen, XEN_ELFNOTE_FEATURES, .ascii "!writable_page_tables")
|
|
ELFNOTE(Xen, XEN_ELFNOTE_PAE_MODE, .asciz "yes")
|
|
ELFNOTE(Xen, XEN_ELFNOTE_L1_MFN_VALID,
|
|
.quad _PAGE_PRESENT; .quad _PAGE_PRESENT)
|
|
ELFNOTE(Xen, XEN_ELFNOTE_MOD_START_PFN, .long 1)
|
|
ELFNOTE(Xen, XEN_ELFNOTE_PADDR_OFFSET, _ASM_PTR 0)
|
|
# define FEATURES_PV (1 << XENFEAT_writable_page_tables)
|
|
#else
|
|
# define FEATURES_PV 0
|
|
#endif
|
|
#ifdef CONFIG_XEN_PVH
|
|
# define FEATURES_PVH (1 << XENFEAT_linux_rsdp_unrestricted)
|
|
#else
|
|
# define FEATURES_PVH 0
|
|
#endif
|
|
#ifdef CONFIG_XEN_DOM0
|
|
# define FEATURES_DOM0 (1 << XENFEAT_dom0)
|
|
#else
|
|
# define FEATURES_DOM0 0
|
|
#endif
|
|
ELFNOTE(Xen, XEN_ELFNOTE_HYPERCALL_PAGE, .globl xen_elfnote_hypercall_page;
|
|
xen_elfnote_hypercall_page: _ASM_PTR xen_elfnote_hypercall_page_value - .)
|
|
ELFNOTE(Xen, XEN_ELFNOTE_SUPPORTED_FEATURES,
|
|
.long FEATURES_PV | FEATURES_PVH | FEATURES_DOM0)
|
|
ELFNOTE(Xen, XEN_ELFNOTE_LOADER, .asciz "generic")
|
|
ELFNOTE(Xen, XEN_ELFNOTE_SUSPEND_CANCEL, .long 1)
|
|
|
|
#endif /*CONFIG_XEN */
|