public / x86: introduce hvmctl hypercall ... as a means to replace all HVMOP_* which a domain can't issue on itself (i.e. intended for use by only the control domain or device model). Signed-off-by: Jan Beulich Reviewed-by: Wei Liu --- v2: Widen cmd field to 32 bits and opaque one to 64. Drop HVMCTL_iter_*. --- a/xen/arch/x86/hvm/Makefile +++ b/xen/arch/x86/hvm/Makefile @@ -2,6 +2,7 @@ subdir-y += svm subdir-y += vmx obj-y += asid.o +obj-y += control.o obj-y += emulate.o obj-y += event.o obj-y += hpet.o --- /dev/null +++ b/xen/arch/x86/hvm/control.c @@ -0,0 +1,82 @@ +/* + * control.c: Hardware virtual machine control operations. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms and conditions of the GNU General Public License, + * version 2, as published by the Free Software Foundation. + * + * This program is distributed in the hope 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 . + */ + +#include +#include +#include +#include + +long do_hvmctl(XEN_GUEST_HANDLE_PARAM(xen_hvmctl_t) u_hvmctl) +{ + xen_hvmctl_t op; + struct domain *d; + int rc; + + BUILD_BUG_ON(sizeof(op.u) > sizeof(op.u.pad)); + + if ( copy_from_guest(&op, u_hvmctl, 1) ) + return -EFAULT; + + if ( op.interface_version != XEN_HVMCTL_INTERFACE_VERSION ) + return -EACCES; + + rc = rcu_lock_remote_domain_by_id(op.domain, &d); + if ( rc ) + return rc; + + if ( !has_hvm_container_domain(d) ) + { + rcu_unlock_domain(d); + return -EINVAL; + } + + rc = xsm_hvm_control(XSM_DM_PRIV, d, op.cmd); + if ( rc ) + { + rcu_unlock_domain(d); + return rc; + } + + switch ( op.cmd ) + { + default: + rc = -EOPNOTSUPP; + break; + } + + rcu_unlock_domain(d); + + if ( rc == -ERESTART ) + { + if ( unlikely(copy_field_to_guest(u_hvmctl, &op, opaque)) ) + rc = -EFAULT; + else + rc = hypercall_create_continuation(__HYPERVISOR_hvmctl, "h", + u_hvmctl); + } + + return rc; +} + +/* + * Local variables: + * mode: C + * c-file-style: "BSD" + * c-basic-offset: 4 + * tab-width: 4 + * indent-tabs-mode: nil + * End: + */ --- a/xen/arch/x86/hvm/hvm.c +++ b/xen/arch/x86/hvm/hvm.c @@ -4111,6 +4111,7 @@ static const struct { COMPAT_CALL(platform_op), COMPAT_CALL(mmuext_op), HYPERCALL(xenpmu_op), + HYPERCALL(hvmctl), HYPERCALL(arch_1) }; --- a/xen/arch/x86/x86_64/compat/entry.S +++ b/xen/arch/x86/x86_64/compat/entry.S @@ -469,6 +469,7 @@ ENTRY(compat_hypercall_table) .quad do_tmem_op .quad do_ni_hypercall /* reserved for XenClient */ .quad do_xenpmu_op /* 40 */ + .quad do_hvmctl .rept __HYPERVISOR_arch_0-((.-compat_hypercall_table)/8) .quad compat_ni_hypercall .endr @@ -520,6 +521,7 @@ ENTRY(compat_hypercall_args_table) .byte 1 /* do_tmem_op */ .byte 0 /* reserved for XenClient */ .byte 2 /* do_xenpmu_op */ /* 40 */ + .byte 1 /* do_hvmctl */ .rept __HYPERVISOR_arch_0-(.-compat_hypercall_args_table) .byte 0 /* compat_ni_hypercall */ .endr --- a/xen/arch/x86/x86_64/entry.S +++ b/xen/arch/x86/x86_64/entry.S @@ -792,6 +792,7 @@ ENTRY(hypercall_table) .quad do_tmem_op .quad do_ni_hypercall /* reserved for XenClient */ .quad do_xenpmu_op /* 40 */ + .quad do_hvmctl .rept __HYPERVISOR_arch_0-((.-hypercall_table)/8) .quad do_ni_hypercall .endr @@ -843,6 +844,7 @@ ENTRY(hypercall_args_table) .byte 1 /* do_tmem_op */ .byte 0 /* reserved for XenClient */ .byte 2 /* do_xenpmu_op */ /* 40 */ + .byte 1 /* do_hvmctl */ .rept __HYPERVISOR_arch_0-(.-hypercall_args_table) .byte 0 /* do_ni_hypercall */ .endr --- a/xen/include/Makefile +++ b/xen/include/Makefile @@ -93,7 +93,7 @@ all: headers.chk headers++.chk PUBLIC_HEADERS := $(filter-out public/arch-% public/dom0_ops.h, $(wildcard public/*.h public/*/*.h) $(public-y)) -PUBLIC_ANSI_HEADERS := $(filter-out public/%ctl.h public/xsm/% public/%hvm/save.h, $(PUBLIC_HEADERS)) +PUBLIC_ANSI_HEADERS := $(filter-out public/%ctl.h public/hvm/control.h public/xsm/% public/%hvm/save.h,$(PUBLIC_HEADERS)) headers.chk: $(PUBLIC_ANSI_HEADERS) Makefile for i in $(filter %.h,$^); do \ --- /dev/null +++ b/xen/include/public/hvm/control.h @@ -0,0 +1,54 @@ +/* + * 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. + */ + +#ifndef __XEN_PUBLIC_HVM_CONTROL_H__ +#define __XEN_PUBLIC_HVM_CONTROL_H__ + +#if !defined(__XEN__) && !defined(__XEN_TOOLS__) +#error "HVM control operations are intended for use by control tools only" +#endif + +#include "../xen.h" + +#define XEN_HVMCTL_INTERFACE_VERSION 0x00000001 + +struct xen_hvmctl { + uint16_t interface_version; /* XEN_HVMCTL_INTERFACE_VERSION */ + domid_t domain; + uint32_t cmd; + uint64_t opaque; /* Must be zero on initial invocation. */ + union { + uint8_t pad[120]; + } u; +}; +typedef struct xen_hvmctl xen_hvmctl_t; +DEFINE_XEN_GUEST_HANDLE(xen_hvmctl_t); + +#endif /* __XEN_PUBLIC_HVM_CONTROL_H__ */ + +/* + * Local variables: + * mode: C + * c-file-style: "BSD" + * c-basic-offset: 4 + * tab-width: 4 + * indent-tabs-mode: nil + * End: + */ --- a/xen/include/public/xen.h +++ b/xen/include/public/xen.h @@ -115,6 +115,7 @@ DEFINE_XEN_GUEST_HANDLE(xen_ulong_t); #define __HYPERVISOR_tmem_op 38 #define __HYPERVISOR_xc_reserved_op 39 /* reserved for XenClient */ #define __HYPERVISOR_xenpmu_op 40 +#define __HYPERVISOR_hvmctl 41 /* Architecture-specific hypercall definitions. */ #define __HYPERVISOR_arch_0 48 --- a/xen/include/xen/hypercall.h +++ b/xen/include/xen/hypercall.h @@ -15,6 +15,7 @@ #include #include #include +#include #include #include @@ -46,6 +47,10 @@ arch_do_sysctl( XEN_GUEST_HANDLE_PARAM(xen_sysctl_t) u_sysctl); extern long +do_hvmctl( + XEN_GUEST_HANDLE_PARAM(xen_hvmctl_t) u_hvmctl); + +extern long do_platform_op( XEN_GUEST_HANDLE_PARAM(xen_platform_op_t) u_xenpf_op); --- a/xen/xsm/flask/hooks.c +++ b/xen/xsm/flask/hooks.c @@ -1183,6 +1183,20 @@ static int flask_hvm_param(struct domain return current_has_perm(d, SECCLASS_HVM, perm); } +static int flask_hvm_control(struct domain *d, unsigned long op) +{ + u32 perm; + + switch ( op ) + { + default: + perm = HVM__HVMCTL; + break; + } + + return current_has_perm(d, SECCLASS_HVM, perm); +} + static int flask_hvm_param_nested(struct domain *d) { return current_has_perm(d, SECCLASS_HVM, HVM__NESTED); @@ -1745,7 +1759,7 @@ static struct xsm_operations flask_ops = .page_offline = flask_page_offline, .tmem_op = flask_tmem_op, .hvm_param = flask_hvm_param, - .hvm_control = flask_hvm_param, + .hvm_control = flask_hvm_control, .hvm_param_nested = flask_hvm_param_nested, .hvm_param_altp2mhvm = flask_hvm_param_altp2mhvm, .hvm_altp2mhvm_op = flask_hvm_altp2mhvm_op,