aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--arch/x86/xen/enlighten.c4
-rw-r--r--arch/x86/xen/setup.c42
-rw-r--r--arch/x86/xen/smp.c1
-rw-r--r--arch/x86/xen/xen-asm_64.S129
-rw-r--r--arch/x86/xen/xen-ops.h3
5 files changed, 174 insertions, 5 deletions
diff --git a/arch/x86/xen/enlighten.c b/arch/x86/xen/enlighten.c
index 48f1a7eca8b9..87d36044054d 100644
--- a/arch/x86/xen/enlighten.c
+++ b/arch/x86/xen/enlighten.c
@@ -1139,6 +1139,10 @@ static const struct pv_cpu_ops xen_cpu_ops __initdata = {
1139 1139
1140 .iret = xen_iret, 1140 .iret = xen_iret,
1141 .irq_enable_sysexit = xen_sysexit, 1141 .irq_enable_sysexit = xen_sysexit,
1142#ifdef CONFIG_X86_64
1143 .usergs_sysret32 = xen_sysret32,
1144 .usergs_sysret64 = xen_sysret64,
1145#endif
1142 1146
1143 .load_tr_desc = paravirt_nop, 1147 .load_tr_desc = paravirt_nop,
1144 .set_ldt = xen_set_ldt, 1148 .set_ldt = xen_set_ldt,
diff --git a/arch/x86/xen/setup.c b/arch/x86/xen/setup.c
index bea3d4f779db..9d7a14402895 100644
--- a/arch/x86/xen/setup.c
+++ b/arch/x86/xen/setup.c
@@ -86,9 +86,11 @@ static void xen_idle(void)
86 */ 86 */
87static void __init fiddle_vdso(void) 87static void __init fiddle_vdso(void)
88{ 88{
89#if defined(CONFIG_X86_32) || defined(CONFIG_IA32_EMULATION)
89 extern const char vdso32_default_start; 90 extern const char vdso32_default_start;
90 u32 *mask = VDSO32_SYMBOL(&vdso32_default_start, NOTE_MASK); 91 u32 *mask = VDSO32_SYMBOL(&vdso32_default_start, NOTE_MASK);
91 *mask |= 1 << VDSO_NOTE_NONEGSEG_BIT; 92 *mask |= 1 << VDSO_NOTE_NONEGSEG_BIT;
93#endif
92} 94}
93 95
94static __cpuinit int register_callback(unsigned type, const void *func) 96static __cpuinit int register_callback(unsigned type, const void *func)
@@ -106,15 +108,48 @@ void __cpuinit xen_enable_sysenter(void)
106{ 108{
107 int cpu = smp_processor_id(); 109 int cpu = smp_processor_id();
108 extern void xen_sysenter_target(void); 110 extern void xen_sysenter_target(void);
111 int ret;
112
113#ifdef CONFIG_X86_32
114 if (!boot_cpu_has(X86_FEATURE_SEP)) {
115 return;
116 }
117#else
118 if (boot_cpu_data.x86_vendor != X86_VENDOR_INTEL &&
119 boot_cpu_data.x86_vendor != X86_VENDOR_CENTAUR) {
120 return;
121 }
122#endif
109 123
110 if (!boot_cpu_has(X86_FEATURE_SEP) || 124 ret = register_callback(CALLBACKTYPE_sysenter, xen_sysenter_target);
111 register_callback(CALLBACKTYPE_sysenter, 125 if(ret != 0) {
112 xen_sysenter_target) != 0) {
113 clear_cpu_cap(&cpu_data(cpu), X86_FEATURE_SEP); 126 clear_cpu_cap(&cpu_data(cpu), X86_FEATURE_SEP);
114 clear_cpu_cap(&boot_cpu_data, X86_FEATURE_SEP); 127 clear_cpu_cap(&boot_cpu_data, X86_FEATURE_SEP);
115 } 128 }
116} 129}
117 130
131void __cpuinit xen_enable_syscall(void)
132{
133#ifdef CONFIG_X86_64
134 int cpu = smp_processor_id();
135 int ret;
136 extern void xen_syscall_target(void);
137 extern void xen_syscall32_target(void);
138
139 ret = register_callback(CALLBACKTYPE_syscall, xen_syscall_target);
140 if (ret != 0) {
141 printk("failed to set syscall: %d\n", ret);
142 clear_cpu_cap(&cpu_data(cpu), X86_FEATURE_SYSCALL);
143 clear_cpu_cap(&boot_cpu_data, X86_FEATURE_SYSCALL);
144 } else {
145 ret = register_callback(CALLBACKTYPE_syscall32,
146 xen_syscall32_target);
147 if (ret != 0)
148 printk("failed to set 32-bit syscall: %d\n", ret);
149 }
150#endif /* CONFIG_X86_64 */
151}
152
118void __init xen_arch_setup(void) 153void __init xen_arch_setup(void)
119{ 154{
120 struct physdev_set_iopl set_iopl; 155 struct physdev_set_iopl set_iopl;
@@ -131,6 +166,7 @@ void __init xen_arch_setup(void)
131 BUG(); 166 BUG();
132 167
133 xen_enable_sysenter(); 168 xen_enable_sysenter();
169 xen_enable_syscall();
134 170
135 set_iopl.iopl = 1; 171 set_iopl.iopl = 1;
136 rc = HYPERVISOR_physdev_op(PHYSDEVOP_set_iopl, &set_iopl); 172 rc = HYPERVISOR_physdev_op(PHYSDEVOP_set_iopl, &set_iopl);
diff --git a/arch/x86/xen/smp.c b/arch/x86/xen/smp.c
index 8310ca0ea375..f702199312a5 100644
--- a/arch/x86/xen/smp.c
+++ b/arch/x86/xen/smp.c
@@ -69,6 +69,7 @@ static __cpuinit void cpu_bringup_and_idle(void)
69 preempt_disable(); 69 preempt_disable();
70 70
71 xen_enable_sysenter(); 71 xen_enable_sysenter();
72 xen_enable_syscall();
72 73
73 cpu = smp_processor_id(); 74 cpu = smp_processor_id();
74 smp_store_cpu_info(cpu); 75 smp_store_cpu_info(cpu);
diff --git a/arch/x86/xen/xen-asm_64.S b/arch/x86/xen/xen-asm_64.S
index b147b495daef..4038cbfe3331 100644
--- a/arch/x86/xen/xen-asm_64.S
+++ b/arch/x86/xen/xen-asm_64.S
@@ -15,6 +15,8 @@
15 15
16#include <asm/asm-offsets.h> 16#include <asm/asm-offsets.h>
17#include <asm/processor-flags.h> 17#include <asm/processor-flags.h>
18#include <asm/errno.h>
19#include <asm/segment.h>
18 20
19#include <xen/interface/xen.h> 21#include <xen/interface/xen.h>
20 22
@@ -138,9 +140,132 @@ ENTRY(xen_adjust_exception_frame)
138 mov 8+8(%rsp),%r11 140 mov 8+8(%rsp),%r11
139 ret $16 141 ret $16
140 142
143hypercall_iret = hypercall_page + __HYPERVISOR_iret * 32
144/*
145 Xen64 iret frame:
146
147 ss
148 rsp
149 rflags
150 cs
151 rip <-- standard iret frame
152
153 flags
154
155 rcx }
156 r11 }<-- pushed by hypercall page
157rsp -> rax }
158 */
141ENTRY(xen_iret) 159ENTRY(xen_iret)
142 pushq $0 160 pushq $0
143 jmp hypercall_page + __HYPERVISOR_iret * 32 1611: jmp hypercall_iret
162ENDPATCH(xen_iret)
163RELOC(xen_iret, 1b+1)
144 164
165/*
166 sysexit is not used for 64-bit processes, so it's
167 only ever used to return to 32-bit compat userspace.
168 */
145ENTRY(xen_sysexit) 169ENTRY(xen_sysexit)
146 ud2a 170 pushq $__USER32_DS
171 pushq %rcx
172 pushq $X86_EFLAGS_IF
173 pushq $__USER32_CS
174 pushq %rdx
175
176 pushq $VGCF_in_syscall
1771: jmp hypercall_iret
178ENDPATCH(xen_sysexit)
179RELOC(xen_sysexit, 1b+1)
180
181ENTRY(xen_sysret64)
182 /* We're already on the usermode stack at this point, but still
183 with the kernel gs, so we can easily switch back */
184 movq %rsp, %gs:pda_oldrsp
185 movq %gs:pda_kernelstack,%rsp
186
187 pushq $__USER_DS
188 pushq %gs:pda_oldrsp
189 pushq %r11
190 pushq $__USER_CS
191 pushq %rcx
192
193 pushq $VGCF_in_syscall
1941: jmp hypercall_iret
195ENDPATCH(xen_sysret64)
196RELOC(xen_sysret64, 1b+1)
197
198ENTRY(xen_sysret32)
199 /* We're already on the usermode stack at this point, but still
200 with the kernel gs, so we can easily switch back */
201 movq %rsp, %gs:pda_oldrsp
202 movq %gs:pda_kernelstack, %rsp
203
204 pushq $__USER32_DS
205 pushq %gs:pda_oldrsp
206 pushq %r11
207 pushq $__USER32_CS
208 pushq %rcx
209
210 pushq $VGCF_in_syscall
2111: jmp hypercall_iret
212ENDPATCH(xen_sysret32)
213RELOC(xen_sysret32, 1b+1)
214
215/*
216 Xen handles syscall callbacks much like ordinary exceptions,
217 which means we have:
218 - kernel gs
219 - kernel rsp
220 - an iret-like stack frame on the stack (including rcx and r11):
221 ss
222 rsp
223 rflags
224 cs
225 rip
226 r11
227 rsp-> rcx
228
229 In all the entrypoints, we undo all that to make it look
230 like a CPU-generated syscall/sysenter and jump to the normal
231 entrypoint.
232 */
233
234.macro undo_xen_syscall
235 mov 0*8(%rsp),%rcx
236 mov 1*8(%rsp),%r11
237 mov 5*8(%rsp),%rsp
238.endm
239
240/* Normal 64-bit system call target */
241ENTRY(xen_syscall_target)
242 undo_xen_syscall
243 jmp system_call_after_swapgs
244ENDPROC(xen_syscall_target)
245
246#ifdef CONFIG_IA32_EMULATION
247
248/* 32-bit compat syscall target */
249ENTRY(xen_syscall32_target)
250 undo_xen_syscall
251 jmp ia32_cstar_target
252ENDPROC(xen_syscall32_target)
253
254/* 32-bit compat sysenter target */
255ENTRY(xen_sysenter_target)
256 undo_xen_syscall
257 jmp ia32_sysenter_target
258ENDPROC(xen_sysenter_target)
259
260#else /* !CONFIG_IA32_EMULATION */
261
262ENTRY(xen_syscall32_target)
263ENTRY(xen_sysenter_target)
264 lea 16(%rsp), %rsp /* strip %rcx,%r11 */
265 mov $-ENOSYS, %rax
266 pushq $VGCF_in_syscall
267 jmp hypercall_iret
268ENDPROC(xen_syscall32_target)
269ENDPROC(xen_sysenter_target)
270
271#endif /* CONFIG_IA32_EMULATION */
diff --git a/arch/x86/xen/xen-ops.h b/arch/x86/xen/xen-ops.h
index c4800a2c5a41..dd3c23152a2e 100644
--- a/arch/x86/xen/xen-ops.h
+++ b/arch/x86/xen/xen-ops.h
@@ -26,6 +26,7 @@ char * __init xen_memory_setup(void);
26void __init xen_arch_setup(void); 26void __init xen_arch_setup(void);
27void __init xen_init_IRQ(void); 27void __init xen_init_IRQ(void);
28void xen_enable_sysenter(void); 28void xen_enable_sysenter(void);
29void xen_enable_syscall(void);
29void xen_vcpu_restore(void); 30void xen_vcpu_restore(void);
30 31
31void __init xen_build_dynamic_phys_to_machine(void); 32void __init xen_build_dynamic_phys_to_machine(void);
@@ -70,6 +71,8 @@ DECL_ASM(void, xen_restore_fl_direct, unsigned long);
70/* These are not functions, and cannot be called normally */ 71/* These are not functions, and cannot be called normally */
71void xen_iret(void); 72void xen_iret(void);
72void xen_sysexit(void); 73void xen_sysexit(void);
74void xen_sysret32(void);
75void xen_sysret64(void);
73void xen_adjust_exception_frame(void); 76void xen_adjust_exception_frame(void);
74 77
75#endif /* XEN_OPS_H */ 78#endif /* XEN_OPS_H */