[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index] [Xen-devel] [PATCH v7 1/7] public / x86: introduce __HYPERCALL_iommu_op
This patch introduces the boilerplate for a new hypercall to allow a domain to control IOMMU mappings for its own pages. Whilst there is duplication of code between the native and compat entry points which appears ripe for some form of combination, I think it is better to maintain the separation as-is because the compat entry point will necessarily gain complexity in subsequent patches. NOTE: This hypercall is only implemented for x86 and is currently restricted by XSM to dom0. Its scope can be expanded in future if need be. Signed-off-by: Paul Durrant <paul.durrant@xxxxxxxxxx> Acked-by: Daniel De Graaf <dgdegra@xxxxxxxxxxxxx> --- Cc: Andrew Cooper <andrew.cooper3@xxxxxxxxxx> Cc: George Dunlap <George.Dunlap@xxxxxxxxxxxxx> Cc: Ian Jackson <ian.jackson@xxxxxxxxxxxxx> Cc: Jan Beulich <jbeulich@xxxxxxxx> Cc: Konrad Rzeszutek Wilk <konrad.wilk@xxxxxxxxxx> Cc: Stefano Stabellini <sstabellini@xxxxxxxxxx> Cc: Tim Deegan <tim@xxxxxxx> Cc: Wei Liu <wei.liu2@xxxxxxxxxx> v7: - Avoid using the full XLAT code to copy back in compat handler. - Use local variable of the requisite handle type to store buf->h and hence avoid excessive casting. v6: - Move iommu_op.c to xen/common as suggested by Kevin, but only build for x86 (as suggested by Jan). v3: - Push op code into XSM check. v2: - Get rid of the can_control_iommu() function, leaving this patch as pure boilerplate. - Re-structure the hypercall to use a buffer array, similar to that used by __HYPERCALL_dm_op, to allow for future expansion of op structure without affecting binary compatibility. - Drop use of __ in public header guard. --- tools/flask/policy/modules/xen.if | 1 + xen/arch/x86/hvm/hypercall.c | 1 + xen/arch/x86/hypercall.c | 1 + xen/arch/x86/pv/hypercall.c | 1 + xen/common/Makefile | 1 + xen/common/iommu_op.c | 193 ++++++++++++++++++++++++++++++++++++ xen/include/Makefile | 1 + xen/include/public/iommu_op.h | 64 ++++++++++++ xen/include/public/xen.h | 1 + xen/include/xen/hypercall.h | 12 +++ xen/include/xlat.lst | 2 + xen/include/xsm/dummy.h | 6 ++ xen/include/xsm/xsm.h | 6 ++ xen/xsm/dummy.c | 1 + xen/xsm/flask/hooks.c | 6 ++ xen/xsm/flask/policy/access_vectors | 2 + 16 files changed, 299 insertions(+) create mode 100644 xen/common/iommu_op.c create mode 100644 xen/include/public/iommu_op.h diff --git a/tools/flask/policy/modules/xen.if b/tools/flask/policy/modules/xen.if index 4e06cfc09b..c2f9fc20d7 100644 --- a/tools/flask/policy/modules/xen.if +++ b/tools/flask/policy/modules/xen.if @@ -60,6 +60,7 @@ define(`create_domain_common', ` allow $1 $2:grant setup; allow $1 $2:hvm { getparam hvmctl sethvmc setparam nested altp2mhvm altp2mhvm_op dm }; + allow $1 $2:resource control_iommu; ') # create_domain(priv, target) diff --git a/xen/arch/x86/hvm/hypercall.c b/xen/arch/x86/hvm/hypercall.c index 56713d1e08..fbc9f10187 100644 --- a/xen/arch/x86/hvm/hypercall.c +++ b/xen/arch/x86/hvm/hypercall.c @@ -138,6 +138,7 @@ static const hypercall_table_t hvm_hypercall_table[] = { COMPAT_CALL(mmuext_op), HYPERCALL(xenpmu_op), COMPAT_CALL(dm_op), + COMPAT_CALL(iommu_op), HYPERCALL(arch_1) }; diff --git a/xen/arch/x86/hypercall.c b/xen/arch/x86/hypercall.c index 74bde5e958..308db24a5f 100644 --- a/xen/arch/x86/hypercall.c +++ b/xen/arch/x86/hypercall.c @@ -70,6 +70,7 @@ const hypercall_args_t hypercall_args_table[NR_hypercalls] = ARGS(dm_op, 3), #endif ARGS(mca, 1), + ARGS(iommu_op, 2), ARGS(arch_1, 1), }; diff --git a/xen/arch/x86/pv/hypercall.c b/xen/arch/x86/pv/hypercall.c index 5d11911735..50bdf34875 100644 --- a/xen/arch/x86/pv/hypercall.c +++ b/xen/arch/x86/pv/hypercall.c @@ -83,6 +83,7 @@ const hypercall_table_t pv_hypercall_table[] = { COMPAT_CALL(dm_op), #endif HYPERCALL(mca), + COMPAT_CALL(iommu_op), HYPERCALL(arch_1), }; diff --git a/xen/common/Makefile b/xen/common/Makefile index 6a05fffc7a..6341bdccee 100644 --- a/xen/common/Makefile +++ b/xen/common/Makefile @@ -13,6 +13,7 @@ obj-$(CONFIG_CRASH_DEBUG) += gdbstub.o obj-y += grant_table.o obj-y += guestcopy.o obj-bin-y += gunzip.init.o +obj-$(CONFIG_X86) += iommu_op.o obj-y += irq.o obj-y += kernel.o obj-y += keyhandler.o diff --git a/xen/common/iommu_op.c b/xen/common/iommu_op.c new file mode 100644 index 0000000000..6acc7b1888 --- /dev/null +++ b/xen/common/iommu_op.c @@ -0,0 +1,193 @@ +/****************************************************************************** + * iommu_op.c + * + * Paravirtualised IOMMU functionality + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; If not, see <http://www.gnu.org/licenses/>. + * + * Copyright (C) 2018 Citrix Systems Inc + */ + +#include <xen/event.h> +#include <xen/guest_access.h> +#include <xen/hypercall.h> + +static void iommu_op(xen_iommu_op_t *op) +{ + switch ( op->op ) + { + default: + op->status = -EOPNOTSUPP; + break; + } +} + +int do_one_iommu_op(xen_iommu_op_buf_t *buf) +{ + const XEN_GUEST_HANDLE(xen_iommu_op_t) h = + guest_handle_cast(buf->h, xen_iommu_op_t); + xen_iommu_op_t op; + int rc; + + if ( buf->size < sizeof(op) ) + return -ENODATA; + + if ( copy_from_guest(&op, h, 1) ) + return -EFAULT; + + if ( op.pad ) + return -EINVAL; + + rc = xsm_iommu_op(XSM_PRIV, current->domain, op.op); + if ( rc ) + return rc; + + iommu_op(&op); + + if ( __copy_field_to_guest(h, &op, status) ) + return -EFAULT; + + return 0; +} + +long do_iommu_op(unsigned int nr_bufs, + XEN_GUEST_HANDLE_PARAM(xen_iommu_op_buf_t) bufs) +{ + unsigned int i; + long rc = 0; + + for ( i = 0; i < nr_bufs; i++ ) + { + xen_iommu_op_buf_t buf; + + if ( ((i & 0xff) == 0xff) && hypercall_preempt_check() ) + { + rc = i; + break; + } + + if ( copy_from_guest_offset(&buf, bufs, i, 1) ) + { + rc = -EFAULT; + break; + } + + rc = do_one_iommu_op(&buf); + if ( rc ) + break; + } + + if ( rc > 0 ) + { + ASSERT(rc < nr_bufs); + nr_bufs -= rc; + guest_handle_add_offset(bufs, rc); + + rc = hypercall_create_continuation(__HYPERVISOR_iommu_op, + "ih", nr_bufs, bufs); + } + + return rc; +} + +#ifdef CONFIG_COMPAT + +int compat_one_iommu_op(compat_iommu_op_buf_t *buf) +{ + const COMPAT_HANDLE(compat_iommu_op_t) h = + compat_handle_cast(buf->h, compat_iommu_op_t); + compat_iommu_op_t cmp; + xen_iommu_op_t nat; + int rc; + + if ( buf->size < sizeof(cmp) ) + return -ENODATA; + + if ( copy_from_compat(&cmp, h, 1) ) + return -EFAULT; + + if ( cmp.pad ) + return -EINVAL; + + rc = xsm_iommu_op(XSM_PRIV, current->domain, cmp.op); + if ( rc ) + return rc; + + XLAT_iommu_op(&nat, &cmp); + + iommu_op(&nat); + + /* + * Avoid the full (and lengthy) XLAT code as the only thing that + * needs copying back is the status field. + */ + cmp.status = nat.status; + + if ( __copy_field_to_compat(h, &cmp, status) ) + return -EFAULT; + + return 0; +} + +int compat_iommu_op(unsigned int nr_bufs, + XEN_GUEST_HANDLE_PARAM(compat_iommu_op_buf_t) bufs) +{ + unsigned int i; + long rc = 0; + + for ( i = 0; i < nr_bufs; i++ ) + { + compat_iommu_op_buf_t buf; + + if ( ((i & 0xff) == 0xff) && hypercall_preempt_check() ) + { + rc = i; + break; + } + + if ( copy_from_guest_offset(&buf, bufs, i, 1) ) + { + rc = -EFAULT; + break; + } + + rc = compat_one_iommu_op(&buf); + if ( rc ) + break; + } + + if ( rc > 0 ) + { + ASSERT(rc < nr_bufs); + nr_bufs -= rc; + guest_handle_add_offset(bufs, rc); + + rc = hypercall_create_continuation(__HYPERVISOR_iommu_op, + "ih", nr_bufs, bufs); + } + + return rc; +} + +#endif /* CONFIG_COMPAT */ + +/* + * Local variables: + * mode: C + * c-file-style: "BSD" + * c-basic-offset: 4 + * tab-width: 4 + * indent-tabs-mode: nil + * End: + */ diff --git a/xen/include/Makefile b/xen/include/Makefile index f7895e4d4e..3dd856af57 100644 --- a/xen/include/Makefile +++ b/xen/include/Makefile @@ -29,6 +29,7 @@ headers-$(CONFIG_X86) += compat/arch-x86/xen-$(compat-arch-y).h headers-$(CONFIG_X86) += compat/hvm/dm_op.h headers-$(CONFIG_X86) += compat/hvm/hvm_op.h headers-$(CONFIG_X86) += compat/hvm/hvm_vcpu.h +headers-$(CONFIG_X86) += compat/iommu_op.h headers-y += compat/arch-$(compat-arch-y).h compat/pmu.h compat/xlat.h headers-$(CONFIG_XSM_FLASK) += compat/xsm/flask_op.h diff --git a/xen/include/public/iommu_op.h b/xen/include/public/iommu_op.h new file mode 100644 index 0000000000..c3b68f665a --- /dev/null +++ b/xen/include/public/iommu_op.h @@ -0,0 +1,64 @@ +/* + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to + * deal in the Software without restriction, including without limitation the + * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or + * sell copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING + * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER + * DEALINGS IN THE SOFTWARE. + * + * Copyright (C) 2018 Citrix Systems Inc + */ + +#ifndef XEN_PUBLIC_IOMMU_OP_H +#define XEN_PUBLIC_IOMMU_OP_H + +#include "xen.h" + +struct xen_iommu_op { + uint16_t op; /* op type */ + uint16_t pad; + int32_t status; /* op completion status: */ + /* 0 for success otherwise, negative errno */ +}; +typedef struct xen_iommu_op xen_iommu_op_t; +DEFINE_XEN_GUEST_HANDLE(xen_iommu_op_t); + +struct xen_iommu_op_buf { + XEN_GUEST_HANDLE(void) h; + xen_ulong_t size; +}; +typedef struct xen_iommu_op_buf xen_iommu_op_buf_t; +DEFINE_XEN_GUEST_HANDLE(xen_iommu_op_buf_t); + +/* ` enum neg_errnoval + * ` HYPERVISOR_iommu_op(unsigned int nr_bufs, + * ` xen_iommu_op_buf_t bufs[]) + * ` + * + * @nr_bufs is the number of buffers in the @bufs array. + * @bufs points to an array of buffers where each contains a struct + * xen_iommu_op. + */ + +#endif /* XEN_PUBLIC_IOMMU_OP_H */ + +/* + * Local variables: + * mode: C + * c-file-style: "BSD" + * c-basic-offset: 4 + * tab-width: 4 + * indent-tabs-mode: nil + * End: + */ diff --git a/xen/include/public/xen.h b/xen/include/public/xen.h index 68ee09810f..35e539d5ab 100644 --- a/xen/include/public/xen.h +++ b/xen/include/public/xen.h @@ -121,6 +121,7 @@ DEFINE_XEN_GUEST_HANDLE(xen_ulong_t); #define __HYPERVISOR_xc_reserved_op 39 /* reserved for XenClient */ #define __HYPERVISOR_xenpmu_op 40 #define __HYPERVISOR_dm_op 41 +#define __HYPERVISOR_iommu_op 42 /* Architecture-specific hypercall definitions. */ #define __HYPERVISOR_arch_0 48 diff --git a/xen/include/xen/hypercall.h b/xen/include/xen/hypercall.h index cc99aea57d..2ebc999f4b 100644 --- a/xen/include/xen/hypercall.h +++ b/xen/include/xen/hypercall.h @@ -16,6 +16,7 @@ #include <public/version.h> #include <public/pmu.h> #include <public/hvm/dm_op.h> +#include <public/iommu_op.h> #include <asm/hypercall.h> #include <xsm/xsm.h> @@ -148,6 +149,10 @@ do_dm_op( unsigned int nr_bufs, XEN_GUEST_HANDLE_PARAM(xen_dm_op_buf_t) bufs); +extern long +do_iommu_op(unsigned int nr_bufs, + XEN_GUEST_HANDLE_PARAM(xen_iommu_op_buf_t) bufs); + #ifdef CONFIG_COMPAT extern int @@ -205,6 +210,13 @@ compat_dm_op( unsigned int nr_bufs, XEN_GUEST_HANDLE_PARAM(void) bufs); +#include <compat/iommu_op.h> + +DEFINE_XEN_GUEST_HANDLE(compat_iommu_op_buf_t); +extern int +compat_iommu_op(unsigned int nr_bufs, + XEN_GUEST_HANDLE_PARAM(compat_iommu_op_buf_t) bufs); + #endif void arch_get_xen_caps(xen_capabilities_info_t *info); diff --git a/xen/include/xlat.lst b/xen/include/xlat.lst index 527332054a..3b15c18c4e 100644 --- a/xen/include/xlat.lst +++ b/xen/include/xlat.lst @@ -77,6 +77,8 @@ ? vcpu_hvm_context hvm/hvm_vcpu.h ? vcpu_hvm_x86_32 hvm/hvm_vcpu.h ? vcpu_hvm_x86_64 hvm/hvm_vcpu.h +! iommu_op iommu_op.h +! iommu_op_buf iommu_op.h ? kexec_exec kexec.h ! kexec_image kexec.h ! kexec_range kexec.h diff --git a/xen/include/xsm/dummy.h b/xen/include/xsm/dummy.h index b0ac1f66b3..34b786993d 100644 --- a/xen/include/xsm/dummy.h +++ b/xen/include/xsm/dummy.h @@ -715,6 +715,12 @@ static XSM_INLINE int xsm_dm_op(XSM_DEFAULT_ARG struct domain *d) return xsm_default_action(action, current->domain, d); } +static XSM_INLINE int xsm_iommu_op(XSM_DEFAULT_ARG struct domain *d, unsigned int op) +{ + XSM_ASSERT_ACTION(XSM_PRIV); + return xsm_default_action(action, current->domain, d); +} + #endif /* CONFIG_X86 */ #include <public/version.h> diff --git a/xen/include/xsm/xsm.h b/xen/include/xsm/xsm.h index 3d67962493..847a1314ed 100644 --- a/xen/include/xsm/xsm.h +++ b/xen/include/xsm/xsm.h @@ -178,6 +178,7 @@ struct xsm_operations { int (*ioport_mapping) (struct domain *d, uint32_t s, uint32_t e, uint8_t allow); int (*pmu_op) (struct domain *d, unsigned int op); int (*dm_op) (struct domain *d); + int (*iommu_op) (struct domain *d, unsigned int op); #endif int (*xen_version) (uint32_t cmd); int (*domain_resource_map) (struct domain *d); @@ -686,6 +687,11 @@ static inline int xsm_dm_op(xsm_default_t def, struct domain *d) return xsm_ops->dm_op(d); } +static inline int xsm_iommu_op(xsm_default_t def, struct domain *d, unsigned int op) +{ + return xsm_ops->iommu_op(d, op); +} + #endif /* CONFIG_X86 */ static inline int xsm_xen_version (xsm_default_t def, uint32_t op) diff --git a/xen/xsm/dummy.c b/xen/xsm/dummy.c index 3290d04527..8532b74b9a 100644 --- a/xen/xsm/dummy.c +++ b/xen/xsm/dummy.c @@ -155,6 +155,7 @@ void __init xsm_fixup_ops (struct xsm_operations *ops) set_to_dummy_if_null(ops, ioport_mapping); set_to_dummy_if_null(ops, pmu_op); set_to_dummy_if_null(ops, dm_op); + set_to_dummy_if_null(ops, iommu_op); #endif set_to_dummy_if_null(ops, xen_version); set_to_dummy_if_null(ops, domain_resource_map); diff --git a/xen/xsm/flask/hooks.c b/xen/xsm/flask/hooks.c index 6da2773aa9..211e69fb38 100644 --- a/xen/xsm/flask/hooks.c +++ b/xen/xsm/flask/hooks.c @@ -1666,6 +1666,11 @@ static int flask_dm_op(struct domain *d) return current_has_perm(d, SECCLASS_HVM, HVM__DM); } +static int flask_iommu_op(struct domain *d) +{ + return current_has_perm(d, SECCLASS_RESOURCE, RESOURCE__CONTROL_IOMMU); +} + #endif /* CONFIG_X86 */ static int flask_xen_version (uint32_t op) @@ -1844,6 +1849,7 @@ static struct xsm_operations flask_ops = { .ioport_mapping = flask_ioport_mapping, .pmu_op = flask_pmu_op, .dm_op = flask_dm_op, + .iommu_op = flask_iommu_op, #endif .xen_version = flask_xen_version, .domain_resource_map = flask_domain_resource_map, diff --git a/xen/xsm/flask/policy/access_vectors b/xen/xsm/flask/policy/access_vectors index d01a7a0d03..802cbb8ea9 100644 --- a/xen/xsm/flask/policy/access_vectors +++ b/xen/xsm/flask/policy/access_vectors @@ -469,6 +469,8 @@ class resource # checked for PHYSDEVOP_setup_gsi (target IRQ) # checked for PHYSDEVOP_pci_mmcfg_reserved (target xen_t) setup +# checked for IOMMU_OP + control_iommu } # Class security describes the FLASK security server itself; these operations -- 2.11.0 _______________________________________________ Xen-devel mailing list Xen-devel@xxxxxxxxxxxxxxxxxxxx https://lists.xenproject.org/mailman/listinfo/xen-devel
|
Lists.xenproject.org is hosted with RackSpace, monitoring our |