[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

[Xen-devel] [RFC 07/10] xen/arm: Implement the code to dispatch the hypercall in assembly



Each hypercalls have different number of arguments. To avoid worry about
the number of arguments, all the hypercall handler are cast to a
5-arguments function. However, based on the C-spec (see 6.3.2.3 paragraph 8
and 6.7.5.3 paraph 2) the behavior is undefined.

This is also the first step to handle the hypercall directly in
assembly.

Signed-off-by: Julien Grall <julien.grall@xxxxxxxxxx>

---
    TODO:
        - Implement do_dispatch_hypercall for ARM32
---
 xen/arch/arm/Makefile           |  1 +
 xen/arch/arm/arm64/Makefile     |  1 +
 xen/arch/arm/arm64/hypercall.S  | 27 +++++++++++++
 xen/arch/arm/hypercall.S        | 88 ++++++++++++++++++++++++++++++++++++++++
 xen/arch/arm/traps.c            | 90 ++++++-----------------------------------
 xen/include/asm-arm/hypercall.h |  9 +++++
 6 files changed, 139 insertions(+), 77 deletions(-)
 create mode 100644 xen/arch/arm/arm64/hypercall.S
 create mode 100644 xen/arch/arm/hypercall.S

diff --git a/xen/arch/arm/Makefile b/xen/arch/arm/Makefile
index 4ac5edd..3bf7455 100644
--- a/xen/arch/arm/Makefile
+++ b/xen/arch/arm/Makefile
@@ -40,6 +40,7 @@ obj-y += device.o
 obj-y += decode.o
 obj-y += processor.o
 obj-y += smc.o
+obj-y += hypercall.o
 
 #obj-bin-y += ....o
 
diff --git a/xen/arch/arm/arm64/Makefile b/xen/arch/arm/arm64/Makefile
index c7243f5..1255b4b 100644
--- a/xen/arch/arm/arm64/Makefile
+++ b/xen/arch/arm/arm64/Makefile
@@ -8,5 +8,6 @@ obj-y += vfp.o
 obj-y += smpboot.o
 obj-y += domctl.o
 obj-y += cache.o
+obj-y += hypercall.o
 
 obj-$(EARLY_PRINTK) += debug.o
diff --git a/xen/arch/arm/arm64/hypercall.S b/xen/arch/arm/arm64/hypercall.S
new file mode 100644
index 0000000..d831181
--- /dev/null
+++ b/xen/arch/arm/arm64/hypercall.S
@@ -0,0 +1,27 @@
+#include <xen/config.h>
+#include <asm/asm_defns.h>
+
+/*
+ * int do_dispatch_hypercall(register_t arg1, register_t arg2,
+ *                           register_t arg3, register_t arg4,
+ *                           register_t arg5, register_t nr)
+ *
+ * x0 - arg1
+ * x1 - arg2
+ * x2 - arg3
+ * x3 - arg4
+ * x4 - arg5
+ * x5 - nr
+ *
+ * return the hypercall result in x0.
+ */
+ENTRY(do_dispatch_hypercall)
+    push    x19, lr                 /* Save lr (x19 is here because the stack 
need to be 16 bytes aligned */
+    ldr     x10, =hypercall_table
+    ldr     x10, [x10, x5, lsl #3]  /* x10 := pointer to hypercall function */
+
+    blr     x10                     /* Call the hypercall */
+
+    pop     x19, lr                 /* Restore lr */
+
+    ret
diff --git a/xen/arch/arm/hypercall.S b/xen/arch/arm/hypercall.S
new file mode 100644
index 0000000..c8680eb
--- /dev/null
+++ b/xen/arch/arm/hypercall.S
@@ -0,0 +1,88 @@
+#include <xen/config.h>
+#include <public/xen.h>
+
+#ifdef CONFIG_ARM_64
+#define ventry .quad
+#else
+#define ventry .word
+#endif
+
+ENTRY(hypercall_table)
+        /* Hypercalls 0-5 are not implemented on ARM */
+        .rept 6
+        ventry do_ni_hypercall
+        .endr
+        ventry do_deprecated_hypercall
+        ventry do_platform_op
+        ventry do_ni_hypercall
+        ventry do_ni_hypercall
+        ventry do_ni_hypercall       /* 10 */
+        ventry do_ni_hypercall
+        ventry do_memory_op
+        ventry do_multicall
+        ventry do_ni_hypercall
+        ventry do_ni_hypercall       /* 15 */
+        ventry do_deprecated_hypercall
+        ventry do_xen_version
+        ventry do_console_io
+        ventry do_deprecated_hypercall
+        ventry do_grant_table_op     /* 20 */
+        ventry do_ni_hypercall
+        ventry do_ni_hypercall
+        ventry do_ni_hypercall
+        ventry do_vcpu_op
+        ventry do_ni_hypercall       /* 25 */
+        ventry do_ni_hypercall
+        ventry do_xsm_op
+        ventry do_ni_hypercall
+        ventry do_sched_op
+        ventry do_ni_hypercall        /* 30 */
+        ventry do_ni_hypercall
+        ventry do_event_channel_op
+        ventry do_physdev_op
+        ventry do_hvm_op
+        ventry do_sysctl             /* 35 */
+        ventry do_domctl
+        .rept NR_hypercalls-((.-hypercall_table)/BYTES_PER_LONG)
+        ventry do_ni_hypercall
+        .endr
+
+ENTRY(hypercall_args_table)
+        /* Hypercalls 0-5 are not implemented on ARM */
+        .rept 6
+        .byte 0 /* do_ni_hypercall          */
+        .endr
+        .byte 2 /* do_deprecated_hypercall  */
+        .byte 1 /* do_platform_op           */
+        .byte 0 /* do_ni_hypercall          */
+        .byte 0 /* do_ni_hypercall          */
+        .byte 0 /* do_ni_hypercall          */ /* 10 */
+        .byte 0 /* do_ni_hypercall          */
+        .byte 2 /* do_memory_op             */
+        .byte 2 /* do_multicall             */
+        .byte 0 /* do_ni_hypercall          */
+        .byte 0 /* do_ni_hypercall          */
+        .byte 1 /* do_deprecated_hypercall  */
+        .byte 2 /* do_xen_version           */
+        .byte 3 /* do_console_io            */
+        .byte 1 /* do_deprecated_hypercall  */
+        .byte 3 /* do_grant_table_op        */  /* 20 */
+        .byte 0 /* do_ni_hypercall          */
+        .byte 0 /* do_ni_hypercall          */
+        .byte 0 /* do_ni_hypercall          */
+        .byte 3 /* do_vcpu_op               */
+        .byte 0 /* do_ni_hypercall          */ /* 25 */
+        .byte 0 /* do_ni_hypercall          */
+        .byte 1 /* do_xsm_op                */
+        .byte 0 /* do_ni_hypercall          */
+        .byte 2 /* do_sched_op              */
+        .byte 0 /* do_ni_hypercall          */ /* 30 */
+        .byte 0 /* do_ni_hypercall          */
+        .byte 2 /* do_event_channel_op      */
+        .byte 2 /* do_physdev_op            */
+        .byte 2 /* do_hvm_op                */
+        .byte 1 /* do_sysctl                */  /* 35 */
+        .byte 1 /* do_domctl                */
+        .rept NR_hypercalls-(.-hypercall_args_table)
+        .byte 0 /* do_ni_hypercall      */
+        .endr
diff --git a/xen/arch/arm/traps.c b/xen/arch/arm/traps.c
index f222d96..cc67d23 100644
--- a/xen/arch/arm/traps.c
+++ b/xen/arch/arm/traps.c
@@ -1171,7 +1171,7 @@ die:
 }
 #endif
 
-static register_t do_deprecated_hypercall(void)
+register_t do_deprecated_hypercall(void)
 {
     struct cpu_user_regs *regs = guest_cpu_user_regs();
     const register_t op =
@@ -1187,56 +1187,6 @@ 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);
-
-typedef struct {
-    arm_hypercall_fn_t fn;
-    int nr_args;
-} arm_hypercall_t;
-
-#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(physdev_op, 2),
-    HYPERCALL_DEPRECATED(physdev_op_compat, 1),
-    HYPERCALL(sysctl, 2),
-    HYPERCALL(hvm_op, 2),
-    HYPERCALL(grant_table_op, 3),
-    HYPERCALL(multicall, 2),
-    HYPERCALL(platform_op, 1),
-    HYPERCALL_ARM(vcpu_op, 3),
-};
-
 #ifndef NDEBUG
 static void do_debug_trap(struct cpu_user_regs *regs, unsigned int code)
 {
@@ -1406,17 +1356,14 @@ static void do_trap_psci(struct cpu_user_regs *regs)
 static void do_trap_hypercall(struct cpu_user_regs *regs, register_t *nr,
                               unsigned long iss)
 {
-    arm_hypercall_fn_t call = NULL;
 #ifndef NDEBUG
     register_t orig_pc = regs->pc;
 #endif
 
-    BUILD_BUG_ON(NR_hypercalls < ARRAY_SIZE(arm_hypercall_table) );
-
     if ( iss != XEN_HYPERCALL_TAG )
         domain_crash_synchronous();
 
-    if ( *nr >= ARRAY_SIZE(arm_hypercall_table) )
+    if ( *nr >= NR_hypercalls )
     {
         perfc_incr(invalid_hypercalls);
         HYPERCALL_RESULT_REG(regs) = -ENOSYS;
@@ -1424,14 +1371,9 @@ static void do_trap_hypercall(struct cpu_user_regs 
*regs, register_t *nr,
     }
 
     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));
+    HYPERCALL_RESULT_REG(regs) = do_dispatch_hypercall(HYPERCALL_ARGS(regs),
+                                                       *nr);
 
 #ifndef NDEBUG
     /*
@@ -1440,13 +1382,16 @@ static void do_trap_hypercall(struct cpu_user_regs 
*regs, register_t *nr,
      */
     if ( orig_pc == regs->pc )
     {
-        switch ( arm_hypercall_table[*nr].nr_args ) {
+        switch ( hypercall_args_table[*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 */
             break;
+        case 0:
+            ASSERT(hypercall_table[*nr] == do_ni_hypercall);
+            break;
         default: BUG();
         }
         *nr = 0xDEADBEEF;
@@ -1458,7 +1403,7 @@ static bool_t 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_table[multi->op]; i++ )
     {
         if ( unlikely(multi->args[i] & 0xffffffff00000000ULL) )
         {
@@ -1474,16 +1419,7 @@ static bool_t check_multicall_32bit_clean(struct 
multicall_entry *multi)
 
 void do_multicall_call(struct multicall_entry *multi)
 {
-    arm_hypercall_fn_t call = NULL;
-
-    if ( multi->op >= ARRAY_SIZE(arm_hypercall_table) )
-    {
-        multi->result = -ENOSYS;
-        return;
-    }
-
-    call = arm_hypercall_table[multi->op].fn;
-    if ( call == NULL )
+    if ( multi->op >= NR_hypercalls )
     {
         multi->result = -ENOSYS;
         return;
@@ -1493,9 +1429,9 @@ void do_multicall_call(struct multicall_entry *multi)
          !check_multicall_32bit_clean(multi) )
         return;
 
-    multi->result = call(multi->args[0], multi->args[1],
-                         multi->args[2], multi->args[3],
-                         multi->args[4]);
+    multi->result = do_dispatch_hypercall(multi->args[0], multi->args[1],
+                                          multi->args[2], multi->args[3],
+                                          multi->args[4], multi->op);
 }
 
 /*
diff --git a/xen/include/asm-arm/hypercall.h b/xen/include/asm-arm/hypercall.h
index a0c5a31..41e43ec 100644
--- a/xen/include/asm-arm/hypercall.h
+++ b/xen/include/asm-arm/hypercall.h
@@ -9,6 +9,15 @@ long do_arm_vcpu_op(int cmd, unsigned int vcpuid, 
XEN_GUEST_HANDLE_PARAM(void) a
 long subarch_do_domctl(struct xen_domctl *domctl, struct domain *d,
                        XEN_GUEST_HANDLE_PARAM(xen_domctl_t) u_domctl);
 
+register_t do_deprecated_hypercall(void);
+
+register_t do_dispatch_hypercall(register_t arg0, register_t arg1,
+                                 register_t arg2, register_t arg3,
+                                 register_t arg4, register_t nr);
+
+extern const uint8_t hypercall_args_table[];
+extern const void *hypercall_table[];
+
 #endif /* __ASM_ARM_HYPERCALL_H__ */
 /*
  * Local variables:
-- 
2.1.4


_______________________________________________
Xen-devel mailing list
Xen-devel@xxxxxxxxxxxxx
http://lists.xen.org/xen-devel


 


Rackspace

Lists.xenproject.org is hosted with RackSpace, monitoring our
servers 24x7x365 and backed by RackSpace's Fanatical Support®.