From: "Jan Beulich" Subject: [PATCH 2/4, RFC] x86_64: system call and exception handling for compatibility mode guest (version 2) Date: Fri, 25 Aug 2006 15:45:39 +0200 Message-ID: <44EF1B23.76E4.0078.0@novell.com> Mime-Version: 1.0 Content-Type: multipart/mixed; boundary="=__Part2E0B8913.0__=" Return-path: List-Unsubscribe: , List-Post: List-Help: List-Subscribe: , Sender: xen-devel-bounces@lists.xensource.com Errors-To: xen-devel-bounces@lists.xensource.com To: xen-devel@lists.xensource.com List-Id: xen-devel@lists.xenproject.org --=__Part2E0B8913.0__= Content-Type: text/plain; charset=US-ASCII Content-Transfer-Encoding: 7bit Content-Disposition: inline This adds several routines and conditionals to deal with the specifics of compatibility mode guests. Compatibility mode hypercall handlers are being stubbed out to crash the domain for the time being. Signed-off-by: Jan Beulich --=__Part2E0B8913.0__= Content-Type: text/plain; name="32on64-hypercall.patch" Content-Transfer-Encoding: 7bit Content-Disposition: attachment; filename="32on64-hypercall.patch" Index: 2006-08-16/xen/arch/x86/traps.c =================================================================== --- 2006-08-16.orig/xen/arch/x86/traps.c 2006-08-25 15:32:40.000000000 +0200 +++ 2006-08-16/xen/arch/x86/traps.c 2006-08-25 15:32:49.000000000 +0200 @@ -137,6 +137,12 @@ static void show_guest_stack(struct cpu_ if ( hvm_guest(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)); Index: 2006-08-16/xen/arch/x86/x86_64/Makefile =================================================================== --- 2006-08-16.orig/xen/arch/x86/x86_64/Makefile 2006-08-25 15:32:40.000000000 +0200 +++ 2006-08-16/xen/arch/x86/x86_64/Makefile 2006-08-25 15:32:49.000000000 +0200 @@ -1,3 +1,9 @@ obj-y += entry.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 Index: 2006-08-16/xen/arch/x86/x86_64/asm-offsets.c =================================================================== --- 2006-08-16.orig/xen/arch/x86/x86_64/asm-offsets.c 2006-08-25 15:32:40.000000000 +0200 +++ 2006-08-16/xen/arch/x86/x86_64/asm-offsets.c 2006-08-25 15:32:49.000000000 +0200 @@ -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); @@ -86,6 +87,10 @@ void __dummy__(void) OFFSET(VCPU_vmx_launched, struct vcpu, arch.hvm_vmx.launched); 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(); Index: 2006-08-16/xen/arch/x86/x86_64/compat/entry.S =================================================================== --- /dev/null 1970-01-01 00:00:00.000000000 +0000 +++ 2006-08-16/xen/arch/x86/x86_64/compat/entry.S 2006-08-25 15:32:49.000000000 +0200 @@ -0,0 +1,369 @@ +/* + * Compatibility hypercall routines. + * + * Copyright (c) 2005, K A Fraser + */ + +#include + +.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 $8,%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 $0xfffcbeff,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 + movl %eax,UREGS_cs+8(%rsp) + movl TRAPBOUNCE_eip(%rdx),%eax + testl %eax,%eax + jz domain_crash_synchronous + 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,domain_crash_synchronous + .quad CFLT3,domain_crash_synchronous, CFLT4,domain_crash_synchronous + .quad CFLT5,domain_crash_synchronous, CFLT6,domain_crash_synchronous + .quad CFLT7,domain_crash_synchronous, CFLT8,domain_crash_synchronous + .quad CFLT9,domain_crash_synchronous, CFLT10,domain_crash_synchronous + .quad CFLT11,domain_crash_synchronous, CFLT12,domain_crash_synchronous + .quad CFLT13,CFIX13 +.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_dom0_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 + +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_dom0_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 + .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_dom0_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 */ + .rept NR_hypercalls-(.-compat_hypercall_args_table) + .byte 0 /* do_ni_hypercall */ + .endr Index: 2006-08-16/xen/arch/x86/x86_64/compat/traps.c =================================================================== --- /dev/null 1970-01-01 00:00:00.000000000 +0000 +++ 2006-08-16/xen/arch/x86/x86_64/compat/traps.c 2006-08-25 15:32:49.000000000 +0200 @@ -0,0 +1,264 @@ +#ifdef CONFIG_COMPAT + +#if 0 /* XXX */ +#include +#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) +{ + int i; + unsigned int *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 long compat_iret(void) +{ + struct cpu_user_regs *regs = guest_cpu_user_regs(); + u32 eflags; + + /* Check worst-case stack frame for overlap with Xen protected area. */ + if ( unlikely(regs->_esp != regs->rsp) ) + domain_crash_synchronous(); + + /* Pop and restore EAX (clobbered by hypercall). */ + if ( unlikely(__copy_from_user(®s->_eax, (void __user *)regs->rsp, 4)) ) + domain_crash_synchronous(); + regs->_esp += 4; + + /* Pop and restore CS and EIP. */ + if ( unlikely(__copy_from_user(®s->_eip, (void __user *)regs->rsp, 8)) ) + domain_crash_synchronous(); + regs->_esp += 8; + + /* + * Pop, 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(__copy_from_user(&eflags, (void __user *)regs->rsp, 4)) ) + domain_crash_synchronous(); + regs->_esp += 4; + if ( unlikely(eflags & X86_EFLAGS_VM) ) + domain_crash_synchronous(); /* XXX */ + regs->_eflags = (eflags & ~X86_EFLAGS_IOPL) | X86_EFLAGS_IF; + + if ( unlikely(ring_0(regs)) ) + domain_crash_synchronous(); + if ( !ring_1(regs) ) + { + /* Return to ring 2/3: pop and restore ESP and SS. */ + if ( __copy_from_user(®s->_esp, (void __user *)regs->rsp, 8) ) + domain_crash_synchronous(); + } + + /* 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; +} + +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 $,%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: + */ Index: 2006-08-16/xen/arch/x86/x86_64/entry.S =================================================================== --- 2006-08-16.orig/xen/arch/x86/x86_64/entry.S 2006-08-25 15:32:40.000000000 +0200 +++ 2006-08-16/xen/arch/x86/x86_64/entry.S 2006-08-25 15:32:49.000000000 +0200 @@ -334,8 +334,15 @@ domain_crash_synchronous: 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. */ @@ -353,6 +360,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 +624,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 Index: 2006-08-16/xen/arch/x86/x86_64/traps.c =================================================================== --- 2006-08-16.orig/xen/arch/x86/x86_64/traps.c 2006-08-25 15:32:40.000000000 +0200 +++ 2006-08-16/xen/arch/x86/x86_64/traps.c 2006-08-25 15:32:49.000000000 +0200 @@ -228,6 +228,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; @@ -239,6 +240,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(); @@ -479,12 +485,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 ( hvm_guest(d->vcpu[0]) ) hvm_hypercall_page_initialise(d, hypercall_page); - else + else if ( !IS_COMPAT(d) ) hypercall_page_initialise_ring3_kernel(hypercall_page); + else + hypercall_page_initialise_ring1_kernel(hypercall_page); } /* Index: 2006-08-16/xen/include/asm-x86/processor.h =================================================================== --- 2006-08-16.orig/xen/include/asm-x86/processor.h 2006-08-25 15:32:40.000000000 +0200 +++ 2006-08-16/xen/include/asm-x86/processor.h 2006-08-25 15:32:49.000000000 +0200 @@ -558,6 +558,12 @@ void show_execution_state(struct cpu_use 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(). */ \ --=__Part2E0B8913.0__= Content-Type: text/plain; charset="us-ascii" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit Content-Disposition: inline _______________________________________________ Xen-devel mailing list Xen-devel@lists.xensource.com http://lists.xensource.com/xen-devel --=__Part2E0B8913.0__=--