diff -r 04f6ad5d9232 arch/powerpc/platforms/xen/hcall.c --- a/arch/powerpc/platforms/xen/hcall.c Mon Mar 05 13:23:38 2007 -0600 +++ b/arch/powerpc/platforms/xen/hcall.c Fri Apr 27 21:50:12 2007 -0500 @@ -34,6 +34,7 @@ #include #include #include +#include #include #include #include @@ -637,6 +638,146 @@ static int xenppc_privcmd_event_channel_ xencomm_free(desc); return ret; } + +static int xenppc_acmcmd_op(privcmd_hypercall_t *hypercall) +{ + xen_acmctl_t kern_op; + xen_acmctl_t __user *user_op = (xen_acmctl_t __user *)hypercall->arg[0]; + void *op_desc; + void *desc = NULL, *desc2 = NULL, *desc3 = NULL, *desc4 = NULL; + int ret = 0; + + if (copy_from_user(&kern_op, user_op, sizeof(xen_acmctl_t))) + return -EFAULT; + + if (kern_op.interface_version != ACM_INTERFACE_VERSION) { + printk(KERN_WARNING "%s: %s %x != %x\n", __func__, current->comm, + kern_op.interface_version, ACM_INTERFACE_VERSION); + return -EACCES; + } + + op_desc = xencomm_map(&kern_op, sizeof(xen_acmctl_t)); + if (op_desc == NULL) + return -ENOMEM; + + switch (kern_op.cmd) { + case ACMOP_setpolicy: + desc = xencomm_map( + xen_guest_handle(kern_op.u.setpolicy.pushcache), + kern_op.u.setpolicy.pushcache_size); + + if (desc == NULL) + ret = -ENOMEM; + + set_xen_guest_handle(kern_op.u.setpolicy.pushcache, + desc); + break; + case ACMOP_getpolicy: + desc = xencomm_map( + xen_guest_handle(kern_op.u.getpolicy.pullcache), + kern_op.u.getpolicy.pullcache_size); + + if (desc == NULL) + ret = -ENOMEM; + + set_xen_guest_handle(kern_op.u.getpolicy.pullcache, + desc); + break; + case ACMOP_dumpstats: + desc = xencomm_map( + xen_guest_handle(kern_op.u.dumpstats.pullcache), + kern_op.u.dumpstats.pullcache_size); + + if (desc == NULL) + ret = -ENOMEM; + + set_xen_guest_handle(kern_op.u.dumpstats.pullcache, + desc); + break; + case ACMOP_getssid: + desc = xencomm_map( + xen_guest_handle(kern_op.u.getssid.ssidbuf), + kern_op.u.getssid.ssidbuf_size); + + if (desc == NULL) + ret = -ENOMEM; + + set_xen_guest_handle(kern_op.u.getssid.ssidbuf, + desc); + break; + case ACMOP_getdecision: + break; + case ACMOP_chgpolicy: + desc = xencomm_map( + xen_guest_handle(kern_op.u.change_policy.policy_pushcache), + kern_op.u.change_policy.policy_pushcache_size); + desc2 = xencomm_map( + xen_guest_handle(kern_op.u.change_policy.del_array), + kern_op.u.change_policy.delarray_size); + desc3 = xencomm_map( + xen_guest_handle(kern_op.u.change_policy.chg_array), + kern_op.u.change_policy.chgarray_size); + desc4 = xencomm_map( + xen_guest_handle(kern_op.u.change_policy.err_array), + kern_op.u.change_policy.errarray_size); + + if (desc == NULL || desc2 == NULL || + desc3 == NULL || desc4 == NULL) { + ret = -ENOMEM; + goto out; + } + + set_xen_guest_handle(kern_op.u.change_policy.policy_pushcache, + desc); + set_xen_guest_handle(kern_op.u.change_policy.del_array, + desc2); + set_xen_guest_handle(kern_op.u.change_policy.chg_array, + desc3); + set_xen_guest_handle(kern_op.u.change_policy.err_array, + desc4); + break; + case ACMOP_relabeldoms: + desc = xencomm_map( + xen_guest_handle(kern_op.u.relabel_doms.relabel_map), + kern_op.u.relabel_doms.relabel_map_size); + desc2 = xencomm_map( + xen_guest_handle(kern_op.u.relabel_doms.err_array), + kern_op.u.relabel_doms.errarray_size); + + if (desc == NULL || desc2 == NULL) { + ret = -ENOMEM; + goto out; + } + + set_xen_guest_handle(kern_op.u.relabel_doms.relabel_map, + desc); + set_xen_guest_handle(kern_op.u.relabel_doms.err_array, + desc2); + break; + default: + printk(KERN_ERR "%s: unknown/unsupported acmctl cmd %d\n", + __func__, kern_op.cmd); + return -ENOSYS; + } + + if (ret) + goto out; /* error mapping the nested pointer */ + + ret = plpar_hcall_norets(XEN_MARK(hypercall->op),op_desc); + + if (copy_to_user(user_op, &kern_op, sizeof(xen_acmctl_t))) { + ret = -EFAULT; + } + +out: + xencomm_free(desc); + xencomm_free(desc2); + xencomm_free(desc3); + xencomm_free(desc4); + xencomm_free(op_desc); + return ret; +} + /* The PowerPC hypervisor runs in a separate address space from Linux * kernel/userspace, i.e. real mode. We must therefore translate userspace @@ -661,12 +802,7 @@ int arch_privcmd_hypercall(privcmd_hyper /* fallthru */ /* below are the hcalls we know will fail and its ok */ case __HYPERVISOR_acm_op: - return plpar_hcall_norets(XEN_MARK(hypercall->op), - hypercall->arg[0], - hypercall->arg[1], - hypercall->arg[2], - hypercall->arg[3], - hypercall->arg[4]); + return xenppc_acmcmd_op(hypercall); } } diff -r 04f6ad5d9232 include/xen/interface/acm_ops.h --- a/include/xen/interface/acm_ops.h Mon Mar 05 13:23:38 2007 -0600 +++ b/include/xen/interface/acm_ops.h Thu Apr 26 17:39:00 2007 -0500 @@ -34,7 +34,7 @@ * This makes sure that old versions of acm tools will stop working in a * well-defined way (rather than crashing the machine, for instance). */ -#define ACM_INTERFACE_VERSION 0xAAAA0008 +#define ACM_INTERFACE_VERSION 0xAAAA000A /************************************************************************/ @@ -49,8 +49,7 @@ #define ACMOP_setpolicy 1 struct acm_setpolicy { /* IN */ - uint32_t interface_version; - XEN_GUEST_HANDLE(void) pushcache; + XEN_GUEST_HANDLE_64(void) pushcache; uint32_t pushcache_size; }; @@ -58,8 +57,7 @@ struct acm_setpolicy { #define ACMOP_getpolicy 2 struct acm_getpolicy { /* IN */ - uint32_t interface_version; - XEN_GUEST_HANDLE(void) pullcache; + XEN_GUEST_HANDLE_64(void) pullcache; uint32_t pullcache_size; }; @@ -67,8 +65,7 @@ struct acm_getpolicy { #define ACMOP_dumpstats 3 struct acm_dumpstats { /* IN */ - uint32_t interface_version; - XEN_GUEST_HANDLE(void) pullcache; + XEN_GUEST_HANDLE_64(void) pullcache; uint32_t pullcache_size; }; @@ -78,20 +75,18 @@ struct acm_dumpstats { #define ACM_GETBY_domainid 2 struct acm_getssid { /* IN */ - uint32_t interface_version; uint32_t get_ssid_by; /* ACM_GETBY_* */ union { domaintype_t domainid; ssidref_t ssidref; } id; - XEN_GUEST_HANDLE(void) ssidbuf; + XEN_GUEST_HANDLE_64(void) ssidbuf; uint32_t ssidbuf_size; }; #define ACMOP_getdecision 5 struct acm_getdecision { /* IN */ - uint32_t interface_version; uint32_t get_decision_by1; /* ACM_GETBY_* */ uint32_t get_decision_by2; /* ACM_GETBY_* */ union { @@ -107,6 +102,50 @@ struct acm_getdecision { uint32_t acm_decision; }; + +#define ACMOP_chgpolicy 6 +struct acm_change_policy { + /* IN */ + XEN_GUEST_HANDLE_64(void) policy_pushcache; + uint32_t policy_pushcache_size; + XEN_GUEST_HANDLE_64(void) del_array; + uint32_t delarray_size; + XEN_GUEST_HANDLE_64(void) chg_array; + uint32_t chgarray_size; + /* OUT */ + /* array with error code */ + XEN_GUEST_HANDLE_64(void) err_array; + uint32_t errarray_size; +}; + +#define ACMOP_relabeldoms 7 +struct acm_relabel_doms { + /* IN */ + XEN_GUEST_HANDLE_64(void) relabel_map; + uint32_t relabel_map_size; + /* OUT */ + XEN_GUEST_HANDLE_64(void) err_array; + uint32_t errarray_size; +}; + +/* future interface to Xen */ +struct xen_acmctl { + uint32_t cmd; + uint32_t interface_version; + union { + struct acm_setpolicy setpolicy; + struct acm_getpolicy getpolicy; + struct acm_dumpstats dumpstats; + struct acm_getssid getssid; + struct acm_getdecision getdecision; + struct acm_change_policy change_policy; + struct acm_relabel_doms relabel_doms; + } u; +}; + +typedef struct xen_acmctl xen_acmctl_t; +DEFINE_XEN_GUEST_HANDLE(xen_acmctl_t); + #endif /* __XEN_PUBLIC_ACM_OPS_H__ */ /*