mirror of
https://github.com/xen-project/xen.git
synced 2026-10-28 02:01:24 +01:00
xen/arm: call hypercall handlers via generated macro
Instead of using a function table use the generated macros for calling the appropriate hypercall handlers. This makes the calls of the handlers type safe. For deprecated hypercalls define stub functions. Signed-off-by: Juergen Gross <jgross@suse.com> Reviewed-by: Julien Grall <jgrall@amazon.com> Tested-by: Michal Orzel <michal.orzel@arm.com>
This commit is contained in:
1 parent
8523851dbc
commit
39fc5f5c02
1 file changed
+24
-93
+24
-93
@@ -1331,67 +1331,20 @@ static register_t do_deprecated_hypercall(void)
|
||||
return -ENOSYS;
|
||||
}
|
||||
|
||||
typedef register_t (*arm_hypercall_fn_t)(
|
||||
register_t, register_t, register_t, register_t, register_t);
|
||||
long dep_sched_op_compat(int cmd, unsigned long arg)
|
||||
{
|
||||
return do_deprecated_hypercall();
|
||||
}
|
||||
|
||||
typedef struct {
|
||||
arm_hypercall_fn_t fn;
|
||||
int nr_args;
|
||||
} arm_hypercall_t;
|
||||
long dep_event_channel_op_compat(XEN_GUEST_HANDLE_PARAM(evtchn_op_t) uop)
|
||||
{
|
||||
return do_deprecated_hypercall();
|
||||
}
|
||||
|
||||
#define HYPERCALL(_name, _nr_args) \
|
||||
[ __HYPERVISOR_ ## _name ] = { \
|
||||
.fn = (arm_hypercall_fn_t) &do_ ## _name, \
|
||||
.nr_args = _nr_args, \
|
||||
}
|
||||
|
||||
#define HYPERCALL_ARM(_name, _nr_args) \
|
||||
[ __HYPERVISOR_ ## _name ] = { \
|
||||
.fn = (arm_hypercall_fn_t) &do_arm_ ## _name, \
|
||||
.nr_args = _nr_args, \
|
||||
}
|
||||
/*
|
||||
* Only use this for hypercalls which were deprecated (i.e. replaced
|
||||
* by something else) before Xen on ARM was created, i.e. *not* for
|
||||
* hypercalls which are simply not yet used on ARM.
|
||||
*/
|
||||
#define HYPERCALL_DEPRECATED(_name, _nr_args) \
|
||||
[ __HYPERVISOR_##_name ] = { \
|
||||
.fn = (arm_hypercall_fn_t) &do_deprecated_hypercall, \
|
||||
.nr_args = _nr_args, \
|
||||
}
|
||||
|
||||
static arm_hypercall_t arm_hypercall_table[] = {
|
||||
HYPERCALL(memory_op, 2),
|
||||
HYPERCALL(domctl, 1),
|
||||
HYPERCALL(sched_op, 2),
|
||||
HYPERCALL_DEPRECATED(sched_op_compat, 2),
|
||||
HYPERCALL(console_io, 3),
|
||||
HYPERCALL(xen_version, 2),
|
||||
HYPERCALL(xsm_op, 1),
|
||||
HYPERCALL(event_channel_op, 2),
|
||||
HYPERCALL_DEPRECATED(event_channel_op_compat, 1),
|
||||
HYPERCALL_ARM(physdev_op, 2),
|
||||
HYPERCALL_DEPRECATED(physdev_op_compat, 1),
|
||||
HYPERCALL(sysctl, 2),
|
||||
HYPERCALL(hvm_op, 2),
|
||||
#ifdef CONFIG_GRANT_TABLE
|
||||
HYPERCALL(grant_table_op, 3),
|
||||
#endif
|
||||
HYPERCALL(multicall, 2),
|
||||
HYPERCALL(platform_op, 1),
|
||||
HYPERCALL(vcpu_op, 3),
|
||||
HYPERCALL(vm_assist, 2),
|
||||
#ifdef CONFIG_ARGO
|
||||
HYPERCALL(argo_op, 5),
|
||||
#endif
|
||||
#ifdef CONFIG_HYPFS
|
||||
HYPERCALL(hypfs_op, 5),
|
||||
#endif
|
||||
#ifdef CONFIG_IOREQ_SERVER
|
||||
HYPERCALL(dm_op, 3),
|
||||
#endif
|
||||
};
|
||||
long dep_physdev_op_compat(XEN_GUEST_HANDLE_PARAM(physdev_op_t) uop)
|
||||
{
|
||||
return do_deprecated_hypercall();
|
||||
}
|
||||
|
||||
#ifndef NDEBUG
|
||||
static void do_debug_trap(struct cpu_user_regs *regs, unsigned int code)
|
||||
@@ -1430,7 +1383,6 @@ static void do_debug_trap(struct cpu_user_regs *regs, unsigned int code)
|
||||
#define HYPERCALL_ARG3(r) (r)->x2
|
||||
#define HYPERCALL_ARG4(r) (r)->x3
|
||||
#define HYPERCALL_ARG5(r) (r)->x4
|
||||
#define HYPERCALL_ARGS(r) (r)->x0, (r)->x1, (r)->x2, (r)->x3, (r)->x4
|
||||
#else
|
||||
#define HYPERCALL_RESULT_REG(r) (r)->r0
|
||||
#define HYPERCALL_ARG1(r) (r)->r0
|
||||
@@ -1438,52 +1390,40 @@ static void do_debug_trap(struct cpu_user_regs *regs, unsigned int code)
|
||||
#define HYPERCALL_ARG3(r) (r)->r2
|
||||
#define HYPERCALL_ARG4(r) (r)->r3
|
||||
#define HYPERCALL_ARG5(r) (r)->r4
|
||||
#define HYPERCALL_ARGS(r) (r)->r0, (r)->r1, (r)->r2, (r)->r3, (r)->r4
|
||||
#endif
|
||||
|
||||
static const unsigned char hypercall_args[] = hypercall_args_arm;
|
||||
|
||||
static void do_trap_hypercall(struct cpu_user_regs *regs, register_t *nr,
|
||||
const union hsr hsr)
|
||||
{
|
||||
arm_hypercall_fn_t call = NULL;
|
||||
struct vcpu *curr = current;
|
||||
|
||||
BUILD_BUG_ON(NR_hypercalls < ARRAY_SIZE(arm_hypercall_table) );
|
||||
|
||||
if ( hsr.iss != XEN_HYPERCALL_TAG )
|
||||
{
|
||||
gprintk(XENLOG_WARNING, "Invalid HVC imm 0x%x\n", hsr.iss);
|
||||
return inject_undef_exception(regs, hsr);
|
||||
}
|
||||
|
||||
if ( *nr >= ARRAY_SIZE(arm_hypercall_table) )
|
||||
{
|
||||
perfc_incr(invalid_hypercalls);
|
||||
HYPERCALL_RESULT_REG(regs) = -ENOSYS;
|
||||
return;
|
||||
}
|
||||
|
||||
curr->hcall_preempted = false;
|
||||
|
||||
perfc_incra(hypercalls, *nr);
|
||||
call = arm_hypercall_table[*nr].fn;
|
||||
if ( call == NULL )
|
||||
{
|
||||
HYPERCALL_RESULT_REG(regs) = -ENOSYS;
|
||||
return;
|
||||
}
|
||||
|
||||
HYPERCALL_RESULT_REG(regs) = call(HYPERCALL_ARGS(regs));
|
||||
call_handlers_arm(*nr, HYPERCALL_RESULT_REG(regs), HYPERCALL_ARG1(regs),
|
||||
HYPERCALL_ARG2(regs), HYPERCALL_ARG3(regs),
|
||||
HYPERCALL_ARG4(regs), HYPERCALL_ARG5(regs));
|
||||
|
||||
#ifndef NDEBUG
|
||||
if ( !curr->hcall_preempted )
|
||||
if ( !curr->hcall_preempted && HYPERCALL_RESULT_REG(regs) != -ENOSYS )
|
||||
{
|
||||
/* Deliberately corrupt parameter regs used by this hypercall. */
|
||||
switch ( arm_hypercall_table[*nr].nr_args ) {
|
||||
switch ( hypercall_args[*nr] ) {
|
||||
case 5: HYPERCALL_ARG5(regs) = 0xDEADBEEF;
|
||||
case 4: HYPERCALL_ARG4(regs) = 0xDEADBEEF;
|
||||
case 3: HYPERCALL_ARG3(regs) = 0xDEADBEEF;
|
||||
case 2: HYPERCALL_ARG2(regs) = 0xDEADBEEF;
|
||||
case 1: /* Don't clobber x0/r0 -- it's the return value */
|
||||
case 0: /* -ENOSYS case */
|
||||
break;
|
||||
default: BUG();
|
||||
}
|
||||
@@ -1520,7 +1460,7 @@ static bool check_multicall_32bit_clean(struct multicall_entry *multi)
|
||||
{
|
||||
int i;
|
||||
|
||||
for ( i = 0; i < arm_hypercall_table[multi->op].nr_args; i++ )
|
||||
for ( i = 0; i < hypercall_args[multi->op]; i++ )
|
||||
{
|
||||
if ( unlikely(multi->args[i] & 0xffffffff00000000ULL) )
|
||||
{
|
||||
@@ -1537,16 +1477,8 @@ static bool check_multicall_32bit_clean(struct multicall_entry *multi)
|
||||
enum mc_disposition arch_do_multicall_call(struct mc_state *state)
|
||||
{
|
||||
struct multicall_entry *multi = &state->call;
|
||||
arm_hypercall_fn_t call = NULL;
|
||||
|
||||
if ( multi->op >= ARRAY_SIZE(arm_hypercall_table) )
|
||||
{
|
||||
multi->result = -ENOSYS;
|
||||
return mc_continue;
|
||||
}
|
||||
|
||||
call = arm_hypercall_table[multi->op].fn;
|
||||
if ( call == NULL )
|
||||
if ( multi->op >= ARRAY_SIZE(hypercall_args) )
|
||||
{
|
||||
multi->result = -ENOSYS;
|
||||
return mc_continue;
|
||||
@@ -1556,9 +1488,8 @@ enum mc_disposition arch_do_multicall_call(struct mc_state *state)
|
||||
!check_multicall_32bit_clean(multi) )
|
||||
return mc_continue;
|
||||
|
||||
multi->result = call(multi->args[0], multi->args[1],
|
||||
multi->args[2], multi->args[3],
|
||||
multi->args[4]);
|
||||
call_handlers_arm(multi->op, multi->result, multi->args[0], multi->args[1],
|
||||
multi->args[2], multi->args[3], multi->args[4]);
|
||||
|
||||
return likely(!regs_mode_is_user(guest_cpu_user_regs()))
|
||||
? mc_continue : mc_preempt;
|
||||
|
||||