@@ -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),
-#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),
+#ifndef NDEBUG
+static const unsigned char hypercall_args_64[] = hypercall_args_hvm64;
+static const unsigned char hypercall_args_32[] = hypercall_args_hvm32;
#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);
-
-#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->rdi, regs->rsi, regs->rdx, regs->r10, regs->r8);
- regs->rax = hvm_hypercall_table[eax].native(rdi, rsi, rdx, r10, r8);
+ call_handlers_hvm64(eax, regs->rax, regs->rdi, regs->rsi, regs->rdx,
+ regs->r10, regs->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;
@@ -22,65 +22,6 @@
#include <xen/hypercall.h>
#include <asm/multicall.h>
-#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; \
@@ -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__ */
@@ -27,119 +27,22 @@
#include <asm/multicall.h>
#include <irq_vectors.h>
-typedef struct {
- hypercall_fn_t *native;
-#ifdef CONFIG_PV32
- hypercall_fn_t *compat;
-#endif
-} pv_hypercall_table_t;
-
+#ifndef NDEBUG
+static const unsigned char hypercall_args_64[] = hypercall_args_pv64;
#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),
+static const unsigned char hypercall_args_32[] = hypercall_args_pv32;
#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)