summaryrefslogtreecommitdiff
path: root/arch/x86/xen/xen-head.S
blob: 5dad6c51cdc34153c1d177a80af05d33c7db249f (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
/* 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>

#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 GSBASE.
	 * Note that, on SMP, the boot cpu uses init data section until
	 * the per cpu areas are set up.
	 */
	movl	$MSR_GS_BASE,%ecx
	xorl	%eax, %eax
	xorl	%edx, %edx
	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
#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), %rcx
	cmp %rax, %rcx
	pop %r8
	pop %r9
	pop %r10
	pop %r11
	pop %rsi
	pop %rdi
	pop %rdx
	pop %rcx
	pop %rax
#endif
	FRAME_END
	/* Use correct hypercall function. */
	jz xen_hypercall_amd
	jmp xen_hypercall_intel
SYM_FUNC_END(xen_hypercall_hvm)

SYM_FUNC_START(xen_hypercall_amd)
	ANNOTATE_NOENDBR
	vmmcall
	RET
SYM_FUNC_END(xen_hypercall_amd)

SYM_FUNC_START(xen_hypercall_intel)
	ANNOTATE_NOENDBR
	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_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 */