[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index] [Xen-devel] [PATCH RFC V3 4/5] 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. All a call does is set per-domain info, and nothing actually happens until VMENTRY time, and then only if all conditions are met (the guest is in user mode, the set value matches CR3, and there are no other pending traps). This mechanism allows bringing in swapped-out pages for inspection. Changes since V2: - Removed superfluous memset(&ctxt, 0, sizeof(struct hvm_hw_cpu)). - Now checking SS.DPL instead of CS.DPL to see if the guest is in user mode. - Removed superfluous fault_info members initialization. - Now returning -EINVAL if !has_hvm_container_domain(d) on XEN_DOMCTL_set_pagefault_info. - Moved struct fault_info from struct domain to struct hvm_domain. - Collapsed explicit initialization of the fault_info members into a one-line assignment on the tools/libxc side. - Now using write_access as a proper bool instead of shifting and OR-ing it with PFEC_user_mode. Signed-off-by: Razvan Cojocaru <rcojocaru@xxxxxxxxxxxxxxx> --- tools/libxc/xc_domain.c | 16 ++++++++++++++++ tools/libxc/xenctrl.h | 4 ++++ xen/arch/x86/hvm/vmx/vmx.c | 37 +++++++++++++++++++++++++++++++++++++ xen/common/domctl.c | 26 ++++++++++++++++++++++++++ xen/include/asm-x86/hvm/domain.h | 7 +++++++ xen/include/public/domctl.h | 14 ++++++++++++++ 6 files changed, 104 insertions(+) diff --git a/tools/libxc/xc_domain.c b/tools/libxc/xc_domain.c index 0230c6c..49f0c61 100644 --- a/tools/libxc/xc_domain.c +++ b/tools/libxc/xc_domain.c @@ -506,6 +506,22 @@ 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 = *info; + + 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 5beb846..a913f10 100644 --- a/tools/libxc/xenctrl.h +++ b/tools/libxc/xenctrl.h @@ -803,6 +803,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 2caa04a..5ea3188 100644 --- a/xen/arch/x86/hvm/vmx/vmx.c +++ b/xen/arch/x86/hvm/vmx/vmx.c @@ -3097,6 +3097,41 @@ out: nvmx_idtv_handling(); } +static void check_pf_injection(void) +{ + struct vcpu *curr = current; + struct domain *d = curr->domain; + struct hvm_hw_cpu ctxt; + struct segment_register seg; + int errcode = PFEC_user_mode; + + if ( !is_hvm_domain(d) + || d->arch.hvm_domain.fault_info.virtual_address == 0 ) + return; + + hvm_funcs.save_cpu_ctxt(curr, &ctxt); + hvm_get_segment_register(curr, x86_seg_ss, &seg); + + if ( seg.attr.fields.dpl == 3 /* Guest is in user mode */ + && !ctxt.pending_event + && ctxt.cr3 == d->arch.hvm_domain.fault_info.address_space ) + { + /* Cache */ + uint64_t virtual_address = d->arch.hvm_domain.fault_info.virtual_address; + uint32_t write_access = d->arch.hvm_domain.fault_info.write_access; + + /* Reset */ + d->arch.hvm_domain.fault_info.address_space = 0; + d->arch.hvm_domain.fault_info.virtual_address = 0; + d->arch.hvm_domain.fault_info.write_access = 0; + + if ( write_access ) + errcode |= PFEC_write_access; + + hvm_inject_page_fault(errcode, virtual_address); + } +} + void vmx_vmenter_helper(const struct cpu_user_regs *regs) { struct vcpu *curr = current; @@ -3137,6 +3172,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/domctl.c b/xen/common/domctl.c index c326aba..0d67601 100644 --- a/xen/common/domctl.c +++ b/xen/common/domctl.c @@ -967,6 +967,32 @@ 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 ) + { + ret = -EINVAL; + + if ( has_hvm_container_domain(d) ) + { + d->arch.hvm_domain.fault_info.address_space = + op->u.set_pagefault_info.address_space; + d->arch.hvm_domain.fault_info.virtual_address = + op->u.set_pagefault_info.virtual_address; + d->arch.hvm_domain.fault_info.write_access = + op->u.set_pagefault_info.write_access; + ret = 0; + } + + rcu_unlock_domain(d); + } + } + break; + default: ret = arch_do_domctl(op, d, u_domctl); break; diff --git a/xen/include/asm-x86/hvm/domain.h b/xen/include/asm-x86/hvm/domain.h index 291a2e0..f9bd098 100644 --- a/xen/include/asm-x86/hvm/domain.h +++ b/xen/include/asm-x86/hvm/domain.h @@ -141,6 +141,13 @@ struct hvm_domain { */ uint64_t sync_tsc; + /* Memory introspection page fault injection data. */ + struct { + uint64_t address_space; + uint64_t virtual_address; + uint32_t write_access; + } fault_info; + union { struct vmx_domain vmx; struct svm_domain svm; 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; }; -- 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 |