2
* Hypercall and fault low-level handling routines.
4
* Copyright (c) 2005, K A Fraser
7
#include <xen/config.h>
9
#include <xen/softirq.h>
10
#include <asm/asm_defns.h>
11
#include <asm/apicdef.h>
13
#include <public/xen.h>
15
#define GET_GUEST_REGS(reg) \
16
movq $~(STACK_SIZE-1),reg; \
18
orq $(STACK_SIZE-CPUINFO_sizeof),reg;
20
#define GET_CURRENT(reg) \
21
movq $STACK_SIZE-8, reg; \
27
/* %rbx: struct vcpu */
29
leaq VCPU_trap_bounce(%rbx),%rdx
30
/* TB_eip = (32-bit syscall && syscall32_addr) ?
31
* syscall32_addr : syscall_addr */
33
cmpw $FLAT_USER_CS32,UREGS_cs(%rsp)
34
cmoveq VCPU_syscall32_addr(%rbx),%rax
36
cmovzq VCPU_syscall_addr(%rbx),%rax
37
movq %rax,TRAPBOUNCE_eip(%rdx)
38
/* TB_flags = VGCF_syscall_disables_events ? TBF_INTERRUPT : 0 */
39
btl $_VGCF_syscall_disables_events,VCPU_guest_context_flags(%rbx)
41
leal (,%rcx,TBF_INTERRUPT),%ecx
42
movb %cl,TRAPBOUNCE_flags(%rdx)
43
call create_bounce_frame
44
andl $~X86_EFLAGS_DF,UREGS_eflags(%rsp)
47
/* %rbx: struct vcpu, interrupts disabled */
49
ASSERT_INTERRUPTS_DISABLED
51
testw $TRAP_syscall,4(%rsp)
57
cmpw $FLAT_USER_CS32,%r11
65
/* No special register assumptions. */
73
movq UREGS_error_code(%rsp),%rsi
76
pushq $__HYPERVISOR_DS # SS
79
pushq $__HYPERVISOR_CS # CS
82
pushq %rsi # error_code/entry_vector
84
.Ldf0: GET_CURRENT(%rbx)
88
leaq VCPU_trap_bounce(%rbx),%rdx
89
movq VCPU_failsafe_addr(%rbx),%rax
90
movq %rax,TRAPBOUNCE_eip(%rdx)
91
movb $TBF_FAILSAFE,TRAPBOUNCE_flags(%rdx)
92
bt $_VGCF_failsafe_disables_events,VCPU_guest_context_flags(%rbx)
94
orb $TBF_INTERRUPT,TRAPBOUNCE_flags(%rdx)
95
1: call create_bounce_frame
98
.section __pre_ex_table,"a"
101
.section __ex_table,"a"
102
.quad .Ldf0,failsafe_callback
106
/* No special register assumptions. */
113
* When entering SYSCALL from kernel mode:
114
* %rax = hypercall vector
115
* %rdi, %rsi, %rdx, %r10, %r8, %9 = hypercall arguments
116
* %rcx = SYSCALL-saved %rip
117
* NB. We must move %r10 to %rcx for C function-calling ABI.
119
* When entering SYSCALL from user mode:
120
* Vector directly to the registered arch.syscall_addr.
122
* Initial work is done by per-CPU stack trampolines. At this point %rsp
123
* has been initialised to point at the correct Xen stack, and %rsp, %rflags
124
* and %cs have been saved. All other registers are still to be saved onto
125
* the stack, starting with %rip, and an appropriate %ss must be saved into
126
* the space left by the trampoline.
131
movl $FLAT_KERNEL_SS,24(%rsp)
134
movl $TRAP_syscall,4(%rsp)
135
movq 24(%rsp),%r11 /* Re-load user RFLAGS into %r11 before SAVE_ALL */
138
movq VCPU_domain(%rbx),%rcx
139
testb $1,DOMAIN_is_32bit_pv(%rcx)
141
testb $TF_kernel_mode,VCPU_thread_flags(%rbx)
146
cmpq $NR_hypercalls,%rax
149
/* Deliberately corrupt parameter regs not used by this hypercall. */
150
pushq %rdi; pushq %rsi; pushq %rdx; pushq %rcx; pushq %r8 ; pushq %r9
151
leaq hypercall_args_table(%rip),%r10
153
sub (%r10,%rax,1),%cl
155
movl $0xDEADBEEF,%eax
157
popq %r9 ; popq %r8 ; popq %rcx; popq %rdx; popq %rsi; popq %rdi
158
movq UREGS_rax(%rsp),%rax
160
pushq UREGS_rip+8(%rsp)
161
#define SHADOW_BYTES 16 /* Shadow EIP + shadow hypercall # */
163
#define SHADOW_BYTES 0 /* No on-stack shadow state */
165
cmpb $0,tb_init_done(%rip)
168
/* Now restore all the registers that trace_hypercall clobbered */
169
movq UREGS_rax+SHADOW_BYTES(%rsp),%rax /* Hypercall # */
170
movq UREGS_rdi+SHADOW_BYTES(%rsp),%rdi /* Arg 1 */
171
movq UREGS_rsi+SHADOW_BYTES(%rsp),%rsi /* Arg 2 */
172
movq UREGS_rdx+SHADOW_BYTES(%rsp),%rdx /* Arg 3 */
173
movq UREGS_r10+SHADOW_BYTES(%rsp),%rcx /* Arg 4 */
174
movq UREGS_rdi+SHADOW_BYTES(%rsp),%r8 /* Arg 5 */
175
movq UREGS_rbp+SHADOW_BYTES(%rsp),%r9 /* Arg 6 */
177
1: leaq hypercall_table(%rip),%r10
178
PERFC_INCR(PERFC_hypercalls, %rax, %rbx)
181
/* Deliberately corrupt parameter regs used by this hypercall. */
182
popq %r10 # Shadow RIP
183
cmpq %r10,UREGS_rip+8(%rsp)
184
popq %rcx # Shadow hypercall index
185
jne skip_clobber /* If RIP has changed then don't clobber. */
186
leaq hypercall_args_table(%rip),%r10
187
movb (%r10,%rcx,1),%cl
188
movl $0xDEADBEEF,%r10d
189
cmpb $1,%cl; jb skip_clobber; movq %r10,UREGS_rdi(%rsp)
190
cmpb $2,%cl; jb skip_clobber; movq %r10,UREGS_rsi(%rsp)
191
cmpb $3,%cl; jb skip_clobber; movq %r10,UREGS_rdx(%rsp)
192
cmpb $4,%cl; jb skip_clobber; movq %r10,UREGS_r10(%rsp)
193
cmpb $5,%cl; jb skip_clobber; movq %r10,UREGS_r8(%rsp)
194
cmpb $6,%cl; jb skip_clobber; movq %r10,UREGS_r9(%rsp)
197
movq %rax,UREGS_rax(%rsp) # save the return value
199
/* %rbx: struct vcpu */
201
cli # tests must not race interrupts
203
movl VCPU_processor(%rbx),%eax
204
shl $IRQSTAT_shift,%rax
205
leaq irq_stat(%rip),%rcx
206
testl $~0,(%rcx,%rax,1)
208
testb $1,VCPU_mce_pending(%rbx)
210
testb $1,VCPU_nmi_pending(%rbx)
213
movq VCPU_vcpu_info(%rbx),%rax
214
testb $0xFF,VCPUINFO_upcall_mask(%rax)
215
jnz restore_all_guest
216
testb $0xFF,VCPUINFO_upcall_pending(%rax)
218
/*process_guest_events:*/
220
leaq VCPU_trap_bounce(%rbx),%rdx
221
movq VCPU_event_addr(%rbx),%rax
222
movq %rax,TRAPBOUNCE_eip(%rdx)
223
movb $TBF_INTERRUPT,TRAPBOUNCE_flags(%rdx)
224
call create_bounce_frame
228
/* %rbx: struct vcpu */
235
/* %rbx: struct vcpu */
237
testb $1 << VCPU_TRAP_MCE,VCPU_async_exception_mask(%rbx)
238
jnz test_guest_events
240
movb $0,VCPU_mce_pending(%rbx)
241
call set_guest_machinecheck_trapbounce
244
movzbl VCPU_async_exception_mask(%rbx),%edx # save mask for the
245
movb %dl,VCPU_mce_old_mask(%rbx) # iret hypercall
246
orl $1 << VCPU_TRAP_MCE,%edx
247
movb %dl,VCPU_async_exception_mask(%rbx)
251
/* %rbx: struct vcpu */
253
cmpw $1 << VCPU_TRAP_NMI,VCPU_async_exception_mask(%rbx)
254
jnz test_guest_events
256
movb $0,VCPU_nmi_pending(%rbx)
257
call set_guest_nmi_trapbounce
260
movzbl VCPU_async_exception_mask(%rbx),%edx # save mask for the
261
movb %dl,VCPU_nmi_old_mask(%rbx) # iret hypercall
262
orl $1 << VCPU_TRAP_NMI,%edx
263
movb %dl,VCPU_async_exception_mask(%rbx)
266
leaq VCPU_trap_bounce(%rbx),%rdx
267
call create_bounce_frame
271
movq $-ENOSYS,UREGS_rax(%rsp)
274
ENTRY(sysenter_entry)
279
.globl sysenter_eflags_saved
280
sysenter_eflags_saved:
284
movl $TRAP_syscall,4(%rsp)
287
cmpb $0,VCPU_sysenter_disables_events(%rbx)
288
movq $0,UREGS_rip(%rsp) /* null rip */
289
movl $3,UREGS_cs(%rsp) /* ring 3 null cs */
290
movq VCPU_sysenter_addr(%rbx),%rax
292
leaq VCPU_trap_bounce(%rbx),%rdx
294
leal (,%rcx,TBF_INTERRUPT),%ecx
296
1: movq VCPU_domain(%rbx),%rdi
297
movq %rax,TRAPBOUNCE_eip(%rdx)
298
movb %cl,TRAPBOUNCE_flags(%rdx)
299
testb $1,DOMAIN_is_32bit_pv(%rdi)
301
call create_bounce_frame
303
2: movl %eax,TRAPBOUNCE_error_code(%rdx)
304
movq VCPU_gp_fault_addr(%rbx),%rax
305
movb $(TBF_EXCEPTION|TBF_EXCEPTION_ERRCODE|TBF_INTERRUPT),%cl
306
movl $TRAP_gp_fault,UREGS_entry_vector(%rsp)
309
ENTRY(int80_direct_trap)
315
/* Check that the callback is non-null. */
316
leaq VCPU_int80_bounce(%rbx),%rdx
317
cmpb $0,TRAPBOUNCE_flags(%rdx)
320
movq VCPU_domain(%rbx),%rax
321
testb $1,DOMAIN_is_32bit_pv(%rax)
322
jnz compat_int80_direct_trap
324
call create_bounce_frame
329
* Setup entry vector and error code as if this was a GPF caused by an
330
* IDT entry with DPL==0.
332
movl $((0x80 << 3) | 0x2),UREGS_error_code(%rsp)
333
movl $TRAP_gp_fault,UREGS_entry_vector(%rsp)
334
/* A GPF wouldn't have incremented the instruction pointer. */
335
subq $2,UREGS_rip(%rsp)
336
jmp handle_exception_saved
338
/* CREATE A BASIC EXCEPTION FRAME ON GUEST OS STACK: */
339
/* { RCX, R11, [DS-GS,] [CR2,] [ERRCODE,] RIP, CS, RFLAGS, RSP, SS } */
340
/* %rdx: trap_bounce, %rbx: struct vcpu */
341
/* On return only %rbx and %rdx are guaranteed non-clobbered. */
343
ASSERT_INTERRUPTS_ENABLED
344
testb $TF_kernel_mode,VCPU_thread_flags(%rbx)
346
/* Push new frame at registered guest-OS stack base. */
349
call toggle_guest_mode
351
movq VCPU_kernel_sp(%rbx),%rsi
353
1: /* In kernel context already: push new frame at existing %rsp. */
354
movq UREGS_rsp+8(%rsp),%rsi
355
andb $0xfc,UREGS_cs+8(%rsp) # Indicate kernel context to guest.
356
2: andq $~0xf,%rsi # Stack frames are 16-byte aligned.
357
movq $HYPERVISOR_VIRT_START,%rax
359
jb 1f # In +ve address space? Then okay.
360
movq $HYPERVISOR_VIRT_END+60,%rax
362
jb domain_crash_synchronous # Above Xen private area? Then okay.
363
1: movb TRAPBOUNCE_flags(%rdx),%cl
365
movq UREGS_ss+8(%rsp),%rax
366
.Lft2: movq %rax,32(%rsi) # SS
367
movq UREGS_rsp+8(%rsp),%rax
368
.Lft3: movq %rax,24(%rsi) # RSP
369
movq VCPU_vcpu_info(%rbx),%rax
370
pushq VCPUINFO_upcall_mask(%rax)
371
testb $TBF_INTERRUPT,%cl
372
setnz %ch # TBF_INTERRUPT -> set upcall mask
373
orb %ch,VCPUINFO_upcall_mask(%rax)
375
shlq $32,%rax # Bits 32-39: saved_upcall_mask
376
movw UREGS_cs+8(%rsp),%ax # Bits 0-15: CS
377
.Lft4: movq %rax,8(%rsi) # CS / saved_upcall_mask
379
testb $0xFF,%al # Bits 0-7: saved_upcall_mask
380
setz %ch # %ch == !saved_upcall_mask
381
movl UREGS_eflags+8(%rsp),%eax
382
andl $~X86_EFLAGS_IF,%eax
383
addb %ch,%ch # Bit 9 (EFLAGS.IF)
384
orb %ch,%ah # Fold EFLAGS.IF into %eax
385
.Lft5: movq %rax,16(%rsi) # RFLAGS
386
movq UREGS_rip+8(%rsp),%rax
387
.Lft6: movq %rax,(%rsi) # RIP
388
testb $TBF_EXCEPTION_ERRCODE,%cl
391
movl TRAPBOUNCE_error_code(%rdx),%eax
392
.Lft7: movq %rax,(%rsi) # ERROR CODE
393
1: testb $TBF_FAILSAFE,%cl
397
.Lft8: movq %rax,24(%rsi) # GS
399
.Lft9: movq %rax,16(%rsi) # FS
401
.Lft10: movq %rax,8(%rsi) # ES
403
.Lft11: movq %rax,(%rsi) # DS
405
movq UREGS_r11+8(%rsp),%rax
406
.Lft12: movq %rax,8(%rsi) # R11
407
movq UREGS_rcx+8(%rsp),%rax
408
.Lft13: movq %rax,(%rsi) # RCX
409
/* Rewrite our stack frame and return to guest-OS mode. */
410
/* IA32 Ref. Vol. 3: TF, VM, RF and NT flags are cleared on trap. */
411
/* Also clear AC: alignment checks shouldn't trigger in kernel mode. */
412
movl $TRAP_syscall,UREGS_entry_vector+8(%rsp)
413
andl $~(X86_EFLAGS_AC|X86_EFLAGS_VM|X86_EFLAGS_RF|\
414
X86_EFLAGS_NT|X86_EFLAGS_TF),UREGS_eflags+8(%rsp)
415
movq $FLAT_KERNEL_SS,UREGS_ss+8(%rsp)
416
movq %rsi,UREGS_rsp+8(%rsp)
417
movq $FLAT_KERNEL_CS,UREGS_cs+8(%rsp)
418
movq TRAPBOUNCE_eip(%rdx),%rax
420
jz domain_crash_synchronous
421
movq %rax,UREGS_rip+8(%rsp)
423
.section __ex_table,"a"
424
.quad .Lft2,domain_crash_synchronous , .Lft3,domain_crash_synchronous
425
.quad .Lft4,domain_crash_synchronous , .Lft5,domain_crash_synchronous
426
.quad .Lft6,domain_crash_synchronous , .Lft7,domain_crash_synchronous
427
.quad .Lft8,domain_crash_synchronous , .Lft9,domain_crash_synchronous
428
.quad .Lft10,domain_crash_synchronous , .Lft11,domain_crash_synchronous
429
.quad .Lft12,domain_crash_synchronous , .Lft13,domain_crash_synchronous
432
domain_crash_synchronous_string:
433
.asciz "domain_crash_sync called from entry.S\n"
435
ENTRY(domain_crash_synchronous)
436
# Get out of the guest-save area of the stack.
439
# create_bounce_frame() temporarily clobbers CS.RPL. Fix up.
440
movq CPUINFO_current_vcpu(%rax),%rax
441
movq VCPU_domain(%rax),%rax
442
testb $1,DOMAIN_is_32bit_pv(%rax)
444
leal (%rax,%rax,2),%eax
445
orb %al,UREGS_cs(%rsp)
446
# printk(domain_crash_synchronous_string)
447
leaq domain_crash_synchronous_string(%rip),%rdi
450
jmp __domain_crash_synchronous
453
/* No special register assumptions. */
456
testb $3,UREGS_cs(%rsp)
458
movq VCPU_domain(%rbx),%rax
459
testb $1,DOMAIN_is_32bit_pv(%rax)
461
jmp compat_test_all_events
464
/* No special register assumptions. */
465
ENTRY(handle_exception)
467
handle_exception_saved:
468
testb $X86_EFLAGS_IF>>8,UREGS_eflags+1(%rsp)
469
jz exception_with_ints_disabled
472
movl UREGS_entry_vector(%rsp),%eax
473
leaq exception_table(%rip),%rdx
475
PERFC_INCR(PERFC_exceptions, %rax, %rbx)
477
testb $3,UREGS_cs(%rsp)
479
leaq VCPU_trap_bounce(%rbx),%rdx
480
movq VCPU_domain(%rbx),%rax
481
testb $1,DOMAIN_is_32bit_pv(%rax)
482
jnz compat_post_handle_exception
483
testb $TBF_EXCEPTION,TRAPBOUNCE_flags(%rdx)
485
call create_bounce_frame
486
movb $0,TRAPBOUNCE_flags(%rdx)
489
/* No special register assumptions. */
490
exception_with_ints_disabled:
491
testb $3,UREGS_cs(%rsp) # interrupts disabled outside Xen?
492
jnz FATAL_exception_with_ints_disabled
494
call search_pre_exception_table
495
testq %rax,%rax # no fixup code for faulting EIP?
497
movq %rax,UREGS_rip(%rsp)
498
subq $8,UREGS_rsp(%rsp) # add ec/ev to previous stack frame
499
testb $15,UREGS_rsp(%rsp) # return %rsp is now aligned?
500
jz 1f # then there is a pad quadword already
504
movq $UREGS_kernel_sizeof/8,%rcx
505
rep; movsq # make room for ec/ev
506
1: movq UREGS_error_code(%rsp),%rax # ec/ev
507
movq %rax,UREGS_kernel_sizeof(%rsp)
508
jmp restore_all_xen # return to fixup code
510
/* No special register assumptions. */
511
FATAL_exception_with_ints_disabled:
512
movl UREGS_entry_vector(%rsp),%edi
519
movl $TRAP_divide_error,4(%rsp)
522
ENTRY(coprocessor_error)
524
movl $TRAP_copro_error,4(%rsp)
527
ENTRY(simd_coprocessor_error)
529
movl $TRAP_simd_error,4(%rsp)
532
ENTRY(device_not_available)
534
movl $TRAP_no_device,4(%rsp)
539
movl $TRAP_debug,4(%rsp)
544
movl $TRAP_int3,4(%rsp)
549
movl $TRAP_overflow,4(%rsp)
554
movl $TRAP_bounds,4(%rsp)
559
movl $TRAP_invalid_op,4(%rsp)
562
ENTRY(coprocessor_segment_overrun)
564
movl $TRAP_copro_seg,4(%rsp)
568
movl $TRAP_invalid_tss,4(%rsp)
571
ENTRY(segment_not_present)
572
movl $TRAP_no_segment,4(%rsp)
576
movl $TRAP_stack_error,4(%rsp)
579
ENTRY(general_protection)
580
movl $TRAP_gp_fault,4(%rsp)
583
ENTRY(alignment_check)
584
movl $TRAP_alignment_check,4(%rsp)
588
movl $TRAP_page_fault,4(%rsp)
591
ENTRY(spurious_interrupt_bug)
593
movl $TRAP_spurious_int,4(%rsp)
602
ENTRY(early_page_fault)
605
call do_early_page_fault
608
handle_ist_exception:
610
testb $3,UREGS_cs(%rsp)
612
/* Interrupted guest context. Copy the context to stack bottom. */
615
movl $UREGS_kernel_sizeof/8,%ecx
619
movl UREGS_entry_vector(%rsp),%eax
620
leaq exception_table(%rip),%rdx
626
movl $TRAP_nmi,4(%rsp)
627
jmp handle_ist_exception
631
movl $TRAP_machine_check,4(%rsp)
632
jmp handle_ist_exception
634
.section .rodata, "a", @progbits
636
ENTRY(exception_table)
637
.quad do_divide_error
644
.quad do_device_not_available
645
.quad 0 # double_fault
646
.quad do_coprocessor_segment_overrun
648
.quad do_segment_not_present
649
.quad do_stack_segment
650
.quad do_general_protection
652
.quad do_spurious_interrupt_bug
653
.quad do_coprocessor_error
654
.quad do_alignment_check
655
.quad do_machine_check
656
.quad do_simd_coprocessor_error
658
ENTRY(hypercall_table)
659
.quad do_set_trap_table /* 0 */
662
.quad do_stack_switch
663
.quad do_set_callbacks
664
.quad do_fpu_taskswitch /* 5 */
665
.quad do_sched_op_compat
667
.quad do_set_debugreg
668
.quad do_get_debugreg
669
.quad do_update_descriptor /* 10 */
670
.quad do_ni_hypercall
673
.quad do_update_va_mapping
674
.quad do_set_timer_op /* 15 */
675
.quad do_event_channel_op_compat
678
.quad do_physdev_op_compat
679
.quad do_grant_table_op /* 20 */
681
.quad do_update_va_mapping_otherdomain
684
.quad do_set_segment_base /* 25 */
689
.quad do_callback_op /* 30 */
691
.quad do_event_channel_op
694
.quad do_sysctl /* 35 */
698
.rept __HYPERVISOR_arch_0-((.-hypercall_table)/8)
699
.quad do_ni_hypercall
701
.quad do_mca /* 48 */
702
.rept NR_hypercalls-((.-hypercall_table)/8)
703
.quad do_ni_hypercall
706
ENTRY(hypercall_args_table)
707
.byte 1 /* do_set_trap_table */ /* 0 */
708
.byte 4 /* do_mmu_update */
709
.byte 2 /* do_set_gdt */
710
.byte 2 /* do_stack_switch */
711
.byte 3 /* do_set_callbacks */
712
.byte 1 /* do_fpu_taskswitch */ /* 5 */
713
.byte 2 /* do_sched_op_compat */
714
.byte 1 /* do_platform_op */
715
.byte 2 /* do_set_debugreg */
716
.byte 1 /* do_get_debugreg */
717
.byte 2 /* do_update_descriptor */ /* 10 */
718
.byte 0 /* do_ni_hypercall */
719
.byte 2 /* do_memory_op */
720
.byte 2 /* do_multicall */
721
.byte 3 /* do_update_va_mapping */
722
.byte 1 /* do_set_timer_op */ /* 15 */
723
.byte 1 /* do_event_channel_op_compat */
724
.byte 2 /* do_xen_version */
725
.byte 3 /* do_console_io */
726
.byte 1 /* do_physdev_op_compat */
727
.byte 3 /* do_grant_table_op */ /* 20 */
728
.byte 2 /* do_vm_assist */
729
.byte 4 /* do_update_va_mapping_otherdomain */
730
.byte 0 /* do_iret */
731
.byte 3 /* do_vcpu_op */
732
.byte 2 /* do_set_segment_base */ /* 25 */
733
.byte 4 /* do_mmuext_op */
734
.byte 1 /* do_xsm_op */
735
.byte 2 /* do_nmi_op */
736
.byte 2 /* do_sched_op */
737
.byte 2 /* do_callback_op */ /* 30 */
738
.byte 2 /* do_xenoprof_op */
739
.byte 2 /* do_event_channel_op */
740
.byte 2 /* do_physdev_op */
741
.byte 2 /* do_hvm_op */
742
.byte 1 /* do_sysctl */ /* 35 */
743
.byte 1 /* do_domctl */
744
.byte 2 /* do_kexec */
745
.byte 1 /* do_tmem_op */
746
.rept __HYPERVISOR_arch_0-(.-hypercall_args_table)
747
.byte 0 /* do_ni_hypercall */
749
.byte 1 /* do_mca */ /* 48 */
750
.rept NR_hypercalls-(.-hypercall_args_table)
751
.byte 0 /* do_ni_hypercall */