[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index] [Xen-devel] [PATCH 5/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 since it could be used to cause IOMMU faults which may bring down a host. Signed-off-by: Paul Durrant <paul.durrant@xxxxxxxxxx> --- 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> Cc: Daniel De Graaf <dgdegra@xxxxxxxxxxxxx> --- tools/flask/policy/modules/xen.if | 1 + xen/arch/x86/Makefile | 1 + xen/arch/x86/hvm/hypercall.c | 1 + xen/arch/x86/hypercall.c | 1 + xen/arch/x86/iommu_op.c | 169 ++++++++++++++++++++++++++++++++++++ xen/arch/x86/pv/hypercall.c | 1 + xen/include/Makefile | 2 + xen/include/public/iommu_op.h | 55 ++++++++++++ xen/include/public/xen.h | 1 + xen/include/xen/hypercall.h | 12 +++ xen/include/xlat.lst | 1 + 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, 266 insertions(+) create mode 100644 xen/arch/x86/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 459880bb01..5a1d447afd 100644 --- a/tools/flask/policy/modules/xen.if +++ b/tools/flask/policy/modules/xen.if @@ -59,6 +59,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/Makefile b/xen/arch/x86/Makefile index d903b7abb9..df3fdc1beb 100644 --- a/xen/arch/x86/Makefile +++ b/xen/arch/x86/Makefile @@ -33,6 +33,7 @@ obj-$(CONFIG_CRASH_DEBUG) += gdbstub.o obj-y += hypercall.o obj-y += i387.o obj-y += i8259.o +obj-y += iommu_op.o obj-y += io_apic.o obj-$(CONFIG_LIVEPATCH) += alternative.o livepatch.o obj-y += msi.o diff --git a/xen/arch/x86/hvm/hypercall.c b/xen/arch/x86/hvm/hypercall.c index 5742dd1797..df96019103 100644 --- a/xen/arch/x86/hvm/hypercall.c +++ b/xen/arch/x86/hvm/hypercall.c @@ -132,6 +132,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 90e88c1d2c..045753e702 100644 --- a/xen/arch/x86/hypercall.c +++ b/xen/arch/x86/hypercall.c @@ -68,6 +68,7 @@ const hypercall_args_t hypercall_args_table[NR_hypercalls] = ARGS(xenpmu_op, 2), ARGS(dm_op, 3), ARGS(mca, 1), + ARGS(iommu_op, 2), ARGS(arch_1, 1), }; diff --git a/xen/arch/x86/iommu_op.c b/xen/arch/x86/iommu_op.c new file mode 100644 index 0000000000..edd8a384b3 --- /dev/null +++ b/xen/arch/x86/iommu_op.c @@ -0,0 +1,169 @@ +/****************************************************************************** + * x86/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 bool can_control_iommu(void) +{ + struct domain *currd = current->domain; + + /* + * IOMMU mappings cannot be manipulated if: + * - the IOMMU is not enabled or, + * - the IOMMU is passed through or, + * - shared EPT configured or, + * - Xen is maintaining an identity map. + */ + if ( !iommu_enabled || iommu_passthrough || + iommu_use_hap_pt(currd) || need_iommu(currd) ) + return false; + + return true; +} + +static void iommu_op(xen_iommu_op_t *op) +{ + switch ( op->op ) + { + default: + op->status = -EOPNOTSUPP; + break; + } +} + +long do_iommu_op(XEN_GUEST_HANDLE_PARAM(xen_iommu_op_t) uops, + unsigned int count) +{ + unsigned int i; + int rc; + + rc = xsm_iommu_op(XSM_PRIV, current->domain); + if ( rc ) + return rc; + + if ( !can_control_iommu() ) + return -EACCES; + + for ( i = 0; i < count; i++ ) + { + xen_iommu_op_t op; + + if ( ((i & 0xff) == 0xff) && hypercall_preempt_check() ) + { + rc = i; + break; + } + + if ( copy_from_guest_offset(&op, uops, i, 1) ) + { + rc = -EFAULT; + break; + } + + iommu_op(&op); + + if ( copy_to_guest_offset(uops, i, &op, 1) ) + { + rc = -EFAULT; + break; + } + } + + if ( rc > 0 ) + { + ASSERT(rc < count); + guest_handle_add_offset(uops, rc); + count -= rc; + + rc = hypercall_create_continuation(__HYPERVISOR_iommu_op, + "hi", uops, count); + } + + return rc; +} + +int compat_iommu_op(XEN_GUEST_HANDLE_PARAM(compat_iommu_op_t) uops, + unsigned int count) +{ + unsigned int i; + int rc; + + rc = xsm_iommu_op(XSM_PRIV, current->domain); + if ( rc ) + return rc; + + if ( !can_control_iommu() ) + return -EACCES; + + for ( i = 0; i < count; i++ ) + { + compat_iommu_op_t cmp; + xen_iommu_op_t nat; + + if ( ((i & 0xff) == 0xff) && hypercall_preempt_check() ) + { + rc = i; + break; + } + + if ( copy_from_guest_offset(&cmp, uops, i, 1) ) + { + rc = -EFAULT; + break; + } + + XLAT_iommu_op(&nat, &cmp); + + iommu_op(&nat); + + XLAT_iommu_op(&cmp, &nat); + + if ( copy_to_guest_offset(uops, i, &cmp, 1) ) + { + rc = -EFAULT; + break; + } + } + + if ( rc > 0 ) + { + ASSERT(rc < count); + guest_handle_add_offset(uops, rc); + count -= rc; + + rc = hypercall_create_continuation(__HYPERVISOR_iommu_op, + "hi", uops, count); + } + + return rc; +} + +/* + * Local variables: + * mode: C + * c-file-style: "BSD" + * c-basic-offset: 4 + * tab-width: 4 + * indent-tabs-mode: nil + * End: + */ diff --git a/xen/arch/x86/pv/hypercall.c b/xen/arch/x86/pv/hypercall.c index bbc3011d1a..d23f9af42f 100644 --- a/xen/arch/x86/pv/hypercall.c +++ b/xen/arch/x86/pv/hypercall.c @@ -80,6 +80,7 @@ const hypercall_table_t pv_hypercall_table[] = { HYPERCALL(xenpmu_op), COMPAT_CALL(dm_op), HYPERCALL(mca), + COMPAT_CALL(iommu_op), HYPERCALL(arch_1), }; diff --git a/xen/include/Makefile b/xen/include/Makefile index 19066a33a0..ac3d6e5aef 100644 --- a/xen/include/Makefile +++ b/xen/include/Makefile @@ -11,6 +11,7 @@ headers-y := \ compat/features.h \ compat/grant_table.h \ compat/kexec.h \ + compat/iommu_op.h \ compat/memory.h \ compat/nmi.h \ compat/physdev.h \ @@ -28,6 +29,7 @@ headers-$(CONFIG_X86) += compat/arch-x86/xen.h headers-$(CONFIG_X86) += compat/arch-x86/xen-$(compat-arch-y).h headers-$(CONFIG_X86) += compat/hvm/hvm_vcpu.h headers-$(CONFIG_X86) += compat/hvm/dm_op.h +headers-$(CONFIG_X86) += compat/iommu_op.h headers-y += compat/arch-$(compat-arch-y).h compat/pmu.h compat/xlat.h headers-$(CONFIG_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..202cb63fb5 --- /dev/null +++ b/xen/include/public/iommu_op.h @@ -0,0 +1,55 @@ +/* + * 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; + uint16_t flags; /* op specific flags */ + 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); + +/* ` enum neg_errnoval + * ` HYPERVISOR_iommu_op(xen_iommu_op_t ops[], + * ` unsigned int count) + * ` + * + * @ops points to an array of @count xen_iommu_op structures. + */ + +#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 308109f176..4200264411 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..8cb62b7d65 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(XEN_GUEST_HANDLE_PARAM(xen_iommu_op_t) ops, + unsigned int count); + #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_t); +extern int +compat_iommu_op(XEN_GUEST_HANDLE_PARAM(compat_iommu_op_t) ops, + unsigned int count); + #endif void arch_get_xen_caps(xen_capabilities_info_t *info); diff --git a/xen/include/xlat.lst b/xen/include/xlat.lst index 3690b97d5d..7409759084 100644 --- a/xen/include/xlat.lst +++ b/xen/include/xlat.lst @@ -76,6 +76,7 @@ ? 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 ? 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 d6ddadcafd..69431c88cd 100644 --- a/xen/include/xsm/dummy.h +++ b/xen/include/xsm/dummy.h @@ -701,6 +701,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) +{ + 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 e3912bcc9d..9d95a4e5bb 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); #endif int (*xen_version) (uint32_t cmd); }; @@ -685,6 +686,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) +{ + return xsm_ops->iommu_op(d); +} + #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 479b103614..21cefdee74 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); } diff --git a/xen/xsm/flask/hooks.c b/xen/xsm/flask/hooks.c index 1802d8dfe6..1bef3269c4 100644 --- a/xen/xsm/flask/hooks.c +++ b/xen/xsm/flask/hooks.c @@ -1670,6 +1670,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) @@ -1843,6 +1848,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, }; diff --git a/xen/xsm/flask/policy/access_vectors b/xen/xsm/flask/policy/access_vectors index 89b99966bb..190017dfc3 100644 --- a/xen/xsm/flask/policy/access_vectors +++ b/xen/xsm/flask/policy/access_vectors @@ -471,6 +471,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 |