[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index] [Xen-devel] [PATCH v2 10/10] xen-access: Add support for vm_event_ng interface
Split xen-access in order to accommodate both vm_event interfaces (legacy and NG). By default, the legacy vm_event is selected but this can be changed by adding the '-n' flag in the command line. Signed-off-by: Petre Pircalabu <ppircalabu@xxxxxxxxxxxxxxx> --- tools/tests/xen-access/Makefile | 7 +- tools/tests/xen-access/vm-event-ng.c | 183 ++++++++++++++++++ tools/tests/xen-access/vm-event.c | 194 +++++++++++++++++++ tools/tests/xen-access/xen-access.c | 348 +++++++++++------------------------ tools/tests/xen-access/xen-access.h | 91 +++++++++ 5 files changed, 582 insertions(+), 241 deletions(-) create mode 100644 tools/tests/xen-access/vm-event-ng.c create mode 100644 tools/tests/xen-access/vm-event.c create mode 100644 tools/tests/xen-access/xen-access.h diff --git a/tools/tests/xen-access/Makefile b/tools/tests/xen-access/Makefile index 131c9f3..17760d8 100644 --- a/tools/tests/xen-access/Makefile +++ b/tools/tests/xen-access/Makefile @@ -7,6 +7,7 @@ CFLAGS += -DXC_WANT_COMPAT_DEVICEMODEL_API CFLAGS += $(CFLAGS_libxenctrl) CFLAGS += $(CFLAGS_libxenguest) CFLAGS += $(CFLAGS_libxenevtchn) +CFLAGS += $(CFLAGS_libxenforeignmemory) CFLAGS += $(CFLAGS_xeninclude) TARGETS-y := xen-access @@ -25,8 +26,10 @@ clean: .PHONY: distclean distclean: clean -xen-access: xen-access.o Makefile - $(CC) -o $@ $< $(LDFLAGS) $(LDLIBS_libxenctrl) $(LDLIBS_libxenguest) $(LDLIBS_libxenevtchn) +OBJS = xen-access.o vm-event.o vm-event-ng.o + +xen-access: $(OBJS) Makefile + $(CC) -o $@ $(OBJS) $(LDFLAGS) $(LDLIBS_libxenctrl) $(LDLIBS_libxenguest) $(LDLIBS_libxenevtchn) $(LDLIBS_libxenforeignmemory) install uninstall: diff --git a/tools/tests/xen-access/vm-event-ng.c b/tools/tests/xen-access/vm-event-ng.c new file mode 100644 index 0000000..2c79f61 --- /dev/null +++ b/tools/tests/xen-access/vm-event-ng.c @@ -0,0 +1,183 @@ +/* + * vm-event-ng.c + * + * Copyright (c) 2019 Bitdefender S.R.L. + * + * 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. + */ + +#include <errno.h> +#include <inttypes.h> +#include <stdlib.h> +#include <string.h> +#include <sys/mman.h> +#include <xenforeignmemory.h> +#include "xen-access.h" + +#ifndef PFN_UP +#define PFN_UP(x) (((x) + XC_PAGE_SIZE-1) >> XC_PAGE_SHIFT) +#endif /* PFN_UP */ + +typedef struct vm_event_channels +{ + vm_event_t vme; + int num_channels; + xenforeignmemory_resource_handle *fres; + struct vm_event_slot *slots; + int *ports; +} vm_event_channels_t; + +#define to_channels(_vme) container_of((_vme), vm_event_channels_t, vme) + +static int vm_event_channels_init(xc_interface *xch, xenevtchn_handle *xce, + domid_t domain_id, vm_event_ops_t *ops, + vm_event_t **vm_event) +{ + vm_event_channels_t *impl = NULL; + int rc, i; + + impl = (vm_event_channels_t *)calloc(1, sizeof(vm_event_channels_t)); + if ( impl == NULL ) + return -ENOMEM; + + rc = xc_monitor_ng_enable(xch, domain_id, &impl->fres, &impl->num_channels, (void**)&impl->slots); + if ( rc ) + { + ERROR("Failed to enable monitor"); + return rc; + } + + impl->ports = calloc(impl->num_channels, sizeof(int)); + if ( impl->ports == NULL ) + { + rc = -ENOMEM; + goto err; + } + + for ( i = 0; i < impl->num_channels; i++) + { + rc = xenevtchn_bind_interdomain(xce, domain_id, impl->slots[i].port); + if ( rc < 0 ) + { + ERROR("Failed to bind vm_event_slot port for vcpu %d", i); + rc = -errno; + goto err; + } + + impl->ports[i] = rc; + } + + *vm_event = (vm_event_t*) impl; + return 0; + +err: + while ( --i >= 0 ) + xenevtchn_unbind(xce, impl->ports[i]); + free(impl->ports); + xc_monitor_ng_disable(xch, domain_id, &impl->fres); + free(impl); + return rc; +} + +static int vcpu_id_by_port(vm_event_channels_t *impl, int port, int *vcpu_id) +{ + int i; + + for ( i = 0; i < impl->num_channels; i++ ) + { + if ( port == impl->ports[i] ) + { + *vcpu_id = i; + return 0; + } + } + + return -EINVAL; +} + +static int vm_event_channels_teardown(vm_event_t *vm_event) +{ + vm_event_channels_t *impl = to_channels(vm_event); + int rc, i; + + if ( impl == NULL || impl->ports == NULL ) + return -EINVAL; + + for ( i = 0; i < impl->num_channels; i++ ) + { + rc = xenevtchn_unbind(vm_event->xce, impl->ports[i]); + if ( rc != 0 ) + { + ERROR("Error unbinding event port"); + return rc; + } + } + + return xc_monitor_ng_disable(impl->vme.xch, impl->vme.domain_id, &impl->fres); +} + +static bool vm_event_channels_get_request(vm_event_t *vm_event, vm_event_request_t *req, int *port) +{ + int vcpu_id; + vm_event_channels_t *impl = to_channels(vm_event); + + if ( vcpu_id_by_port(impl, *port, &vcpu_id) != 0 ) + return false; + + if ( impl->slots[vcpu_id].state != STATE_VM_EVENT_SLOT_SUBMIT ) + return false; + + memcpy(req, &impl->slots[vcpu_id].u.req, sizeof(*req)); + + return true; +} + +static void vm_event_channels_put_response(vm_event_t *vm_event, vm_event_response_t *rsp, int port) +{ + int vcpu_id; + vm_event_channels_t *impl = to_channels(vm_event); + + if ( vcpu_id_by_port(impl, port, &vcpu_id) != 0 ) + return; + + memcpy(&impl->slots[vcpu_id].u.rsp, rsp, sizeof(*rsp)); + impl->slots[vcpu_id].state = STATE_VM_EVENT_SLOT_FINISH; +} + +static int vm_event_channels_notify_port(vm_event_t *vm_event, int port) +{ + return xenevtchn_notify(vm_event->xce, port); +} + +vm_event_ops_t channel_ops = { + .get_request = vm_event_channels_get_request, + .put_response = vm_event_channels_put_response, + .notify_port = vm_event_channels_notify_port, + .init = vm_event_channels_init, + .teardown = vm_event_channels_teardown, +}; + +/* + * Local variables: + * mode: C + * c-file-style: "BSD" + * c-basic-offset: 4 + * indent-tabs-mode: nil + * End: + */ diff --git a/tools/tests/xen-access/vm-event.c b/tools/tests/xen-access/vm-event.c new file mode 100644 index 0000000..e6b20ce --- /dev/null +++ b/tools/tests/xen-access/vm-event.c @@ -0,0 +1,194 @@ +/* + * vm-event.c + * + * Copyright (c) 2019 Bitdefender S.R.L. + * + * 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. + */ + +#include <errno.h> +#include <inttypes.h> +#include <stdlib.h> +#include <string.h> +#include <sys/mman.h> +#include "xen-access.h" + +typedef struct vm_event_ring { + vm_event_t vme; + int port; + vm_event_back_ring_t back_ring; + uint32_t evtchn_port; + void *ring_page; +} vm_event_ring_t; + +#define to_ring(_vme) container_of((_vme), vm_event_ring_t, vme) + +static int vm_event_ring_init(xc_interface *xch, xenevtchn_handle *xce, + domid_t domain_id, vm_event_ops_t *ops, + vm_event_t **vm_event) +{ + vm_event_ring_t *impl; + int rc; + + impl = (vm_event_ring_t*) calloc (1, sizeof(vm_event_ring_t)); + if ( impl == NULL ) + return -ENOMEM; + + /* Enable mem_access */ + impl->ring_page = xc_monitor_enable(xch, domain_id, &impl->evtchn_port); + if ( impl->ring_page == NULL ) + { + switch ( errno ) + { + case EBUSY: + ERROR("xenaccess is (or was) active on this domain"); + break; + case ENODEV: + ERROR("EPT not supported for this guest"); + break; + default: + perror("Error enabling mem_access"); + break; + } + rc = -errno; + goto err; + } + + /* Bind event notification */ + rc = xenevtchn_bind_interdomain(xce, domain_id, impl->evtchn_port); + if ( rc < 0 ) + { + ERROR("Failed to bind event channel"); + munmap(impl->ring_page, XC_PAGE_SIZE); + xc_monitor_disable(xch, domain_id); + goto err; + } + + impl->port = rc; + + /* Initialise ring */ + SHARED_RING_INIT((vm_event_sring_t *)impl->ring_page); + BACK_RING_INIT(&impl->back_ring, (vm_event_sring_t *)impl->ring_page, + XC_PAGE_SIZE); + + *vm_event = (vm_event_t*) impl; + return 0; + +err: + free(impl); + return rc; +} + +static int vm_event_ring_teardown(vm_event_t *vm_event) +{ + vm_event_ring_t *impl = to_ring(vm_event); + int rc; + + if ( impl->ring_page != NULL ) + munmap(impl->ring_page, XC_PAGE_SIZE); + + /* Tear down domain xenaccess in Xen */ + rc = xc_monitor_disable(vm_event->xch, vm_event->domain_id); + if ( rc != 0 ) + { + ERROR("Error tearing down domain xenaccess in xen"); + return rc; + } + + /* Unbind VIRQ */ + rc = xenevtchn_unbind(vm_event->xce, impl->port); + if ( rc != 0 ) + { + ERROR("Error unbinding event port"); + return rc; + } + + return 0; +} + +/* + * Note that this function is not thread safe. + */ +static bool vm_event_ring_get_request(vm_event_t *vm_event, vm_event_request_t *req, int *port) +{ + vm_event_back_ring_t *back_ring; + RING_IDX req_cons; + vm_event_ring_t *impl = to_ring(vm_event); + + if ( !RING_HAS_UNCONSUMED_REQUESTS(&impl->back_ring) ) + return false; + + back_ring = &impl->back_ring; + req_cons = back_ring->req_cons; + + /* Copy request */ + memcpy(req, RING_GET_REQUEST(back_ring, req_cons), sizeof(*req)); + req_cons++; + + /* Update ring */ + back_ring->req_cons = req_cons; + back_ring->sring->req_event = req_cons + 1; + + *port = impl->port; + + return true; +} + +/* + * Note that this function is not thread safe. + */ +static void vm_event_ring_put_response(vm_event_t *vm_event, vm_event_response_t *rsp, int port) +{ + vm_event_back_ring_t *back_ring; + RING_IDX rsp_prod; + vm_event_ring_t *impl = to_ring(vm_event); + + back_ring = &impl->back_ring; + rsp_prod = back_ring->rsp_prod_pvt; + + /* Copy response */ + memcpy(RING_GET_RESPONSE(back_ring, rsp_prod), rsp, sizeof(*rsp)); + rsp_prod++; + + /* Update ring */ + back_ring->rsp_prod_pvt = rsp_prod; + RING_PUSH_RESPONSES(back_ring); +} + +static int vm_event_ring_notify_port(vm_event_t *vm_event, int port) +{ + return xenevtchn_notify(vm_event->xce, port); +} + +vm_event_ops_t ring_ops = { + .get_request = vm_event_ring_get_request, + .put_response = vm_event_ring_put_response, + .notify_port = vm_event_ring_notify_port, + .init = vm_event_ring_init, + .teardown = vm_event_ring_teardown, +}; + +/* + * Local variables: + * mode: C + * c-file-style: "BSD" + * c-basic-offset: 4 + * indent-tabs-mode: nil + * End: + */ diff --git a/tools/tests/xen-access/xen-access.c b/tools/tests/xen-access/xen-access.c index abf17a2..9157f23 100644 --- a/tools/tests/xen-access/xen-access.c +++ b/tools/tests/xen-access/xen-access.c @@ -35,14 +35,9 @@ #include <time.h> #include <signal.h> #include <unistd.h> -#include <sys/mman.h> #include <poll.h> #include <getopt.h> -#include <xenctrl.h> -#include <xenevtchn.h> -#include <xen/vm_event.h> - #include <xen-tools/libs.h> #if defined(__arm__) || defined(__aarch64__) @@ -52,9 +47,7 @@ #define START_PFN 0ULL #endif -#define DPRINTF(a, b...) fprintf(stderr, a, ## b) -#define ERROR(a, b...) fprintf(stderr, a "\n", ## b) -#define PERROR(a, b...) fprintf(stderr, a ": %s\n", ## b, strerror(errno)) +#include "xen-access.h" /* From xen/include/asm-x86/processor.h */ #define X86_TRAP_DEBUG 1 @@ -63,32 +56,14 @@ /* From xen/include/asm-x86/x86-defns.h */ #define X86_CR4_PGE 0x00000080 /* enable global pages */ -typedef struct vm_event { - domid_t domain_id; - xenevtchn_handle *xce_handle; - int port; - vm_event_back_ring_t back_ring; - uint32_t evtchn_port; - void *ring_page; -} vm_event_t; - -typedef struct xenaccess { - xc_interface *xc_handle; - - xen_pfn_t max_gpfn; - - vm_event_t vm_event; -} xenaccess_t; - static int interrupted; -bool evtchn_bind = 0, evtchn_open = 0, mem_access_enable = 0; static void close_handler(int sig) { interrupted = sig; } -int xc_wait_for_event_or_timeout(xc_interface *xch, xenevtchn_handle *xce, unsigned long ms) +static int xc_wait_for_event_or_timeout(xc_interface *xch, xenevtchn_handle *xce, unsigned long ms) { struct pollfd fd = { .fd = xenevtchn_fd(xce), .events = POLLIN | POLLERR }; int port; @@ -129,161 +104,85 @@ int xc_wait_for_event_or_timeout(xc_interface *xch, xenevtchn_handle *xce, unsig return -errno; } -int xenaccess_teardown(xc_interface *xch, xenaccess_t *xenaccess) +static int vm_event_teardown(vm_event_t *vm_event) { int rc; - if ( xenaccess == NULL ) + if ( vm_event == NULL ) return 0; - /* Tear down domain xenaccess in Xen */ - if ( xenaccess->vm_event.ring_page != NULL ) - munmap(xenaccess->vm_event.ring_page, XC_PAGE_SIZE); - - if ( mem_access_enable ) - { - rc = xc_monitor_disable(xenaccess->xc_handle, - xenaccess->vm_event.domain_id); - if ( rc != 0 ) - { - ERROR("Error tearing down domain xenaccess in xen"); - return rc; - } - } - - /* Unbind VIRQ */ - if ( evtchn_bind ) - { - rc = xenevtchn_unbind(xenaccess->vm_event.xce_handle, - xenaccess->vm_event.port); - if ( rc != 0 ) - { - ERROR("Error unbinding event port"); - return rc; - } - } + rc = vm_event->ops->teardown(vm_event); + if ( rc != 0 ) + return rc; /* Close event channel */ - if ( evtchn_open ) + rc = xenevtchn_close(vm_event->xce); + if ( rc != 0 ) { - rc = xenevtchn_close(xenaccess->vm_event.xce_handle); - if ( rc != 0 ) - { - ERROR("Error closing event channel"); - return rc; - } + ERROR("Error closing event channel"); + return rc; } /* Close connection to Xen */ - rc = xc_interface_close(xenaccess->xc_handle); + rc = xc_interface_close(vm_event->xch); if ( rc != 0 ) { ERROR("Error closing connection to xen"); return rc; } - xenaccess->xc_handle = NULL; - - free(xenaccess); return 0; } -xenaccess_t *xenaccess_init(xc_interface **xch_r, domid_t domain_id) +static vm_event_t *vm_event_init(domid_t domain_id, vm_event_ops_t *ops) { - xenaccess_t *xenaccess = 0; + vm_event_t *vm_event; xc_interface *xch; + xenevtchn_handle *xce; + xen_pfn_t max_gpfn; int rc; + if ( ops == NULL ) + return NULL; + xch = xc_interface_open(NULL, NULL, 0); if ( xch == NULL ) - goto err_iface; + goto err; DPRINTF("xenaccess init\n"); - *xch_r = xch; - - /* Allocate memory */ - xenaccess = malloc(sizeof(xenaccess_t)); - memset(xenaccess, 0, sizeof(xenaccess_t)); - - /* Open connection to xen */ - xenaccess->xc_handle = xch; - - /* Set domain id */ - xenaccess->vm_event.domain_id = domain_id; - - /* Enable mem_access */ - xenaccess->vm_event.ring_page = - xc_monitor_enable(xenaccess->xc_handle, - xenaccess->vm_event.domain_id, - &xenaccess->vm_event.evtchn_port); - if ( xenaccess->vm_event.ring_page == NULL ) - { - switch ( errno ) - { - case EBUSY: - ERROR("xenaccess is (or was) active on this domain"); - break; - case ENODEV: - ERROR("EPT not supported for this guest"); - break; - default: - perror("Error enabling mem_access"); - break; - } - goto err; - } - mem_access_enable = 1; /* Open event channel */ - xenaccess->vm_event.xce_handle = xenevtchn_open(NULL, 0); - if ( xenaccess->vm_event.xce_handle == NULL ) + xce = xenevtchn_open(NULL, 0); + if ( xce == NULL ) { ERROR("Failed to open event channel"); goto err; } - evtchn_open = 1; - - /* Bind event notification */ - rc = xenevtchn_bind_interdomain(xenaccess->vm_event.xce_handle, - xenaccess->vm_event.domain_id, - xenaccess->vm_event.evtchn_port); - if ( rc < 0 ) - { - ERROR("Failed to bind event channel"); - goto err; - } - evtchn_bind = 1; - xenaccess->vm_event.port = rc; - - /* Initialise ring */ - SHARED_RING_INIT((vm_event_sring_t *)xenaccess->vm_event.ring_page); - BACK_RING_INIT(&xenaccess->vm_event.back_ring, - (vm_event_sring_t *)xenaccess->vm_event.ring_page, - XC_PAGE_SIZE); /* Get max_gpfn */ - rc = xc_domain_maximum_gpfn(xenaccess->xc_handle, - xenaccess->vm_event.domain_id, - &xenaccess->max_gpfn); - + rc = xc_domain_maximum_gpfn(xch, domain_id, &max_gpfn); if ( rc ) { ERROR("Failed to get max gpfn"); goto err; } + DPRINTF("max_gpfn = %"PRI_xen_pfn"\n", max_gpfn); - DPRINTF("max_gpfn = %"PRI_xen_pfn"\n", xenaccess->max_gpfn); + rc = ops->init(xch, xce, domain_id, ops, &vm_event); + if ( rc < 0 ) + goto err; - return xenaccess; + vm_event->xch = xch; + vm_event->xce = xce; + vm_event->domain_id = domain_id; + vm_event->ops = ops; + vm_event->max_gpfn = max_gpfn; - err: - rc = xenaccess_teardown(xch, xenaccess); - if ( rc ) - { - ERROR("Failed to teardown xenaccess structure!\n"); - } + return vm_event; - err_iface: + err: + xenevtchn_close(xce); + xc_interface_close(xch); return NULL; } @@ -298,26 +197,6 @@ static inline int control_singlestep(xc_interface *xch, domid_t domain_id, } /* - * Note that this function is not thread safe. - */ -static void get_request(vm_event_t *vm_event, vm_event_request_t *req) -{ - vm_event_back_ring_t *back_ring; - RING_IDX req_cons; - - back_ring = &vm_event->back_ring; - req_cons = back_ring->req_cons; - - /* Copy request */ - memcpy(req, RING_GET_REQUEST(back_ring, req_cons), sizeof(*req)); - req_cons++; - - /* Update ring */ - back_ring->req_cons = req_cons; - back_ring->sring->req_event = req_cons + 1; -} - -/* * X86 control register names */ static const char* get_x86_ctrl_reg_name(uint32_t index) @@ -335,29 +214,9 @@ static const char* get_x86_ctrl_reg_name(uint32_t index) return names[index]; } -/* - * Note that this function is not thread safe. - */ -static void put_response(vm_event_t *vm_event, vm_event_response_t *rsp) -{ - vm_event_back_ring_t *back_ring; - RING_IDX rsp_prod; - - back_ring = &vm_event->back_ring; - rsp_prod = back_ring->rsp_prod_pvt; - - /* Copy response */ - memcpy(RING_GET_RESPONSE(back_ring, rsp_prod), rsp, sizeof(*rsp)); - rsp_prod++; - - /* Update ring */ - back_ring->rsp_prod_pvt = rsp_prod; - RING_PUSH_RESPONSES(back_ring); -} - void usage(char* progname) { - fprintf(stderr, "Usage: %s [-m] <domain_id> write|exec", progname); + fprintf(stderr, "Usage: %s [-m] [-n] <domain_id> write|exec", progname); #if defined(__i386__) || defined(__x86_64__) fprintf(stderr, "|breakpoint|altp2m_write|altp2m_exec|debug|cpuid|desc_access|write_ctrlreg_cr4|altp2m_write_no_gpt"); #elif defined(__arm__) || defined(__aarch64__) @@ -367,19 +226,22 @@ void usage(char* progname) "\n" "Logs first page writes, execs, or breakpoint traps that occur on the domain.\n" "\n" - "-m requires this program to run, or else the domain may pause\n"); + "-m requires this program to run, or else the domain may pause\n" + "-n uses the per-vcpu channels vm_event interface\n"); } +extern vm_event_ops_t ring_ops; +extern vm_event_ops_t channel_ops; + int main(int argc, char *argv[]) { struct sigaction act; domid_t domain_id; - xenaccess_t *xenaccess; + vm_event_t *vm_event; vm_event_request_t req; vm_event_response_t rsp; int rc = -1; int rc1; - xc_interface *xch; xenmem_access_t default_access = XENMEM_access_rwx; xenmem_access_t after_first_access = XENMEM_access_rwx; int memaccess = 0; @@ -394,6 +256,7 @@ int main(int argc, char *argv[]) int write_ctrlreg_cr4 = 0; int altp2m_write_no_gpt = 0; uint16_t altp2m_view_id = 0; + int new_interface = 0; char* progname = argv[0]; char* command; @@ -402,11 +265,12 @@ int main(int argc, char *argv[]) struct option long_options[] = { { "mem-access-listener", no_argument, 0, 'm' }, + { "new-interface", no_argument, 0, 'n' }, }; while ( 1 ) { - c = getopt_long(argc, argv, "m", long_options, &option_index); + c = getopt_long(argc, argv, "mn", long_options, &option_index); if ( c == -1 ) break; @@ -416,6 +280,10 @@ int main(int argc, char *argv[]) required = 1; break; + case 'n': + new_interface = 1; + break; + default: usage(progname); return -1; @@ -495,10 +363,11 @@ int main(int argc, char *argv[]) return -1; } - xenaccess = xenaccess_init(&xch, domain_id); - if ( xenaccess == NULL ) + vm_event = vm_event_init(domain_id, + (new_interface) ? &channel_ops : &ring_ops); + if ( vm_event == NULL ) { - ERROR("Error initialising xenaccess"); + ERROR("Error initialising vm_event"); return 1; } @@ -514,7 +383,7 @@ int main(int argc, char *argv[]) sigaction(SIGALRM, &act, NULL); /* Set whether the access listener is required */ - rc = xc_domain_set_access_required(xch, domain_id, required); + rc = xc_domain_set_access_required(vm_event->xch, domain_id, required); if ( rc < 0 ) { ERROR("Error %d setting mem_access listener required\n", rc); @@ -529,13 +398,13 @@ int main(int argc, char *argv[]) if( altp2m_write_no_gpt ) { - rc = xc_monitor_inguest_pagefault(xch, domain_id, 1); + rc = xc_monitor_inguest_pagefault(vm_event->xch, domain_id, 1); if ( rc < 0 ) { ERROR("Error %d setting inguest pagefault\n", rc); goto exit; } - rc = xc_monitor_emul_unimplemented(xch, domain_id, 1); + rc = xc_monitor_emul_unimplemented(vm_event->xch, domain_id, 1); if ( rc < 0 ) { ERROR("Error %d failed to enable emul unimplemented\n", rc); @@ -543,14 +412,15 @@ int main(int argc, char *argv[]) } } - rc = xc_altp2m_set_domain_state( xch, domain_id, 1 ); + rc = xc_altp2m_set_domain_state( vm_event->xch, domain_id, 1 ); if ( rc < 0 ) { ERROR("Error %d enabling altp2m on domain!\n", rc); goto exit; } - rc = xc_altp2m_create_view( xch, domain_id, default_access, &altp2m_view_id ); + rc = xc_altp2m_create_view( vm_event->xch, domain_id, default_access, + &altp2m_view_id ); if ( rc < 0 ) { ERROR("Error %d creating altp2m view!\n", rc); @@ -560,24 +430,24 @@ int main(int argc, char *argv[]) DPRINTF("altp2m view created with id %u\n", altp2m_view_id); DPRINTF("Setting altp2m mem_access permissions.. "); - for( ; gfn < xenaccess->max_gpfn; ++gfn ) + for( ; gfn < vm_event->max_gpfn; ++gfn ) { - rc = xc_altp2m_set_mem_access( xch, domain_id, altp2m_view_id, gfn, - default_access); + rc = xc_altp2m_set_mem_access( vm_event->xch, domain_id, + altp2m_view_id, gfn, default_access); if ( !rc ) perm_set++; } DPRINTF("done! Permissions set on %lu pages.\n", perm_set); - rc = xc_altp2m_switch_to_view( xch, domain_id, altp2m_view_id ); + rc = xc_altp2m_switch_to_view( vm_event->xch, domain_id, altp2m_view_id ); if ( rc < 0 ) { ERROR("Error %d switching to altp2m view!\n", rc); goto exit; } - rc = xc_monitor_singlestep( xch, domain_id, 1 ); + rc = xc_monitor_singlestep( vm_event->xch, domain_id, 1 ); if ( rc < 0 ) { ERROR("Error %d failed to enable singlestep monitoring!\n", rc); @@ -588,15 +458,15 @@ int main(int argc, char *argv[]) if ( memaccess && !altp2m ) { /* Set the default access type and convert all pages to it */ - rc = xc_set_mem_access(xch, domain_id, default_access, ~0ull, 0); + rc = xc_set_mem_access(vm_event->xch, domain_id, default_access, ~0ull, 0); if ( rc < 0 ) { ERROR("Error %d setting default mem access type\n", rc); goto exit; } - rc = xc_set_mem_access(xch, domain_id, default_access, START_PFN, - (xenaccess->max_gpfn - START_PFN) ); + rc = xc_set_mem_access(vm_event->xch, domain_id, default_access, START_PFN, + (vm_event->max_gpfn - START_PFN) ); if ( rc < 0 ) { @@ -608,7 +478,7 @@ int main(int argc, char *argv[]) if ( breakpoint ) { - rc = xc_monitor_software_breakpoint(xch, domain_id, 1); + rc = xc_monitor_software_breakpoint(vm_event->xch, domain_id, 1); if ( rc < 0 ) { ERROR("Error %d setting breakpoint trapping with vm_event\n", rc); @@ -618,7 +488,7 @@ int main(int argc, char *argv[]) if ( debug ) { - rc = xc_monitor_debug_exceptions(xch, domain_id, 1, 1); + rc = xc_monitor_debug_exceptions(vm_event->xch, domain_id, 1, 1); if ( rc < 0 ) { ERROR("Error %d setting debug exception listener with vm_event\n", rc); @@ -628,7 +498,7 @@ int main(int argc, char *argv[]) if ( cpuid ) { - rc = xc_monitor_cpuid(xch, domain_id, 1); + rc = xc_monitor_cpuid(vm_event->xch, domain_id, 1); if ( rc < 0 ) { ERROR("Error %d setting cpuid listener with vm_event\n", rc); @@ -638,7 +508,7 @@ int main(int argc, char *argv[]) if ( desc_access ) { - rc = xc_monitor_descriptor_access(xch, domain_id, 1); + rc = xc_monitor_descriptor_access(vm_event->xch, domain_id, 1); if ( rc < 0 ) { ERROR("Error %d setting descriptor access listener with vm_event\n", rc); @@ -648,7 +518,7 @@ int main(int argc, char *argv[]) if ( privcall ) { - rc = xc_monitor_privileged_call(xch, domain_id, 1); + rc = xc_monitor_privileged_call(vm_event->xch, domain_id, 1); if ( rc < 0 ) { ERROR("Error %d setting privileged call trapping with vm_event\n", rc); @@ -659,7 +529,7 @@ int main(int argc, char *argv[]) if ( write_ctrlreg_cr4 ) { /* Mask the CR4.PGE bit so no events will be generated for global TLB flushes. */ - rc = xc_monitor_write_ctrlreg(xch, domain_id, VM_EVENT_X86_CR4, 1, 1, + rc = xc_monitor_write_ctrlreg(vm_event->xch, domain_id, VM_EVENT_X86_CR4, 1, 1, X86_CR4_PGE, 1); if ( rc < 0 ) { @@ -671,41 +541,43 @@ int main(int argc, char *argv[]) /* Wait for access */ for ( ; ; ) { + int port = 0; + if ( interrupted ) { /* Unregister for every event */ DPRINTF("xenaccess shutting down on signal %d\n", interrupted); if ( breakpoint ) - rc = xc_monitor_software_breakpoint(xch, domain_id, 0); + rc = xc_monitor_software_breakpoint(vm_event->xch, domain_id, 0); if ( debug ) - rc = xc_monitor_debug_exceptions(xch, domain_id, 0, 0); + rc = xc_monitor_debug_exceptions(vm_event->xch, domain_id, 0, 0); if ( cpuid ) - rc = xc_monitor_cpuid(xch, domain_id, 0); + rc = xc_monitor_cpuid(vm_event->xch, domain_id, 0); if ( desc_access ) - rc = xc_monitor_descriptor_access(xch, domain_id, 0); + rc = xc_monitor_descriptor_access(vm_event->xch, domain_id, 0); if ( write_ctrlreg_cr4 ) - rc = xc_monitor_write_ctrlreg(xch, domain_id, VM_EVENT_X86_CR4, 0, 0, 0, 0); + rc = xc_monitor_write_ctrlreg(vm_event->xch, domain_id, VM_EVENT_X86_CR4, 0, 0, 0, 0); if ( privcall ) - rc = xc_monitor_privileged_call(xch, domain_id, 0); + rc = xc_monitor_privileged_call(vm_event->xch, domain_id, 0); if ( altp2m ) { - rc = xc_altp2m_switch_to_view( xch, domain_id, 0 ); - rc = xc_altp2m_destroy_view(xch, domain_id, altp2m_view_id); - rc = xc_altp2m_set_domain_state(xch, domain_id, 0); - rc = xc_monitor_singlestep(xch, domain_id, 0); + rc = xc_altp2m_switch_to_view( vm_event->xch, domain_id, 0 ); + rc = xc_altp2m_destroy_view(vm_event->xch, domain_id, altp2m_view_id); + rc = xc_altp2m_set_domain_state(vm_event->xch, domain_id, 0); + rc = xc_monitor_singlestep(vm_event->xch, domain_id, 0); } else { - rc = xc_set_mem_access(xch, domain_id, XENMEM_access_rwx, ~0ull, 0); - rc = xc_set_mem_access(xch, domain_id, XENMEM_access_rwx, START_PFN, - (xenaccess->max_gpfn - START_PFN) ); + rc = xc_set_mem_access(vm_event->xch, domain_id, XENMEM_access_rwx, ~0ull, 0); + rc = xc_set_mem_access(vm_event->xch, domain_id, XENMEM_access_rwx, START_PFN, + (vm_event->max_gpfn - START_PFN) ); } shutting_down = 1; } - rc = xc_wait_for_event_or_timeout(xch, xenaccess->vm_event.xce_handle, 100); + rc = xc_wait_for_event_or_timeout(vm_event->xch, vm_event->xce, 100); if ( rc < -1 ) { ERROR("Error getting event"); @@ -717,10 +589,10 @@ int main(int argc, char *argv[]) DPRINTF("Got event from Xen\n"); } - while ( RING_HAS_UNCONSUMED_REQUESTS(&xenaccess->vm_event.back_ring) ) - { - get_request(&xenaccess->vm_event, &req); + port = rc; + while ( vm_event->ops->get_request(vm_event, &req, &port) ) + { if ( req.version != VM_EVENT_INTERFACE_VERSION ) { ERROR("Error: vm_event interface version mismatch!\n"); @@ -744,7 +616,7 @@ int main(int argc, char *argv[]) * At shutdown we have already reset all the permissions so really no use getting it again. */ xenmem_access_t access; - rc = xc_get_mem_access(xch, domain_id, req.u.mem_access.gfn, &access); + rc = xc_get_mem_access(vm_event->xch, domain_id, req.u.mem_access.gfn, &access); if (rc < 0) { ERROR("Error %d getting mem_access event\n", rc); @@ -777,7 +649,7 @@ int main(int argc, char *argv[]) } else if ( default_access != after_first_access ) { - rc = xc_set_mem_access(xch, domain_id, after_first_access, + rc = xc_set_mem_access(vm_event->xch, domain_id, after_first_access, req.u.mem_access.gfn, 1); if (rc < 0) { @@ -798,7 +670,7 @@ int main(int argc, char *argv[]) req.vcpu_id); /* Reinject */ - rc = xc_hvm_inject_trap(xch, domain_id, req.vcpu_id, + rc = xc_hvm_inject_trap(vm_event->xch, domain_id, req.vcpu_id, X86_TRAP_INT3, req.u.software_breakpoint.type, -1, req.u.software_breakpoint.insn_length, 0); @@ -846,7 +718,7 @@ int main(int argc, char *argv[]) req.u.debug_exception.insn_length); /* Reinject */ - rc = xc_hvm_inject_trap(xch, domain_id, req.vcpu_id, + rc = xc_hvm_inject_trap(vm_event->xch, domain_id, req.vcpu_id, X86_TRAP_DEBUG, req.u.debug_exception.type, -1, req.u.debug_exception.insn_length, @@ -914,17 +786,15 @@ int main(int argc, char *argv[]) } /* Put the response on the ring */ - put_response(&xenaccess->vm_event, &rsp); - } - - /* Tell Xen page is ready */ - rc = xenevtchn_notify(xenaccess->vm_event.xce_handle, - xenaccess->vm_event.port); + put_response(vm_event, &rsp, port); - if ( rc != 0 ) - { - ERROR("Error resuming page"); - interrupted = -1; + /* Tell Xen page is ready */ + rc = notify_port(vm_event, port); + if ( rc != 0 ) + { + ERROR("Error resuming page"); + interrupted = -1; + } } if ( shutting_down ) @@ -937,13 +807,13 @@ exit: { uint32_t vcpu_id; for ( vcpu_id = 0; vcpu_id<XEN_LEGACY_MAX_VCPUS; vcpu_id++) - rc = control_singlestep(xch, domain_id, vcpu_id, 0); + rc = control_singlestep(vm_event->xch, domain_id, vcpu_id, 0); } - /* Tear down domain xenaccess */ - rc1 = xenaccess_teardown(xch, xenaccess); + /* Tear down domain */ + rc1 = vm_event_teardown(vm_event); if ( rc1 != 0 ) - ERROR("Error tearing down xenaccess"); + ERROR("Error tearing down vm_event"); if ( rc == 0 ) rc = rc1; diff --git a/tools/tests/xen-access/xen-access.h b/tools/tests/xen-access/xen-access.h new file mode 100644 index 0000000..9fc640c --- /dev/null +++ b/tools/tests/xen-access/xen-access.h @@ -0,0 +1,91 @@ +/* + * xen-access.h + * + * Copyright (c) 2019 Bitdefender S.R.L. + * + * 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_ACCESS_H +#define XEN_ACCESS_H + +#include <xenctrl.h> +#include <xenevtchn.h> +#include <xen/vm_event.h> + +#ifndef container_of +#define container_of(ptr, type, member) ({ \ + const typeof( ((type *)0)->member ) *__mptr = (ptr); \ + (type *)( (char *)__mptr - offsetof(type,member) );}) +#endif /* container_of */ + +#define DPRINTF(a, b...) fprintf(stderr, a, ## b) +#define ERROR(a, b...) fprintf(stderr, a "\n", ## b) +#define PERROR(a, b...) fprintf(stderr, a ": %s\n", ## b, strerror(errno)) + +struct vm_event_ops; + +typedef struct vm_event { + xc_interface *xch; + domid_t domain_id; + xenevtchn_handle *xce; + xen_pfn_t max_gpfn; + struct vm_event_ops *ops; +} vm_event_t; + +typedef struct vm_event_ops { + int (*init)(xc_interface *, xenevtchn_handle *, domid_t, + struct vm_event_ops *, vm_event_t **); + int (*teardown)(vm_event_t *); + bool (*get_request)(vm_event_t *, vm_event_request_t *, int *); + void (*put_response)(vm_event_t *, vm_event_response_t *, int); + int (*notify_port)(vm_event_t *, int port); +} vm_event_ops_t; + +static inline bool get_request(vm_event_t *vm_event, vm_event_request_t *req, + int *port) +{ + return ( vm_event ) ? vm_event->ops->get_request(vm_event, req, port) : + false; +} + +static inline void put_response(vm_event_t *vm_event, vm_event_response_t *rsp, int port) +{ + if ( vm_event ) + vm_event->ops->put_response(vm_event, rsp, port); +} + +static inline int notify_port(vm_event_t *vm_event, int port) +{ + if ( !vm_event ) + return -EINVAL; + + return vm_event->ops->notify_port(vm_event, port); +} + +#endif /* XEN_ACCESS_H */ + +/* + * Local variables: + * mode: C + * c-file-style: "BSD" + * c-basic-offset: 4 + * indent-tabs-mode: nil + * End: + */ -- 2.7.4 _______________________________________________ Xen-devel mailing list Xen-devel@xxxxxxxxxxxxxxxxxxxx https://lists.xenproject.org/mailman/listinfo/xen-devel
|
Lists.xenproject.org is hosted with RackSpace, monitoring our |