[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index] [Xen-devel] [PATCH RFC 6/9] xen, libxc: Request page fault injection via libxc
Added new XEN_DOMCTL_set_pagefault_info hypercall, used by libxc's new xc_domain_set_pagefault_info() function to set per-domain page fault injection information. This information is then used to call hvm_inject_page_fault() at the first VMENTRY where the guest status matches and there are no other pending traps. Signed-off-by: Razvan Cojocaru <rcojocaru@xxxxxxxxxxxxxxx> --- tools/libxc/xc_domain.c | 17 +++++++++++++++++ tools/libxc/xenctrl.h | 4 ++++ xen/arch/x86/hvm/vmx/vmx.c | 39 +++++++++++++++++++++++++++++++++++++++ xen/common/domain.c | 5 +++++ xen/common/domctl.c | 21 +++++++++++++++++++++ xen/include/public/domctl.h | 14 ++++++++++++++ xen/include/xen/sched.h | 7 +++++++ 7 files changed, 107 insertions(+) diff --git a/tools/libxc/xc_domain.c b/tools/libxc/xc_domain.c index d5d6d12..701b65f 100644 --- a/tools/libxc/xc_domain.c +++ b/tools/libxc/xc_domain.c @@ -486,6 +486,23 @@ int xc_domain_hvm_setcontext(xc_interface *xch, return ret; } +int xc_domain_set_pagefault_info(xc_interface *xch, + uint32_t domid, + xen_domctl_set_pagefault_info_t *info) +{ + DECLARE_DOMCTL; + + if (info == NULL) + return -1; + + domctl.cmd = XEN_DOMCTL_set_pagefault_info; + domctl.domain = (domid_t)domid; + domctl.u.set_pagefault_info.address_space = info->address_space; + domctl.u.set_pagefault_info.virtual_address = info->virtual_address; + domctl.u.set_pagefault_info.write_access = info->write_access; + return do_domctl(xch, &domctl); +} + int xc_vcpu_getcontext(xc_interface *xch, uint32_t domid, uint32_t vcpu, diff --git a/tools/libxc/xenctrl.h b/tools/libxc/xenctrl.h index abd8947..088f02f 100644 --- a/tools/libxc/xenctrl.h +++ b/tools/libxc/xenctrl.h @@ -752,6 +752,10 @@ int xc_domain_hvm_setcontext(xc_interface *xch, const char *xc_domain_get_native_protocol(xc_interface *xch, uint32_t domid); +int xc_domain_set_pagefault_info(xc_interface *xch, + uint32_t domid, + xen_domctl_set_pagefault_info_t *info); + /** * This function returns information about the execution context of a * particular vcpu of a domain. diff --git a/xen/arch/x86/hvm/vmx/vmx.c b/xen/arch/x86/hvm/vmx/vmx.c index b4c12cd..4a9a7c8 100644 --- a/xen/arch/x86/hvm/vmx/vmx.c +++ b/xen/arch/x86/hvm/vmx/vmx.c @@ -416,6 +416,7 @@ static void vmx_restore_dr(struct vcpu *v) static void vmx_vmcs_save(struct vcpu *v, struct hvm_hw_cpu *c) { unsigned long ev; + unsigned long cs_arbytes; vmx_vmcs_enter(v); @@ -430,6 +431,9 @@ static void vmx_vmcs_save(struct vcpu *v, struct hvm_hw_cpu *c) __vmread(GUEST_SYSENTER_CS, &c->sysenter_cs); __vmread(GUEST_SYSENTER_ESP, &c->sysenter_esp); __vmread(GUEST_SYSENTER_EIP, &c->sysenter_eip); + __vmread(GUEST_CS_AR_BYTES, &cs_arbytes); + + c->cs_arbytes = (uint32_t)cs_arbytes; c->pending_event = 0; c->error_code = 0; @@ -3111,6 +3115,39 @@ out: nvmx_idtv_handling(); } +static void check_pf_injection(void) +{ + struct vcpu *curr = current; + struct domain *d = curr->domain; + struct hvm_hw_cpu ctxt; + uint32_t cs_dpl; + + if ( !is_hvm_domain(d) || d->fault_info.virtual_address == 0 ) + return; + + memset(&ctxt, 0, sizeof(struct hvm_hw_cpu)); + hvm_funcs.save_cpu_ctxt(curr, &ctxt); + + cs_dpl = (ctxt.cs_arbytes >> 5) & 3; + + if ( cs_dpl == 3 /* Guest is in user mode */ + && !ctxt.pending_event + && ctxt.cr3 == d->fault_info.address_space ) + { + /* Cache */ + uint64_t virtual_address = d->fault_info.virtual_address; + uint32_t write_access = d->fault_info.write_access; + + /* Reset */ + d->fault_info.address_space = 0; + d->fault_info.virtual_address = 0; + d->fault_info.write_access = 0; + + hvm_inject_page_fault((write_access << 1) | PFEC_user_mode, + virtual_address); + } +} + void vmx_vmenter_helper(const struct cpu_user_regs *regs) { struct vcpu *curr = current; @@ -3151,6 +3188,8 @@ void vmx_vmenter_helper(const struct cpu_user_regs *regs) if ( unlikely(need_flush) ) vpid_sync_all(); + check_pf_injection(); + out: HVMTRACE_ND(VMENTRY, 0, 1/*cycles*/, 0, 0, 0, 0, 0, 0, 0); diff --git a/xen/common/domain.c b/xen/common/domain.c index c3a576e..9402924 100644 --- a/xen/common/domain.c +++ b/xen/common/domain.c @@ -255,6 +255,11 @@ struct domain *domain_create( d->domain_id = domid; + /* Memory introspection page fault variables set-up. */ + d->fault_info.address_space = 0; + d->fault_info.virtual_address = 0; + d->fault_info.write_access = 0; + lock_profile_register_struct(LOCKPROF_TYPE_PERDOM, d, domid, "Domain"); if ( (err = xsm_alloc_security_domain(d)) != 0 ) diff --git a/xen/common/domctl.c b/xen/common/domctl.c index 000993f..461e207 100644 --- a/xen/common/domctl.c +++ b/xen/common/domctl.c @@ -975,6 +975,27 @@ long do_domctl(XEN_GUEST_HANDLE_PARAM(xen_domctl_t) u_domctl) } break; + case XEN_DOMCTL_set_pagefault_info: + { + struct domain *d; + + ret = -ESRCH; + d = rcu_lock_domain_by_id(op->domain); + if ( d != NULL ) + { + d->fault_info.address_space = + op->u.set_pagefault_info.address_space; + d->fault_info.virtual_address = + op->u.set_pagefault_info.virtual_address; + d->fault_info.write_access = + op->u.set_pagefault_info.write_access; + + rcu_unlock_domain(d); + ret = 0; + } + } + break; + default: ret = arch_do_domctl(op, d, u_domctl); break; diff --git a/xen/include/public/domctl.h b/xen/include/public/domctl.h index 5b11bbf..c8bf3f8 100644 --- a/xen/include/public/domctl.h +++ b/xen/include/public/domctl.h @@ -936,6 +936,18 @@ typedef struct xen_domctl_vcpu_msrs xen_domctl_vcpu_msrs_t; DEFINE_XEN_GUEST_HANDLE(xen_domctl_vcpu_msrs_t); #endif +/* XEN_DOMCTL_set_pagefault_info requests that a page fault occur at + * the next VMENTRY. + * */ +struct xen_domctl_set_pagefault_info { + uint64_t address_space; + uint64_t virtual_address; + uint32_t write_access; +}; +typedef struct xen_domctl_set_pagefault_info xen_domctl_set_pagefault_info_t; +DEFINE_XEN_GUEST_HANDLE(xen_domctl_set_pagefault_info_t); + + struct xen_domctl { uint32_t cmd; #define XEN_DOMCTL_createdomain 1 @@ -1012,6 +1024,7 @@ struct xen_domctl { #define XEN_DOMCTL_gdbsx_pausevcpu 1001 #define XEN_DOMCTL_gdbsx_unpausevcpu 1002 #define XEN_DOMCTL_gdbsx_domstatus 1003 +#define XEN_DOMCTL_set_pagefault_info 1004 uint32_t interface_version; /* XEN_DOMCTL_INTERFACE_VERSION */ domid_t domain; union { @@ -1068,6 +1081,7 @@ struct xen_domctl { struct xen_domctl_cacheflush cacheflush; struct xen_domctl_gdbsx_pauseunp_vcpu gdbsx_pauseunp_vcpu; struct xen_domctl_gdbsx_domstatus gdbsx_domstatus; + struct xen_domctl_set_pagefault_info set_pagefault_info; uint8_t pad[128]; } u; }; diff --git a/xen/include/xen/sched.h b/xen/include/xen/sched.h index f920e1a..fe78a9a 100644 --- a/xen/include/xen/sched.h +++ b/xen/include/xen/sched.h @@ -447,6 +447,13 @@ struct domain nodemask_t node_affinity; unsigned int last_alloc_node; spinlock_t node_affinity_lock; + + /* Memory introspection page fault injection data. */ + struct { + uint64_t address_space; + uint64_t virtual_address; + uint32_t write_access; + } fault_info; }; struct domain_setup_info -- 1.7.9.5 _______________________________________________ Xen-devel mailing list Xen-devel@xxxxxxxxxxxxx http://lists.xen.org/xen-devel
|
Lists.xenproject.org is hosted with RackSpace, monitoring our |