debuggers.hg

changeset 22736:d45e74f45cb1

mem_access test tool: xen-access

Added a test tool to let the memory access APIs be tested. This tool
logs to stdout the memory accesses that the domain given is performing.

Signed-off-by: Joe Epstein <jepstein98@gmail.com>
Signed-off-by: Keir Fraser <keir@xen.org>
author Joe Epstein <jepstein98@gmail.com>
date Sat Jan 08 11:06:18 2011 +0000 (2011-01-08)
parents b0e8e00f5be2
children 946d84529a07
files tools/tests/xen-access/Makefile tools/tests/xen-access/xen-access.c
line diff
     1.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
     1.2 +++ b/tools/tests/xen-access/Makefile	Sat Jan 08 11:06:18 2011 +0000
     1.3 @@ -0,0 +1,36 @@
     1.4 +XEN_ROOT=../../..
     1.5 +include $(XEN_ROOT)/tools/Rules.mk
     1.6 +
     1.7 +CFLAGS   += -Werror
     1.8 +
     1.9 +INCLUDES += -I $(XEN_XC)
    1.10 +INCLUDES += -I $(XEN_LIBXC)
    1.11 +INCLUDES += -I $(XEN_INCLUDE)
    1.12 +CFLAGS   += $(INCLUDES)
    1.13 +
    1.14 +TARGETS-y := 
    1.15 +TARGETS-$(CONFIG_X86) += xen-access
    1.16 +TARGETS := $(TARGETS-y)
    1.17 +
    1.18 +SUBDIRS-y :=
    1.19 +SUBDIRS := $(SUBDIRS-y)
    1.20 +
    1.21 +.PHONY: all
    1.22 +all: build
    1.23 +
    1.24 +.PHONY: build
    1.25 +build: $(TARGETS)
    1.26 +	set -e; for d in $(SUBDIRS); do $(MAKE) -C $$d; done
    1.27 +
    1.28 +.PHONY: clean
    1.29 +clean:
    1.30 +	$(RM) *.o $(TARGETS) *~ $(DEPS)
    1.31 +	set -e; for d in $(SUBDIRS); do $(MAKE) -C $$d clean; done
    1.32 +
    1.33 +%.o: %.c Makefile
    1.34 +	$(CC) -c $(CFLAGS) -o $@ $<
    1.35 +
    1.36 +xen-access: %: %.o Makefile
    1.37 +	$(CC) $(CFLAGS) -o $@ $< $(LDFLAGS) $(LDLIBS_libxenctrl)
    1.38 +# $(LDLIBS_libxenguest) $(LDLIBS_libxenstore)
    1.39 +-include $(DEPS)
     2.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
     2.2 +++ b/tools/tests/xen-access/xen-access.c	Sat Jan 08 11:06:18 2011 +0000
     2.3 @@ -0,0 +1,668 @@
     2.4 +/*
     2.5 + * xen-access.c
     2.6 + *
     2.7 + * Exercises the basic per-page access mechanisms
     2.8 + *
     2.9 + * Copyright (c) 2011 Virtuata, Inc.
    2.10 + * Copyright (c) 2009 by Citrix Systems, Inc. (Patrick Colp), based on
    2.11 + *   xenpaging.c
    2.12 + *
    2.13 + * Permission is hereby granted, free of charge, to any person obtaining a copy
    2.14 + * of this software and associated documentation files (the "Software"), to
    2.15 + * deal in the Software without restriction, including without limitation the
    2.16 + * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
    2.17 + * sell copies of the Software, and to permit persons to whom the Software is
    2.18 + * furnished to do so, subject to the following conditions:
    2.19 + *
    2.20 + * The above copyright notice and this permission notice shall be included in
    2.21 + * all copies or substantial portions of the Software.
    2.22 + *
    2.23 + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
    2.24 + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
    2.25 + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
    2.26 + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
    2.27 + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
    2.28 + * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
    2.29 + * DEALINGS IN THE SOFTWARE.
    2.30 + */
    2.31 +
    2.32 +#include <inttypes.h>
    2.33 +#include <stdlib.h>
    2.34 +#include <stdarg.h>
    2.35 +#include <time.h>
    2.36 +#include <signal.h>
    2.37 +#include <unistd.h>
    2.38 +#include <sys/poll.h>
    2.39 +#include <xc_private.h>
    2.40 +#include <xg_save_restore.h>
    2.41 +
    2.42 +#include <xen/mem_event.h>
    2.43 +
    2.44 +//#if 0
    2.45 +#undef DPRINTF
    2.46 +#define DPRINTF(a, b...) fprintf(stderr, a, ## b)
    2.47 +//#endif
    2.48 +
    2.49 +/* Spinlock and mem event definitions */
    2.50 +
    2.51 +#define SPIN_LOCK_UNLOCKED 0
    2.52 +
    2.53 +#define ADDR (*(volatile long *) addr)
    2.54 +/**
    2.55 + * test_and_set_bit - Set a bit and return its old value
    2.56 + * @nr: Bit to set
    2.57 + * @addr: Address to count from
    2.58 + *
    2.59 + * This operation is atomic and cannot be reordered.
    2.60 + * It also implies a memory barrier.
    2.61 + */
    2.62 +static inline int test_and_set_bit(int nr, volatile void *addr)
    2.63 +{
    2.64 +    int oldbit;
    2.65 +
    2.66 +    asm volatile (
    2.67 +        "btsl %2,%1\n\tsbbl %0,%0"
    2.68 +        : "=r" (oldbit), "=m" (ADDR)
    2.69 +        : "Ir" (nr), "m" (ADDR) : "memory");
    2.70 +    return oldbit;
    2.71 +}
    2.72 +
    2.73 +typedef int spinlock_t;
    2.74 +
    2.75 +static inline void spin_lock(spinlock_t *lock)
    2.76 +{
    2.77 +    while ( test_and_set_bit(1, lock) );
    2.78 +}
    2.79 +
    2.80 +static inline void spin_lock_init(spinlock_t *lock)
    2.81 +{
    2.82 +    *lock = SPIN_LOCK_UNLOCKED;
    2.83 +}
    2.84 +
    2.85 +static inline void spin_unlock(spinlock_t *lock)
    2.86 +{
    2.87 +    *lock = SPIN_LOCK_UNLOCKED;
    2.88 +}
    2.89 +
    2.90 +static inline int spin_trylock(spinlock_t *lock)
    2.91 +{
    2.92 +    return !test_and_set_bit(1, lock);
    2.93 +}
    2.94 +
    2.95 +#define mem_event_ring_lock_init(_m)  spin_lock_init(&(_m)->ring_lock)
    2.96 +#define mem_event_ring_lock(_m)       spin_lock(&(_m)->ring_lock)
    2.97 +#define mem_event_ring_unlock(_m)     spin_unlock(&(_m)->ring_lock)
    2.98 +
    2.99 +typedef struct mem_event {
   2.100 +    domid_t domain_id;
   2.101 +    xc_evtchn *xce_handle;
   2.102 +    int port;
   2.103 +    mem_event_back_ring_t back_ring;
   2.104 +    mem_event_shared_page_t *shared_page;
   2.105 +    void *ring_page;
   2.106 +    spinlock_t ring_lock;
   2.107 +} mem_event_t;
   2.108 +
   2.109 +typedef struct xc_platform_info {
   2.110 +    unsigned long max_mfn;
   2.111 +    unsigned long hvirt_start;
   2.112 +    unsigned int  pt_levels;
   2.113 +    unsigned int  guest_width;
   2.114 +} xc_platform_info_t;
   2.115 +
   2.116 +typedef struct xenaccess {
   2.117 +    xc_interface *xc_handle;
   2.118 +
   2.119 +    xc_platform_info_t *platform_info;
   2.120 +    xc_domaininfo_t    *domain_info;
   2.121 +
   2.122 +    mem_event_t mem_event;
   2.123 +} xenaccess_t;
   2.124 +
   2.125 +static int interrupted;
   2.126 +
   2.127 +static void close_handler(int sig)
   2.128 +{
   2.129 +    interrupted = sig;
   2.130 +}
   2.131 +
   2.132 +int xc_wait_for_event_or_timeout(xc_interface *xch, xc_evtchn *xce, unsigned long ms)
   2.133 +{
   2.134 +    struct pollfd fd = { .fd = xc_evtchn_fd(xce), .events = POLLIN | POLLERR };
   2.135 +    int port;
   2.136 +    int rc;
   2.137 +
   2.138 +    rc = poll(&fd, 1, ms);
   2.139 +    if ( rc == -1 )
   2.140 +    {
   2.141 +        if (errno == EINTR)
   2.142 +            return 0;
   2.143 +
   2.144 +        ERROR("Poll exited with an error");
   2.145 +        goto err;
   2.146 +    }
   2.147 +
   2.148 +    if ( rc == 1 )
   2.149 +    {
   2.150 +        port = xc_evtchn_pending(xce);
   2.151 +        if ( port == -1 )
   2.152 +        {
   2.153 +            ERROR("Failed to read port from event channel");
   2.154 +            goto err;
   2.155 +        }
   2.156 +
   2.157 +        rc = xc_evtchn_unmask(xce, port);
   2.158 +        if ( rc != 0 )
   2.159 +        {
   2.160 +            ERROR("Failed to unmask event channel port");
   2.161 +            goto err;
   2.162 +        }
   2.163 +    }
   2.164 +    else
   2.165 +        port = -1;
   2.166 +
   2.167 +    return port;
   2.168 +
   2.169 + err:
   2.170 +    return -errno;
   2.171 +}
   2.172 +
   2.173 +static void *init_page(void)
   2.174 +{
   2.175 +    void *buffer;
   2.176 +    int ret;
   2.177 +
   2.178 +    /* Allocated page memory */
   2.179 +    ret = posix_memalign(&buffer, PAGE_SIZE, PAGE_SIZE);
   2.180 +    if ( ret != 0 )
   2.181 +        goto out_alloc;
   2.182 +
   2.183 +    /* Lock buffer in memory so it can't be paged out */
   2.184 +    ret = mlock(buffer, PAGE_SIZE);
   2.185 +    if ( ret != 0 )
   2.186 +        goto out_lock;
   2.187 +
   2.188 +    return buffer;
   2.189 +
   2.190 +    munlock(buffer, PAGE_SIZE);
   2.191 + out_lock:
   2.192 +    free(buffer);
   2.193 + out_alloc:
   2.194 +    return NULL;
   2.195 +}
   2.196 +
   2.197 +xenaccess_t *xenaccess_init(xc_interface **xch_r, domid_t domain_id)
   2.198 +{
   2.199 +    xenaccess_t *xenaccess;
   2.200 +    xc_interface *xch;
   2.201 +    int rc;
   2.202 +
   2.203 +    xch = xc_interface_open(NULL, NULL, 0);
   2.204 +    if ( !xch )
   2.205 +        goto err_iface;
   2.206 +
   2.207 +    DPRINTF("xenaccess init\n");
   2.208 +    *xch_r = xch;
   2.209 +
   2.210 +    /* Allocate memory */
   2.211 +    xenaccess = malloc(sizeof(xenaccess_t));
   2.212 +    memset(xenaccess, 0, sizeof(xenaccess_t));
   2.213 +
   2.214 +    /* Open connection to xen */
   2.215 +    xenaccess->xc_handle = xch;
   2.216 +
   2.217 +    /* Set domain id */
   2.218 +    xenaccess->mem_event.domain_id = domain_id;
   2.219 +
   2.220 +    /* Initialise shared page */
   2.221 +    xenaccess->mem_event.shared_page = init_page();
   2.222 +    if ( xenaccess->mem_event.shared_page == NULL )
   2.223 +    {
   2.224 +        ERROR("Error initialising shared page");
   2.225 +        goto err;
   2.226 +    }
   2.227 +
   2.228 +    /* Initialise ring page */
   2.229 +    xenaccess->mem_event.ring_page = init_page();
   2.230 +    if ( xenaccess->mem_event.ring_page == NULL )
   2.231 +    {
   2.232 +        ERROR("Error initialising ring page");
   2.233 +        goto err;
   2.234 +    }
   2.235 +
   2.236 +
   2.237 +    /* Initialise ring */
   2.238 +    SHARED_RING_INIT((mem_event_sring_t *)xenaccess->mem_event.ring_page);
   2.239 +    BACK_RING_INIT(&xenaccess->mem_event.back_ring,
   2.240 +                   (mem_event_sring_t *)xenaccess->mem_event.ring_page,
   2.241 +                   PAGE_SIZE);
   2.242 +
   2.243 +    /* Initialise lock */
   2.244 +    mem_event_ring_lock_init(&xenaccess->mem_event);
   2.245 +
   2.246 +    /* Initialise Xen */
   2.247 +    rc = xc_mem_event_enable(xenaccess->xc_handle, xenaccess->mem_event.domain_id,
   2.248 +                             xenaccess->mem_event.shared_page,
   2.249 +                             xenaccess->mem_event.ring_page);
   2.250 +    if ( rc != 0 )
   2.251 +    {
   2.252 +        switch ( errno ) {
   2.253 +            case EBUSY:
   2.254 +                ERROR("xenaccess is (or was) active on this domain");
   2.255 +                break;
   2.256 +            case ENODEV:
   2.257 +                ERROR("EPT not supported for this guest");
   2.258 +                break;
   2.259 +            default:
   2.260 +                perror("Error initialising shared page");
   2.261 +                break;
   2.262 +        }
   2.263 +        goto err;
   2.264 +    }
   2.265 +
   2.266 +    /* Open event channel */
   2.267 +    xenaccess->mem_event.xce_handle = xc_evtchn_open(NULL, 0);
   2.268 +    if ( xenaccess->mem_event.xce_handle == NULL )
   2.269 +    {
   2.270 +        ERROR("Failed to open event channel");
   2.271 +        goto err;
   2.272 +    }
   2.273 +
   2.274 +    /* Bind event notification */
   2.275 +    rc = xc_evtchn_bind_interdomain(xenaccess->mem_event.xce_handle,
   2.276 +                                    xenaccess->mem_event.domain_id,
   2.277 +                                    xenaccess->mem_event.shared_page->port);
   2.278 +    if ( rc < 0 )
   2.279 +    {
   2.280 +        ERROR("Failed to bind event channel");
   2.281 +        goto err;
   2.282 +    }
   2.283 +
   2.284 +    xenaccess->mem_event.port = rc;
   2.285 +
   2.286 +    /* Get platform info */
   2.287 +    xenaccess->platform_info = malloc(sizeof(xc_platform_info_t));
   2.288 +    if ( xenaccess->platform_info == NULL )
   2.289 +    {
   2.290 +        ERROR("Error allocating memory for platform info");
   2.291 +        goto err;
   2.292 +    }
   2.293 +
   2.294 +    rc = get_platform_info(xenaccess->xc_handle, domain_id,
   2.295 +                           &xenaccess->platform_info->max_mfn,
   2.296 +                           &xenaccess->platform_info->hvirt_start,
   2.297 +                           &xenaccess->platform_info->pt_levels,
   2.298 +                           &xenaccess->platform_info->guest_width);
   2.299 +    if ( rc != 1 )
   2.300 +    {
   2.301 +        ERROR("Error getting platform info");
   2.302 +        goto err;
   2.303 +    }
   2.304 +
   2.305 +    /* Get domaininfo */
   2.306 +    xenaccess->domain_info = malloc(sizeof(xc_domaininfo_t));
   2.307 +    if ( xenaccess->domain_info == NULL )
   2.308 +    {
   2.309 +        ERROR("Error allocating memory for domain info");
   2.310 +        goto err;
   2.311 +    }
   2.312 +
   2.313 +    rc = xc_domain_getinfolist(xenaccess->xc_handle, domain_id, 1,
   2.314 +                               xenaccess->domain_info);
   2.315 +    if ( rc != 1 )
   2.316 +    {
   2.317 +        ERROR("Error getting domain info");
   2.318 +        goto err;
   2.319 +    }
   2.320 +
   2.321 +    DPRINTF("max_pages = %"PRIx64"\n", xenaccess->domain_info->max_pages);
   2.322 +
   2.323 +    return xenaccess;
   2.324 +
   2.325 + err:
   2.326 +    if ( xenaccess )
   2.327 +    {
   2.328 +        if ( xenaccess->mem_event.shared_page )
   2.329 +        {
   2.330 +            munlock(xenaccess->mem_event.shared_page, PAGE_SIZE);
   2.331 +            free(xenaccess->mem_event.shared_page);
   2.332 +        }
   2.333 +
   2.334 +        if ( xenaccess->mem_event.ring_page )
   2.335 +        {
   2.336 +            munlock(xenaccess->mem_event.ring_page, PAGE_SIZE);
   2.337 +            free(xenaccess->mem_event.ring_page);
   2.338 +        }
   2.339 +
   2.340 +        free(xenaccess->platform_info);
   2.341 +        free(xenaccess->domain_info);
   2.342 +        free(xenaccess);
   2.343 +    }
   2.344 +
   2.345 + err_iface:
   2.346 +    return NULL;
   2.347 +}
   2.348 +
   2.349 +int xenaccess_teardown(xc_interface *xch, xenaccess_t *xenaccess)
   2.350 +{
   2.351 +    int rc;
   2.352 +
   2.353 +    if ( xenaccess == NULL )
   2.354 +        return 0;
   2.355 +
   2.356 +    /* Tear down domain xenaccess in Xen */
   2.357 +    rc = xc_mem_event_disable(xenaccess->xc_handle, xenaccess->mem_event.domain_id);
   2.358 +    if ( rc != 0 )
   2.359 +    {
   2.360 +        ERROR("Error tearing down domain xenaccess in xen");
   2.361 +    }
   2.362 +
   2.363 +    /* Unbind VIRQ */
   2.364 +    rc = xc_evtchn_unbind(xenaccess->mem_event.xce_handle, xenaccess->mem_event.port);
   2.365 +    if ( rc != 0 )
   2.366 +    {
   2.367 +        ERROR("Error unbinding event port");
   2.368 +    }
   2.369 +    xenaccess->mem_event.port = -1;
   2.370 +
   2.371 +    /* Close event channel */
   2.372 +    rc = xc_evtchn_close(xenaccess->mem_event.xce_handle);
   2.373 +    if ( rc != 0 )
   2.374 +    {
   2.375 +        ERROR("Error closing event channel");
   2.376 +    }
   2.377 +    xenaccess->mem_event.xce_handle = NULL;
   2.378 +
   2.379 +    /* Close connection to Xen */
   2.380 +    rc = xc_interface_close(xenaccess->xc_handle);
   2.381 +    if ( rc != 0 )
   2.382 +    {
   2.383 +        ERROR("Error closing connection to xen");
   2.384 +    }
   2.385 +    xenaccess->xc_handle = NULL;
   2.386 +
   2.387 +    return 0;
   2.388 +}
   2.389 +
   2.390 +int get_request(mem_event_t *mem_event, mem_event_request_t *req)
   2.391 +{
   2.392 +    mem_event_back_ring_t *back_ring;
   2.393 +    RING_IDX req_cons;
   2.394 +
   2.395 +    mem_event_ring_lock(mem_event);
   2.396 +
   2.397 +    back_ring = &mem_event->back_ring;
   2.398 +    req_cons = back_ring->req_cons;
   2.399 +
   2.400 +    /* Copy request */
   2.401 +    memcpy(req, RING_GET_REQUEST(back_ring, req_cons), sizeof(*req));
   2.402 +    req_cons++;
   2.403 +
   2.404 +    /* Update ring */
   2.405 +    back_ring->req_cons = req_cons;
   2.406 +    back_ring->sring->req_event = req_cons + 1;
   2.407 +
   2.408 +    mem_event_ring_unlock(mem_event);
   2.409 +
   2.410 +    return 0;
   2.411 +}
   2.412 +
   2.413 +static int put_response(mem_event_t *mem_event, mem_event_response_t *rsp)
   2.414 +{
   2.415 +    mem_event_back_ring_t *back_ring;
   2.416 +    RING_IDX rsp_prod;
   2.417 +
   2.418 +    mem_event_ring_lock(mem_event);
   2.419 +
   2.420 +    back_ring = &mem_event->back_ring;
   2.421 +    rsp_prod = back_ring->rsp_prod_pvt;
   2.422 +
   2.423 +    /* Copy response */
   2.424 +    memcpy(RING_GET_RESPONSE(back_ring, rsp_prod), rsp, sizeof(*rsp));
   2.425 +    rsp_prod++;
   2.426 +
   2.427 +    /* Update ring */
   2.428 +    back_ring->rsp_prod_pvt = rsp_prod;
   2.429 +    RING_PUSH_RESPONSES(back_ring);
   2.430 +
   2.431 +    mem_event_ring_unlock(mem_event);
   2.432 +
   2.433 +    return 0;
   2.434 +}
   2.435 +
   2.436 +static int xenaccess_resume_page(xenaccess_t *paging, mem_event_response_t *rsp)
   2.437 +{
   2.438 +    int ret;
   2.439 +
   2.440 +    /* Put the page info on the ring */
   2.441 +    ret = put_response(&paging->mem_event, rsp);
   2.442 +    if ( ret != 0 )
   2.443 +        goto out;
   2.444 +
   2.445 +    /* Tell Xen page is ready */
   2.446 +    ret = xc_mem_access_resume(paging->xc_handle, paging->mem_event.domain_id,
   2.447 +                               rsp->gfn);
   2.448 +    ret = xc_evtchn_notify(paging->mem_event.xce_handle,
   2.449 +                           paging->mem_event.port);
   2.450 +
   2.451 + out:
   2.452 +    return ret;
   2.453 +}
   2.454 +
   2.455 +void usage(char* progname)
   2.456 +{
   2.457 +    fprintf(stderr,
   2.458 +            "Usage: %s [-m] <domain_id> write|exec|int3\n"
   2.459 +            "\n"
   2.460 +            "Logs first page writes, execs, or int3 traps that occur on the domain.\n"
   2.461 +            "\n"
   2.462 +            "-m requires this program to run, or else the domain may pause\n",
   2.463 +            progname);
   2.464 +}
   2.465 +
   2.466 +int main(int argc, char *argv[])
   2.467 +{
   2.468 +    struct sigaction act;
   2.469 +    domid_t domain_id;
   2.470 +    xenaccess_t *xenaccess;
   2.471 +    mem_event_request_t req;
   2.472 +    mem_event_response_t rsp;
   2.473 +    int rc = -1;
   2.474 +    int rc1;
   2.475 +    xc_interface *xch;
   2.476 +    hvmmem_access_t default_access = HVMMEM_access_rwx;
   2.477 +    hvmmem_access_t after_first_access = HVMMEM_access_rwx;
   2.478 +    int required = 0;
   2.479 +    int int3 = 0;
   2.480 +    int shutting_down = 0;
   2.481 +
   2.482 +    char* progname = argv[0];
   2.483 +    argv++;
   2.484 +    argc--;
   2.485 +
   2.486 +    if ( argc == 3 && argv[0][0] == '-' )
   2.487 +    {
   2.488 +        argv++;
   2.489 +        argc--;
   2.490 +
   2.491 +        if ( !strcmp(argv[0], "-m") )
   2.492 +            required = 1;
   2.493 +        else
   2.494 +        {
   2.495 +            usage(progname);
   2.496 +            return -1;
   2.497 +        }
   2.498 +    }
   2.499 +
   2.500 +    if ( argc != 2 )
   2.501 +    {
   2.502 +        usage(progname);
   2.503 +        return -1;
   2.504 +    }
   2.505 +
   2.506 +    domain_id = atoi(argv[0]);
   2.507 +    argv++;
   2.508 +    argc--;
   2.509 +
   2.510 +    if ( !strcmp(argv[0], "write") )
   2.511 +    {
   2.512 +        default_access = HVMMEM_access_rx;
   2.513 +        after_first_access = HVMMEM_access_rwx;
   2.514 +    }
   2.515 +    else if ( !strcmp(argv[0], "exec") )
   2.516 +    {
   2.517 +        default_access = HVMMEM_access_rw;
   2.518 +        after_first_access = HVMMEM_access_rwx;
   2.519 +    }
   2.520 +    else if ( !strcmp(argv[0], "int3") )
   2.521 +    {
   2.522 +        int3 = 1;
   2.523 +    }
   2.524 +    else
   2.525 +    {
   2.526 +        usage(argv[0]);
   2.527 +        return -1;
   2.528 +    }
   2.529 +
   2.530 +    xenaccess = xenaccess_init(&xch, domain_id);
   2.531 +    if ( xenaccess == NULL )
   2.532 +    {
   2.533 +        ERROR("Error initialising xenaccess");
   2.534 +        return 1;
   2.535 +    }
   2.536 +
   2.537 +    DPRINTF("starting %s %u\n", argv[0], domain_id);
   2.538 +
   2.539 +    /* ensure that if we get a signal, we'll do cleanup, then exit */
   2.540 +    act.sa_handler = close_handler;
   2.541 +    act.sa_flags = 0;
   2.542 +    sigemptyset(&act.sa_mask);
   2.543 +    sigaction(SIGHUP,  &act, NULL);
   2.544 +    sigaction(SIGTERM, &act, NULL);
   2.545 +    sigaction(SIGINT,  &act, NULL);
   2.546 +    sigaction(SIGALRM, &act, NULL);
   2.547 +
   2.548 +    /* Set whether the access listener is required */
   2.549 +    xc_domain_set_access_required(xch, domain_id, required);
   2.550 +
   2.551 +    /* Set the default access type and convert all pages to it */
   2.552 +    rc = xc_hvm_set_mem_access(xch, domain_id, default_access, ~0ull, 0);
   2.553 +    rc = xc_hvm_set_mem_access(xch, domain_id, default_access, 0, xenaccess->domain_info->max_pages);
   2.554 +
   2.555 +    if ( int3 )
   2.556 +        rc = xc_set_hvm_param(xch, domain_id, HVM_PARAM_MEMORY_EVENT_INT3, HVMPME_mode_sync);
   2.557 +    else
   2.558 +        rc = xc_set_hvm_param(xch, domain_id, HVM_PARAM_MEMORY_EVENT_INT3, HVMPME_mode_disabled);
   2.559 +
   2.560 +    /* Wait for access */
   2.561 +    for (;;)
   2.562 +    {
   2.563 +        if ( interrupted )
   2.564 +        {
   2.565 +            DPRINTF("xenaccess shutting down on signal %d\n", interrupted);
   2.566 +
   2.567 +            /* Unregister for every event */
   2.568 +            rc = xc_hvm_set_mem_access(xch, domain_id, HVMMEM_access_rwx, ~0ull, 0);
   2.569 +            rc = xc_hvm_set_mem_access(xch, domain_id, HVMMEM_access_rwx, 0, xenaccess->domain_info->max_pages);
   2.570 +            rc = xc_set_hvm_param(xch, domain_id, HVM_PARAM_MEMORY_EVENT_INT3, HVMPME_mode_disabled);
   2.571 +
   2.572 +            shutting_down = 1;
   2.573 +        }
   2.574 +
   2.575 +        rc = xc_wait_for_event_or_timeout(xch, xenaccess->mem_event.xce_handle, 100);
   2.576 +        if ( rc < -1 )
   2.577 +        {
   2.578 +            ERROR("Error getting event");
   2.579 +            interrupted = -1;
   2.580 +            continue;
   2.581 +        }
   2.582 +        else if ( rc != -1 )
   2.583 +        {
   2.584 +            DPRINTF("Got event from Xen\n");
   2.585 +        }
   2.586 +
   2.587 +        while ( RING_HAS_UNCONSUMED_REQUESTS(&xenaccess->mem_event.back_ring) )
   2.588 +        {
   2.589 +            hvmmem_access_t access;
   2.590 +
   2.591 +            rc = get_request(&xenaccess->mem_event, &req);
   2.592 +            if ( rc != 0 )
   2.593 +            {
   2.594 +                ERROR("Error getting request");
   2.595 +                interrupted = -1;
   2.596 +                continue;
   2.597 +            }
   2.598 +
   2.599 +            memset( &rsp, 0, sizeof (rsp) );
   2.600 +            rsp.vcpu_id = req.vcpu_id;
   2.601 +            rsp.flags = req.flags;
   2.602 +
   2.603 +            switch (req.reason) {
   2.604 +            case MEM_EVENT_REASON_VIOLATION:
   2.605 +                rc = xc_hvm_get_mem_access(xch, domain_id, req.gfn, &access);
   2.606 +
   2.607 +                printf("PAGE ACCESS: %c%c%c for GFN %lx (offset %06lx) gla %016lx (vcpu %d)\n",
   2.608 +                        req.access_r ? 'r' : '-',
   2.609 +                        req.access_w ? 'w' : '-',
   2.610 +                        req.access_x ? 'x' : '-',
   2.611 +                        req.gfn,
   2.612 +                        req.offset,
   2.613 +                        req.gla,
   2.614 +                        req.vcpu_id);
   2.615 +
   2.616 +                if ( default_access != after_first_access )
   2.617 +                    rc = xc_hvm_set_mem_access(xch, domain_id, after_first_access, req.gfn, 1);
   2.618 +
   2.619 +
   2.620 +                rsp.gfn = req.gfn;
   2.621 +                rsp.p2mt = req.p2mt;
   2.622 +                break;
   2.623 +            case MEM_EVENT_REASON_INT3:
   2.624 +                printf("INT3: rip=%016lx, gfn=%lx (vcpu %d)\n", req.gla, req.gfn,
   2.625 +                        req.vcpu_id);
   2.626 +
   2.627 +                /* Reinject */
   2.628 +                rc = xc_hvm_inject_trap(xch, domain_id, req.vcpu_id, 3, -1, 0);
   2.629 +
   2.630 +                break;
   2.631 +            default:
   2.632 +                fprintf(stderr, "UNKNOWN REASON CODE %d\n", req.reason);
   2.633 +            }
   2.634 +
   2.635 +            rc = xenaccess_resume_page(xenaccess, &rsp);
   2.636 +            if ( rc != 0 )
   2.637 +            {
   2.638 +                ERROR("Error resuming page");
   2.639 +                interrupted = -1;
   2.640 +                continue;
   2.641 +            }
   2.642 +        }
   2.643 +
   2.644 +        if ( shutting_down )
   2.645 +            break;
   2.646 +    }
   2.647 +    DPRINTF("xenaccess shut down on signal %d\n", interrupted);
   2.648 +
   2.649 +    /* Tear down domain xenaccess */
   2.650 +    rc1 = xenaccess_teardown(xch, xenaccess);
   2.651 +    if ( rc1 != 0 )
   2.652 +        ERROR("Error tearing down xenaccess");
   2.653 +
   2.654 +    if ( rc == 0 )
   2.655 +        rc = rc1;
   2.656 +
   2.657 +    xc_interface_close(xch);
   2.658 +
   2.659 +    DPRINTF("xenaccess exit code %d\n", rc);
   2.660 +    return rc;
   2.661 +}
   2.662 +
   2.663 +
   2.664 +/*
   2.665 + * Local variables:
   2.666 + * mode: C
   2.667 + * c-set-style: "BSD"
   2.668 + * c-basic-offset: 4
   2.669 + * indent-tabs-mode: nil
   2.670 + * End:
   2.671 + */