xen-devel.lists.xenproject.org archive mirror
 help / color / mirror / Atom feed
From: Ian Campbell <ian.campbell@citrix.com>
To: xen-devel@lists.xen.org
Cc: Stefano Stabellini <stefano.stabellini@citrix.com>,
	Tim Deegan <tim@xen.org>, Ian Campbell <Ian.Campbell@citrix.com>
Subject: [PATCH 3/4] arm: implement hypercall continuations
Date: Wed, 25 Jul 2012 14:44:00 +0000	[thread overview]
Message-ID: <1343227442-2781-3-git-send-email-ian.campbell@citrix.com> (raw)
In-Reply-To: <1343224660.18971.97.camel@zakaz.uk.xensource.com>

Largely cribbed from x86, register names differ and the return value is r0 ==
the first argument rather than the hypercall number (which is r12).

We must only clobber the hypercall arguments if PC has not been changed since
continuations rely on them.

Multicall variant is untested, On ARM do_multicall_call is currently a BUG() so
we obviously don't use that yet. I have left a BUG in the hypercall
continuation path too since it will need validation once multicalls are
implemented.

Since the multicall state is local we do not need a globally atomic
{test,set}_bit. However we do need to be atomic WRT interrupts so can't just
use the naive RMW version. Stick with the global atomic implementation for now
but keep the __ as documentaion of the intention.

Signed-off-by: Ian Campbell <Ian.Campbell@citrix.com>
---
v3: split out array bounds check. change to argument clobbering separated out
    into its own patch earlier in the series.
v2: dropped change to handling of hvc with immediate != XEN_HYPERCALL_TAG
---
 xen/arch/arm/domain.c        |   87 ++++++++++++++++++++++++++++++++++++++++++
 xen/arch/arm/dummy.S         |    1 -
 xen/arch/arm/traps.c         |   29 +++++++++-----
 xen/include/asm-arm/bitops.h |    9 ++++
 4 files changed, 115 insertions(+), 11 deletions(-)

diff --git a/xen/arch/arm/domain.c b/xen/arch/arm/domain.c
index f61568b..ee58d68 100644
--- a/xen/arch/arm/domain.c
+++ b/xen/arch/arm/domain.c
@@ -5,6 +5,7 @@
 #include <xen/softirq.h>
 #include <xen/wait.h>
 #include <xen/errno.h>
+#include <xen/bitops.h>
 
 #include <asm/current.h>
 #include <asm/regs.h>
@@ -224,6 +225,92 @@ void sync_vcpu_execstate(struct vcpu *v)
     /* Nothing to do -- no lazy switching */
 }
 
