Skip to content

Instantly share code, notes, and snippets.

@Wenzel
Last active December 29, 2020 01:24
Show Gist options
  • Save Wenzel/c9fc0ab4f6d4e878e39dcca0fa2a79f4 to your computer and use it in GitHub Desktop.
Save Wenzel/c9fc0ab4f6d4e878e39dcca0fa2a79f4 to your computer and use it in GitHub Desktop.
xen-access modified with singlestep option
/*
* xen-access.c
*
* Exercises the basic per-page access mechanisms
*
* Copyright (c) 2011 Virtuata, Inc.
* Copyright (c) 2009 by Citrix Systems, Inc. (Patrick Colp), based on
* xenpaging.c
*
* 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 <stdarg.h>
#include <stdbool.h>
#include <string.h>
#include <time.h>
#include <signal.h>
#include <unistd.h>
#include <sys/mman.h>
#include <poll.h>
#include <xenctrl.h>
#include <xenevtchn.h>
#include <xen/vm_event.h>
#if defined(__arm__) || defined(__aarch64__)
#include <xen/arch-arm.h>
#define START_PFN (GUEST_RAM0_BASE >> 12)
#elif defined(__i386__) || defined(__x86_64__)
#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))
/* From xen/include/asm-x86/processor.h */
#define X86_TRAP_DEBUG 1
#define X86_TRAP_INT3 3
#define MAX_VCPUS 2
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)
{
struct pollfd fd = { .fd = xenevtchn_fd(xce), .events = POLLIN | POLLERR };
int port;
int rc;
rc = poll(&fd, 1, ms);
if ( rc == -1 )
{
if (errno == EINTR)
return 0;
ERROR("Poll exited with an error");
goto err;
}
if ( rc == 1 )
{
printf("xenevtchn_pending\n");
port = xenevtchn_pending(xce);
if ( port == -1 )
{
ERROR("Failed to read port from event channel");
goto err;
}
printf("xenevthcn_unmasking\n");
rc = xenevtchn_unmask(xce, port);
if ( rc != 0 )
{
ERROR("Failed to unmask event channel port");
goto err;
}
}
else
port = -1;
return port;
err:
return -errno;
}
int xenaccess_teardown(xc_interface *xch, xenaccess_t *xenaccess)
{
int rc;
if ( xenaccess == NULL )
return 0;
/* Tear down domain xenaccess in Xen */
printf("teardown: munmap\n");
if ( xenaccess->vm_event.ring_page )
munmap(xenaccess->vm_event.ring_page, XC_PAGE_SIZE);
if ( mem_access_enable )
{
printf("teardown: xc_monitor_disable\n");
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 )
{
printf("teardown: xenevtchn_unbind\n");
rc = xenevtchn_unbind(xenaccess->vm_event.xce_handle,
xenaccess->vm_event.port);
if ( rc != 0 )
{
ERROR("Error unbinding event port");
return rc;
}
}
/* Close event channel */
if ( evtchn_open )
{
printf("teardown: xenevtchn_close\n");
rc = xenevtchn_close(xenaccess->vm_event.xce_handle);
if ( rc != 0 )
{
ERROR("Error closing event channel");
return rc;
}
}
/* Close connection to Xen */
printf("teardown: xc_interface_close\n");
rc = xc_interface_close(xenaccess->xc_handle);
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)
{
xenaccess_t *xenaccess = 0;
xc_interface *xch;
int rc;
xch = xc_interface_open(NULL, NULL, 0);
if ( !xch )
goto err_iface;
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 )
{
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);
if ( rc )
{
ERROR("Failed to get max gpfn");
goto err;
}
DPRINTF("max_gpfn = %"PRI_xen_pfn"\n", xenaccess->max_gpfn);
return xenaccess;
err:
rc = xenaccess_teardown(xch, xenaccess);
if ( rc )
{
ERROR("Failed to teardown xenaccess structure!\n");
}
err_iface:
return NULL;
}
static inline
int control_singlestep(
xc_interface *xch,
domid_t domain_id,
unsigned long vcpu,
bool enable)
{
uint32_t op = enable ?
XEN_DOMCTL_DEBUG_OP_SINGLE_STEP_ON : XEN_DOMCTL_DEBUG_OP_SINGLE_STEP_OFF;
return xc_domain_debug_control(xch, domain_id, op, vcpu);
}
/*
* 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;
}
/*
* 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);
#if defined(__i386__) || defined(__x86_64__)
fprintf(stderr, "|singlestep|breakpoint|altp2m_write|altp2m_exec|debug|cpuid|desc_access");
#elif defined(__arm__) || defined(__aarch64__)
fprintf(stderr, "|privcall");
#endif
fprintf(stderr,
"\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");
}
int main(int argc, char *argv[])
{
struct sigaction act;
domid_t domain_id;
xenaccess_t *xenaccess;
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;
int required = 0;
int breakpoint = 0;
int singlestep = 0;
int shutting_down = 0;
int privcall = 0;
int altp2m = 0;
int debug = 0;
int cpuid = 0;
int desc_access = 0;
uint16_t altp2m_view_id = 0;
char* progname = argv[0];
argv++;
argc--;
if ( argc == 3 && argv[0][0] == '-' )
{
if ( !strcmp(argv[0], "-m") )
required = 1;
else
{
usage(progname);
return -1;
}
argv++;
argc--;
}
if ( argc != 2 )
{
usage(progname);
return -1;
}
domain_id = atoi(argv[0]);
argv++;
argc--;
if ( !strcmp(argv[0], "write") )
{
default_access = XENMEM_access_rx;
after_first_access = XENMEM_access_rwx;
memaccess = 1;
}
else if ( !strcmp(argv[0], "exec") )
{
default_access = XENMEM_access_rw;
after_first_access = XENMEM_access_rwx;
memaccess = 1;
}
#if defined(__i386__) || defined(__x86_64__)
else if ( !strcmp(argv[0], "breakpoint") )
{
breakpoint = 1;
}
else if ( !strcmp(argv[0], "singlestep") )
{
singlestep = 1;
}
else if ( !strcmp(argv[0], "altp2m_write") )
{
default_access = XENMEM_access_rx;
altp2m = 1;
memaccess = 1;
}
else if ( !strcmp(argv[0], "altp2m_exec") )
{
default_access = XENMEM_access_rw;
altp2m = 1;
memaccess = 1;
}
else if ( !strcmp(argv[0], "debug") )
{
debug = 1;
}
else if ( !strcmp(argv[0], "cpuid") )
{
cpuid = 1;
}
else if ( !strcmp(argv[0], "desc_access") )
{
desc_access = 1;
}
#elif defined(__arm__) || defined(__aarch64__)
else if ( !strcmp(argv[0], "privcall") )
{
privcall = 1;
}
#endif
else
{
usage(argv[0]);
return -1;
}
xenaccess = xenaccess_init(&xch, domain_id);
if ( xenaccess == NULL )
{
ERROR("Error initialising xenaccess");
return 1;
}
DPRINTF("starting %s %u\n", argv[0], domain_id);
/* ensure that if we get a signal, we'll do cleanup, then exit */
act.sa_handler = close_handler;
act.sa_flags = 0;
sigemptyset(&act.sa_mask);
sigaction(SIGHUP, &act, NULL);
sigaction(SIGTERM, &act, NULL);
sigaction(SIGINT, &act, NULL);
sigaction(SIGALRM, &act, NULL);
/* Set whether the access listener is required */
rc = xc_domain_set_access_required(xch, domain_id, required);
if ( rc < 0 )
{
ERROR("Error %d setting mem_access listener required\n", rc);
goto exit;
}
/* With altp2m we just create a new, restricted view of the memory */
if ( memaccess && altp2m )
{
xen_pfn_t gfn = 0;
unsigned long perm_set = 0;
rc = xc_altp2m_set_domain_state( 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 );
if ( rc < 0 )
{
ERROR("Error %d creating altp2m view!\n", rc);
goto exit;
}
DPRINTF("altp2m view created with id %u\n", altp2m_view_id);
DPRINTF("Setting altp2m mem_access permissions.. ");
for(; gfn < xenaccess->max_gpfn; ++gfn)
{
rc = xc_altp2m_set_mem_access( 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 );
if ( rc < 0 )
{
ERROR("Error %d switching to altp2m view!\n", rc);
goto exit;
}
rc = xc_monitor_singlestep( xch, domain_id, 1 );
if ( rc < 0 )
{
ERROR("Error %d failed to enable singlestep monitoring!\n", rc);
goto exit;
}
}
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);
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) );
if ( rc < 0 )
{
ERROR("Error %d setting all memory to access type %d\n", rc,
default_access);
goto exit;
}
}
if ( breakpoint )
{
rc = xc_monitor_software_breakpoint(xch, domain_id, 1);
if ( rc < 0 )
{
ERROR("Error %d setting breakpoint trapping with vm_event\n", rc);
goto exit;
}
}
if ( singlestep )
{
printf("monitor_singlestep on\n");
rc = xc_monitor_singlestep(xch, domain_id, 1);
if ( rc < 0 )
{
ERROR("Error %d setting singlestep with vm_event\n", rc);
goto exit;
}
uint32_t vcpu_id;
for ( vcpu_id = 0; vcpu_id<MAX_VCPUS; vcpu_id++) {
printf("control_singlestep on\n");
rc = control_singlestep(xch, domain_id, vcpu_id, 1);
}
}
if ( debug )
{
rc = xc_monitor_debug_exceptions(xch, domain_id, 1, 1);
if ( rc < 0 )
{
ERROR("Error %d setting debug exception listener with vm_event\n", rc);
goto exit;
}
}
if ( cpuid )
{
rc = xc_monitor_cpuid(xch, domain_id, 1);
if ( rc < 0 )
{
ERROR("Error %d setting cpuid listener with vm_event\n", rc);
goto exit;
}
}
if ( desc_access )
{
rc = xc_monitor_descriptor_access(xch, domain_id, 1);
if ( rc < 0 )
{
ERROR("Error %d setting descriptor access listener with vm_event\n", rc);
goto exit;
}
}
if ( privcall )
{
rc = xc_monitor_privileged_call(xch, domain_id, 1);
if ( rc < 0 )
{
ERROR("Error %d setting privileged call trapping with vm_event\n", rc);
goto exit;
}
}
printf("-- Listening\n");
/* Wait for access */
for (;;)
{
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);
if ( singlestep ) {
uint32_t vcpu_id;
for ( vcpu_id = 0; vcpu_id<MAX_VCPUS; vcpu_id++) {
printf("control_singlestep off\n");
rc = control_singlestep(xch, domain_id, vcpu_id, 0);
}
printf("monitor singlestep off\n");
rc = xc_monitor_singlestep(xch, domain_id, 0);
}
if ( debug )
rc = xc_monitor_debug_exceptions(xch, domain_id, 0, 0);
if ( cpuid )
rc = xc_monitor_cpuid(xch, domain_id, 0);
if ( desc_access )
rc = xc_monitor_descriptor_access(xch, domain_id, 0);
if ( privcall )
rc = xc_monitor_privileged_call(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);
} 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) );
}
shutting_down = 1;
break;
}
rc = xc_wait_for_event_or_timeout(xch, xenaccess->vm_event.xce_handle, 100);
if ( rc < -1 )
{
ERROR("Error getting event");
interrupted = -1;
continue;
}
else if ( rc != -1 )
{
DPRINTF("Got event from Xen\n");
}
while ( RING_HAS_UNCONSUMED_REQUESTS(&xenaccess->vm_event.back_ring) )
{
get_request(&xenaccess->vm_event, &req);
if ( req.version != VM_EVENT_INTERFACE_VERSION )
{
ERROR("Error: vm_event interface version mismatch!\n");
interrupted = -1;
continue;
}
memset( &rsp, 0, sizeof (rsp) );
rsp.version = VM_EVENT_INTERFACE_VERSION;
rsp.vcpu_id = req.vcpu_id;
rsp.flags = (req.flags & VM_EVENT_FLAG_VCPU_PAUSED);
rsp.reason = req.reason;
switch (req.reason) {
case VM_EVENT_REASON_MEM_ACCESS:
if ( !shutting_down )
{
/*
* This serves no other purpose here then demonstrating the use of the API.
* 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);
if (rc < 0)
{
ERROR("Error %d getting mem_access event\n", rc);
interrupted = -1;
continue;
}
}
printf("PAGE ACCESS: %c%c%c for GFN %"PRIx64" (offset %06"
PRIx64") gla %016"PRIx64" (valid: %c; fault in gpt: %c; fault with gla: %c) (vcpu %u [%c], altp2m view %u)\n",
(req.u.mem_access.flags & MEM_ACCESS_R) ? 'r' : '-',
(req.u.mem_access.flags & MEM_ACCESS_W) ? 'w' : '-',
(req.u.mem_access.flags & MEM_ACCESS_X) ? 'x' : '-',
req.u.mem_access.gfn,
req.u.mem_access.offset,
req.u.mem_access.gla,
(req.u.mem_access.flags & MEM_ACCESS_GLA_VALID) ? 'y' : 'n',
(req.u.mem_access.flags & MEM_ACCESS_FAULT_IN_GPT) ? 'y' : 'n',
(req.u.mem_access.flags & MEM_ACCESS_FAULT_WITH_GLA) ? 'y': 'n',
req.vcpu_id,
(req.flags & VM_EVENT_FLAG_VCPU_PAUSED) ? 'p' : 'r',
req.altp2m_idx);
if ( altp2m && req.flags & VM_EVENT_FLAG_ALTERNATE_P2M)
{
DPRINTF("\tSwitching back to default view!\n");
rsp.flags |= (VM_EVENT_FLAG_ALTERNATE_P2M | VM_EVENT_FLAG_TOGGLE_SINGLESTEP);
rsp.altp2m_idx = 0;
}
else if ( default_access != after_first_access )
{
rc = xc_set_mem_access(xch, domain_id, after_first_access,
req.u.mem_access.gfn, 1);
if (rc < 0)
{
ERROR("Error %d setting gfn to access_type %d\n", rc,
after_first_access);
interrupted = -1;
continue;
}
}
rsp.u.mem_access = req.u.mem_access;
break;
case VM_EVENT_REASON_SOFTWARE_BREAKPOINT:
printf("Breakpoint: rip=%016"PRIx64", gfn=%"PRIx64" (vcpu %d)\n",
req.data.regs.x86.rip,
req.u.software_breakpoint.gfn,
req.vcpu_id);
/* Reinject */
rc = xc_hvm_inject_trap(xch, domain_id, req.vcpu_id,
X86_TRAP_INT3,
req.u.software_breakpoint.type, -1,
req.u.software_breakpoint.insn_length, 0);
if (rc < 0)
{
ERROR("Error %d injecting breakpoint\n", rc);
interrupted = -1;
continue;
}
break;
case VM_EVENT_REASON_PRIVILEGED_CALL:
printf("Privileged call: pc=%"PRIx64" (vcpu %d)\n",
req.data.regs.arm.pc,
req.vcpu_id);
rsp.data.regs.arm = req.data.regs.arm;
rsp.data.regs.arm.pc += 4;
rsp.flags |= VM_EVENT_FLAG_SET_REGISTERS;
break;
case VM_EVENT_REASON_SINGLESTEP:
printf("Singlestep: rip=%016"PRIx64", vcpu %d, altp2m %u\n",
req.data.regs.x86.rip,
req.vcpu_id,
req.altp2m_idx);
if ( altp2m )
{
printf("\tSwitching altp2m to view %u!\n", altp2m_view_id);
rsp.flags |= VM_EVENT_FLAG_ALTERNATE_P2M;
rsp.altp2m_idx = altp2m_view_id;
}
if ( !singlestep )
rsp.flags |= VM_EVENT_FLAG_TOGGLE_SINGLESTEP;
// debug: do one singlestep and quit
interrupted = 1;
break;
case VM_EVENT_REASON_DEBUG_EXCEPTION:
printf("Debug exception: rip=%016"PRIx64", vcpu %d. Type: %u. Length: %u\n",
req.data.regs.x86.rip,
req.vcpu_id,
req.u.debug_exception.type,
req.u.debug_exception.insn_length);
/* Reinject */
rc = xc_hvm_inject_trap(xch, domain_id, req.vcpu_id,
X86_TRAP_DEBUG,
req.u.debug_exception.type, -1,
req.u.debug_exception.insn_length,
req.data.regs.x86.cr2);
if (rc < 0)
{
ERROR("Error %d injecting breakpoint\n", rc);
interrupted = -1;
continue;
}
break;
case VM_EVENT_REASON_CPUID:
printf("CPUID executed: rip=%016"PRIx64", vcpu %d. Insn length: %"PRIu32" " \
"0x%"PRIx32" 0x%"PRIx32": EAX=0x%"PRIx64" EBX=0x%"PRIx64" ECX=0x%"PRIx64" EDX=0x%"PRIx64"\n",
req.data.regs.x86.rip,
req.vcpu_id,
req.u.cpuid.insn_length,
req.u.cpuid.leaf,
req.u.cpuid.subleaf,
req.data.regs.x86.rax,
req.data.regs.x86.rbx,
req.data.regs.x86.rcx,
req.data.regs.x86.rdx);
rsp.flags |= VM_EVENT_FLAG_SET_REGISTERS;
rsp.data = req.data;
rsp.data.regs.x86.rip += req.u.cpuid.insn_length;
break;
case VM_EVENT_REASON_DESCRIPTOR_ACCESS:
printf("Descriptor access: rip=%016"PRIx64", vcpu %d: "\
"VMExit info=0x%"PRIx32", descriptor=%d, is write=%d\n",
req.data.regs.x86.rip,
req.vcpu_id,
req.u.desc_access.arch.vmx.instr_info,
req.u.desc_access.descriptor,
req.u.desc_access.is_write);
rsp.flags |= VM_EVENT_FLAG_EMULATE;
break;
default:
fprintf(stderr, "UNKNOWN REASON CODE %d\n", req.reason);
}
/* Put the response on the ring */
put_response(&xenaccess->vm_event, &rsp);
}
/* Tell Xen page is ready */
printf("xenevtchn_notify\n");
rc = xenevtchn_notify(xenaccess->vm_event.xce_handle,
xenaccess->vm_event.port);
if ( rc != 0 )
{
ERROR("Error resuming page");
interrupted = -1;
}
if ( shutting_down )
break;
}
DPRINTF("-- xenaccess shut down on signal %d\n", interrupted);
exit:
if ( altp2m )
{
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);
}
/* Tear down domain xenaccess */
rc1 = xenaccess_teardown(xch, xenaccess);
if ( rc1 != 0 )
ERROR("Error tearing down xenaccess");
if ( rc == 0 )
rc = rc1;
DPRINTF("xenaccess exit code %d\n", rc);
return rc;
}
/*
* Local variables:
* mode: C
* c-file-style: "BSD"
* c-basic-offset: 4
* indent-tabs-mode: nil
* End:
*/
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment