ia64/xen-unstable

view xen/arch/x86/x86_64/compat/entry.S @ 16195:4970cbf9b19e

x86: Fix xentrace of hypercalls in debug builds of Xen.

Based on a patch by Yosuke Iwamatsu <y-iwamatsu@ab.jp.nec.com>

Signed-off-by: Keir Fraser <keir@xensource.com>
author Keir Fraser <keir@xensource.com>
date Tue Oct 23 09:41:06 2007 +0100 (2007-10-23)
parents 42d8dadb5864
children aeebd173c3fa
line source
1 /*
2 * Compatibility hypercall routines.
3 */
5 #include <xen/config.h>
6 #include <xen/errno.h>
7 #include <xen/softirq.h>
8 #include <asm/asm_defns.h>
9 #include <asm/apicdef.h>
10 #include <asm/page.h>
11 #include <asm/desc.h>
12 #include <public/xen.h>
14 #define GET_GUEST_REGS(reg) \
15 movq $~(STACK_SIZE-1),reg; \
16 andq %rsp,reg; \
17 orq $(STACK_SIZE-CPUINFO_sizeof),reg;
19 #define GET_CURRENT(reg) \
20 movq $STACK_SIZE-8, reg; \
21 orq %rsp, reg; \
22 andq $~7,reg; \
23 movq (reg),reg;
25 ALIGN
26 ENTRY(compat_hypercall)
27 pushq $0
28 movl $TRAP_syscall,4(%rsp)
29 SAVE_ALL
30 GET_CURRENT(%rbx)
32 cmpl $NR_hypercalls,%eax
33 jae compat_bad_hypercall
34 #ifndef NDEBUG
35 /* Deliberately corrupt parameter regs not used by this hypercall. */
36 pushq UREGS_rbx(%rsp); pushq %rcx; pushq %rdx; pushq %rsi; pushq %rdi
37 pushq UREGS_rbp+5*8(%rsp)
38 leaq compat_hypercall_args_table(%rip),%r10
39 movq $6,%rcx
40 subb (%r10,%rax,1),%cl
41 movq %rsp,%rdi
42 movl $0xDEADBEEF,%eax
43 rep stosq
44 popq %r8 ; popq %r9 ; xchgl %r8d,%r9d /* Args 5&6: zero extend */
45 popq %rdx; popq %rcx; xchgl %edx,%ecx /* Args 3&4: zero extend */
46 popq %rdi; popq %rsi; xchgl %edi,%esi /* Args 1&2: zero extend */
47 movl UREGS_rax(%rsp),%eax
48 pushq %rax
49 pushq UREGS_rip+8(%rsp)
50 #define SHADOW_BYTES 16 /* Shadow EIP + shadow hypercall # */
51 #else
52 /* Relocate argument registers and zero-extend to 64 bits. */
53 movl %eax,%eax /* Hypercall # */
54 xchgl %ecx,%esi /* Arg 2, Arg 4 */
55 movl %edx,%edx /* Arg 3 */
56 movl %edi,%r8d /* Arg 5 */
57 movl %ebp,%r9d /* Arg 6 */
58 movl UREGS_rbx(%rsp),%edi /* Arg 1 */
59 #define SHADOW_BYTES 0 /* No on-stack shadow state */
60 #endif
61 cmpb $0,tb_init_done(%rip)
62 je compat_tracing_off
63 call trace_hypercall
64 /* Now restore all the registers that trace_hypercall clobbered */
65 movl UREGS_rax+SHADOW_BYTES(%rsp),%eax /* Hypercall # */
66 movl UREGS_rbx+SHADOW_BYTES(%rsp),%edi /* Arg 1 */
67 movl UREGS_rcx+SHADOW_BYTES(%rsp),%esi /* Arg 2 */
68 movl UREGS_rdx+SHADOW_BYTES(%rsp),%edx /* Arg 3 */
69 movl UREGS_rsi+SHADOW_BYTES(%rsp),%ecx /* Arg 4 */
70 movl UREGS_rdi+SHADOW_BYTES(%rsp),%r8d /* Arg 5 */
71 movl UREGS_rbp+SHADOW_BYTES(%rsp),%r9d /* Arg 6 */
72 #undef SHADOW_BYTES
73 compat_tracing_off:
74 leaq compat_hypercall_table(%rip),%r10
75 PERFC_INCR(PERFC_hypercalls, %rax, %rbx)
76 callq *(%r10,%rax,8)
77 #ifndef NDEBUG
78 /* Deliberately corrupt parameter regs used by this hypercall. */
79 popq %r10 # Shadow RIP
80 cmpq %r10,UREGS_rip+8(%rsp)
81 popq %rcx # Shadow hypercall index
82 jne compat_skip_clobber /* If RIP has changed then don't clobber. */
83 leaq compat_hypercall_args_table(%rip),%r10
84 movb (%r10,%rcx,1),%cl
85 movl $0xDEADBEEF,%r10d
86 testb %cl,%cl; jz compat_skip_clobber; movl %r10d,UREGS_rbx(%rsp)
87 cmpb $2, %cl; jb compat_skip_clobber; movl %r10d,UREGS_rcx(%rsp)
88 cmpb $3, %cl; jb compat_skip_clobber; movl %r10d,UREGS_rdx(%rsp)
89 cmpb $4, %cl; jb compat_skip_clobber; movl %r10d,UREGS_rsi(%rsp)
90 cmpb $5, %cl; jb compat_skip_clobber; movl %r10d,UREGS_rdi(%rsp)
91 cmpb $6, %cl; jb compat_skip_clobber; movl %r10d,UREGS_rbp(%rsp)
92 compat_skip_clobber:
93 #endif
94 movl %eax,UREGS_rax(%rsp) # save the return value
96 /* %rbx: struct vcpu */
97 ENTRY(compat_test_all_events)
98 cli # tests must not race interrupts
99 /*compat_test_softirqs:*/
100 movl VCPU_processor(%rbx),%eax
101 shlq $IRQSTAT_shift,%rax
102 leaq irq_stat(%rip),%rcx
103 testl $~0,(%rcx,%rax,1)
104 jnz compat_process_softirqs
105 testb $1,VCPU_nmi_pending(%rbx)
106 jnz compat_process_nmi
107 compat_test_guest_events:
108 movq VCPU_vcpu_info(%rbx),%rax
109 testb $0xFF,COMPAT_VCPUINFO_upcall_mask(%rax)
110 jnz compat_restore_all_guest
111 testb $0xFF,COMPAT_VCPUINFO_upcall_pending(%rax)
112 jz compat_restore_all_guest
113 /*compat_process_guest_events:*/
114 sti
115 leaq VCPU_trap_bounce(%rbx),%rdx
116 movl VCPU_event_addr(%rbx),%eax
117 movl %eax,TRAPBOUNCE_eip(%rdx)
118 movl VCPU_event_sel(%rbx),%eax
119 movw %ax,TRAPBOUNCE_cs(%rdx)
120 movb $TBF_INTERRUPT,TRAPBOUNCE_flags(%rdx)
121 call compat_create_bounce_frame
122 jmp compat_test_all_events
124 ALIGN
125 /* %rbx: struct vcpu */
126 compat_process_softirqs:
127 sti
128 call do_softirq
129 jmp compat_test_all_events
131 ALIGN
132 /* %rbx: struct vcpu */
133 compat_process_nmi:
134 testb $1,VCPU_nmi_masked(%rbx)
135 jnz compat_test_guest_events
136 movb $0,VCPU_nmi_pending(%rbx)
137 movzwl VCPU_nmi_cs(%rbx),%eax
138 movl VCPU_nmi_addr(%rbx),%ecx
139 testl %eax,%eax
140 jz compat_test_guest_events
141 movb $1,VCPU_nmi_masked(%rbx)
142 sti
143 leaq VCPU_trap_bounce(%rbx),%rdx
144 movw %ax,TRAPBOUNCE_cs(%rdx)
145 movl %ecx,TRAPBOUNCE_eip(%rdx)
146 movw $FLAT_COMPAT_KERNEL_CS,TRAPBOUNCE_cs(%rdx)
147 movb $TBF_INTERRUPT,TRAPBOUNCE_flags(%rdx)
148 call compat_create_bounce_frame
149 jmp compat_test_all_events
151 compat_bad_hypercall:
152 movl $-ENOSYS,UREGS_rax(%rsp)
153 jmp compat_test_all_events
155 /* %rbx: struct vcpu, interrupts disabled */
156 compat_restore_all_guest:
157 ASSERT_INTERRUPTS_DISABLED
158 RESTORE_ALL
159 addq $8,%rsp
160 .Lft0: iretq
162 .section .fixup,"ax"
163 .Lfx0: sti
164 SAVE_ALL
165 movq UREGS_error_code(%rsp),%rsi
166 movq %rsp,%rax
167 andq $~0xf,%rsp
168 pushq $__HYPERVISOR_DS # SS
169 pushq %rax # RSP
170 pushfq # RFLAGS
171 pushq $__HYPERVISOR_CS # CS
172 leaq .Ldf0(%rip),%rax
173 pushq %rax # RIP
174 pushq %rsi # error_code/entry_vector
175 jmp handle_exception
176 .Ldf0: GET_CURRENT(%rbx)
177 jmp compat_test_all_events
178 compat_failsafe_callback:
179 GET_CURRENT(%rbx)
180 leaq VCPU_trap_bounce(%rbx),%rdx
181 movl VCPU_failsafe_addr(%rbx),%eax
182 movl %eax,TRAPBOUNCE_eip(%rdx)
183 movl VCPU_failsafe_sel(%rbx),%eax
184 movw %ax,TRAPBOUNCE_cs(%rdx)
185 movb $TBF_FAILSAFE,TRAPBOUNCE_flags(%rdx)
186 btq $_VGCF_failsafe_disables_events,VCPU_guest_context_flags(%rbx)
187 jnc 1f
188 orb $TBF_INTERRUPT,TRAPBOUNCE_flags(%rdx)
189 1: call compat_create_bounce_frame
190 jmp compat_test_all_events
191 .previous
192 .section __pre_ex_table,"a"
193 .quad .Lft0,.Lfx0
194 .previous
195 .section __ex_table,"a"
196 .quad .Ldf0,compat_failsafe_callback
197 .previous
199 /* %rdx: trap_bounce, %rbx: struct vcpu */
200 ENTRY(compat_post_handle_exception)
201 testb $TBF_EXCEPTION,TRAPBOUNCE_flags(%rdx)
202 jz compat_test_all_events
203 call compat_create_bounce_frame
204 movb $0,TRAPBOUNCE_flags(%rdx)
205 jmp compat_test_all_events
207 ENTRY(compat_int80_direct_trap)
208 call compat_create_bounce_frame
209 jmp compat_test_all_events
211 /* CREATE A BASIC EXCEPTION FRAME ON GUEST OS (RING-1) STACK: */
212 /* {[ERRCODE,] EIP, CS, EFLAGS, [ESP, SS]} */
213 /* %rdx: trap_bounce, %rbx: struct vcpu */
214 /* On return only %rbx and %rdx are guaranteed non-clobbered. */
215 compat_create_bounce_frame:
216 ASSERT_INTERRUPTS_ENABLED
217 mov %fs,%edi
218 testb $2,UREGS_cs+8(%rsp)
219 jz 1f
220 /* Push new frame at registered guest-OS stack base. */
221 movl VCPU_kernel_sp(%rbx),%esi
222 .Lft1: mov VCPU_kernel_ss(%rbx),%fs
223 subl $2*4,%esi
224 movl UREGS_rsp+8(%rsp),%eax
225 .Lft2: movl %eax,%fs:(%rsi)
226 movl UREGS_ss+8(%rsp),%eax
227 .Lft3: movl %eax,%fs:4(%rsi)
228 jmp 2f
229 1: /* In kernel context already: push new frame at existing %rsp. */
230 movl UREGS_rsp+8(%rsp),%esi
231 .Lft4: mov UREGS_ss+8(%rsp),%fs
232 2:
233 movb TRAPBOUNCE_flags(%rdx),%cl
234 subl $3*4,%esi
235 movq VCPU_vcpu_info(%rbx),%rax
236 pushq COMPAT_VCPUINFO_upcall_mask(%rax)
237 testb $TBF_INTERRUPT,%cl
238 setnz %ch # TBF_INTERRUPT -> set upcall mask
239 orb %ch,COMPAT_VCPUINFO_upcall_mask(%rax)
240 popq %rax
241 shll $16,%eax # Bits 16-23: saved_upcall_mask
242 movw UREGS_cs+8(%rsp),%ax # Bits 0-15: CS
243 .Lft5: movl %eax,%fs:4(%rsi) # CS / saved_upcall_mask
244 shrl $16,%eax
245 testb %al,%al # Bits 0-7: saved_upcall_mask
246 setz %ch # %ch == !saved_upcall_mask
247 movl UREGS_eflags+8(%rsp),%eax
248 andl $~X86_EFLAGS_IF,%eax
249 shlb $1,%ch # Bit 9 (EFLAGS.IF)
250 orb %ch,%ah # Fold EFLAGS.IF into %eax
251 .Lft6: movl %eax,%fs:2*4(%rsi) # EFLAGS
252 movl UREGS_rip+8(%rsp),%eax
253 .Lft7: movl %eax,%fs:(%rsi) # EIP
254 testb $TBF_EXCEPTION_ERRCODE,%cl
255 jz 1f
256 subl $4,%esi
257 movl TRAPBOUNCE_error_code(%rdx),%eax
258 .Lft8: movl %eax,%fs:(%rsi) # ERROR CODE
259 1:
260 testb $TBF_FAILSAFE,%cl
261 jz 2f
262 subl $4*4,%esi
263 movl %gs,%eax
264 .Lft9: movl %eax,%fs:3*4(%rsi) # GS
265 .Lft10: movl %edi,%fs:2*4(%rsi) # FS
266 movl %es,%eax
267 .Lft11: movl %eax,%fs:1*4(%rsi) # ES
268 movl %ds,%eax
269 .Lft12: movl %eax,%fs:0*4(%rsi) # DS
270 2:
271 /* Rewrite our stack frame and return to guest-OS mode. */
272 /* IA32 Ref. Vol. 3: TF, VM, RF and NT flags are cleared on trap. */
273 andl $~(X86_EFLAGS_VM|X86_EFLAGS_RF|\
274 X86_EFLAGS_NT|X86_EFLAGS_TF),UREGS_eflags+8(%rsp)
275 mov %fs,UREGS_ss+8(%rsp)
276 movl %esi,UREGS_rsp+8(%rsp)
277 .Lft13: mov %edi,%fs
278 movzwl TRAPBOUNCE_cs(%rdx),%eax
279 /* Null selectors (0-3) are not allowed. */
280 testl $~3,%eax
281 jz domain_crash_synchronous
282 movl %eax,UREGS_cs+8(%rsp)
283 movl TRAPBOUNCE_eip(%rdx),%eax
284 movl %eax,UREGS_rip+8(%rsp)
285 ret
286 .section .fixup,"ax"
287 .Lfx13:
288 xorl %edi,%edi
289 jmp .Lft13
290 .previous
291 .section __ex_table,"a"
292 .quad .Lft1,domain_crash_synchronous , .Lft2,compat_crash_page_fault
293 .quad .Lft3,compat_crash_page_fault_4 , .Lft4,domain_crash_synchronous
294 .quad .Lft5,compat_crash_page_fault_4 , .Lft6,compat_crash_page_fault_8
295 .quad .Lft7,compat_crash_page_fault , .Lft8,compat_crash_page_fault
296 .quad .Lft9,compat_crash_page_fault_12, .Lft10,compat_crash_page_fault_8
297 .quad .Lft11,compat_crash_page_fault_4 , .Lft12,compat_crash_page_fault
298 .quad .Lft13,.Lfx13
299 .previous
301 compat_crash_page_fault_12:
302 addl $4,%esi
303 compat_crash_page_fault_8:
304 addl $4,%esi
305 compat_crash_page_fault_4:
306 addl $4,%esi
307 compat_crash_page_fault:
308 .Lft14: mov %edi,%fs
309 movl %esi,%edi
310 call show_page_walk
311 jmp domain_crash_synchronous
312 .section .fixup,"ax"
313 .Lfx14:
314 xorl %edi,%edi
315 jmp .Lft14
316 .previous
317 .section __ex_table,"a"
318 .quad .Lft14,.Lfx14
319 .previous
321 .section .rodata, "a", @progbits
323 ENTRY(compat_hypercall_table)
324 .quad compat_set_trap_table /* 0 */
325 .quad do_mmu_update
326 .quad compat_set_gdt
327 .quad do_stack_switch
328 .quad compat_set_callbacks
329 .quad do_fpu_taskswitch /* 5 */
330 .quad do_sched_op_compat
331 .quad compat_platform_op
332 .quad do_set_debugreg
333 .quad do_get_debugreg
334 .quad compat_update_descriptor /* 10 */
335 .quad compat_ni_hypercall
336 .quad compat_memory_op
337 .quad compat_multicall
338 .quad compat_update_va_mapping
339 .quad compat_set_timer_op /* 15 */
340 .quad do_event_channel_op_compat
341 .quad compat_xen_version
342 .quad do_console_io
343 .quad compat_physdev_op_compat
344 .quad compat_grant_table_op /* 20 */
345 .quad compat_vm_assist
346 .quad compat_update_va_mapping_otherdomain
347 .quad compat_iret
348 .quad compat_vcpu_op
349 .quad compat_ni_hypercall /* 25 */
350 .quad compat_mmuext_op
351 .quad do_xsm_op
352 .quad compat_nmi_op
353 .quad compat_sched_op
354 .quad compat_callback_op /* 30 */
355 .quad compat_xenoprof_op
356 .quad do_event_channel_op
357 .quad compat_physdev_op
358 .quad do_hvm_op
359 .quad do_sysctl /* 35 */
360 .quad do_domctl
361 .quad compat_kexec_op
362 .rept NR_hypercalls-((.-compat_hypercall_table)/8)
363 .quad compat_ni_hypercall
364 .endr
366 ENTRY(compat_hypercall_args_table)
367 .byte 1 /* compat_set_trap_table */ /* 0 */
368 .byte 4 /* compat_mmu_update */
369 .byte 2 /* compat_set_gdt */
370 .byte 2 /* compat_stack_switch */
371 .byte 4 /* compat_set_callbacks */
372 .byte 1 /* compat_fpu_taskswitch */ /* 5 */
373 .byte 2 /* compat_sched_op_compat */
374 .byte 1 /* compat_platform_op */
375 .byte 2 /* compat_set_debugreg */
376 .byte 1 /* compat_get_debugreg */
377 .byte 4 /* compat_update_descriptor */ /* 10 */
378 .byte 0 /* compat_ni_hypercall */
379 .byte 2 /* compat_memory_op */
380 .byte 2 /* compat_multicall */
381 .byte 4 /* compat_update_va_mapping */
382 .byte 2 /* compat_set_timer_op */ /* 15 */
383 .byte 1 /* compat_event_channel_op_compat */
384 .byte 2 /* compat_xen_version */
385 .byte 3 /* compat_console_io */
386 .byte 1 /* compat_physdev_op_compat */
387 .byte 3 /* compat_grant_table_op */ /* 20 */
388 .byte 2 /* compat_vm_assist */
389 .byte 5 /* compat_update_va_mapping_otherdomain */
390 .byte 0 /* compat_iret */
391 .byte 3 /* compat_vcpu_op */
392 .byte 0 /* compat_ni_hypercall */ /* 25 */
393 .byte 4 /* compat_mmuext_op */
394 .byte 1 /* do_xsm_op */
395 .byte 2 /* compat_nmi_op */
396 .byte 2 /* compat_sched_op */
397 .byte 2 /* compat_callback_op */ /* 30 */
398 .byte 2 /* compat_xenoprof_op */
399 .byte 2 /* compat_event_channel_op */
400 .byte 2 /* compat_physdev_op */
401 .byte 2 /* do_hvm_op */
402 .byte 1 /* do_sysctl */ /* 35 */
403 .byte 1 /* do_domctl */
404 .byte 2 /* compat_kexec_op */
405 .rept NR_hypercalls-(.-compat_hypercall_args_table)
406 .byte 0 /* compat_ni_hypercall */
407 .endr