xen-devel.lists.xenproject.org archive mirror
 help / color / mirror / Atom feed
From: Julien Grall <julien.grall@citrix.com>
To: xen-devel@lists.xenproject.org
Cc: Julien Grall <julien.grall@citrix.com>,
	ian.campbell@citrix.com, stefano.stabellini@eu.citrix.com
Subject: [RFC 07/10] xen/arm: Implement the code to dispatch the hypercall in assembly
Date: Tue, 15 Dec 2015 17:52:05 +0000	[thread overview]
Message-ID: <1450201928-4928-8-git-send-email-julien.grall@citrix.com> (raw)
In-Reply-To: <1450201928-4928-1-git-send-email-julien.grall@citrix.com>

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@citrix.com>

---
    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

  parent reply	other threads:[~2015-12-15 17:54 UTC|newest]

Thread overview: 13+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2015-12-15 17:51 [RFC 00/10] xen/arm: Implement the hypercall handling in assembly Julien Grall
2015-12-15 17:51 ` [RFC 01/10] xen/arm: move lr, push and pop in a separate header Julien Grall
2015-12-15 17:52 ` [RFC 02/10] xen/arm: Drop unused defines in asm/bug.h Julien Grall
2015-12-15 17:52 ` [RFC 03/10] xen/arm: Implement assembly version of WARN/BUG/ASSERT_FAILED Julien Grall
2015-12-15 17:52 ` [RFC 04/10] xen/arm64: Add an assembly macro for perf counter Julien Grall
2015-12-15 17:52 ` [RFC 05/10] xen/arm: gic_inject: Introduce a local variable to store current Julien Grall
2015-12-15 17:52 ` [RFC 06/10] xen/arm: gic: Allow the LRs to be cleared lazily Julien Grall
2015-12-15 17:52 ` Julien Grall [this message]
2015-12-15 17:52 ` [RFC 08/10] xen/arm64: Implement the hypercall handing fully in assembly Julien Grall
2015-12-15 17:52 ` [RFC 09/10] xen/arm: Remove the C version of do_trap_hypercall Julien Grall
2015-12-15 17:52 ` [RFC 10/10] xen/arm: Factorize the C code to dispatch HVC Julien Grall
2015-12-15 18:33 ` [RFC 00/10] xen/arm: Implement the hypercall handling in assembly Andrew Cooper
2015-12-16 11:19   ` Ian Campbell

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=1450201928-4928-8-git-send-email-julien.grall@citrix.com \
    --to=julien.grall@citrix.com \
    --cc=ian.campbell@citrix.com \
    --cc=stefano.stabellini@eu.citrix.com \
    --cc=xen-devel@lists.xenproject.org \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).