diff --git a/xen/arch/x86/hvm/hypercall.c b/xen/arch/x86/hvm/hypercall.c index a9c9ad721f..ae601185fc 100644 --- a/xen/arch/x86/hvm/hypercall.c +++ b/xen/arch/x86/hvm/hypercall.c @@ -111,56 +111,10 @@ long cf_check hvm_physdev_op(int cmd, XEN_GUEST_HANDLE_PARAM(void) arg) return compat_physdev_op(cmd, arg); } -#define HYPERCALL(x) \ - [ __HYPERVISOR_ ## x ] = { (hypercall_fn_t *) do_ ## x, \ - (hypercall_fn_t *) do_ ## x } - -#define HVM_CALL(x) \ - [ __HYPERVISOR_ ## x ] = { (hypercall_fn_t *) hvm_ ## x, \ - (hypercall_fn_t *) hvm_ ## x } - -#define COMPAT_CALL(x) \ - [ __HYPERVISOR_ ## x ] = { (hypercall_fn_t *) do_ ## x, \ - (hypercall_fn_t *) compat_ ## x } - -static const struct { - hypercall_fn_t *native, *compat; -} hvm_hypercall_table[] = { - HVM_CALL(memory_op), - COMPAT_CALL(multicall), -#ifdef CONFIG_GRANT_TABLE - HVM_CALL(grant_table_op), +#ifndef NDEBUG +static const unsigned char hypercall_args_64[] = hypercall_args_hvm64; +static const unsigned char hypercall_args_32[] = hypercall_args_hvm32; #endif - HYPERCALL(vm_assist), - COMPAT_CALL(vcpu_op), - HVM_CALL(physdev_op), - COMPAT_CALL(xen_version), - HYPERCALL(console_io), - HYPERCALL(event_channel_op), - COMPAT_CALL(sched_op), - COMPAT_CALL(set_timer_op), - COMPAT_CALL(xsm_op), - HYPERCALL(hvm_op), - HYPERCALL(sysctl), - HYPERCALL(domctl), -#ifdef CONFIG_ARGO - COMPAT_CALL(argo_op), -#endif - COMPAT_CALL(platform_op), -#ifdef CONFIG_PV - COMPAT_CALL(mmuext_op), -#endif - HYPERCALL(xenpmu_op), - COMPAT_CALL(dm_op), -#ifdef CONFIG_HYPFS - HYPERCALL(hypfs_op), -#endif - HYPERCALL(paging_domctl_cont) -}; - -#undef HYPERCALL -#undef HVM_CALL -#undef COMPAT_CALL int hvm_hypercall(struct cpu_user_regs *regs) { @@ -206,23 +160,6 @@ int hvm_hypercall(struct cpu_user_regs *regs) return ret; } - BUILD_BUG_ON(ARRAY_SIZE(hvm_hypercall_table) > - ARRAY_SIZE(hypercall_args_table)); - - if ( eax >= ARRAY_SIZE(hvm_hypercall_table) ) - { - regs->rax = -ENOSYS; - return HVM_HCALL_completed; - } - - eax = array_index_nospec(eax, ARRAY_SIZE(hvm_hypercall_table)); - - if ( !hvm_hypercall_table[eax].native ) - { - regs->rax = -ENOSYS; - return HVM_HCALL_completed; - } - /* * Caching is intended for instruction emulation only. Disable it * for any accesses by hypercall argument copy-in / copy-out. @@ -233,85 +170,27 @@ int hvm_hypercall(struct cpu_user_regs *regs) if ( mode == 8 ) { - unsigned long rdi = regs->rdi; - unsigned long rsi = regs->rsi; - unsigned long rdx = regs->rdx; - unsigned long r10 = regs->r10; - unsigned long r8 = regs->r8; - HVM_DBG_LOG(DBG_LEVEL_HCALL, "hcall%lu(%lx, %lx, %lx, %lx, %lx)", - eax, rdi, rsi, rdx, r10, r8); + eax, regs->rdi, regs->rsi, regs->rdx, regs->r10, regs->r8); -#ifndef NDEBUG - /* Deliberately corrupt parameter regs not used by this hypercall. */ - switch ( hypercall_args_table[eax].native ) - { - case 0: rdi = 0xdeadbeefdeadf00dUL; fallthrough; - case 1: rsi = 0xdeadbeefdeadf00dUL; fallthrough; - case 2: rdx = 0xdeadbeefdeadf00dUL; fallthrough; - case 3: r10 = 0xdeadbeefdeadf00dUL; fallthrough; - case 4: r8 = 0xdeadbeefdeadf00dUL; - } -#endif + call_handlers_hvm64(eax, regs->rax, regs->rdi, regs->rsi, regs->rdx, + regs->r10, regs->r8); - regs->rax = hvm_hypercall_table[eax].native(rdi, rsi, rdx, r10, r8); - -#ifndef NDEBUG - if ( !curr->hcall_preempted ) - { - /* Deliberately corrupt parameter regs used by this hypercall. */ - switch ( hypercall_args_table[eax].native ) - { - case 5: regs->r8 = 0xdeadbeefdeadf00dUL; fallthrough; - case 4: regs->r10 = 0xdeadbeefdeadf00dUL; fallthrough; - case 3: regs->rdx = 0xdeadbeefdeadf00dUL; fallthrough; - case 2: regs->rsi = 0xdeadbeefdeadf00dUL; fallthrough; - case 1: regs->rdi = 0xdeadbeefdeadf00dUL; - } - } -#endif + if ( !curr->hcall_preempted && regs->rax != -ENOSYS ) + clobber_regs(regs, get_nargs(hypercall_args_64, eax)); } else { - unsigned int ebx = regs->ebx; - unsigned int ecx = regs->ecx; - unsigned int edx = regs->edx; - unsigned int esi = regs->esi; - unsigned int edi = regs->edi; - HVM_DBG_LOG(DBG_LEVEL_HCALL, "hcall%lu(%x, %x, %x, %x, %x)", eax, - ebx, ecx, edx, esi, edi); - -#ifndef NDEBUG - /* Deliberately corrupt parameter regs not used by this hypercall. */ - switch ( hypercall_args_table[eax].compat ) - { - case 0: ebx = 0xdeadf00d; fallthrough; - case 1: ecx = 0xdeadf00d; fallthrough; - case 2: edx = 0xdeadf00d; fallthrough; - case 3: esi = 0xdeadf00d; fallthrough; - case 4: edi = 0xdeadf00d; - } -#endif + regs->ebx, regs->ecx, regs->edx, regs->esi, regs->edi); curr->hcall_compat = true; - regs->eax = hvm_hypercall_table[eax].compat(ebx, ecx, edx, esi, edi); + call_handlers_hvm32(eax, regs->eax, regs->ebx, regs->ecx, regs->edx, + regs->esi, regs->edi); curr->hcall_compat = false; -#ifndef NDEBUG - if ( !curr->hcall_preempted ) - { - /* Deliberately corrupt parameter regs used by this hypercall. */ - switch ( hypercall_args_table[eax].compat ) - { - case 5: regs->rdi = 0xdeadf00d; fallthrough; - case 4: regs->rsi = 0xdeadf00d; fallthrough; - case 3: regs->rdx = 0xdeadf00d; fallthrough; - case 2: regs->rcx = 0xdeadf00d; fallthrough; - case 1: regs->rbx = 0xdeadf00d; - } - } -#endif + if ( !curr->hcall_preempted && regs->eax != -ENOSYS ) + clobber_regs32(regs, get_nargs(hypercall_args_32, eax)); } hvmemul_cache_restore(curr, token); @@ -332,31 +211,20 @@ int hvm_hypercall(struct cpu_user_regs *regs) enum mc_disposition hvm_do_multicall_call(struct mc_state *state) { struct vcpu *curr = current; - hypercall_fn_t *func = NULL; if ( hvm_guest_x86_mode(curr) == 8 ) { struct multicall_entry *call = &state->call; - if ( call->op < ARRAY_SIZE(hvm_hypercall_table) ) - func = array_access_nospec(hvm_hypercall_table, call->op).native; - if ( func ) - call->result = func(call->args[0], call->args[1], call->args[2], - call->args[3], call->args[4]); - else - call->result = -ENOSYS; + call_handlers_hvm64(call->op, call->result, call->args[0], call->args[1], + call->args[2], call->args[3], call->args[4]); } else { struct compat_multicall_entry *call = &state->compat_call; - if ( call->op < ARRAY_SIZE(hvm_hypercall_table) ) - func = array_access_nospec(hvm_hypercall_table, call->op).compat; - if ( func ) - call->result = func(call->args[0], call->args[1], call->args[2], - call->args[3], call->args[4]); - else - call->result = -ENOSYS; + call_handlers_hvm32(call->op, call->result, call->args[0], call->args[1], + call->args[2], call->args[3], call->args[4]); } return !hvm_get_cpl(curr) ? mc_continue : mc_preempt; diff --git a/xen/arch/x86/hypercall.c b/xen/arch/x86/hypercall.c index 07e1a45ef5..6b73cff9b9 100644 --- a/xen/arch/x86/hypercall.c +++ b/xen/arch/x86/hypercall.c @@ -22,65 +22,6 @@ #include #include -#ifdef CONFIG_COMPAT -#define ARGS(x, n) \ - [ __HYPERVISOR_ ## x ] = { n, n } -#define COMP(x, n, c) \ - [ __HYPERVISOR_ ## x ] = { n, c } -#else -#define ARGS(x, n) [ __HYPERVISOR_ ## x ] = { n } -#define COMP(x, n, c) ARGS(x, n) -#endif - -const hypercall_args_t hypercall_args_table[NR_hypercalls] = -{ - ARGS(set_trap_table, 1), - ARGS(mmu_update, 4), - ARGS(set_gdt, 2), - ARGS(stack_switch, 2), - COMP(set_callbacks, 3, 4), - ARGS(fpu_taskswitch, 1), - ARGS(sched_op_compat, 2), - ARGS(platform_op, 1), - ARGS(set_debugreg, 2), - ARGS(get_debugreg, 1), - COMP(update_descriptor, 2, 4), - ARGS(memory_op, 2), - ARGS(multicall, 2), - COMP(update_va_mapping, 3, 4), - COMP(set_timer_op, 1, 2), - ARGS(event_channel_op_compat, 1), - ARGS(xen_version, 2), - ARGS(console_io, 3), - ARGS(physdev_op_compat, 1), - ARGS(grant_table_op, 3), - ARGS(vm_assist, 2), - COMP(update_va_mapping_otherdomain, 4, 5), - ARGS(vcpu_op, 3), - COMP(set_segment_base, 2, 0), - ARGS(mmuext_op, 4), - ARGS(xsm_op, 1), - ARGS(nmi_op, 2), - ARGS(sched_op, 2), - ARGS(callback_op, 2), - ARGS(xenoprof_op, 2), - ARGS(event_channel_op, 2), - ARGS(physdev_op, 2), - ARGS(sysctl, 1), - ARGS(domctl, 1), - ARGS(kexec_op, 2), - ARGS(argo_op, 5), - ARGS(xenpmu_op, 2), - ARGS(hvm_op, 2), - ARGS(dm_op, 3), - ARGS(hypfs_op, 5), - ARGS(mca, 1), - ARGS(paging_domctl_cont, 1), -}; - -#undef COMP -#undef ARGS - #define NEXT_ARG(fmt, args) \ ({ \ unsigned long __arg; \ diff --git a/xen/arch/x86/include/asm/hypercall.h b/xen/arch/x86/include/asm/hypercall.h index 2d243b48bc..ab8bd12e60 100644 --- a/xen/arch/x86/include/asm/hypercall.h +++ b/xen/arch/x86/include/asm/hypercall.h @@ -17,19 +17,6 @@ #define __HYPERVISOR_paging_domctl_cont __HYPERVISOR_arch_1 -typedef unsigned long hypercall_fn_t( - unsigned long, unsigned long, unsigned long, - unsigned long, unsigned long); - -typedef struct { - uint8_t native; -#ifdef CONFIG_COMPAT - uint8_t compat; -#endif -} hypercall_args_t; - -extern const hypercall_args_t hypercall_args_table[NR_hypercalls]; - #ifdef CONFIG_PV void pv_hypercall(struct cpu_user_regs *regs); #endif @@ -56,4 +43,46 @@ compat_common_vcpu_op( #endif /* CONFIG_COMPAT */ +#ifndef NDEBUG +static inline unsigned int _get_nargs(const unsigned char *tbl, unsigned int c) +{ + return tbl[c]; +} +#define get_nargs(t, c) _get_nargs(t, array_index_nospec(c, ARRAY_SIZE(t))) +#else +#define get_nargs(tbl, c) 0 +#endif + +static inline void clobber_regs(struct cpu_user_regs *regs, + unsigned int nargs) +{ +#ifndef NDEBUG + /* Deliberately corrupt used parameter regs. */ + switch ( nargs ) + { + case 5: regs->r8 = 0xdeadbeefdeadf00dUL; fallthrough; + case 4: regs->r10 = 0xdeadbeefdeadf00dUL; fallthrough; + case 3: regs->rdx = 0xdeadbeefdeadf00dUL; fallthrough; + case 2: regs->rsi = 0xdeadbeefdeadf00dUL; fallthrough; + case 1: regs->rdi = 0xdeadbeefdeadf00dUL; + } +#endif +} + +static inline void clobber_regs32(struct cpu_user_regs *regs, + unsigned int nargs) +{ +#ifndef NDEBUG + /* Deliberately corrupt used parameter regs. */ + switch ( nargs ) + { + case 5: regs->edi = 0xdeadf00dU; fallthrough; + case 4: regs->esi = 0xdeadf00dU; fallthrough; + case 3: regs->edx = 0xdeadf00dU; fallthrough; + case 2: regs->ecx = 0xdeadf00dU; fallthrough; + case 1: regs->ebx = 0xdeadf00dU; + } +#endif +} + #endif /* __ASM_X86_HYPERCALL_H__ */ diff --git a/xen/arch/x86/pv/hypercall.c b/xen/arch/x86/pv/hypercall.c index fe8dfe9e8f..bf64bb41bb 100644 --- a/xen/arch/x86/pv/hypercall.c +++ b/xen/arch/x86/pv/hypercall.c @@ -27,119 +27,22 @@ #include #include -typedef struct { - hypercall_fn_t *native; +#ifndef NDEBUG +static const unsigned char hypercall_args_64[] = hypercall_args_pv64; #ifdef CONFIG_PV32 - hypercall_fn_t *compat; +static const unsigned char hypercall_args_32[] = hypercall_args_pv32; #endif -} pv_hypercall_table_t; - -#ifdef CONFIG_PV32 -#define HYPERCALL(x) \ - [ __HYPERVISOR_ ## x ] = { (hypercall_fn_t *) do_ ## x, \ - (hypercall_fn_t *) do_ ## x } -#define COMPAT_CALL(x) \ - [ __HYPERVISOR_ ## x ] = { (hypercall_fn_t *) do_ ## x, \ - (hypercall_fn_t *) compat_ ## x } -#else -#define HYPERCALL(x) \ - [ __HYPERVISOR_ ## x ] = { (hypercall_fn_t *) do_ ## x } -#define COMPAT_CALL(x) HYPERCALL(x) #endif -static const pv_hypercall_table_t pv_hypercall_table[] = { - COMPAT_CALL(set_trap_table), - HYPERCALL(mmu_update), - COMPAT_CALL(set_gdt), - HYPERCALL(stack_switch), - COMPAT_CALL(set_callbacks), - HYPERCALL(fpu_taskswitch), - HYPERCALL(sched_op_compat), -#ifndef CONFIG_PV_SHIM_EXCLUSIVE - COMPAT_CALL(platform_op), -#endif - HYPERCALL(set_debugreg), - HYPERCALL(get_debugreg), - COMPAT_CALL(update_descriptor), - COMPAT_CALL(memory_op), - COMPAT_CALL(multicall), - COMPAT_CALL(update_va_mapping), - COMPAT_CALL(set_timer_op), - HYPERCALL(event_channel_op_compat), - COMPAT_CALL(xen_version), - HYPERCALL(console_io), - COMPAT_CALL(physdev_op_compat), -#if defined(CONFIG_GRANT_TABLE) || defined(CONFIG_PV_SHIM) - COMPAT_CALL(grant_table_op), -#endif - HYPERCALL(vm_assist), - COMPAT_CALL(update_va_mapping_otherdomain), - COMPAT_CALL(iret), - COMPAT_CALL(vcpu_op), - HYPERCALL(set_segment_base), - COMPAT_CALL(mmuext_op), - COMPAT_CALL(xsm_op), - COMPAT_CALL(nmi_op), - COMPAT_CALL(sched_op), - COMPAT_CALL(callback_op), -#ifdef CONFIG_XENOPROF - COMPAT_CALL(xenoprof_op), -#endif - HYPERCALL(event_channel_op), - COMPAT_CALL(physdev_op), -#ifndef CONFIG_PV_SHIM_EXCLUSIVE - HYPERCALL(sysctl), - HYPERCALL(domctl), -#endif -#ifdef CONFIG_KEXEC - COMPAT_CALL(kexec_op), -#endif -#ifdef CONFIG_ARGO - COMPAT_CALL(argo_op), -#endif - HYPERCALL(xenpmu_op), -#ifdef CONFIG_HVM - HYPERCALL(hvm_op), - COMPAT_CALL(dm_op), -#endif -#ifdef CONFIG_HYPFS - HYPERCALL(hypfs_op), -#endif - HYPERCALL(mca), -#ifndef CONFIG_PV_SHIM_EXCLUSIVE - HYPERCALL(paging_domctl_cont), -#endif -}; - -#undef COMPAT_CALL -#undef HYPERCALL - /* Forced inline to cause 'compat' to be evaluated at compile time. */ static void always_inline _pv_hypercall(struct cpu_user_regs *regs, bool compat) { struct vcpu *curr = current; - unsigned long eax = compat ? regs->eax : regs->rax; + unsigned long eax; ASSERT(guest_kernel_mode(curr, regs)); - BUILD_BUG_ON(ARRAY_SIZE(pv_hypercall_table) > - ARRAY_SIZE(hypercall_args_table)); - - if ( eax >= ARRAY_SIZE(pv_hypercall_table) ) - { - regs->rax = -ENOSYS; - return; - } - - eax = array_index_nospec(eax, ARRAY_SIZE(pv_hypercall_table)); - - if ( !pv_hypercall_table[eax].native ) - { - regs->rax = -ENOSYS; - return; - } - curr->hcall_preempted = false; if ( !compat ) @@ -150,17 +53,8 @@ _pv_hypercall(struct cpu_user_regs *regs, bool compat) unsigned long r10 = regs->r10; unsigned long r8 = regs->r8; -#ifndef NDEBUG - /* Deliberately corrupt parameter regs not used by this hypercall. */ - switch ( hypercall_args_table[eax].native ) - { - case 0: rdi = 0xdeadbeefdeadf00dUL; fallthrough; - case 1: rsi = 0xdeadbeefdeadf00dUL; fallthrough; - case 2: rdx = 0xdeadbeefdeadf00dUL; fallthrough; - case 3: r10 = 0xdeadbeefdeadf00dUL; fallthrough; - case 4: r8 = 0xdeadbeefdeadf00dUL; - } -#endif + eax = regs->rax; + if ( unlikely(tb_init_done) ) { unsigned long args[5] = { rdi, rsi, rdx, r10, r8 }; @@ -168,22 +62,10 @@ _pv_hypercall(struct cpu_user_regs *regs, bool compat) __trace_hypercall(TRC_PV_HYPERCALL_V2, eax, args); } - regs->rax = pv_hypercall_table[eax].native(rdi, rsi, rdx, r10, r8); + call_handlers_pv64(eax, regs->rax, rdi, rsi, rdx, r10, r8); -#ifndef NDEBUG - if ( !curr->hcall_preempted ) - { - /* Deliberately corrupt parameter regs used by this hypercall. */ - switch ( hypercall_args_table[eax].native ) - { - case 5: regs->r8 = 0xdeadbeefdeadf00dUL; fallthrough; - case 4: regs->r10 = 0xdeadbeefdeadf00dUL; fallthrough; - case 3: regs->rdx = 0xdeadbeefdeadf00dUL; fallthrough; - case 2: regs->rsi = 0xdeadbeefdeadf00dUL; fallthrough; - case 1: regs->rdi = 0xdeadbeefdeadf00dUL; - } - } -#endif + if ( !curr->hcall_preempted && regs->rax != -ENOSYS ) + clobber_regs(regs, get_nargs(hypercall_args_64, eax)); } #ifdef CONFIG_PV32 else @@ -194,17 +76,7 @@ _pv_hypercall(struct cpu_user_regs *regs, bool compat) unsigned int esi = regs->esi; unsigned int edi = regs->edi; -#ifndef NDEBUG - /* Deliberately corrupt parameter regs not used by this hypercall. */ - switch ( hypercall_args_table[eax].compat ) - { - case 0: ebx = 0xdeadf00d; fallthrough; - case 1: ecx = 0xdeadf00d; fallthrough; - case 2: edx = 0xdeadf00d; fallthrough; - case 3: esi = 0xdeadf00d; fallthrough; - case 4: edi = 0xdeadf00d; - } -#endif + eax = regs->eax; if ( unlikely(tb_init_done) ) { @@ -214,23 +86,11 @@ _pv_hypercall(struct cpu_user_regs *regs, bool compat) } curr->hcall_compat = true; - regs->eax = pv_hypercall_table[eax].compat(ebx, ecx, edx, esi, edi); + call_handlers_pv32(eax, regs->eax, ebx, ecx, edx, esi, edi); curr->hcall_compat = false; -#ifndef NDEBUG - if ( !curr->hcall_preempted ) - { - /* Deliberately corrupt parameter regs used by this hypercall. */ - switch ( hypercall_args_table[eax].compat ) - { - case 5: regs->edi = 0xdeadf00d; fallthrough; - case 4: regs->esi = 0xdeadf00d; fallthrough; - case 3: regs->edx = 0xdeadf00d; fallthrough; - case 2: regs->ecx = 0xdeadf00d; fallthrough; - case 1: regs->ebx = 0xdeadf00d; - } - } -#endif + if ( !curr->hcall_preempted && regs->eax != -ENOSYS ) + clobber_regs32(regs, get_nargs(hypercall_args_32, eax)); } #endif /* CONFIG_PV32 */ @@ -256,13 +116,8 @@ enum mc_disposition pv_do_multicall_call(struct mc_state *state) struct compat_multicall_entry *call = &state->compat_call; op = call->op; - if ( (op < ARRAY_SIZE(pv_hypercall_table)) && - pv_hypercall_table[op].compat ) - call->result = pv_hypercall_table[op].compat( - call->args[0], call->args[1], call->args[2], - call->args[3], call->args[4]); - else - call->result = -ENOSYS; + call_handlers_pv32(op, call->result, call->args[0], call->args[1], + call->args[2], call->args[3], call->args[4]); } else #endif @@ -270,13 +125,8 @@ enum mc_disposition pv_do_multicall_call(struct mc_state *state) struct multicall_entry *call = &state->call; op = call->op; - if ( (op < ARRAY_SIZE(pv_hypercall_table)) && - pv_hypercall_table[op].native ) - call->result = pv_hypercall_table[op].native( - call->args[0], call->args[1], call->args[2], - call->args[3], call->args[4]); - else - call->result = -ENOSYS; + call_handlers_pv64(op, call->result, call->args[0], call->args[1], + call->args[2], call->args[3], call->args[4]); } return unlikely(op == __HYPERVISOR_iret)