+#define next_arg(fmt, args) ({                                              \
+    unsigned long __arg;                                                    \
+    switch ( *(fmt)++ )                                                     \
+    {                                                                       \
+    case 'i': __arg = (unsigned long)va_arg(args, unsigned int);  break;    \
+    case 'l': __arg = (unsigned long)va_arg(args, unsigned long); break;    \
+    case 'h': __arg = (unsigned long)va_arg(args, void *);        break;    \
+    default:  __arg = 0; BUG();                                             \
+    }                                                                       \
+    __arg;                                                                  \
+})
+
+void hypercall_cancel_continuation(void)
+{
+    struct cpu_user_regs *regs = guest_cpu_user_regs();
+    struct mc_state *mcs = &current->mc_state;
+
+    if ( test_bit(_MCSF_in_multicall, &mcs->flags) )
+    {
+        __clear_bit(_MCSF_call_preempted, &mcs->flags);
+    }
+    else
+    {
+        regs->pc += 4; /* undo re-execute 'hvc #XEN_HYPERCALL_TAG' */
+    }
+}
+
+unsigned long hypercall_create_continuation(
+    unsigned int op, const char *format, ...)
+{
+    struct mc_state *mcs = &current->mc_state;
+    struct cpu_user_regs *regs;
+    const char *p = format;
+    unsigned long arg, rc;
+    unsigned int i;
+    va_list args;
+
+    /* All hypercalls take at least one argument */
+    BUG_ON( !p || *p == '\0' );
+
+    va_start(args, format);
+
+    if ( test_bit(_MCSF_in_multicall, &mcs->flags) )
+    {
+        BUG(); /* XXX multicalls not implemented yet. */
+
+        __set_bit(_MCSF_call_preempted, &mcs->flags);
+
+        for ( i = 0; *p != '\0'; i++ )
+            mcs->call.args[i] = next_arg(p, args);
+
+        /* Return value gets written back to mcs->call.result */
+        rc = mcs->call.result;
+    }
+    else
+    {
+        regs      = guest_cpu_user_regs();
+        regs->r12 = op;
+
+        /* Ensure the hypercall trap instruction is re-executed. */
+        regs->pc -= 4;  /* re-execute 'hvc #XEN_HYPERCALL_TAG' */
+
+        for ( i = 0; *p != '\0'; i++ )
+        {
+            arg = next_arg(p, args);
+
+            switch ( i )
+            {
+            case 0: regs->r0 = arg; break;
+            case 1: regs->r1 = arg; break;
+            case 2: regs->r2 = arg; break;
+            case 3: regs->r3 = arg; break;
+            case 4: regs->r4 = arg; break;
+            case 5: regs->r5 = arg; break;
+            }
+        }
+
+        /* Return value gets written back to r0 */
+        rc = regs->r0;
+    }
+
+    va_end(args);
+
+    return rc;
+}
+
 void startup_cpu_idle_loop(void)
 {
     struct vcpu *v = current;
diff --git a/xen/arch/arm/dummy.S b/xen/arch/arm/dummy.S
index cab9522..5406077 100644
--- a/xen/arch/arm/dummy.S
+++ b/xen/arch/arm/dummy.S
@@ -46,7 +46,6 @@ DUMMY(domain_relinquish_resources);
 DUMMY(domain_set_time_offset);
 DUMMY(dom_cow);
 DUMMY(gmfn_to_mfn);
-DUMMY(hypercall_create_continuation);
 DUMMY(send_timer_event);
 DUMMY(share_xen_page_with_privileged_guests);
 DUMMY(wallclock_time);
diff --git a/xen/arch/arm/traps.c b/xen/arch/arm/traps.c
index 6201d38..7b12832 100644
--- a/xen/arch/arm/traps.c
+++ b/xen/arch/arm/traps.c
@@ -470,6 +470,9 @@ static void do_debug_trap(struct cpu_user_regs *regs, unsigned int code)
 static void do_trap_hypercall(struct cpu_user_regs *regs, unsigned long iss)
 {
     arm_hypercall_fn_t call = NULL;
+#ifndef NDEBUG
+    uint32_t orig_pc = regs->pc;
+#endif
 
     if ( iss != XEN_HYPERCALL_TAG )
     {
@@ -495,17 +498,23 @@ static void do_trap_hypercall(struct cpu_user_regs *regs, unsigned long iss)
     regs->r0 = call(regs->r0, regs->r1, regs->r2, regs->r3, regs->r4);
 
 #ifndef NDEBUG
-    /* Clobber argument registers */
-    switch ( arm_hypercall_table[regs->r12].nr_args ) {
-    case 5: regs->r4 = 0xDEADBEEF;
-    case 4: regs->r3 = 0xDEADBEEF;
-    case 3: regs->r2 = 0xDEADBEEF;
-    case 2: regs->r1 = 0xDEADBEEF;
-    case 1: /* Don't clobber r0 -- it's the return value */
-        break;
-    default: BUG();
+    /*
+     * Clobber argument registers only if pc is unchanged, otherwise
+     * this is a hypercall continuation.
+     */
+    if ( orig_pc == regs->pc )
+    {
+        switch ( arm_hypercall_table[regs->r12].nr_args ) {
+        case 5: regs->r4 = 0xDEADBEEF;
+        case 4: regs->r3 = 0xDEADBEEF;
+        case 3: regs->r2 = 0xDEADBEEF;
+        case 2: regs->r1 = 0xDEADBEEF;
+        case 1: /* Don't clobber r0 -- it's the return value */
+            break;
+        default: BUG();
+        }
+        regs->r12 = 0xDEADBEEF;
     }
-    regs->r12 = 0xDEADBEEF;
 #endif
 }
 
diff --git a/xen/include/asm-arm/bitops.h b/xen/include/asm-arm/bitops.h
index e5c1781..87de5db 100644
--- a/xen/include/asm-arm/bitops.h
+++ b/xen/include/asm-arm/bitops.h
@@ -23,6 +23,15 @@ extern int _test_and_change_bit(int nr, volatile void * p);
 #define test_and_clear_bit(n,p)   _test_and_clear_bit(n,p)
 #define test_and_change_bit(n,p)  _test_and_change_bit(n,p)
 
+/*
+ * Non-atomic bit manipulation.
+ *
+ * Implemented using atomics to be interrupt safe. Could alternatively
+ * implement with local interrupt masking.
+ */
+#define __set_bit(n,p)            _set_bit(n,p)
+#define __clear_bit(n,p)          _clear_bit(n,p)
+
 #define BIT(nr)                 (1UL << (nr))
 #define BIT_MASK(nr)            (1UL << ((nr) % BITS_PER_LONG))
 #define BIT_WORD(nr)            ((nr) / BITS_PER_LONG)
-- 
1.7.9.1

  parent reply	other threads:[~2012-07-25 14:44 UTC|newest]

Thread overview: 11+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2012-07-25 13:57 [PATCH 0/4] arm: hypercall handling improvements Ian Campbell
2012-07-25 14:43 ` [PATCH 1/4] arm: clobber only argument registers Ian Campbell
2012-07-25 15:15   ` Stefano Stabellini
2012-07-25 14:43 ` [PATCH 2/4] arm: add bounds check on hypercall array Ian Campbell
2012-07-25 15:16   ` Stefano Stabellini
2012-07-25 15:21     ` Ian Campbell
2012-07-25 15:40       ` Stefano Stabellini
2012-07-25 14:44 ` Ian Campbell [this message]
2012-07-25 15:45   ` [PATCH 3/4] arm: implement hypercall continuations Stefano Stabellini
2012-07-25 14:44 ` [PATCH 4/4] arm: kill a guest which uses hvc with an immediate operand != XEN_HYPERCALL_TAG Ian Campbell
2012-07-25 16:42 ` [PATCH 0/4] arm: hypercall handling improvements 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=1343227442-2781-3-git-send-email-ian.campbell@citrix.com \
    --to=ian.campbell@citrix.com \
    --cc=stefano.stabellini@citrix.com \
    --cc=tim@xen.org \
    --cc=xen-devel@lists.xen.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).