diff options
author | kaf24@scramble.cl.cam.ac.uk <kaf24@scramble.cl.cam.ac.uk> | 2004-11-25 17:24:07 +0000 |
---|---|---|
committer | kaf24@scramble.cl.cam.ac.uk <kaf24@scramble.cl.cam.ac.uk> | 2004-11-25 17:24:07 +0000 |
commit | a8bcd6b668d01a28f6a14e4f2a96c84861605617 (patch) | |
tree | 9f7e825b788fb848b73d044cfc4f900b7620ae2c /xen/common/multicall.c | |
parent | 3d833e2c3c1fb89e00e675746e59d6591d21e0a4 (diff) | |
download | xen-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.c | 76 |
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; +} |