[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index] Re: [Xen-devel] [PATCH V3 5/5] xen: Handle resumed instruction based on previous mem_event reply
> From: Razvan Cojocaru [mailto:rcojocaru@xxxxxxxxxxxxxxx] > Sent: Thursday, September 04, 2014 2:34 AM > > In a scenario where a page fault that triggered a mem_event occured, > p2m_mem_access_check() will now be able to either 1) emulate the > current instruction, or 2) emulate it, but don't allow it to perform > any writes. > > Signed-off-by: Razvan Cojocaru <rcojocaru@xxxxxxxxxxxxxxx> Acked-by: Kevin Tian <kevin.tian@xxxxxxxxx> for vmx part. > --- > xen/arch/x86/domain.c | 3 ++ > xen/arch/x86/hvm/vmx/vmx.c | 16 ++++++++ > xen/arch/x86/mm/p2m.c | 84 > ++++++++++++++++++++++++++++++++++++++++ > xen/include/asm-x86/domain.h | 9 +++++ > xen/include/asm-x86/hvm/hvm.h | 2 + > xen/include/public/mem_event.h | 12 +++--- > 6 files changed, 121 insertions(+), 5 deletions(-) > > diff --git a/xen/arch/x86/domain.c b/xen/arch/x86/domain.c > index f7e0e78..7b1dfe6 100644 > --- a/xen/arch/x86/domain.c > +++ b/xen/arch/x86/domain.c > @@ -415,6 +415,9 @@ int vcpu_initialise(struct vcpu *v) > > v->arch.flags = TF_kernel_mode; > > + /* By default, do not emulate */ > + v->arch.mem_event.emulate_flags = 0; > + > rc = mapcache_vcpu_init(v); > if ( rc ) > return rc; > diff --git a/xen/arch/x86/hvm/vmx/vmx.c b/xen/arch/x86/hvm/vmx/vmx.c > index b08664e..cc317a4 100644 > --- a/xen/arch/x86/hvm/vmx/vmx.c > +++ b/xen/arch/x86/hvm/vmx/vmx.c > @@ -1695,6 +1695,21 @@ static void > vmx_enable_msr_exit_interception(struct domain *d) > MSR_TYPE_W); > } > > +static bool_t vmx_exited_by_nested_pagefault(void) > +{ > + unsigned long exit_qualification, exit_reason; > + > + __vmread(VM_EXIT_REASON, &exit_reason); > + ASSERT(exit_reason == EXIT_REASON_EPT_VIOLATION); > + > + __vmread(EXIT_QUALIFICATION, &exit_qualification); > + > + if ( (exit_qualification & EPT_GLA_FAULT) == 0 ) > + return 0; > + > + return 1; > +} > + > static struct hvm_function_table __initdata vmx_function_table = { > .name = "VMX", > .cpu_up_prepare = vmx_cpu_up_prepare, > @@ -1754,6 +1769,7 @@ static struct hvm_function_table __initdata > vmx_function_table = { > .nhvm_hap_walk_L1_p2m = nvmx_hap_walk_L1_p2m, > .hypervisor_cpuid_leaf = vmx_hypervisor_cpuid_leaf, > .enable_msr_exit_interception = vmx_enable_msr_exit_interception, > + .exited_by_nested_pagefault = vmx_exited_by_nested_pagefault, > }; > > const struct hvm_function_table * __init start_vmx(void) > diff --git a/xen/arch/x86/mm/p2m.c b/xen/arch/x86/mm/p2m.c > index 6ed4109..3f35832 100644 > --- a/xen/arch/x86/mm/p2m.c > +++ b/xen/arch/x86/mm/p2m.c > @@ -1391,6 +1391,7 @@ bool_t p2m_mem_access_check(paddr_t gpa, > unsigned long gla, > p2m_access_t p2ma; > mem_event_request_t *req; > int rc; > + unsigned long eip = guest_cpu_user_regs()->eip; > > /* First, handle rx2rw conversion automatically. > * These calls to p2m->set_entry() must succeed: we have the gfn > @@ -1443,6 +1444,36 @@ bool_t p2m_mem_access_check(paddr_t gpa, > unsigned long gla, > return 1; > } > } > + else if ( v->arch.mem_event.emulate_flags == 0 && > + hvm_funcs.exited_by_nested_pagefault && > + !hvm_funcs.exited_by_nested_pagefault() ) /* don't send a > mem_event */ > + { > + v->arch.mem_event.emulate_flags = > MEM_EVENT_FLAG_EMULATE; > + v->arch.mem_event.gpa = gpa; > + v->arch.mem_event.eip = eip; > + } > + > + /* The previous mem_event reply does not match the current state. */ > + if ( v->arch.mem_event.gpa != gpa || v->arch.mem_event.eip != eip ) > + { > + /* Don't emulate the current instruction, send a new mem_event. > */ > + v->arch.mem_event.emulate_flags = 0; > + > + /* Make sure to mark the current state to match it again against > + * the new mem_event about to be sent. */ > + v->arch.mem_event.gpa = gpa; > + v->arch.mem_event.eip = eip; > + } > + > + if ( v->arch.mem_event.emulate_flags ) > + { > + > hvm_mem_event_emulate_one((v->arch.mem_event.emulate_flags & > + > MEM_EVENT_FLAG_EMULATE_NOWRITE) != 0, > + TRAP_invalid_op, > HVM_DELIVER_NO_ERROR_CODE); > + > + v->arch.mem_event.emulate_flags = 0; > + return 1; > + } > > *req_ptr = NULL; > req = xzalloc(mem_event_request_t); > @@ -1498,6 +1529,59 @@ void p2m_mem_access_resume(struct domain *d) > > v = d->vcpu[rsp.vcpu_id]; > > + /* Mark vcpu for skipping one instruction upon rescheduling */ > + if ( rsp.flags & MEM_EVENT_FLAG_EMULATE ) > + { > + xenmem_access_t access; > + bool_t violation = 1; > + > + v->arch.mem_event.emulate_flags = 0; > + > + if ( p2m_get_mem_access(d, rsp.gfn, &access) == 0 ) > + { > + switch ( access ) > + { > + case XENMEM_access_n: > + case XENMEM_access_n2rwx: > + default: > + violation = rsp.access_r || rsp.access_w || > rsp.access_x; > + break; > + > + case XENMEM_access_r: > + violation = rsp.access_w || rsp.access_x; > + break; > + > + case XENMEM_access_w: > + violation = rsp.access_r || rsp.access_x; > + break; > + > + case XENMEM_access_x: > + violation = rsp.access_r || rsp.access_w; > + break; > + > + case XENMEM_access_rx: > + case XENMEM_access_rx2rw: > + violation = rsp.access_w; > + break; > + > + case XENMEM_access_wx: > + violation = rsp.access_r; > + break; > + > + case XENMEM_access_rw: > + violation = rsp.access_x; > + break; > + > + case XENMEM_access_rwx: > + violation = 0; > + break; > + } > + } > + > + if ( violation ) > + v->arch.mem_event.emulate_flags = rsp.flags; > + } > + > /* Unpause domain */ > if ( rsp.flags & MEM_EVENT_FLAG_VCPU_PAUSED ) > mem_event_vcpu_unpause(v); > diff --git a/xen/include/asm-x86/domain.h b/xen/include/asm-x86/domain.h > index 83329ed..440aa81 100644 > --- a/xen/include/asm-x86/domain.h > +++ b/xen/include/asm-x86/domain.h > @@ -458,6 +458,15 @@ struct arch_vcpu > > /* A secondary copy of the vcpu time info. */ > XEN_GUEST_HANDLE(vcpu_time_info_t) time_info_guest; > + > + /* Should we emulate the next matching instruction on VCPU resume > + * after a mem_event? */ > + struct { > + uint32_t emulate_flags; > + unsigned long gpa; > + unsigned long eip; > + } mem_event; > + > } __cacheline_aligned; > > smap_check_policy_t smap_policy_change(struct vcpu *v, > diff --git a/xen/include/asm-x86/hvm/hvm.h > b/xen/include/asm-x86/hvm/hvm.h > index 3b0bde9..9ab126c 100644 > --- a/xen/include/asm-x86/hvm/hvm.h > +++ b/xen/include/asm-x86/hvm/hvm.h > @@ -208,6 +208,8 @@ struct hvm_function_table { > uint32_t *ecx, uint32_t *edx); > > void (*enable_msr_exit_interception)(struct domain *d); > + > + bool_t (*exited_by_nested_pagefault)(void); > }; > > extern struct hvm_function_table hvm_funcs; > diff --git a/xen/include/public/mem_event.h > b/xen/include/public/mem_event.h > index d3dd9c6..92c063c 100644 > --- a/xen/include/public/mem_event.h > +++ b/xen/include/public/mem_event.h > @@ -31,11 +31,13 @@ > #include "io/ring.h" > > /* Memory event flags */ > -#define MEM_EVENT_FLAG_VCPU_PAUSED (1 << 0) > -#define MEM_EVENT_FLAG_DROP_PAGE (1 << 1) > -#define MEM_EVENT_FLAG_EVICT_FAIL (1 << 2) > -#define MEM_EVENT_FLAG_FOREIGN (1 << 3) > -#define MEM_EVENT_FLAG_DUMMY (1 << 4) > +#define MEM_EVENT_FLAG_VCPU_PAUSED (1 << 0) > +#define MEM_EVENT_FLAG_DROP_PAGE (1 << 1) > +#define MEM_EVENT_FLAG_EVICT_FAIL (1 << 2) > +#define MEM_EVENT_FLAG_FOREIGN (1 << 3) > +#define MEM_EVENT_FLAG_DUMMY (1 << 4) > +#define MEM_EVENT_FLAG_EMULATE (1 << 5) > +#define MEM_EVENT_FLAG_EMULATE_NOWRITE (1 << 6) > > /* Reasons for the memory event request */ > #define MEM_EVENT_REASON_UNKNOWN 0 /* typical reason */ > -- > 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 |