[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index] [Xen-changelog] [xen master] x86/altp2m: support for setting restrictions for an array of pages
commit 9383de210e747f15d0fd10ade89e35d543fbc4e8 Author: Razvan Cojocaru <rcojocaru@xxxxxxxxxxxxxxx> AuthorDate: Fri Mar 30 18:39:05 2018 +0300 Commit: George Dunlap <george.dunlap@xxxxxxxxxx> CommitDate: Wed Apr 4 14:12:11 2018 +0100 x86/altp2m: support for setting restrictions for an array of pages For the default EPT view we have xc_set_mem_access_multi(), which is able to set an array of pages to an array of access rights with a single hypercall. However, this functionality was lacking for the altp2m subsystem, which could only set page restrictions for one page at a time. This patch addresses the gap. HVMOP_altp2m_set_mem_access_multi has been added as a HVMOP (as opposed to a DOMCTL) for consistency with its HVMOP_altp2m_set_mem_access counterpart (and hence with the original altp2m design, where domains are allowed - with the proper altp2m access rights - to alter these settings), in the absence of an official position on the issue from the original altp2m designers. Signed-off-by: Razvan Cojocaru <rcojocaru@xxxxxxxxxxxxxxx> Signed-off-by: Petre Pircalabu <ppircalabu@xxxxxxxxxxxxxxx> Acked-by: Wei Liu <wei.liu2@xxxxxxxxxx> Reviewed-by: George Dunlap <george.dunlap@xxxxxxxxxx> --- tools/libxc/include/xenctrl.h | 3 + tools/libxc/xc_altp2m.c | 41 ++++++++++++ xen/arch/x86/hvm/hvm.c | 143 +++++++++++++++++++++++++++++++++++++++- xen/include/Makefile | 3 +- xen/include/public/hvm/hvm_op.h | 39 +++++++++-- xen/include/xlat.lst | 1 + 6 files changed, 223 insertions(+), 7 deletions(-) diff --git a/tools/libxc/include/xenctrl.h b/tools/libxc/include/xenctrl.h index 058e832c47..408fa1c6a4 100644 --- a/tools/libxc/include/xenctrl.h +++ b/tools/libxc/include/xenctrl.h @@ -1961,6 +1961,9 @@ int xc_altp2m_switch_to_view(xc_interface *handle, uint32_t domid, int xc_altp2m_set_mem_access(xc_interface *handle, uint32_t domid, uint16_t view_id, xen_pfn_t gfn, xenmem_access_t access); +int xc_altp2m_set_mem_access_multi(xc_interface *handle, uint32_t domid, + uint16_t view_id, uint8_t *access, + uint64_t *gfns, uint32_t nr); int xc_altp2m_change_gfn(xc_interface *handle, uint32_t domid, uint16_t view_id, xen_pfn_t old_gfn, xen_pfn_t new_gfn); diff --git a/tools/libxc/xc_altp2m.c b/tools/libxc/xc_altp2m.c index 07fcd18326..ce4a1e4d60 100644 --- a/tools/libxc/xc_altp2m.c +++ b/tools/libxc/xc_altp2m.c @@ -213,3 +213,44 @@ int xc_altp2m_change_gfn(xc_interface *handle, uint32_t domid, return rc; } +int xc_altp2m_set_mem_access_multi(xc_interface *xch, uint32_t domid, + uint16_t view_id, uint8_t *access, + uint64_t *gfns, uint32_t nr) +{ + int rc; + + DECLARE_HYPERCALL_BUFFER(xen_hvm_altp2m_op_t, arg); + DECLARE_HYPERCALL_BOUNCE(access, nr * sizeof(*access), + XC_HYPERCALL_BUFFER_BOUNCE_IN); + DECLARE_HYPERCALL_BOUNCE(gfns, nr * sizeof(*gfns), + XC_HYPERCALL_BUFFER_BOUNCE_IN); + + arg = xc_hypercall_buffer_alloc(xch, arg, sizeof(*arg)); + if ( arg == NULL ) + return -1; + + arg->version = HVMOP_ALTP2M_INTERFACE_VERSION; + arg->cmd = HVMOP_altp2m_set_mem_access_multi; + arg->domain = domid; + arg->u.set_mem_access_multi.view = view_id; + arg->u.set_mem_access_multi.nr = nr; + + if ( xc_hypercall_bounce_pre(xch, gfns) || + xc_hypercall_bounce_pre(xch, access) ) + { + PERROR("Could not bounce memory for HVMOP_altp2m_set_mem_access_multi"); + return -1; + } + + set_xen_guest_handle(arg->u.set_mem_access_multi.pfn_list, gfns); + set_xen_guest_handle(arg->u.set_mem_access_multi.access_list, access); + + rc = xencall2(xch->xcall, __HYPERVISOR_hvm_op, HVMOP_altp2m, + HYPERCALL_BUFFER_AS_ARG(arg)); + + xc_hypercall_buffer_free(xch, arg); + xc_hypercall_bounce_post(xch, access); + xc_hypercall_bounce_post(xch, gfns); + + return rc; +} diff --git a/xen/arch/x86/hvm/hvm.c b/xen/arch/x86/hvm/hvm.c index 569b124603..1376ce5942 100644 --- a/xen/arch/x86/hvm/hvm.c +++ b/xen/arch/x86/hvm/hvm.c @@ -74,6 +74,8 @@ #include <public/arch-x86/cpuid.h> #include <asm/cpuid.h> +#include <compat/hvm/hvm_op.h> + bool_t __read_mostly hvm_enabled; #ifdef DBG_LEVEL_0 @@ -4507,8 +4509,10 @@ static int do_altp2m_op( case HVMOP_altp2m_destroy_p2m: case HVMOP_altp2m_switch_p2m: case HVMOP_altp2m_set_mem_access: + case HVMOP_altp2m_set_mem_access_multi: case HVMOP_altp2m_change_gfn: break; + default: return -EOPNOTSUPP; } @@ -4630,6 +4634,39 @@ static int do_altp2m_op( a.u.set_mem_access.view); break; + case HVMOP_altp2m_set_mem_access_multi: + if ( a.u.set_mem_access_multi.pad || + a.u.set_mem_access_multi.opaque > a.u.set_mem_access_multi.nr ) + { + rc = -EINVAL; + break; + } + + /* + * Unlike XENMEM_access_op_set_access_multi, we don't need any bits of + * the 'continuation' counter to be zero (to stash a command in). + * However, 0x40 is a good 'stride' to make sure that we make + * a reasonable amount of forward progress before yielding, + * so use a mask of 0x3F here. + */ + rc = p2m_set_mem_access_multi(d, a.u.set_mem_access_multi.pfn_list, + a.u.set_mem_access_multi.access_list, + a.u.set_mem_access_multi.nr, + a.u.set_mem_access_multi.opaque, + 0x3F, + a.u.set_mem_access_multi.view); + if ( rc > 0 ) + { + a.u.set_mem_access_multi.opaque = rc; + if ( __copy_field_to_guest(guest_handle_cast(arg, xen_hvm_altp2m_op_t), + &a, u.set_mem_access_multi.opaque) ) + rc = -EFAULT; + else + rc = hypercall_create_continuation(__HYPERVISOR_hvm_op, "lh", + HVMOP_altp2m, arg); + } + break; + case HVMOP_altp2m_change_gfn: if ( a.u.change_gfn.pad1 || a.u.change_gfn.pad2 ) rc = -EINVAL; @@ -4648,6 +4685,110 @@ static int do_altp2m_op( return rc; } +DEFINE_XEN_GUEST_HANDLE(compat_hvm_altp2m_op_t); + +/* + * Manually define the CHECK_ macros for hvm_altp2m_op and + * hvm_altp2m_set_mem_access_multi as the generated versions can't handle + * correctly the translation of all fields from compat_(*) to xen_(*). + */ +#ifndef CHECK_hvm_altp2m_op +#define CHECK_hvm_altp2m_op \ + CHECK_SIZE_(struct, hvm_altp2m_op); \ + CHECK_FIELD_(struct, hvm_altp2m_op, version); \ + CHECK_FIELD_(struct, hvm_altp2m_op, cmd); \ + CHECK_FIELD_(struct, hvm_altp2m_op, domain); \ + CHECK_FIELD_(struct, hvm_altp2m_op, pad1); \ + CHECK_FIELD_(struct, hvm_altp2m_op, pad2) +#endif /* CHECK_hvm_altp2m_op */ + +#ifndef CHECK_hvm_altp2m_set_mem_access_multi +#define CHECK_hvm_altp2m_set_mem_access_multi \ + CHECK_FIELD_(struct, hvm_altp2m_set_mem_access_multi, view); \ + CHECK_FIELD_(struct, hvm_altp2m_set_mem_access_multi, pad); \ + CHECK_FIELD_(struct, hvm_altp2m_set_mem_access_multi, nr); \ + CHECK_FIELD_(struct, hvm_altp2m_set_mem_access_multi, opaque) +#endif /* CHECK_hvm_altp2m_set_mem_access_multi */ + +CHECK_hvm_altp2m_op; +CHECK_hvm_altp2m_set_mem_access_multi; + +static int compat_altp2m_op( + XEN_GUEST_HANDLE_PARAM(void) arg) +{ + int rc = 0; + struct compat_hvm_altp2m_op a; + union + { + XEN_GUEST_HANDLE_PARAM(void) hnd; + struct xen_hvm_altp2m_op *altp2m_op; + } nat; + + if ( !hvm_altp2m_supported() ) + return -EOPNOTSUPP; + + if ( copy_from_guest(&a, arg, 1) ) + return -EFAULT; + + if ( a.pad1 || a.pad2 || + (a.version != HVMOP_ALTP2M_INTERFACE_VERSION) ) + return -EINVAL; + + set_xen_guest_handle(nat.hnd, COMPAT_ARG_XLAT_VIRT_BASE); + + switch ( a.cmd ) + { + case HVMOP_altp2m_set_mem_access_multi: +#define XLAT_hvm_altp2m_set_mem_access_multi_HNDL_pfn_list(_d_, _s_); \ + guest_from_compat_handle((_d_)->pfn_list, (_s_)->pfn_list) +#define XLAT_hvm_altp2m_set_mem_access_multi_HNDL_access_list(_d_, _s_); \ + guest_from_compat_handle((_d_)->access_list, (_s_)->access_list) + XLAT_hvm_altp2m_set_mem_access_multi(&nat.altp2m_op->u.set_mem_access_multi, + &a.u.set_mem_access_multi); +#undef XLAT_hvm_altp2m_set_mem_access_multi_HNDL_pfn_list +#undef XLAT_hvm_altp2m_set_mem_access_multi_HNDL_access_list + break; + + default: + return do_altp2m_op(arg); + } + + /* Manually fill the common part of the xen_hvm_altp2m_op structure. */ + nat.altp2m_op->version = a.version; + nat.altp2m_op->cmd = a.cmd; + nat.altp2m_op->domain = a.domain; + nat.altp2m_op->pad1 = a.pad1; + nat.altp2m_op->pad2 = a.pad2; + + rc = do_altp2m_op(nat.hnd); + + switch ( a.cmd ) + { + case HVMOP_altp2m_set_mem_access_multi: + /* + * The return code can be positive only if it is the return value + * of hypercall_create_continuation. In this case, the opaque value + * must be copied back to the guest. + */ + if ( rc > 0 ) + { + ASSERT(rc == __HYPERVISOR_hvm_op); + a.u.set_mem_access_multi.opaque = + nat.altp2m_op->u.set_mem_access_multi.opaque; + if ( __copy_field_to_guest(guest_handle_cast(arg, + compat_hvm_altp2m_op_t), + &a, u.set_mem_access_multi.opaque) ) + rc = -EFAULT; + } + break; + + default: + ASSERT_UNREACHABLE(); + } + + return rc; +} + static int hvmop_get_mem_type( XEN_GUEST_HANDLE_PARAM(xen_hvm_get_mem_type_t) arg) { @@ -4795,7 +4936,7 @@ long do_hvm_op(unsigned long op, XEN_GUEST_HANDLE_PARAM(void) arg) break; case HVMOP_altp2m: - rc = do_altp2m_op(arg); + rc = current->hcall_compat ? compat_altp2m_op(arg) : do_altp2m_op(arg); break; default: diff --git a/xen/include/Makefile b/xen/include/Makefile index 69052ade24..8762ab3334 100644 --- a/xen/include/Makefile +++ b/xen/include/Makefile @@ -26,8 +26,9 @@ headers-$(CONFIG_X86) += compat/arch-x86/pmu.h headers-$(CONFIG_X86) += compat/arch-x86/xen-mca.h 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/hvm/hvm_op.h +headers-$(CONFIG_X86) += compat/hvm/hvm_vcpu.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/hvm/hvm_op.h b/xen/include/public/hvm/hvm_op.h index 0bdafdf59a..bbba99e5f5 100644 --- a/xen/include/public/hvm/hvm_op.h +++ b/xen/include/public/hvm/hvm_op.h @@ -83,6 +83,13 @@ DEFINE_XEN_GUEST_HANDLE(xen_hvm_set_pci_link_route_t); /* Flushes all VCPU TLBs: @arg must be NULL. */ #define HVMOP_flush_tlbs 5 +/* + * hvmmem_type_t should not be defined when generating the corresponding + * compat header. This will ensure that the improperly named HVMMEM_(*) + * values are defined only once. + */ +#ifndef XEN_GENERATING_COMPAT_HEADERS + typedef enum { HVMMEM_ram_rw, /* Normal read/write guest RAM */ HVMMEM_ram_ro, /* Read-only; writes are discarded */ @@ -102,6 +109,8 @@ typedef enum { to HVMMEM_ram_rw. */ } hvmmem_type_t; +#endif /* XEN_GENERATING_COMPAT_HEADERS */ + /* Hint from PV drivers for pagetable destruction. */ #define HVMOP_pagetable_dying 9 struct xen_hvm_pagetable_dying { @@ -237,6 +246,23 @@ struct xen_hvm_altp2m_set_mem_access { typedef struct xen_hvm_altp2m_set_mem_access xen_hvm_altp2m_set_mem_access_t; DEFINE_XEN_GUEST_HANDLE(xen_hvm_altp2m_set_mem_access_t); +struct xen_hvm_altp2m_set_mem_access_multi { + /* view */ + uint16_t view; + uint16_t pad; + /* Number of pages */ + uint32_t nr; + /* + * Used for continuation purposes. + * Must be set to zero upon initial invocation. + */ + uint64_t opaque; + /* List of pfns to set access for */ + XEN_GUEST_HANDLE(const_uint64) pfn_list; + /* Corresponding list of access settings for pfn_list */ + XEN_GUEST_HANDLE(const_uint8) access_list; +}; + struct xen_hvm_altp2m_change_gfn { /* view */ uint16_t view; @@ -268,15 +294,18 @@ struct xen_hvm_altp2m_op { #define HVMOP_altp2m_set_mem_access 7 /* Change a p2m entry to have a different gfn->mfn mapping */ #define HVMOP_altp2m_change_gfn 8 +/* Set access for an array of pages */ +#define HVMOP_altp2m_set_mem_access_multi 9 domid_t domain; uint16_t pad1; uint32_t pad2; union { - struct xen_hvm_altp2m_domain_state domain_state; - struct xen_hvm_altp2m_vcpu_enable_notify enable_notify; - struct xen_hvm_altp2m_view view; - struct xen_hvm_altp2m_set_mem_access set_mem_access; - struct xen_hvm_altp2m_change_gfn change_gfn; + struct xen_hvm_altp2m_domain_state domain_state; + struct xen_hvm_altp2m_vcpu_enable_notify enable_notify; + struct xen_hvm_altp2m_view view; + struct xen_hvm_altp2m_set_mem_access set_mem_access; + struct xen_hvm_altp2m_change_gfn change_gfn; + struct xen_hvm_altp2m_set_mem_access_multi set_mem_access_multi; uint8_t pad[64]; } u; }; diff --git a/xen/include/xlat.lst b/xen/include/xlat.lst index a727ab042e..527332054a 100644 --- a/xen/include/xlat.lst +++ b/xen/include/xlat.lst @@ -73,6 +73,7 @@ ? dm_op_set_pci_intx_level hvm/dm_op.h ? dm_op_set_pci_link_route hvm/dm_op.h ? dm_op_track_dirty_vram hvm/dm_op.h +! hvm_altp2m_set_mem_access_multi hvm/hvm_op.h ? vcpu_hvm_context hvm/hvm_vcpu.h ? vcpu_hvm_x86_32 hvm/hvm_vcpu.h ? vcpu_hvm_x86_64 hvm/hvm_vcpu.h -- generated by git-patchbot for /home/xen/git/xen.git#master _______________________________________________ Xen-changelog mailing list Xen-changelog@xxxxxxxxxxxxxxxxxxxx https://lists.xenproject.org/xen-changelog
|
Lists.xenproject.org is hosted with RackSpace, monitoring our |