From: kaf24@firebug.cl.cam.ac.uk Date: Fri, 26 Aug 2005 17:42:34 +0000 (+0000) Subject: Clean up and fix hypercall macros in XenLinux: we must assume that X-Git-Tag: archive/raspbian/4.8.0-1+rpi1~1^2~16814^2~86^2~1 X-Git-Url: https://dgit.raspbian.org/?a=commitdiff_plain;h=edf2226577a60fe13d1a363b24cd54edce6c33f4;p=xen.git Clean up and fix hypercall macros in XenLinux: we must assume that all register parameters are clobbered on return. Furthermore, multicall arrays are clobbered on return from a multicall (only the result field can be trusted!). These restrictions are enforced by debug builds of Xen in the following ways: 1. On completion of a multicall, the call array is overwritten with garbage before writing in the result fields. 2. On completion of a hypercall, all parameter registers are overwritten with garbage. Signed-off-by: Keir Fraser --- diff --git a/linux-2.6-xen-sparse/drivers/xen/privcmd/privcmd.c b/linux-2.6-xen-sparse/drivers/xen/privcmd/privcmd.c index c1f3508dd9..68107dfac4 100644 --- a/linux-2.6-xen-sparse/drivers/xen/privcmd/privcmd.c +++ b/linux-2.6-xen-sparse/drivers/xen/privcmd/privcmd.c @@ -63,16 +63,19 @@ static int privcmd_ioctl(struct inode *inode, struct file *file, "popl %%edi; popl %%esi; popl %%edx; popl %%ecx; popl %%ebx" : "=a" (ret) : "0" (&hypercall) : "memory" ); #elif defined (__x86_64__) - __asm__ __volatile__ ( - "movq %5,%%r10; movq %6,%%r8;" TRAP_INSTR - : "=a" (ret) - : "a" ((unsigned long)hypercall.op), - "D" ((unsigned long)hypercall.arg[0]), - "S" ((unsigned long)hypercall.arg[1]), - "d" ((unsigned long)hypercall.arg[2]), - "g" ((unsigned long)hypercall.arg[3]), - "g" ((unsigned long)hypercall.arg[4]) - : "r11","rcx","r8","r10","memory"); + { + long ign1, ign2, ign3; + __asm__ __volatile__ ( + "movq %5,%%r10; movq %6,%%r8;" TRAP_INSTR + : "=a" (ret), "=D" (ign1), "=S" (ign2), "=d" (ign3) + : "0" ((unsigned long)hypercall.op), + "1" ((unsigned long)hypercall.arg[0]), + "2" ((unsigned long)hypercall.arg[1]), + "3" ((unsigned long)hypercall.arg[2]), + "g" ((unsigned long)hypercall.arg[3]), + "g" ((unsigned long)hypercall.arg[4]) + : "r11","rcx","r8","r10","memory"); + } #endif } break; diff --git a/linux-2.6-xen-sparse/include/asm-xen/asm-i386/hypercall.h b/linux-2.6-xen-sparse/include/asm-xen/asm-i386/hypercall.h index b8191cc3e3..cef2389a5e 100644 --- a/linux-2.6-xen-sparse/include/asm-xen/asm-i386/hypercall.h +++ b/linux-2.6-xen-sparse/include/asm-xen/asm-i386/hypercall.h @@ -29,551 +29,362 @@ #ifndef __HYPERCALL_H__ #define __HYPERCALL_H__ + #include -/* - * Assembler stubs for hyper-calls. - */ +#define _hypercall0(type, name) \ +({ \ + long __res; \ + asm volatile ( \ + TRAP_INSTR \ + : "=a" (__res) \ + : "0" (__HYPERVISOR_##name) \ + : "memory" ); \ + (type)__res; \ +}) + +#define _hypercall1(type, name, a1) \ +({ \ + long __res, __ign1; \ + asm volatile ( \ + TRAP_INSTR \ + : "=a" (__res), "=b" (__ign1) \ + : "0" (__HYPERVISOR_##name), "1" ((long)(a1)) \ + : "memory" ); \ + (type)__res; \ +}) + +#define _hypercall2(type, name, a1, a2) \ +({ \ + long __res, __ign1, __ign2; \ + asm volatile ( \ + TRAP_INSTR \ + : "=a" (__res), "=b" (__ign1), "=c" (__ign2) \ + : "0" (__HYPERVISOR_##name), "1" ((long)(a1)), \ + "2" ((long)(a2)) \ + : "memory" ); \ + (type)__res; \ +}) + +#define _hypercall3(type, name, a1, a2, a3) \ +({ \ + long __res, __ign1, __ign2, __ign3; \ + asm volatile ( \ + TRAP_INSTR \ + : "=a" (__res), "=b" (__ign1), "=c" (__ign2), \ + "=d" (__ign3) \ + : "0" (__HYPERVISOR_##name), "1" ((long)(a1)), \ + "2" ((long)(a2)), "3" ((long)(a3)) \ + : "memory" ); \ + (type)__res; \ +}) + +#define _hypercall4(type, name, a1, a2, a3, a4) \ +({ \ + long __res, __ign1, __ign2, __ign3, __ign4; \ + asm volatile ( \ + TRAP_INSTR \ + : "=a" (__res), "=b" (__ign1), "=c" (__ign2), \ + "=d" (__ign3), "=S" (__ign4) \ + : "0" (__HYPERVISOR_##name), "1" ((long)(a1)), \ + "2" ((long)(a2)), "3" ((long)(a3)), \ + "4" ((long)(a4)) \ + : "memory" ); \ + (type)__res; \ +}) + +#define _hypercall5(type, name, a1, a2, a3, a4, a5) \ +({ \ + long __res, __ign1, __ign2, __ign3, __ign4, __ign5; \ + asm volatile ( \ + TRAP_INSTR \ + : "=a" (__res), "=b" (__ign1), "=c" (__ign2), \ + "=d" (__ign3), "=S" (__ign4), "=D" (__ign5) \ + : "0" (__HYPERVISOR_##name), "1" ((long)(a1)), \ + "2" ((long)(a2)), "3" ((long)(a3)), \ + "4" ((long)(a4)), "5" ((long)(a5)) \ + : "memory" ); \ + (type)__res; \ +}) static inline int HYPERVISOR_set_trap_table( - trap_info_t *table) + trap_info_t *table) { - int ret; - unsigned long ignore; - - __asm__ __volatile__ ( - TRAP_INSTR - : "=a" (ret), "=b" (ignore) - : "0" (__HYPERVISOR_set_trap_table), "1" (table) - : "memory" ); - - return ret; + return _hypercall1(int, set_trap_table, table); } static inline int HYPERVISOR_mmu_update( - mmu_update_t *req, int count, int *success_count, domid_t domid) + mmu_update_t *req, int count, int *success_count, domid_t domid) { - int ret; - unsigned long ign1, ign2, ign3, ign4; - - __asm__ __volatile__ ( - TRAP_INSTR - : "=a" (ret), "=b" (ign1), "=c" (ign2), "=d" (ign3), "=S" (ign4) - : "0" (__HYPERVISOR_mmu_update), "1" (req), "2" (count), - "3" (success_count), "4" (domid) - : "memory" ); - - return ret; + return _hypercall4(int, mmu_update, req, count, success_count, domid); } static inline int HYPERVISOR_mmuext_op( - struct mmuext_op *op, int count, int *success_count, domid_t domid) + struct mmuext_op *op, int count, int *success_count, domid_t domid) { - int ret; - unsigned long ign1, ign2, ign3, ign4; - - __asm__ __volatile__ ( - TRAP_INSTR - : "=a" (ret), "=b" (ign1), "=c" (ign2), "=d" (ign3), "=S" (ign4) - : "0" (__HYPERVISOR_mmuext_op), "1" (op), "2" (count), - "3" (success_count), "4" (domid) - : "memory" ); - - return ret; + return _hypercall4(int, mmuext_op, op, count, success_count, domid); } static inline int HYPERVISOR_set_gdt( - unsigned long *frame_list, int entries) + unsigned long *frame_list, int entries) { - int ret; - unsigned long ign1, ign2; - - __asm__ __volatile__ ( - TRAP_INSTR - : "=a" (ret), "=b" (ign1), "=c" (ign2) - : "0" (__HYPERVISOR_set_gdt), "1" (frame_list), "2" (entries) - : "memory" ); - - - return ret; + return _hypercall2(int, set_gdt, frame_list, entries); } static inline int HYPERVISOR_stack_switch( - unsigned long ss, unsigned long esp) + unsigned long ss, unsigned long esp) { - int ret; - unsigned long ign1, ign2; - - __asm__ __volatile__ ( - TRAP_INSTR - : "=a" (ret), "=b" (ign1), "=c" (ign2) - : "0" (__HYPERVISOR_stack_switch), "1" (ss), "2" (esp) - : "memory" ); - - return ret; + return _hypercall2(int, stack_switch, ss, esp); } static inline int HYPERVISOR_set_callbacks( - unsigned long event_selector, unsigned long event_address, - unsigned long failsafe_selector, unsigned long failsafe_address) + unsigned long event_selector, unsigned long event_address, + unsigned long failsafe_selector, unsigned long failsafe_address) { - int ret; - unsigned long ign1, ign2, ign3, ign4; - - __asm__ __volatile__ ( - TRAP_INSTR - : "=a" (ret), "=b" (ign1), "=c" (ign2), "=d" (ign3), "=S" (ign4) - : "0" (__HYPERVISOR_set_callbacks), "1" (event_selector), - "2" (event_address), "3" (failsafe_selector), "4" (failsafe_address) - : "memory" ); - - return ret; + return _hypercall4(int, set_callbacks, + event_selector, event_address, + failsafe_selector, failsafe_address); } static inline int HYPERVISOR_fpu_taskswitch( - int set) + int set) { - int ret; - unsigned long ign; - - __asm__ __volatile__ ( - TRAP_INSTR - : "=a" (ret), "=b" (ign) - : "0" (__HYPERVISOR_fpu_taskswitch), "1" (set) - : "memory" ); - - return ret; + return _hypercall1(int, fpu_taskswitch, set); } static inline int HYPERVISOR_yield( - void) + void) { - int ret; - unsigned long ign; - - __asm__ __volatile__ ( - TRAP_INSTR - : "=a" (ret), "=b" (ign) - : "0" (__HYPERVISOR_sched_op), "1" (SCHEDOP_yield) - : "memory", "ecx" ); - - return ret; + return _hypercall2(int, sched_op, SCHEDOP_yield, 0); } static inline int HYPERVISOR_block( - void) + void) { - int ret; - unsigned long ign1; - __asm__ __volatile__ ( - TRAP_INSTR - : "=a" (ret), "=b" (ign1) - : "0" (__HYPERVISOR_sched_op), "1" (SCHEDOP_block) - : "memory", "ecx" ); - - return ret; + return _hypercall2(int, sched_op, SCHEDOP_block, 0); } static inline int HYPERVISOR_shutdown( - void) + void) { - int ret; - unsigned long ign1; - __asm__ __volatile__ ( - TRAP_INSTR - : "=a" (ret), "=b" (ign1) - : "0" (__HYPERVISOR_sched_op), - "1" (SCHEDOP_shutdown | (SHUTDOWN_poweroff << SCHEDOP_reasonshift)) - : "memory", "ecx" ); - - return ret; + return _hypercall2(int, sched_op, SCHEDOP_shutdown | + (SHUTDOWN_poweroff << SCHEDOP_reasonshift), 0); } static inline int HYPERVISOR_reboot( - void) -{ - int ret; - unsigned long ign1; - __asm__ __volatile__ ( - TRAP_INSTR - : "=a" (ret), "=b" (ign1) - : "0" (__HYPERVISOR_sched_op), - "1" (SCHEDOP_shutdown | (SHUTDOWN_reboot << SCHEDOP_reasonshift)) - : "memory", "ecx" ); - - return ret; -} - -static inline int -HYPERVISOR_suspend( - unsigned long srec) + void) { - int ret; - unsigned long ign1, ign2; - - /* NB. On suspend, control software expects a suspend record in %esi. */ - __asm__ __volatile__ ( - TRAP_INSTR - : "=a" (ret), "=b" (ign1), "=S" (ign2) - : "0" (__HYPERVISOR_sched_op), - "b" (SCHEDOP_shutdown | (SHUTDOWN_suspend << SCHEDOP_reasonshift)), - "S" (srec) : "memory", "ecx"); - - return ret; + return _hypercall2(int, sched_op, SCHEDOP_shutdown | + (SHUTDOWN_reboot << SCHEDOP_reasonshift), 0); } static inline int HYPERVISOR_crash( - void) + void) { - int ret; - unsigned long ign1; - __asm__ __volatile__ ( - TRAP_INSTR - : "=a" (ret), "=b" (ign1) - : "0" (__HYPERVISOR_sched_op), - "1" (SCHEDOP_shutdown | (SHUTDOWN_crash << SCHEDOP_reasonshift)) - : "memory", "ecx" ); - - return ret; + return _hypercall2(int, sched_op, SCHEDOP_shutdown | + (SHUTDOWN_crash << SCHEDOP_reasonshift), 0); } static inline long HYPERVISOR_set_timer_op( - u64 timeout) + u64 timeout) { - int ret; - unsigned long timeout_hi = (unsigned long)(timeout>>32); - unsigned long timeout_lo = (unsigned long)timeout; - unsigned long ign1, ign2; - - __asm__ __volatile__ ( - TRAP_INSTR - : "=a" (ret), "=b" (ign1), "=c" (ign2) - : "0" (__HYPERVISOR_set_timer_op), "b" (timeout_lo), "c" (timeout_hi) - : "memory"); - - return ret; + unsigned long timeout_hi = (unsigned long)(timeout>>32); + unsigned long timeout_lo = (unsigned long)timeout; + return _hypercall2(long, set_timer_op, timeout_lo, timeout_hi); } static inline int HYPERVISOR_dom0_op( - dom0_op_t *dom0_op) + dom0_op_t *dom0_op) { - int ret; - unsigned long ign1; - - dom0_op->interface_version = DOM0_INTERFACE_VERSION; - __asm__ __volatile__ ( - TRAP_INSTR - : "=a" (ret), "=b" (ign1) - : "0" (__HYPERVISOR_dom0_op), "1" (dom0_op) - : "memory"); - - return ret; + dom0_op->interface_version = DOM0_INTERFACE_VERSION; + return _hypercall1(int, dom0_op, dom0_op); } static inline int HYPERVISOR_set_debugreg( - int reg, unsigned long value) + int reg, unsigned long value) { - int ret; - unsigned long ign1, ign2; - __asm__ __volatile__ ( - TRAP_INSTR - : "=a" (ret), "=b" (ign1), "=c" (ign2) - : "0" (__HYPERVISOR_set_debugreg), "1" (reg), "2" (value) - : "memory" ); - - return ret; + return _hypercall2(int, set_debugreg, reg, value); } static inline unsigned long HYPERVISOR_get_debugreg( - int reg) + int reg) { - unsigned long ret; - unsigned long ign; - __asm__ __volatile__ ( - TRAP_INSTR - : "=a" (ret), "=b" (ign) - : "0" (__HYPERVISOR_get_debugreg), "1" (reg) - : "memory" ); - - return ret; + return _hypercall1(unsigned long, get_debugreg, reg); } static inline int HYPERVISOR_update_descriptor( - u64 ma, u64 desc) + u64 ma, u64 desc) { - int ret; - unsigned long ign1, ign2, ign3, ign4; - - __asm__ __volatile__ ( - TRAP_INSTR - : "=a" (ret), "=b" (ign1), "=c" (ign2), "=d" (ign3), "=S" (ign4) - : "0" (__HYPERVISOR_update_descriptor), - "1" ((unsigned long)ma), "2" ((unsigned long)(ma>>32)), - "3" ((unsigned long)desc), "4" ((unsigned long)(desc>>32)) - : "memory" ); - - return ret; + return _hypercall4(int, update_descriptor, ma, ma>>32, desc, desc>>32); } static inline int HYPERVISOR_dom_mem_op( - unsigned int op, unsigned long *extent_list, - unsigned long nr_extents, unsigned int extent_order) + unsigned int op, unsigned long *extent_list, + unsigned long nr_extents, unsigned int extent_order) { - int ret; - unsigned long ign1, ign2, ign3, ign4, ign5; - - __asm__ __volatile__ ( - TRAP_INSTR - : "=a" (ret), "=b" (ign1), "=c" (ign2), "=d" (ign3), "=S" (ign4), - "=D" (ign5) - : "0" (__HYPERVISOR_dom_mem_op), "1" (op), "2" (extent_list), - "3" (nr_extents), "4" (extent_order), "5" (DOMID_SELF) - : "memory" ); - - return ret; + return _hypercall5(int, dom_mem_op, op, extent_list, + nr_extents, extent_order, DOMID_SELF); } static inline int HYPERVISOR_multicall( - void *call_list, int nr_calls) + void *call_list, int nr_calls) { - int ret; - unsigned long ign1, ign2; - - __asm__ __volatile__ ( - TRAP_INSTR - : "=a" (ret), "=b" (ign1), "=c" (ign2) - : "0" (__HYPERVISOR_multicall), "1" (call_list), "2" (nr_calls) - : "memory" ); - - return ret; + return _hypercall2(int, multicall, call_list, nr_calls); } static inline int HYPERVISOR_update_va_mapping( - unsigned long va, pte_t new_val, unsigned long flags) + unsigned long va, pte_t new_val, unsigned long flags) { - int ret; - unsigned long ign1, ign2, ign3, ign4; - - __asm__ __volatile__ ( - TRAP_INSTR - : "=a" (ret), "=b" (ign1), "=c" (ign2), "=d" (ign3), "=S" (ign4) - : "0" (__HYPERVISOR_update_va_mapping), - "1" (va), "2" ((new_val).pte_low), + unsigned long pte_hi = 0; #ifdef CONFIG_X86_PAE - "3" ((new_val).pte_high), -#else - "3" (0), + pte_hi = new_val.pte_high; #endif - "4" (flags) - : "memory" ); - - return ret; + return _hypercall4(int, update_va_mapping, va, + new_val.pte_low, pte_hi, flags); } static inline int HYPERVISOR_event_channel_op( - void *op) + void *op) { - int ret; - unsigned long ignore; - __asm__ __volatile__ ( - TRAP_INSTR - : "=a" (ret), "=b" (ignore) - : "0" (__HYPERVISOR_event_channel_op), "1" (op) - : "memory" ); - - return ret; + return _hypercall1(int, event_channel_op, op); } static inline int HYPERVISOR_xen_version( - int cmd) + int cmd) { - int ret; - unsigned long ignore; - - __asm__ __volatile__ ( - TRAP_INSTR - : "=a" (ret), "=b" (ignore) - : "0" (__HYPERVISOR_xen_version), "1" (cmd) - : "memory" ); - - return ret; + return _hypercall1(int, xen_version, cmd); } static inline int HYPERVISOR_console_io( - int cmd, int count, char *str) + int cmd, int count, char *str) { - int ret; - unsigned long ign1, ign2, ign3; - __asm__ __volatile__ ( - TRAP_INSTR - : "=a" (ret), "=b" (ign1), "=c" (ign2), "=d" (ign3) - : "0" (__HYPERVISOR_console_io), "1" (cmd), "2" (count), "3" (str) - : "memory" ); - - return ret; + return _hypercall3(int, console_io, cmd, count, str); } static inline int HYPERVISOR_physdev_op( - void *physdev_op) + void *physdev_op) { - int ret; - unsigned long ign; - - __asm__ __volatile__ ( - TRAP_INSTR - : "=a" (ret), "=b" (ign) - : "0" (__HYPERVISOR_physdev_op), "1" (physdev_op) - : "memory" ); - - return ret; + return _hypercall1(int, physdev_op, physdev_op); } static inline int HYPERVISOR_grant_table_op( - unsigned int cmd, void *uop, unsigned int count) + unsigned int cmd, void *uop, unsigned int count) { - int ret; - unsigned long ign1, ign2, ign3; - - __asm__ __volatile__ ( - TRAP_INSTR - : "=a" (ret), "=b" (ign1), "=c" (ign2), "=d" (ign3) - : "0" (__HYPERVISOR_grant_table_op), "1" (cmd), "2" (uop), "3" (count) - : "memory" ); - - return ret; + return _hypercall3(int, grant_table_op, cmd, uop, count); } static inline int HYPERVISOR_update_va_mapping_otherdomain( - unsigned long va, pte_t new_val, unsigned long flags, domid_t domid) + unsigned long va, pte_t new_val, unsigned long flags, domid_t domid) { - int ret; - unsigned long ign1, ign2, ign3, ign4, ign5; - - __asm__ __volatile__ ( - TRAP_INSTR - : "=a" (ret), "=b" (ign1), "=c" (ign2), "=d" (ign3), - "=S" (ign4), "=D" (ign5) - : "0" (__HYPERVISOR_update_va_mapping_otherdomain), - "1" (va), "2" ((new_val).pte_low), + unsigned long pte_hi = 0; #ifdef CONFIG_X86_PAE - "3" ((new_val).pte_high), -#else - "3" (0), + pte_hi = new_val.pte_high; #endif - "4" (flags), "5" (domid) : - "memory" ); - - return ret; + return _hypercall5(int, update_va_mapping_otherdomain, va, + new_val.pte_low, pte_hi, flags, domid); } static inline int HYPERVISOR_vm_assist( - unsigned int cmd, unsigned int type) + unsigned int cmd, unsigned int type) { - int ret; - unsigned long ign1, ign2; - - __asm__ __volatile__ ( - TRAP_INSTR - : "=a" (ret), "=b" (ign1), "=c" (ign2) - : "0" (__HYPERVISOR_vm_assist), "1" (cmd), "2" (type) - : "memory" ); - - return ret; + return _hypercall2(int, vm_assist, cmd, type); } static inline int HYPERVISOR_boot_vcpu( - unsigned long vcpu, vcpu_guest_context_t *ctxt) + unsigned long vcpu, vcpu_guest_context_t *ctxt) { - int ret; - unsigned long ign1, ign2; - - __asm__ __volatile__ ( - TRAP_INSTR - : "=a" (ret), "=b" (ign1), "=c" (ign2) - : "0" (__HYPERVISOR_boot_vcpu), "1" (vcpu), "2" (ctxt) - : "memory"); - - return ret; + return _hypercall2(int, boot_vcpu, vcpu, ctxt); } static inline int -HYPERVISOR_vcpu_down( - int vcpu) +HYPERVISOR_vcpu_up( + int vcpu) { - int ret; - unsigned long ign1; - /* Yes, I really do want to clobber edx here: when we resume a - vcpu after unpickling a multi-processor domain, it returns - here, but clobbers all of the call clobbered registers. */ - __asm__ __volatile__ ( - TRAP_INSTR - : "=a" (ret), "=b" (ign1) - : "0" (__HYPERVISOR_sched_op), - "1" (SCHEDOP_vcpu_down | (vcpu << SCHEDOP_vcpushift)) - : "memory", "ecx", "edx" ); - - return ret; + return _hypercall2(int, sched_op, SCHEDOP_vcpu_up | + (vcpu << SCHEDOP_vcpushift), 0); } static inline int -HYPERVISOR_vcpu_up( - int vcpu) +HYPERVISOR_vcpu_pickle( + int vcpu, vcpu_guest_context_t *ctxt) { - int ret; - unsigned long ign1; - __asm__ __volatile__ ( - TRAP_INSTR - : "=a" (ret), "=b" (ign1) - : "0" (__HYPERVISOR_sched_op), - "1" (SCHEDOP_vcpu_up | (vcpu << SCHEDOP_vcpushift)) - : "memory", "ecx" ); - - return ret; + return _hypercall2(int, sched_op, SCHEDOP_vcpu_pickle | + (vcpu << SCHEDOP_vcpushift), ctxt); } static inline int -HYPERVISOR_vcpu_pickle( - int vcpu, vcpu_guest_context_t *ctxt) +HYPERVISOR_suspend( + unsigned long srec) { - int ret; - unsigned long ign1, ign2; - __asm__ __volatile__ ( - TRAP_INSTR - : "=a" (ret), "=b" (ign1), "=c" (ign2) - : "0" (__HYPERVISOR_sched_op), - "1" (SCHEDOP_vcpu_pickle | (vcpu << SCHEDOP_vcpushift)), - "2" (ctxt) - : "memory" ); + int ret; + unsigned long ign1, ign2; + + /* On suspend, control software expects a suspend record in %esi. */ + __asm__ __volatile__ ( + TRAP_INSTR + : "=a" (ret), "=b" (ign1), "=S" (ign2) + : "0" (__HYPERVISOR_sched_op), + "1" (SCHEDOP_shutdown | (SHUTDOWN_suspend << + SCHEDOP_reasonshift)), + "2" (srec) : "memory", "ecx"); - return ret; + return ret; +} + +static inline int +HYPERVISOR_vcpu_down( + int vcpu) +{ + int ret; + unsigned long ign1; + /* Yes, I really do want to clobber edx here: when we resume a + vcpu after unpickling a multi-processor domain, it returns + here, but clobbers all of the call clobbered registers. */ + __asm__ __volatile__ ( + TRAP_INSTR + : "=a" (ret), "=b" (ign1) + : "0" (__HYPERVISOR_sched_op), + "1" (SCHEDOP_vcpu_down | (vcpu << SCHEDOP_vcpushift)) + : "memory", "ecx", "edx" ); + return ret; } #endif /* __HYPERCALL_H__ */ + +/* + * Local variables: + * c-file-style: "linux" + * indent-tabs-mode: t + * c-indent-level: 8 + * c-basic-offset: 8 + * tab-width: 8 + * End: + */ diff --git a/linux-2.6-xen-sparse/include/asm-xen/asm-x86_64/hypercall.h b/linux-2.6-xen-sparse/include/asm-xen/asm-x86_64/hypercall.h index d382b16abb..b94728293a 100644 --- a/linux-2.6-xen-sparse/include/asm-xen/asm-x86_64/hypercall.h +++ b/linux-2.6-xen-sparse/include/asm-xen/asm-x86_64/hypercall.h @@ -5,6 +5,10 @@ * * Copyright (c) 2002-2004, K A Fraser * + * 64-bit updates: + * Benjamin Liu + * Jun Nakajima + * * This file may be distributed separately from the Linux kernel, or * incorporated into other software packages, subject to the following license: * @@ -26,497 +30,331 @@ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS * IN THE SOFTWARE. */ -/* - * Benjamin Liu - * Jun Nakajima - * Ported to x86-64. - * - */ #ifndef __HYPERCALL_H__ #define __HYPERCALL_H__ + #include #define __syscall_clobber "r11","rcx","memory" -/* - * Assembler stubs for hyper-calls. - */ +#define _hypercall0(type, name) \ +({ \ + long __res; \ + asm volatile ( \ + TRAP_INSTR \ + : "=a" (__res) \ + : "0" (__HYPERVISOR_##name) \ + : __syscall_clobber ); \ + (type)__res; \ +}) + +#define _hypercall1(type, name, a1) \ +({ \ + long __res, __ign1; \ + asm volatile ( \ + TRAP_INSTR \ + : "=a" (__res), "=D" (__ign1) \ + : "0" (__HYPERVISOR_##name), "1" ((long)(a1)) \ + : __syscall_clobber ); \ + (type)__res; \ +}) + +#define _hypercall2(type, name, a1, a2) \ +({ \ + long __res, __ign1, __ign2; \ + asm volatile ( \ + TRAP_INSTR \ + : "=a" (__res), "=D" (__ign1), "=S" (__ign2) \ + : "0" (__HYPERVISOR_##name), "1" ((long)(a1)), \ + "2" ((long)(a2)) \ + : __syscall_clobber ); \ + (type)__res; \ +}) + +#define _hypercall3(type, name, a1, a2, a3) \ +({ \ + long __res, __ign1, __ign2, __ign3; \ + asm volatile ( \ + TRAP_INSTR \ + : "=a" (__res), "=D" (__ign1), "=S" (__ign2), \ + "=d" (__ign3) \ + : "0" (__HYPERVISOR_##name), "1" ((long)(a1)), \ + "2" ((long)(a2)), "3" ((long)(a3)) \ + : __syscall_clobber ); \ + (type)__res; \ +}) + +#define _hypercall4(type, name, a1, a2, a3, a4) \ +({ \ + long __res, __ign1, __ign2, __ign3; \ + asm volatile ( \ + "movq %8,%%r10; " TRAP_INSTR \ + : "=a" (__res), "=D" (__ign1), "=S" (__ign2), \ + "=d" (__ign3) \ + : "0" (__HYPERVISOR_##name), "1" ((long)(a1)), \ + "2" ((long)(a2)), "3" ((long)(a3)), \ + "g" ((long)(a4)) \ + : __syscall_clobber, "r10" ); \ + (type)__res; \ +}) + +#define _hypercall5(type, name, a1, a2, a3, a4, a5) \ +({ \ + long __res, __ign1, __ign2, __ign3; \ + asm volatile ( \ + "movq %8,%%r10; movq %9,%%r8; " TRAP_INSTR \ + : "=a" (__res), "=D" (__ign1), "=S" (__ign2), \ + "=d" (__ign3) \ + : "0" (__HYPERVISOR_##name), "1" ((long)(a1)), \ + "2" ((long)(a2)), "3" ((long)(a3)), \ + "g" ((long)(a4)), "g" ((long)(a5)) \ + : __syscall_clobber, "r10", "r8" ); \ + (type)__res; \ +}) + static inline int HYPERVISOR_set_trap_table( - trap_info_t *table) + trap_info_t *table) { - int ret; - - __asm__ __volatile__ ( - TRAP_INSTR - : "=a" (ret) - : "0" ((unsigned long)__HYPERVISOR_set_trap_table), "D" (table) - : __syscall_clobber ); - - return ret; + return _hypercall1(int, set_trap_table, table); } static inline int HYPERVISOR_mmu_update( - mmu_update_t *req, int count, int *success_count, domid_t domid) + mmu_update_t *req, int count, int *success_count, domid_t domid) { - int ret; - - __asm__ __volatile__ ( - "movq %5, %%r10;" TRAP_INSTR - : "=a" (ret) - : "0" ((unsigned long)__HYPERVISOR_mmu_update), "D" (req), "S" ((long)count), - "d" (success_count), "g" ((unsigned long)domid) - : __syscall_clobber, "r10" ); - - return ret; + return _hypercall4(int, mmu_update, req, count, success_count, domid); } static inline int HYPERVISOR_mmuext_op( - struct mmuext_op *op, int count, int *success_count, domid_t domid) + struct mmuext_op *op, int count, int *success_count, domid_t domid) { - int ret; - - __asm__ __volatile__ ( - "movq %5, %%r10;" TRAP_INSTR - : "=a" (ret) - : "0" (__HYPERVISOR_mmuext_op), "D" (op), "S" ((long)count), - "d" (success_count), "g" ((unsigned long)domid) - : __syscall_clobber, "r10" ); - - return ret; + return _hypercall4(int, mmuext_op, op, count, success_count, domid); } static inline int HYPERVISOR_set_gdt( - unsigned long *frame_list, int entries) + unsigned long *frame_list, int entries) { - int ret; - - __asm__ __volatile__ ( - TRAP_INSTR - : "=a" (ret) - : "0" ((unsigned long)__HYPERVISOR_set_gdt), "D" (frame_list), "S" ((long)entries) - : __syscall_clobber ); - - - return ret; + return _hypercall2(int, set_gdt, frame_list, entries); } + static inline int HYPERVISOR_stack_switch( - unsigned long ss, unsigned long esp) + unsigned long ss, unsigned long esp) { - int ret; - - __asm__ __volatile__ ( - TRAP_INSTR - : "=a" (ret) - : "0" ((unsigned long)__HYPERVISOR_stack_switch), "D" (ss), "S" (esp) - : __syscall_clobber ); - - return ret; + return _hypercall2(int, stack_switch, ss, esp); } static inline int HYPERVISOR_set_callbacks( - unsigned long event_address, unsigned long failsafe_address, - unsigned long syscall_address) + unsigned long event_address, unsigned long failsafe_address, + unsigned long syscall_address) { - int ret; - - __asm__ __volatile__ ( - TRAP_INSTR - : "=a" (ret) - : "0" ((unsigned long)__HYPERVISOR_set_callbacks), "D" (event_address), - "S" (failsafe_address), "d" (syscall_address) - : __syscall_clobber ); - - return ret; + return _hypercall3(int, set_callbacks, + event_address, failsafe_address, syscall_address); } static inline int HYPERVISOR_fpu_taskswitch( - int set) + int set) { - int ret; - __asm__ __volatile__ ( - TRAP_INSTR - : "=a" (ret) : "0" ((unsigned long)__HYPERVISOR_fpu_taskswitch), - "D" ((unsigned long) set) : __syscall_clobber ); - - return ret; + return _hypercall1(int, fpu_taskswitch, set); } static inline int HYPERVISOR_yield( - void) + void) { - int ret; - - __asm__ __volatile__ ( - TRAP_INSTR - : "=a" (ret) - : "0" ((unsigned long)__HYPERVISOR_sched_op), "D" ((unsigned long)SCHEDOP_yield) - : __syscall_clobber ); - - return ret; + return _hypercall2(int, sched_op, SCHEDOP_yield, 0); } static inline int HYPERVISOR_block( - void) + void) { - int ret; - __asm__ __volatile__ ( - TRAP_INSTR - : "=a" (ret) - : "0" ((unsigned long)__HYPERVISOR_sched_op), "D" ((unsigned long)SCHEDOP_block) - : __syscall_clobber ); - - return ret; + return _hypercall2(int, sched_op, SCHEDOP_block, 0); } static inline int HYPERVISOR_shutdown( - void) + void) { - int ret; - __asm__ __volatile__ ( - TRAP_INSTR - : "=a" (ret) - : "0" ((unsigned long)__HYPERVISOR_sched_op), - "D" ((unsigned long)(SCHEDOP_shutdown | (SHUTDOWN_poweroff << SCHEDOP_reasonshift))) - : __syscall_clobber ); - - return ret; + return _hypercall2(int, sched_op, SCHEDOP_shutdown | + (SHUTDOWN_poweroff << SCHEDOP_reasonshift), 0); } static inline int HYPERVISOR_reboot( - void) + void) { - int ret; - - __asm__ __volatile__ ( - TRAP_INSTR - : "=a" (ret) - : "0" ((unsigned long)__HYPERVISOR_sched_op), - "D" ((unsigned long)(SCHEDOP_shutdown | (SHUTDOWN_reboot << SCHEDOP_reasonshift))) - : __syscall_clobber ); - - return ret; + return _hypercall2(int, sched_op, SCHEDOP_shutdown | + (SHUTDOWN_reboot << SCHEDOP_reasonshift), 0); } -static inline int -HYPERVISOR_suspend( - unsigned long srec) -{ - int ret; - - /* NB. On suspend, control software expects a suspend record in %esi. */ - __asm__ __volatile__ ( - TRAP_INSTR - : "=a" (ret) - : "0" ((unsigned long)__HYPERVISOR_sched_op), - "D" ((unsigned long)(SCHEDOP_shutdown | (SHUTDOWN_suspend << SCHEDOP_reasonshift))), - "S" (srec) - : __syscall_clobber ); - - return ret; -} - -/* - * We can have the timeout value in a single argument for the hypercall, but - * that will break the common code. - */ static inline long HYPERVISOR_set_timer_op( - u64 timeout) + u64 timeout) { - int ret; - - __asm__ __volatile__ ( - TRAP_INSTR - : "=a" (ret) - : "0" ((unsigned long)__HYPERVISOR_set_timer_op), - "D" (timeout) - : __syscall_clobber ); - - return ret; + return _hypercall1(long, set_timer_op, timeout); } static inline int HYPERVISOR_dom0_op( - dom0_op_t *dom0_op) + dom0_op_t *dom0_op) { - int ret; - - dom0_op->interface_version = DOM0_INTERFACE_VERSION; - __asm__ __volatile__ ( - TRAP_INSTR - : "=a" (ret) - : "0" ((unsigned long)__HYPERVISOR_dom0_op), "D" (dom0_op) - : __syscall_clobber ); - - return ret; + dom0_op->interface_version = DOM0_INTERFACE_VERSION; + return _hypercall1(int, dom0_op, dom0_op); } static inline int HYPERVISOR_set_debugreg( - int reg, unsigned long value) + int reg, unsigned long value) { - int ret; - - __asm__ __volatile__ ( - TRAP_INSTR - : "=a" (ret) - : "0" ((unsigned long)__HYPERVISOR_set_debugreg), "D" ((unsigned long)reg), "S" (value) - : __syscall_clobber ); - - return ret; + return _hypercall2(int, set_debugreg, reg, value); } static inline unsigned long HYPERVISOR_get_debugreg( - int reg) + int reg) { - unsigned long ret; - - __asm__ __volatile__ ( - TRAP_INSTR - : "=a" (ret) - : "0" ((unsigned long)__HYPERVISOR_get_debugreg), "D" ((unsigned long)reg) - : __syscall_clobber ); - - return ret; + return _hypercall1(unsigned long, get_debugreg, reg); } static inline int HYPERVISOR_update_descriptor( - unsigned long ma, unsigned long word) + unsigned long ma, unsigned long word) { - int ret; - - __asm__ __volatile__ ( - TRAP_INSTR - : "=a" (ret) - : "0" ((unsigned long)__HYPERVISOR_update_descriptor), "D" (ma), - "S" (word) - : __syscall_clobber ); - - return ret; + return _hypercall2(int, update_descriptor, ma, word); } static inline int HYPERVISOR_dom_mem_op( - unsigned int op, unsigned long *extent_list, - unsigned long nr_extents, unsigned int extent_order) + unsigned int op, unsigned long *extent_list, + unsigned long nr_extents, unsigned int extent_order) { - int ret; - - __asm__ __volatile__ ( - "movq %5,%%r10; movq %6,%%r8;" TRAP_INSTR - : "=a" (ret) - : "0" ((unsigned long)__HYPERVISOR_dom_mem_op), "D" ((unsigned long)op), "S" (extent_list), - "d" (nr_extents), "g" ((unsigned long) extent_order), "g" ((unsigned long) DOMID_SELF) - : __syscall_clobber,"r8","r10"); - - return ret; + return _hypercall5(int, dom_mem_op, op, extent_list, + nr_extents, extent_order, DOMID_SELF); } static inline int HYPERVISOR_multicall( - void *call_list, int nr_calls) + void *call_list, int nr_calls) { - int ret; - - __asm__ __volatile__ ( - TRAP_INSTR - : "=a" (ret) - : "0" ((unsigned long)__HYPERVISOR_multicall), "D" (call_list), "S" ((unsigned long)nr_calls) - : __syscall_clobber); - - return ret; + return _hypercall2(int, multicall, call_list, nr_calls); } static inline int HYPERVISOR_update_va_mapping( - unsigned long page_nr, pte_t new_val, unsigned long flags) + unsigned long va, pte_t new_val, unsigned long flags) { - int ret; - - __asm__ __volatile__ ( - TRAP_INSTR - : "=a" (ret) - : "0" ((unsigned long)__HYPERVISOR_update_va_mapping), - "D" (page_nr), "S" (new_val.pte), "d" (flags) - : __syscall_clobber); - - return ret; + return _hypercall3(int, update_va_mapping, va, new_val.pte, flags); } static inline int HYPERVISOR_event_channel_op( - void *op) + void *op) { - int ret; - __asm__ __volatile__ ( - TRAP_INSTR - : "=a" (ret) - : "0" ((unsigned long)__HYPERVISOR_event_channel_op), "D" (op) - : __syscall_clobber); - - return ret; + return _hypercall1(int, event_channel_op, op); } static inline int HYPERVISOR_xen_version( - int cmd) + int cmd) { - int ret; - - __asm__ __volatile__ ( - TRAP_INSTR - : "=a" (ret) - : "0" ((unsigned long)__HYPERVISOR_xen_version), "D" ((unsigned long)cmd) - : __syscall_clobber); - - return ret; + return _hypercall1(int, xen_version, cmd); } static inline int HYPERVISOR_console_io( - int cmd, int count, char *str) + int cmd, int count, char *str) { - int ret; - __asm__ __volatile__ ( - TRAP_INSTR - : "=a" (ret) - : "0" ((unsigned long)__HYPERVISOR_console_io), "D" ((unsigned long)cmd), "S" ((unsigned long)count), "d" (str) - : __syscall_clobber); - - return ret; + return _hypercall3(int, console_io, cmd, count, str); } static inline int HYPERVISOR_physdev_op( - void *physdev_op) + void *physdev_op) { - int ret; - - __asm__ __volatile__ ( - TRAP_INSTR - : "=a" (ret) - : "0" ((unsigned long)__HYPERVISOR_physdev_op), "D" (physdev_op) - : __syscall_clobber); - - return ret; + return _hypercall1(int, physdev_op, physdev_op); } static inline int HYPERVISOR_grant_table_op( - unsigned int cmd, void *uop, unsigned int count) + unsigned int cmd, void *uop, unsigned int count) { - int ret; - - __asm__ __volatile__ ( - TRAP_INSTR - : "=a" (ret) - : "0" ((unsigned long)__HYPERVISOR_grant_table_op), "D" ((unsigned long)cmd), "S" ((unsigned long)uop), "d" (count) - : __syscall_clobber); - - return ret; + return _hypercall3(int, grant_table_op, cmd, uop, count); } static inline int HYPERVISOR_update_va_mapping_otherdomain( - unsigned long page_nr, pte_t new_val, unsigned long flags, domid_t domid) + unsigned long va, pte_t new_val, unsigned long flags, domid_t domid) { - int ret; - - __asm__ __volatile__ ( - "movq %5, %%r10;" TRAP_INSTR - : "=a" (ret) - : "0" ((unsigned long)__HYPERVISOR_update_va_mapping_otherdomain), - "D" (page_nr), "S" (new_val.pte), "d" (flags), "g" ((unsigned long)domid) - : __syscall_clobber,"r10"); - - return ret; + return _hypercall4(int, update_va_mapping_otherdomain, va, + new_val.pte, flags, domid); } static inline int HYPERVISOR_vm_assist( - unsigned int cmd, unsigned int type) + unsigned int cmd, unsigned int type) { - int ret; - - __asm__ __volatile__ ( - TRAP_INSTR - : "=a" (ret) - : "0" ((unsigned long)__HYPERVISOR_vm_assist), "D" ((unsigned long)cmd), "S" ((unsigned long)type) - : __syscall_clobber); - - return ret; + return _hypercall2(int, vm_assist, cmd, type); } static inline int -HYPERVISOR_switch_to_user(void) +HYPERVISOR_boot_vcpu( + unsigned long vcpu, vcpu_guest_context_t *ctxt) { - int ret; - __asm__ __volatile__ ( - TRAP_INSTR - : "=a" (ret) : "0" ((unsigned long)__HYPERVISOR_switch_to_user) : __syscall_clobber ); - - return ret; + return _hypercall2(int, boot_vcpu, vcpu, ctxt); } static inline int -HYPERVISOR_boot_vcpu( - unsigned long vcpu, vcpu_guest_context_t *ctxt) +HYPERVISOR_vcpu_up( + int vcpu) { - int ret; + return _hypercall2(int, sched_op, SCHEDOP_vcpu_up | + (vcpu << SCHEDOP_vcpushift), 0); +} - __asm__ __volatile__ ( - TRAP_INSTR - : "=a" (ret) - : "0" (__HYPERVISOR_boot_vcpu), "D" (vcpu), "S" (ctxt) - : __syscall_clobber); +static inline int +HYPERVISOR_vcpu_pickle( + int vcpu, vcpu_guest_context_t *ctxt) +{ + return _hypercall2(int, sched_op, SCHEDOP_vcpu_pickle | + (vcpu << SCHEDOP_vcpushift), ctxt); +} - return ret; +static inline int +HYPERVISOR_switch_to_user(void) +{ + return _hypercall0(int, switch_to_user); } static inline int HYPERVISOR_set_segment_base( - int reg, unsigned long value) + int reg, unsigned long value) { - int ret; - - __asm__ __volatile__ ( - TRAP_INSTR - : "=a" (ret) - : "0" ((unsigned long)__HYPERVISOR_set_segment_base), "D" ((unsigned long)reg), "S" (value) - : __syscall_clobber ); - - return ret; + return _hypercall2(int, set_segment_base, reg, value); } static inline int -HYPERVISOR_vcpu_pickle( - int vcpu, vcpu_guest_context_t *ctxt) +HYPERVISOR_suspend( + unsigned long srec) { - int ret; - - __asm__ __volatile__ ( - TRAP_INSTR - : "=a" (ret) - : "0" ((unsigned long)__HYPERVISOR_sched_op), - "D" ((unsigned long)SCHEDOP_vcpu_pickle | (vcpu << SCHEDOP_vcpushift)), - "S" ((unsigned long)ctxt) - : __syscall_clobber ); - - return ret; + return _hypercall2(int, sched_op, SCHEDOP_shutdown | + (SHUTDOWN_suspend << SCHEDOP_reasonshift), srec); } #endif /* __HYPERCALL_H__ */ + +/* + * Local variables: + * c-file-style: "linux" + * indent-tabs-mode: t + * c-indent-level: 8 + * c-basic-offset: 8 + * tab-width: 8 + * End: + */ diff --git a/xen/arch/x86/x86_32/asm-offsets.c b/xen/arch/x86/x86_32/asm-offsets.c index 2a9f84ba4c..22b911fd04 100644 --- a/xen/arch/x86/x86_32/asm-offsets.c +++ b/xen/arch/x86/x86_32/asm-offsets.c @@ -71,6 +71,9 @@ void __dummy__(void) OFFSET(VCPUINFO_upcall_mask, vcpu_info_t, evtchn_upcall_mask); BLANK(); + DEFINE(CPUINFO_sizeof, sizeof(struct cpu_info)); + BLANK(); + OFFSET(TRAPBOUNCE_error_code, struct trap_bounce, error_code); OFFSET(TRAPBOUNCE_cr2, struct trap_bounce, cr2); OFFSET(TRAPBOUNCE_flags, struct trap_bounce, flags); diff --git a/xen/arch/x86/x86_32/entry.S b/xen/arch/x86/x86_32/entry.S index 911594b910..e6a7b5b543 100644 --- a/xen/arch/x86/x86_32/entry.S +++ b/xen/arch/x86/x86_32/entry.S @@ -61,6 +61,11 @@ #include #include +#define GET_GUEST_REGS(reg) \ + movl $~(STACK_SIZE-1),reg; \ + andl %esp,reg; \ + orl $(STACK_SIZE-CPUINFO_sizeof),reg; + #define GET_CURRENT(reg) \ movl $STACK_SIZE-4, reg; \ orl %esp, reg; \ @@ -273,7 +278,41 @@ ENTRY(hypercall) GET_CURRENT(%ebx) andl $(NR_hypercalls-1),%eax PERFC_INCR(PERFC_hypercalls, %eax) +#ifndef NDEBUG + /* Deliberately corrupt parameter regs not used by this hypercall. */ + pushl %eax + pushl UREGS_eip+4(%esp) + pushl 28(%esp) # EBP + pushl 28(%esp) # EDI + pushl 28(%esp) # ESI + pushl 28(%esp) # EDX + pushl 28(%esp) # ECX + pushl 28(%esp) # EBX + movzb hypercall_args_table(,%eax,1),%ecx + leal (%esp,%ecx,4),%edi + subl $6,%ecx + negl %ecx + movl %eax,%esi + movl $0xDEADBEEF,%eax + rep stosl + movl %esi,%eax +#endif call *hypercall_table(,%eax,4) +#ifndef NDEBUG + /* Deliberately corrupt parameter regs used by this hypercall. */ + addl $24,%esp # Shadow parameters + popl %ecx # Shadow EIP + cmpl %ecx,UREGS_eip(%esp) + popl %ecx # Shadow hypercall index + jne skip_clobber # If EIP has changed then don't clobber + movzb hypercall_args_table(,%ecx,1),%ecx + movl %esp,%edi + movl %eax,%esi + movl $0xDEADBEEF,%eax + rep stosl + movl %esi,%eax +skip_clobber: +#endif movl %eax,UREGS_eax(%esp) # save the return value test_all_events: @@ -674,12 +713,14 @@ ENTRY(setup_vm86_frame) do_arch_sched_op: # Ensure we return success even if we return via schedule_tail() xorl %eax,%eax - movl %eax,UREGS_eax+4(%esp) + GET_GUEST_REGS(%ecx) + movl %eax,UREGS_eax(%ecx) jmp do_sched_op do_switch_vm86: - # Discard the return address - addl $4,%esp + # Reset the stack pointer + GET_GUEST_REGS(%ecx) + movl %ecx,%esp # GS:ESI == Ring-1 stack activation movl UREGS_esp(%esp),%esi @@ -768,3 +809,36 @@ ENTRY(hypercall_table) .rept NR_hypercalls-((.-hypercall_table)/4) .long do_ni_hypercall .endr + +ENTRY(hypercall_args_table) + .byte 1 /* do_set_trap_table */ /* 0 */ + .byte 4 /* do_mmu_update */ + .byte 2 /* do_set_gdt */ + .byte 2 /* do_stack_switch */ + .byte 4 /* do_set_callbacks */ + .byte 1 /* do_fpu_taskswitch */ /* 5 */ + .byte 2 /* do_arch_sched_op */ + .byte 1 /* do_dom0_op */ + .byte 2 /* do_set_debugreg */ + .byte 1 /* do_get_debugreg */ + .byte 4 /* do_update_descriptor */ /* 10 */ + .byte 0 /* do_ni_hypercall */ + .byte 5 /* do_dom_mem_op */ + .byte 2 /* do_multicall */ + .byte 4 /* do_update_va_mapping */ + .byte 2 /* do_set_timer_op */ /* 15 */ + .byte 1 /* do_event_channel_op */ + .byte 1 /* do_xen_version */ + .byte 3 /* do_console_io */ + .byte 1 /* do_physdev_op */ + .byte 3 /* do_grant_table_op */ /* 20 */ + .byte 2 /* do_vm_assist */ + .byte 5 /* do_update_va_mapping_otherdomain */ + .byte 0 /* do_switch_vm86 */ + .byte 2 /* do_boot_vcpu */ + .byte 0 /* do_ni_hypercall */ /* 25 */ + .byte 4 /* do_mmuext_op */ + .byte 1 /* do_acm_op */ + .rept NR_hypercalls-(.-hypercall_args_table) + .byte 0 /* do_ni_hypercall */ + .endr diff --git a/xen/arch/x86/x86_64/asm-offsets.c b/xen/arch/x86/x86_64/asm-offsets.c index d19610a99f..742212154a 100644 --- a/xen/arch/x86/x86_64/asm-offsets.c +++ b/xen/arch/x86/x86_64/asm-offsets.c @@ -71,6 +71,9 @@ void __dummy__(void) OFFSET(VCPUINFO_upcall_mask, vcpu_info_t, evtchn_upcall_mask); BLANK(); + DEFINE(CPUINFO_sizeof, sizeof(struct cpu_info)); + BLANK(); + OFFSET(TRAPBOUNCE_error_code, struct trap_bounce, error_code); OFFSET(TRAPBOUNCE_cr2, struct trap_bounce, cr2); OFFSET(TRAPBOUNCE_flags, struct trap_bounce, flags); diff --git a/xen/arch/x86/x86_64/entry.S b/xen/arch/x86/x86_64/entry.S index 3db22487bf..0474a0dba5 100644 --- a/xen/arch/x86/x86_64/entry.S +++ b/xen/arch/x86/x86_64/entry.S @@ -12,6 +12,11 @@ #include #include +#define GET_GUEST_REGS(reg) \ + movq $~(STACK_SIZE-1),reg; \ + andq %rsp,reg; \ + orq $(STACK_SIZE-CPUINFO_sizeof),reg; + #define GET_CURRENT(reg) \ movq $STACK_SIZE-8, reg; \ orq %rsp, reg; \ @@ -120,10 +125,42 @@ ENTRY(syscall_enter) /*hypercall:*/ movq %r10,%rcx andq $(NR_hypercalls-1),%rax +#ifndef NDEBUG + /* Deliberately corrupt parameter regs not used by this hypercall. */ + pushq %rdi; pushq %rsi; pushq %rdx; pushq %rcx; pushq %r8 ; pushq %r9 + leaq hypercall_args_table(%rip),%r10 + movq $6,%rcx + sub (%r10,%rax,1),%cl + movq %rsp,%rdi + movl $0xDEADBEEF,%eax + rep stosq + popq %r9 ; popq %r8 ; popq %rcx; popq %rdx; popq %rsi; popq %rdi + movq UREGS_rax(%rsp),%rax + andq $(NR_hypercalls-1),%rax + pushq %rax + pushq UREGS_rip+8(%rsp) +#endif leaq hypercall_table(%rip),%r10 PERFC_INCR(PERFC_hypercalls, %rax) callq *(%r10,%rax,8) - movq %rax,UREGS_rax(%rsp) # save the return value +#ifndef NDEBUG + /* Deliberately corrupt parameter regs used by this hypercall. */ + popq %r10 # Shadow RIP + cmpq %r10,UREGS_rip(%rsp) + popq %rcx # Shadow hypercall index + jne skip_clobber /* If RIP has changed then don't clobber. */ + leaq hypercall_args_table(%rip),%r10 + movb (%r10,%rcx,1),%cl + movl $0xDEADBEEF,%r10d + cmpb $1,%cl; jb skip_clobber; movq %r10,UREGS_rdi(%rsp) + cmpb $2,%cl; jb skip_clobber; movq %r10,UREGS_rsi(%rsp) + cmpb $3,%cl; jb skip_clobber; movq %r10,UREGS_rdx(%rsp) + cmpb $4,%cl; jb skip_clobber; movq %r10,UREGS_r10(%rsp) + cmpb $5,%cl; jb skip_clobber; movq %r10,UREGS_r8(%rsp) + cmpb $6,%cl; jb skip_clobber; movq %r10,UREGS_r9(%rsp) +skip_clobber: +#endif + movq %rax,UREGS_rax(%rsp) # save the return value /* %rbx: struct vcpu */ test_all_events: @@ -538,7 +575,8 @@ ENTRY(nmi) do_arch_sched_op: # Ensure we return success even if we return via schedule_tail() xorl %eax,%eax - movq %rax,UREGS_rax+8(%rsp) + GET_GUEST_REGS(%r10) + movq %rax,UREGS_rax(%r10) jmp do_sched_op .data @@ -597,3 +635,36 @@ ENTRY(hypercall_table) .rept NR_hypercalls-((.-hypercall_table)/4) .quad do_ni_hypercall .endr + +ENTRY(hypercall_args_table) + .byte 1 /* do_set_trap_table */ /* 0 */ + .byte 4 /* do_mmu_update */ + .byte 2 /* do_set_gdt */ + .byte 2 /* do_stack_switch */ + .byte 3 /* do_set_callbacks */ + .byte 1 /* do_fpu_taskswitch */ /* 5 */ + .byte 2 /* do_arch_sched_op */ + .byte 1 /* do_dom0_op */ + .byte 2 /* do_set_debugreg */ + .byte 1 /* do_get_debugreg */ + .byte 2 /* do_update_descriptor */ /* 10 */ + .byte 0 /* do_ni_hypercall */ + .byte 5 /* do_dom_mem_op */ + .byte 2 /* do_multicall */ + .byte 3 /* do_update_va_mapping */ + .byte 1 /* do_set_timer_op */ /* 15 */ + .byte 1 /* do_event_channel_op */ + .byte 1 /* do_xen_version */ + .byte 3 /* do_console_io */ + .byte 1 /* do_physdev_op */ + .byte 3 /* do_grant_table_op */ /* 20 */ + .byte 2 /* do_vm_assist */ + .byte 4 /* do_update_va_mapping_otherdomain */ + .byte 0 /* do_switch_to_user */ + .byte 2 /* do_boot_vcpu */ + .byte 2 /* do_set_segment_base */ /* 25 */ + .byte 4 /* do_mmuext_op */ + .byte 1 /* do_acm_op */ + .rept NR_hypercalls-(.-hypercall_args_table) + .byte 0 /* do_ni_hypercall */ + .endr diff --git a/xen/common/multicall.c b/xen/common/multicall.c index a3af8ef221..a811f68266 100644 --- a/xen/common/multicall.c +++ b/xen/common/multicall.c @@ -45,6 +45,18 @@ long do_multicall(multicall_entry_t *call_list, unsigned int nr_calls) do_multicall_call(&mcs->call); +#ifndef NDEBUG + { + /* + * Deliberately corrupt the contents of the multicall structure. + * The caller must depend only on the 'result' field on return. + */ + multicall_entry_t corrupt; + memset(&corrupt, 0xAA, sizeof(corrupt)); + (void)__copy_to_user(&call_list[i], &corrupt, sizeof(corrupt)); + } +#endif + if ( unlikely(__put_user(mcs->call.result, &call_list[i].result)) ) { DPRINTK("Error writing result back to multicall block.\n");