aboutsummaryrefslogtreecommitdiffstats
path: root/xen/common/multicall.c
diff options
context:
space:
mode:
authorkaf24@scramble.cl.cam.ac.uk <kaf24@scramble.cl.cam.ac.uk>2004-11-25 17:24:07 +0000
committerkaf24@scramble.cl.cam.ac.uk <kaf24@scramble.cl.cam.ac.uk>2004-11-25 17:24:07 +0000
commita8bcd6b668d01a28f6a14e4f2a96c84861605617 (patch)
tree9f7e825b788fb848b73d044cfc4f900b7620ae2c /xen/common/multicall.c
parent3d833e2c3c1fb89e00e675746e59d6591d21e0a4 (diff)
downloadxen-a8bcd6b668d01a28f6a14e4f2a96c84861605617.tar.gz
xen-a8bcd6b668d01a28f6a14e4f2a96c84861605617.tar.bz2
xen-a8bcd6b668d01a28f6a14e4f2a96c84861605617.zip
bitkeeper revision 1.1159.187.15 (41a61537tODn12flBND8W6jum0b79Q)
Fix hypercall preemption. At the same time I reimplemented most of the multi-hypercall in arch-independent C code.
Diffstat (limited to 'xen/common/multicall.c')
-rw-r--r--xen/common/multicall.c76
1 files changed, 76 insertions, 0 deletions
diff --git a/xen/common/multicall.c b/xen/common/multicall.c
new file mode 100644
index 0000000000..04b5a7bdd2
--- /dev/null
+++ b/xen/common/multicall.c
@@ -0,0 +1,76 @@
+/******************************************************************************
+ * multicall.c
+ */
+
+#include <xen/config.h>
+#include <xen/types.h>
+#include <xen/lib.h>
+#include <xen/mm.h>
+#include <xen/perfc.h>
+#include <xen/sched.h>
+#include <xen/event.h>
+#include <xen/multicall.h>
+
+struct mc_state mc_state[NR_CPUS];
+
+long do_multicall(multicall_entry_t *call_list, unsigned int nr_calls)
+{
+ struct mc_state *mcs = &mc_state[smp_processor_id()];
+ unsigned int i;
+
+ if ( unlikely(__test_and_set_bit(_MCSF_in_multicall, &mcs->flags)) )
+ {
+ DPRINTK("Multicall reentry is disallowed.\n");
+ return -EINVAL;
+ }
+
+ if ( unlikely(!array_access_ok(VERIFY_WRITE, call_list,
+ nr_calls, sizeof(*call_list))) )
+ {
+ DPRINTK("Bad memory range %p for %u*%u bytes.\n",
+ call_list, nr_calls, sizeof(*call_list));
+ goto fault;
+ }
+
+ for ( i = 0; i < nr_calls; i++ )
+ {
+ if ( unlikely(__copy_from_user(&mcs->call, &call_list[i],
+ sizeof(*call_list))) )
+ {
+ DPRINTK("Error copying from user range %p for %u bytes.\n",
+ &call_list[i], sizeof(*call_list));
+ goto fault;
+ }
+
+ do_multicall_call(&mcs->call);
+
+ if ( unlikely(__put_user(mcs->call.args[5], &call_list[i].args[5])) )
+ {
+ DPRINTK("Error writing result back to multicall block.\n");
+ goto fault;
+ }
+
+ if ( hypercall_preempt_check() )
+ {
+ /* If the sub-call wasn't preempted, skip over it. */
+ if ( !test_bit(_MCSF_call_preempted, &mcs->flags) )
+ i++;
+
+ /* Only create a continuation if there is work left to be done. */
+ if ( i < nr_calls )
+ {
+ mcs->flags = 0;
+ hypercall_create_continuation(
+ __HYPERVISOR_multicall, 2, &call_list[i], nr_calls-i);
+ return __HYPERVISOR_multicall;
+ }
+ }
+ }
+
+ mcs->flags = 0;
+ return 0;
+
+ fault:
+ mcs->flags = 0;
+ return -EFAULT;
+}