[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index] [Xen-changelog] [xen-unstable] Add entry points for handling hypercalls from and returning to
# HG changeset patch # User Emmanuel Ackaouy <ack@xxxxxxxxxxxxx> # Date 1168018467 0 # Node ID 5a690aa51fb5d67e72c1cca442758b214f98dedd # Parent 7c5eea5feebd78eb314a87338e8632ce206d6634 Add entry points for handling hypercalls from and returning to compatibility mode guests. Signed-off-by: Jan Beulich <jbeulich@xxxxxxxxxx> --- xen/arch/x86/traps.c | 6 xen/arch/x86/x86_64/Makefile | 6 xen/arch/x86/x86_64/asm-offsets.c | 6 xen/arch/x86/x86_64/compat/entry.S | 395 +++++++++++++++++++++++++++++++++++++ xen/arch/x86/x86_64/compat/traps.c | 312 +++++++++++++++++++++++++++++ xen/arch/x86/x86_64/entry.S | 29 ++ xen/arch/x86/x86_64/traps.c | 12 + xen/include/asm-x86/processor.h | 6 8 files changed, 769 insertions(+), 3 deletions(-) diff -r 7c5eea5feebd -r 5a690aa51fb5 xen/arch/x86/traps.c --- a/xen/arch/x86/traps.c Fri Jan 05 17:32:00 2007 +0000 +++ b/xen/arch/x86/traps.c Fri Jan 05 17:34:27 2007 +0000 @@ -123,6 +123,12 @@ static void show_guest_stack(struct cpu_ if ( is_hvm_vcpu(current) ) return; + if ( IS_COMPAT(container_of(regs, struct cpu_info, guest_cpu_user_regs)->current_vcpu->domain) ) + { + compat_show_guest_stack(regs, debug_stack_lines); + return; + } + if ( vm86_mode(regs) ) { stack = (unsigned long *)((regs->ss << 4) + (regs->esp & 0xffff)); diff -r 7c5eea5feebd -r 5a690aa51fb5 xen/arch/x86/x86_64/Makefile --- a/xen/arch/x86/x86_64/Makefile Fri Jan 05 17:32:00 2007 +0000 +++ b/xen/arch/x86/x86_64/Makefile Fri Jan 05 17:34:27 2007 +0000 @@ -2,3 +2,9 @@ obj-y += gpr_switch.o obj-y += gpr_switch.o obj-y += mm.o obj-y += traps.o + +ifeq ($(CONFIG_COMPAT),y) +# extra dependencies +entry.o: compat/entry.S +traps.o: compat/traps.c +endif diff -r 7c5eea5feebd -r 5a690aa51fb5 xen/arch/x86/x86_64/asm-offsets.c --- a/xen/arch/x86/x86_64/asm-offsets.c Fri Jan 05 17:32:00 2007 +0000 +++ b/xen/arch/x86/x86_64/asm-offsets.c Fri Jan 05 17:34:27 2007 +0000 @@ -53,6 +53,7 @@ void __dummy__(void) BLANK(); OFFSET(VCPU_processor, struct vcpu, processor); + OFFSET(VCPU_domain, struct vcpu, domain); OFFSET(VCPU_vcpu_info, struct vcpu, vcpu_info); OFFSET(VCPU_trap_bounce, struct vcpu, arch.trap_bounce); OFFSET(VCPU_thread_flags, struct vcpu, arch.flags); @@ -87,6 +88,10 @@ void __dummy__(void) OFFSET(VCPU_vmx_cr2, struct vcpu, arch.hvm_vmx.cpu_cr2); BLANK(); + OFFSET(DOMAIN_domain_flags, struct domain, domain_flags); + DEFINE(_DOMF_compat, _DOMF_compat); + BLANK(); + OFFSET(VMCB_rax, struct vmcb_struct, rax); OFFSET(VMCB_tsc_offset, struct vmcb_struct, tsc_offset); BLANK(); @@ -95,6 +100,7 @@ void __dummy__(void) OFFSET(VCPUINFO_upcall_mask, vcpu_info_t, evtchn_upcall_mask); BLANK(); + OFFSET(CPUINFO_current_vcpu, struct cpu_info, current_vcpu); DEFINE(CPUINFO_sizeof, sizeof(struct cpu_info)); BLANK(); diff -r 7c5eea5feebd -r 5a690aa51fb5 xen/arch/x86/x86_64/compat/entry.S --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/xen/arch/x86/x86_64/compat/entry.S Fri Jan 05 17:34:27 2007 +0000 @@ -0,0 +1,395 @@ +/* + * Compatibility hypercall routines. + */ + +#include <asm/desc.h> + +.text + +ENTRY(compat_hypercall) + pushq $0 + movl $TRAP_syscall,4(%rsp) + SAVE_ALL + GET_CURRENT(%rbx) + + cmpl $NR_hypercalls,%eax + jae compat_bad_hypercall +#ifndef NDEBUG + /* Deliberately corrupt parameter regs not used by this hypercall. */ + pushq UREGS_rbx(%rsp); pushq %rcx; pushq %rdx; pushq %rsi; pushq %rdi; pushq UREGS_rbp+5*8(%rsp) + leaq compat_hypercall_args_table(%rip),%r10 + movq $6,%rcx + subb (%r10,%rax,1),%cl + movq %rsp,%rdi + movl $0xDEADBEEF,%eax + rep stosq + popq %r9 ; popq %r8 ; popq %rcx; popq %rdx; popq %rsi; popq %rdi + movl UREGS_rax(%rsp),%eax + pushq %rax + pushq UREGS_rip+8(%rsp) +#else + movl %eax,%eax + movl %ebp,%r9d + movl %edi,%r8d + xchgl %ecx,%esi + movl UREGS_rbx(%rsp),%edi +#endif + leaq compat_hypercall_table(%rip),%r10 + PERFC_INCR(PERFC_hypercalls, %rax) + callq *(%r10,%rax,8) +#ifndef NDEBUG + /* Deliberately corrupt parameter regs used by this hypercall. */ + popq %r10 # Shadow RIP + cmpq %r10,UREGS_rip+8(%rsp) + popq %rcx # Shadow hypercall index + jne compat_skip_clobber /* If RIP has changed then don't clobber. */ + leaq compat_hypercall_args_table(%rip),%r10 + movb (%r10,%rcx,1),%cl + movl $0xDEADBEEF,%r10d + testb %cl,%cl; jz compat_skip_clobber; movl %r10d,UREGS_rbx(%rsp) + cmpb $2, %cl; jb compat_skip_clobber; movl %r10d,UREGS_rcx(%rsp) + cmpb $3, %cl; jb compat_skip_clobber; movl %r10d,UREGS_rdx(%rsp) + cmpb $4, %cl; jb compat_skip_clobber; movl %r10d,UREGS_rsi(%rsp) + cmpb $5, %cl; jb compat_skip_clobber; movl %r10d,UREGS_rdi(%rsp) + cmpb $6, %cl; jb compat_skip_clobber; movl %r10d,UREGS_rbp(%rsp) +compat_skip_clobber: +#endif + movl %eax,UREGS_rax(%rsp) # save the return value + +/* %rbx: struct vcpu */ +compat_test_all_events: + cli # tests must not race interrupts +/*compat_test_softirqs:*/ + movl VCPU_processor(%rbx),%eax + shlq $IRQSTAT_shift,%rax + leaq irq_stat(%rip),%rcx + testl $~0,(%rcx,%rax,1) + jnz compat_process_softirqs + btrq $_VCPUF_nmi_pending,VCPU_flags(%rbx) + jc compat_process_nmi +compat_test_guest_events: + movq VCPU_vcpu_info(%rbx),%rax + testb $0xFF,VCPUINFO_upcall_mask(%rax) + jnz compat_restore_all_guest + testb $0xFF,VCPUINFO_upcall_pending(%rax) + jz compat_restore_all_guest +/*compat_process_guest_events:*/ + sti + leaq VCPU_trap_bounce(%rbx),%rdx + movl VCPU_event_addr(%rbx),%eax + movl %eax,TRAPBOUNCE_eip(%rdx) + movl VCPU_event_sel(%rbx),%eax + movl %eax,TRAPBOUNCE_cs(%rdx) + movw $TBF_INTERRUPT,TRAPBOUNCE_flags(%rdx) + call compat_create_bounce_frame + jmp compat_test_all_events + + ALIGN +/* %rbx: struct vcpu */ +compat_process_softirqs: + sti + call do_softirq + jmp compat_test_all_events + + ALIGN +/* %rbx: struct vcpu */ +compat_process_nmi: + movl VCPU_nmi_addr(%rbx),%eax + testl %eax,%eax + jz compat_test_all_events + btsq $_VCPUF_nmi_masked,VCPU_flags(%rbx) + jc 1f + sti + leaq VCPU_trap_bounce(%rbx),%rdx + movl %eax,TRAPBOUNCE_eip(%rdx) + movl $FLAT_COMPAT_KERNEL_CS,TRAPBOUNCE_cs(%rdx) + movw $TBF_INTERRUPT,TRAPBOUNCE_flags(%rdx) + call compat_create_bounce_frame + jmp compat_test_all_events +1: + btsq $_VCPUF_nmi_pending,VCPU_flags(%rbx) + jmp compat_test_guest_events + +compat_bad_hypercall: + movl $-ENOSYS,UREGS_rax(%rsp) + jmp compat_test_all_events + +/* %rbx: struct vcpu, interrupts disabled */ +compat_restore_all_guest: + RESTORE_ALL + addq $8,%rsp +CFLT0: iretq + +.section .fixup,"ax" +CFIX0: popq -15*8-8(%rsp) # error_code/entry_vector + SAVE_ALL # 15*8 bytes pushed + movq -8(%rsp),%rsi # error_code/entry_vector + sti # after stack abuse (-1024(%rsp)) + pushq $__HYPERVISOR_DS # SS + leaq 8(%rsp),%rax + pushq %rax # RSP + pushfq # RFLAGS + pushq $__HYPERVISOR_CS # CS + leaq CDBLFLT0(%rip),%rax + pushq %rax # RIP + pushq %rsi # error_code/entry_vector + jmp handle_exception +CDBLFLT0:GET_CURRENT(%rbx) + jmp compat_test_all_events +compat_failsafe_callback: + GET_CURRENT(%rbx) + leaq VCPU_trap_bounce(%rbx),%rdx + movl VCPU_failsafe_addr(%rbx),%eax + movl %eax,TRAPBOUNCE_eip(%rdx) + movl VCPU_failsafe_sel(%rbx),%eax + movl %eax,TRAPBOUNCE_cs(%rdx) + movw $TBF_FAILSAFE,TRAPBOUNCE_flags(%rdx) + btq $_VGCF_failsafe_disables_events,VCPU_guest_context_flags(%rbx) + jnc 1f + orw $TBF_INTERRUPT,TRAPBOUNCE_flags(%rdx) +1: + call compat_create_bounce_frame + jmp compat_test_all_events +.previous +.section __pre_ex_table,"a" + .quad CFLT0,CFIX0 +.previous +.section __ex_table,"a" + .quad CDBLFLT0,compat_failsafe_callback +.previous + +/* %rdx: trap_bounce, %rbx: struct vcpu */ +compat_post_handle_exception: + testb $TBF_EXCEPTION,TRAPBOUNCE_flags(%rdx) + jz compat_test_all_events + call compat_create_bounce_frame + jmp compat_test_all_events + +/* CREATE A BASIC EXCEPTION FRAME ON GUEST OS (RING-1) STACK: */ +/* {[ERRCODE,] EIP, CS, EFLAGS, [ESP, SS]} */ +/* %rdx: trap_bounce, %rbx: struct vcpu */ +/* On return only %rbx is guaranteed non-clobbered. */ +compat_create_bounce_frame: + mov %fs,%edi + testb $2,UREGS_cs+8(%rsp) + jz 1f + /* Push new frame at registered guest-OS stack base. */ + movl VCPU_kernel_sp(%rbx),%esi +CFLT1: mov VCPU_kernel_ss(%rbx),%fs + subl $2*4,%esi + movl UREGS_rsp+8(%rsp),%eax +CFLT2: movl %eax,%fs:(%rsi) + movl UREGS_ss+8(%rsp),%eax +CFLT3: movl %eax,%fs:4(%rsi) + jmp 2f +1: /* In kernel context already: push new frame at existing %rsp. */ + movl UREGS_rsp+8(%rsp),%esi +CFLT4: mov UREGS_ss+8(%rsp),%fs +2: + movb TRAPBOUNCE_flags(%rdx),%cl + subl $3*4,%esi + movq VCPU_vcpu_info(%rbx),%rax + pushq VCPUINFO_upcall_mask(%rax) + testb $TBF_INTERRUPT,%cl + setnz %ch # TBF_INTERRUPT -> set upcall mask + orb %ch,VCPUINFO_upcall_mask(%rax) + popq %rax + shll $16,%eax # Bits 16-23: saved_upcall_mask + movw UREGS_cs+8(%rsp),%ax # Bits 0-15: CS +CFLT5: movl %eax,%fs:4(%rsi) # CS / saved_upcall_mask + shrl $16,%eax + testb %al,%al # Bits 0-7: saved_upcall_mask + setz %ch # %ch == !saved_upcall_mask + movl UREGS_eflags+8(%rsp),%eax + andl $~X86_EFLAGS_IF,%eax + shlb $1,%ch # Bit 9 (EFLAGS.IF) + orb %ch,%ah # Fold EFLAGS.IF into %eax +CFLT6: movl %eax,%fs:2*4(%rsi) # EFLAGS + movl UREGS_rip+8(%rsp),%eax +CFLT7: movl %eax,%fs:(%rsi) # EIP + testb $TBF_EXCEPTION_ERRCODE,%cl + jz 1f + subl $4,%esi + movl TRAPBOUNCE_error_code(%rdx),%eax +CFLT8: movl %eax,%fs:(%rsi) # ERROR CODE +1: + testb $TBF_FAILSAFE,%cl + jz 2f + subl $4*4,%esi + movl %gs,%eax +CFLT9: movl %eax,%fs:3*4(%rsi) # GS +CFLT10: movl %edi,%fs:2*4(%rsi) # FS + movl %es,%eax +CFLT11: movl %eax,%fs:1*4(%rsi) # ES + movl %ds,%eax +CFLT12: movl %eax,%fs:0*4(%rsi) # DS +2: + /* Rewrite our stack frame and return to guest-OS mode. */ + /* IA32 Ref. Vol. 3: TF, VM, RF and NT flags are cleared on trap. */ + movl $TRAP_syscall,UREGS_entry_vector+8(%rsp) + andl $~(X86_EFLAGS_VM|X86_EFLAGS_RF|\ + X86_EFLAGS_NT|X86_EFLAGS_TF),UREGS_eflags+8(%rsp) + mov %fs,UREGS_ss+8(%rsp) + movl %esi,UREGS_rsp+8(%rsp) +CFLT13: mov %edi,%fs + movzwl TRAPBOUNCE_cs(%rdx),%eax + /* Null selectors (0-3) are not allowed. */ + testl $~3,%eax + jz domain_crash_synchronous + movl %eax,UREGS_cs+8(%rsp) + movl TRAPBOUNCE_eip(%rdx),%eax + movl %eax,UREGS_rip+8(%rsp) + movb $0,TRAPBOUNCE_flags(%rdx) + ret +.section .fixup,"ax" +CFIX13: + xorl %edi,%edi + jmp CFLT13 +.previous +.section __ex_table,"a" + .quad CFLT1,domain_crash_synchronous , CFLT2,compat_crash_page_fault + .quad CFLT3,compat_crash_page_fault_4 , CFLT4,domain_crash_synchronous + .quad CFLT5,compat_crash_page_fault_4 , CFLT6,compat_crash_page_fault_8 + .quad CFLT7,compat_crash_page_fault , CFLT8,compat_crash_page_fault + .quad CFLT9,compat_crash_page_fault_12, CFLT10,compat_crash_page_fault_8 + .quad CFLT11,compat_crash_page_fault_4 , CFLT12,compat_crash_page_fault + .quad CFLT13,CFIX13 +.previous + +compat_crash_page_fault_12: + addl $4,%esi +compat_crash_page_fault_8: + addl $4,%esi +compat_crash_page_fault_4: + addl $4,%esi +compat_crash_page_fault: +CFLT14: mov %edi,%fs + movl %esi,%edi + call show_page_walk + jmp domain_crash_synchronous +.section .fixup,"ax" +CFIX14: + xorl %edi,%edi + jmp CFLT14 +.previous +.section __ex_table,"a" + .quad CFLT14,CFIX14 +.previous + +.section .rodata, "a", @progbits + +#define compat_set_trap_table domain_crash_synchronous +#define compat_mmu_update domain_crash_synchronous +#define compat_set_gdt domain_crash_synchronous +#define compat_stack_switch domain_crash_synchronous +#define compat_fpu_taskswitch domain_crash_synchronous +#define compat_arch_sched_op_compat domain_crash_synchronous +#define compat_platform_op domain_crash_synchronous +#define compat_set_debugreg domain_crash_synchronous +#define compat_get_debugreg domain_crash_synchronous +#define compat_update_descriptor domain_crash_synchronous +#define compat_memory_op domain_crash_synchronous +#define compat_multicall domain_crash_synchronous +#define compat_update_va_mapping domain_crash_synchronous +#define compat_set_timer_op domain_crash_synchronous +#define compat_event_channel_op_compat domain_crash_synchronous +#define compat_xen_version domain_crash_synchronous +#define compat_console_io domain_crash_synchronous +#define compat_physdev_op_compat domain_crash_synchronous +#define compat_grant_table_op domain_crash_synchronous +#define compat_vm_assist domain_crash_synchronous +#define compat_update_va_mapping_otherdomain domain_crash_synchronous +#define compat_vcpu_op domain_crash_synchronous +#define compat_mmuext_op domain_crash_synchronous +#define compat_acm_op domain_crash_synchronous +#define compat_nmi_op domain_crash_synchronous +#define compat_arch_sched_op domain_crash_synchronous +#define compat_xenoprof_op domain_crash_synchronous +#define compat_event_channel_op domain_crash_synchronous +#define compat_physdev_op domain_crash_synchronous +#define compat_sysctl domain_crash_synchronous +#define compat_domctl domain_crash_synchronous + +ENTRY(compat_hypercall_table) + .quad compat_set_trap_table /* 0 */ + .quad compat_mmu_update + .quad compat_set_gdt + .quad compat_stack_switch + .quad compat_set_callbacks + .quad compat_fpu_taskswitch /* 5 */ + .quad compat_arch_sched_op_compat + .quad compat_platform_op + .quad compat_set_debugreg + .quad compat_get_debugreg + .quad compat_update_descriptor /* 10 */ + .quad do_ni_hypercall + .quad compat_memory_op + .quad compat_multicall + .quad compat_update_va_mapping + .quad compat_set_timer_op /* 15 */ + .quad compat_event_channel_op_compat + .quad compat_xen_version + .quad compat_console_io + .quad compat_physdev_op_compat + .quad compat_grant_table_op /* 20 */ + .quad compat_vm_assist + .quad compat_update_va_mapping_otherdomain + .quad compat_iret + .quad compat_vcpu_op + .quad do_ni_hypercall /* 25 */ + .quad compat_mmuext_op + .quad compat_acm_op + .quad compat_nmi_op + .quad compat_arch_sched_op + .quad compat_callback_op /* 30 */ + .quad compat_xenoprof_op + .quad compat_event_channel_op + .quad compat_physdev_op + .quad do_ni_hypercall + .quad compat_sysctl /* 35 */ + .quad compat_domctl + .rept NR_hypercalls-((.-compat_hypercall_table)/8) + .quad do_ni_hypercall + .endr + +ENTRY(compat_hypercall_args_table) + .byte 1 /* compat_set_trap_table */ /* 0 */ + .byte 4 /* compat_mmu_update */ + .byte 2 /* compat_set_gdt */ + .byte 2 /* compat_stack_switch */ + .byte 4 /* compat_set_callbacks */ + .byte 1 /* compat_fpu_taskswitch */ /* 5 */ + .byte 2 /* compat_arch_sched_op_compat */ + .byte 1 /* compat_platform_op */ + .byte 2 /* compat_set_debugreg */ + .byte 1 /* compat_get_debugreg */ + .byte 4 /* compat_update_descriptor */ /* 10 */ + .byte 0 /* do_ni_hypercall */ + .byte 2 /* compat_memory_op */ + .byte 2 /* compat_multicall */ + .byte 4 /* compat_update_va_mapping */ + .byte 2 /* compat_set_timer_op */ /* 15 */ + .byte 1 /* compat_event_channel_op_compat */ + .byte 2 /* compat_xen_version */ + .byte 3 /* compat_console_io */ + .byte 1 /* compat_physdev_op_compat */ + .byte 3 /* compat_grant_table_op */ /* 20 */ + .byte 2 /* compat_vm_assist */ + .byte 5 /* compat_update_va_mapping_otherdomain */ + .byte 0 /* compat_iret */ + .byte 3 /* compat_vcpu_op */ + .byte 0 /* do_ni_hypercall */ /* 25 */ + .byte 4 /* compat_mmuext_op */ + .byte 1 /* compat_acm_op */ + .byte 2 /* compat_nmi_op */ + .byte 2 /* compat_arch_sched_op */ + .byte 2 /* compat_callback_op */ /* 30 */ + .byte 2 /* compat_xenoprof_op */ + .byte 2 /* compat_event_channel_op */ + .byte 2 /* compat_physdev_op */ + .byte 0 /* do_ni_hypercall */ + .byte 1 /* compat_sysctl */ /* 35 */ + .byte 1 /* compat_domctl */ + .rept NR_hypercalls-(.-compat_hypercall_args_table) + .byte 0 /* do_ni_hypercall */ + .endr diff -r 7c5eea5feebd -r 5a690aa51fb5 xen/arch/x86/x86_64/compat/traps.c --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/xen/arch/x86/x86_64/compat/traps.c Fri Jan 05 17:34:27 2007 +0000 @@ -0,0 +1,312 @@ +#ifdef CONFIG_COMPAT + +#if 0 /* XXX */ +#include <compat/callback.h> +#else +struct compat_xen_callback { + unsigned int cs; + unsigned int eip; +}; +typedef struct compat_xen_callback xen_callback_compat_t; + +struct compat_callback_register { + uint16_t type; + uint16_t flags; + xen_callback_compat_t address; +}; + +struct compat_callback_unregister { + uint16_t type; + uint16_t _unused; +}; +#endif + +void compat_show_guest_stack(struct cpu_user_regs *regs, int debug_stack_lines) +{ + unsigned int i, *stack, addr; + + stack = (unsigned int *)(unsigned long)regs->_esp; + printk("Guest stack trace from esp=%08lx:\n ", (unsigned long)stack); + + for ( i = 0; i < debug_stack_lines * 8; i++ ) + { + if ( (((long)stack + 3) & (STACK_SIZE - 4)) == 0 ) + break; + if ( get_user(addr, stack) ) + { + if ( i != 0 ) + printk("\n "); + printk("Fault while accessing guest memory."); + i = 1; + break; + } + if ( (i != 0) && ((i % 8) == 0) ) + printk("\n "); + printk(" %08x", addr); + stack++; + } + if ( i == 0 ) + printk("Stack empty."); + printk("\n"); +} + +unsigned int compat_iret(void) +{ + struct cpu_user_regs *regs = guest_cpu_user_regs(); + u32 eflags; + + /* Restore EAX (clobbered by hypercall). */ + if ( unlikely(__get_user(regs->_eax, (u32 __user *)regs->rsp)) ) + goto exit_and_crash; + + /* Restore CS and EIP. */ + if ( unlikely(__get_user(regs->_eip, (u32 __user *)regs->rsp + 1)) || + unlikely(__get_user(regs->cs, (u32 __user *)regs->rsp + 2)) ) + goto exit_and_crash; + + /* + * Fix up and restore EFLAGS. We fix up in a local staging area + * to avoid firing the BUG_ON(IOPL) check in arch_getdomaininfo_ctxt. + */ + if ( unlikely(__get_user(eflags, (u32 __user *)regs->rsp + 3)) ) + goto exit_and_crash; + regs->_eflags = (eflags & ~X86_EFLAGS_IOPL) | X86_EFLAGS_IF; + + if ( unlikely(eflags & X86_EFLAGS_VM) ) + { + /* + * Cannot return to VM86 mode: inject a GP fault instead. Note that + * the GP fault is reported on the first VM86 mode instruction, not on + * the IRET (which is why we can simply leave the stack frame as-is + * (except for perhaps having to copy it), which in turn seems better + * than teaching create_bounce_frame() to needlessly deal with vm86 + * mode frames). + */ + const struct trap_info *ti; + u32 x, ksp = current->arch.guest_context.kernel_sp - 40; + unsigned int i; + int rc = 0; + + gdprintk(XENLOG_ERR, "VM86 mode unavailable (ksp:%08X->%08X)\n", + regs->_esp, ksp); + if ( ksp < regs->_esp ) + { + for (i = 1; i < 10; ++i) + { + rc |= __get_user(x, (u32 __user *)regs->rsp + i); + rc |= __put_user(x, (u32 __user *)(unsigned long)ksp + i); + } + } + else if ( ksp > regs->_esp ) + { + for (i = 9; i > 0; ++i) + { + rc |= __get_user(x, (u32 __user *)regs->rsp + i); + rc |= __put_user(x, (u32 __user *)(unsigned long)ksp + i); + } + } + if ( rc ) + goto exit_and_crash; + regs->_esp = ksp; + regs->ss = current->arch.guest_context.kernel_ss; + + ti = ¤t->arch.guest_context.trap_ctxt[13]; + if ( TI_GET_IF(ti) ) + eflags &= ~X86_EFLAGS_IF; + regs->_eflags = eflags & ~(X86_EFLAGS_VM|X86_EFLAGS_RF| + X86_EFLAGS_NT|X86_EFLAGS_TF); + + if ( unlikely(__put_user(0, (u32 __user *)regs->rsp)) ) + goto exit_and_crash; + regs->_eip = ti->address; + regs->cs = ti->cs; + } + else if ( unlikely(ring_0(regs)) ) + goto exit_and_crash; + else if ( !ring_1(regs) ) + { + /* Return to ring 2/3: restore ESP and SS. */ + if ( __get_user(regs->ss, (u32 __user *)regs->rsp + 5) + || __get_user(regs->_esp, (u32 __user *)regs->rsp + 4)) + goto exit_and_crash; + } + else + regs->_esp += 16; + + /* No longer in NMI context. */ + clear_bit(_VCPUF_nmi_masked, ¤t->vcpu_flags); + + /* Restore upcall mask from supplied EFLAGS.IF. */ + current->vcpu_info->evtchn_upcall_mask = !(eflags & X86_EFLAGS_IF); + + /* + * The hypercall exit path will overwrite EAX with this return + * value. + */ + return regs->_eax; + + exit_and_crash: + gdprintk(XENLOG_ERR, "Fatal error\n"); + domain_crash(current->domain); + return 0; +} + +static long compat_register_guest_callback(struct compat_callback_register *reg) +{ + long ret = 0; + struct vcpu *v = current; + + fixup_guest_code_selector(v->domain, reg->address.cs); + + switch ( reg->type ) + { + case CALLBACKTYPE_event: + v->arch.guest_context.event_callback_cs = reg->address.cs; + v->arch.guest_context.event_callback_eip = reg->address.eip; + break; + + case CALLBACKTYPE_failsafe: + v->arch.guest_context.failsafe_callback_cs = reg->address.cs; + v->arch.guest_context.failsafe_callback_eip = reg->address.eip; + if ( reg->flags & CALLBACKF_mask_events ) + set_bit(_VGCF_failsafe_disables_events, + &v->arch.guest_context.flags); + else + clear_bit(_VGCF_failsafe_disables_events, + &v->arch.guest_context.flags); + break; + + case CALLBACKTYPE_nmi: + ret = register_guest_nmi_callback(reg->address.eip); + break; + + default: + ret = -EINVAL; + break; + } + + return ret; +} + +static long compat_unregister_guest_callback(struct compat_callback_unregister *unreg) +{ + long ret; + + switch ( unreg->type ) + { + case CALLBACKTYPE_nmi: + ret = unregister_guest_nmi_callback(); + break; + + default: + ret = -EINVAL; + break; + } + + return ret; +} + + +long compat_callback_op(int cmd, XEN_GUEST_HANDLE(void) arg) +{ + long ret; + + switch ( cmd ) + { + case CALLBACKOP_register: + { + struct compat_callback_register reg; + + ret = -EFAULT; + if ( copy_from_guest(®, arg, 1) ) + break; + + ret = compat_register_guest_callback(®); + } + break; + + case CALLBACKOP_unregister: + { + struct compat_callback_unregister unreg; + + ret = -EFAULT; + if ( copy_from_guest(&unreg, arg, 1) ) + break; + + ret = compat_unregister_guest_callback(&unreg); + } + break; + + default: + ret = -EINVAL; + break; + } + + return ret; +} + +long compat_set_callbacks(unsigned long event_selector, + unsigned long event_address, + unsigned long failsafe_selector, + unsigned long failsafe_address) +{ + struct compat_callback_register event = { + .type = CALLBACKTYPE_event, + .address = { + .cs = event_selector, + .eip = event_address + } + }; + struct compat_callback_register failsafe = { + .type = CALLBACKTYPE_failsafe, + .address = { + .cs = failsafe_selector, + .eip = failsafe_address + } + }; + + compat_register_guest_callback(&event); + compat_register_guest_callback(&failsafe); + + return 0; +} + +#endif /* CONFIG_COMPAT */ + +static void hypercall_page_initialise_ring1_kernel(void *hypercall_page) +{ + char *p; + int i; + + /* Fill in all the transfer points with template machine code. */ + + for ( i = 0; i < (PAGE_SIZE / 32); i++ ) + { + p = (char *)(hypercall_page + (i * 32)); + *(u8 *)(p+ 0) = 0xb8; /* mov $<i>,%eax */ + *(u32 *)(p+ 1) = i; + *(u16 *)(p+ 5) = 0x82cd; /* int $0x82 */ + *(u8 *)(p+ 7) = 0xc3; /* ret */ + } + + /* + * HYPERVISOR_iret is special because it doesn't return and expects a + * special stack frame. Guests jump at this transfer point instead of + * calling it. + */ + p = (char *)(hypercall_page + (__HYPERVISOR_iret * 32)); + *(u8 *)(p+ 0) = 0x50; /* push %eax */ + *(u8 *)(p+ 1) = 0xb8; /* mov $__HYPERVISOR_iret,%eax */ + *(u32 *)(p+ 2) = __HYPERVISOR_iret; + *(u16 *)(p+ 6) = 0x82cd; /* int $0x82 */ +} + +/* + * Local variables: + * mode: C + * c-set-style: "BSD" + * c-basic-offset: 4 + * tab-width: 4 + * indent-tabs-mode: nil + * End: + */ diff -r 7c5eea5feebd -r 5a690aa51fb5 xen/arch/x86/x86_64/entry.S --- a/xen/arch/x86/x86_64/entry.S Fri Jan 05 17:32:00 2007 +0000 +++ b/xen/arch/x86/x86_64/entry.S Fri Jan 05 17:34:27 2007 +0000 @@ -324,7 +324,16 @@ domain_crash_synchronous: GET_GUEST_REGS(%rax) movq %rax,%rsp # create_bounce_frame() temporarily clobbers CS.RPL. Fix up. +#ifdef CONFIG_COMPAT + movq CPUINFO_current_vcpu(%rax),%rax + movq VCPU_domain(%rax),%rax + btl $_DOMF_compat,DOMAIN_domain_flags(%rax) + setnc %al + leal (%rax,%rax,2),%eax + orb %al,UREGS_cs(%rsp) +#else orb $3,UREGS_cs(%rsp) +#endif # printk(domain_crash_synchronous_string) leaq domain_crash_synchronous_string(%rip),%rdi xorl %eax,%eax @@ -336,8 +345,15 @@ ENTRY(ret_from_intr) ENTRY(ret_from_intr) GET_CURRENT(%rbx) testb $3,UREGS_cs(%rsp) - jnz test_all_events - jmp restore_all_xen + jz restore_all_xen +#ifndef CONFIG_COMPAT + jmp test_all_events +#else + movq VCPU_domain(%rbx),%rax + btl $_DOMF_compat,DOMAIN_domain_flags(%rax) + jnc test_all_events + jmp compat_test_all_events +#endif ALIGN /* No special register assumptions. */ @@ -355,6 +371,11 @@ handle_exception: testb $3,UREGS_cs(%rsp) jz restore_all_xen leaq VCPU_trap_bounce(%rbx),%rdx +#ifdef CONFIG_COMPAT + movq VCPU_domain(%rbx),%rax + btl $_DOMF_compat,DOMAIN_domain_flags(%rax) + jc compat_post_handle_exception +#endif testb $TBF_EXCEPTION,TRAPBOUNCE_flags(%rdx) jz test_all_events call create_bounce_frame @@ -612,3 +633,7 @@ ENTRY(hypercall_args_table) .rept NR_hypercalls-(.-hypercall_args_table) .byte 0 /* do_ni_hypercall */ .endr + +#ifdef CONFIG_COMPAT +#include "compat/entry.S" +#endif diff -r 7c5eea5feebd -r 5a690aa51fb5 xen/arch/x86/x86_64/traps.c --- a/xen/arch/x86/x86_64/traps.c Fri Jan 05 17:32:00 2007 +0000 +++ b/xen/arch/x86/x86_64/traps.c Fri Jan 05 17:34:27 2007 +0000 @@ -246,6 +246,7 @@ unsigned long do_iret(void) } asmlinkage void syscall_enter(void); +asmlinkage void compat_hypercall(void); void __init percpu_traps_init(void) { char *stack_bottom, *stack; @@ -257,6 +258,11 @@ void __init percpu_traps_init(void) set_intr_gate(TRAP_double_fault, &double_fault); idt_table[TRAP_double_fault].a |= 1UL << 32; /* IST1 */ idt_table[TRAP_nmi].a |= 2UL << 32; /* IST2 */ + +#ifdef CONFIG_COMPAT + /* The hypercall entry vector is only accessible from ring 1. */ + _set_gate(idt_table+HYPERCALL_VECTOR, 15, 1, &compat_hypercall); +#endif } stack_bottom = (char *)get_stack_bottom(); @@ -503,12 +509,16 @@ static void hypercall_page_initialise_ri *(u16 *)(p+ 9) = 0x050f; /* syscall */ } +#include "compat/traps.c" + void hypercall_page_initialise(struct domain *d, void *hypercall_page) { if ( is_hvm_domain(d) ) hvm_hypercall_page_initialise(d, hypercall_page); + else if ( !IS_COMPAT(d) ) + hypercall_page_initialise_ring3_kernel(hypercall_page); else - hypercall_page_initialise_ring3_kernel(hypercall_page); + hypercall_page_initialise_ring1_kernel(hypercall_page); } /* diff -r 7c5eea5feebd -r 5a690aa51fb5 xen/include/asm-x86/processor.h --- a/xen/include/asm-x86/processor.h Fri Jan 05 17:32:00 2007 +0000 +++ b/xen/include/asm-x86/processor.h Fri Jan 05 17:34:27 2007 +0000 @@ -559,6 +559,12 @@ void show_page_walk(unsigned long addr); void show_page_walk(unsigned long addr); asmlinkage void fatal_trap(int trapnr, struct cpu_user_regs *regs); +#ifdef CONFIG_COMPAT +void compat_show_guest_stack(struct cpu_user_regs *, int lines); +#else +#define compat_show_guest_stack(regs, lines) ((void)0) +#endif + /* Dumps current register and stack state. */ #define dump_execution_state() \ /* NB. Needs interrupts enabled else we end up in fatal_trap(). */ \ _______________________________________________ Xen-changelog mailing list Xen-changelog@xxxxxxxxxxxxxxxxxxx http://lists.xensource.com/xen-changelog
|
Lists.xenproject.org is hosted with RackSpace, monitoring our |