[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index] [Xen-changelog] [xen master] x86: handle resumed instruction based on previous mem_event reply
commit 1e71f2d7418dfdcf6356e4be8e9311ea607a1877 Author: Razvan Cojocaru <rcojocaru@xxxxxxxxxxxxxxx> AuthorDate: Thu Sep 18 14:57:45 2014 +0200 Commit: Jan Beulich <jbeulich@xxxxxxxx> CommitDate: Thu Sep 18 14:57:45 2014 +0200 x86: handle resumed instruction based on previous mem_event reply 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: Tim Deegan <tim@xxxxxxx> Acked-by: Jan Beulich <jbeulich@xxxxxxxx> --- xen/arch/x86/domain.c | 3 ++ xen/arch/x86/mm/p2m.c | 75 ++++++++++++++++++++++++++++++++++++++++ xen/include/asm-x86/domain.h | 11 ++++++ xen/include/public/mem_event.h | 21 ++++++++--- 4 files changed, 105 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/mm/p2m.c b/xen/arch/x86/mm/p2m.c index 7587797..54859c8 100644 --- a/xen/arch/x86/mm/p2m.c +++ b/xen/arch/x86/mm/p2m.c @@ -1395,6 +1395,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 @@ -1448,6 +1449,30 @@ bool_t p2m_mem_access_check(paddr_t gpa, unsigned long gla, } } + /* 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); if ( req ) @@ -1502,6 +1527,56 @@ 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; + + 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; + } + } + + v->arch.mem_event.emulate_flags = violation ? rsp.flags : 0; + } + /* 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 8fc5a45..7abe1b3 100644 --- a/xen/include/asm-x86/domain.h +++ b/xen/include/asm-x86/domain.h @@ -459,6 +459,17 @@ 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/public/mem_event.h b/xen/include/public/mem_event.h index d3dd9c6..599f9e8 100644 --- a/xen/include/public/mem_event.h +++ b/xen/include/public/mem_event.h @@ -31,11 +31,22 @@ #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) +/* + * Emulate the fault-causing instruction (if set in the event response flags). + * This will allow the guest to continue execution without lifting the page + * access restrictions. + */ +#define MEM_EVENT_FLAG_EMULATE (1 << 5) +/* + * Same as MEM_EVENT_FLAG_EMULATE, but with write operations or operations + * potentially having side effects (like memory mapped or port I/O) disabled. + */ +#define MEM_EVENT_FLAG_EMULATE_NOWRITE (1 << 6) /* Reasons for the memory event request */ #define MEM_EVENT_REASON_UNKNOWN 0 /* typical reason */ -- generated by git-patchbot for /home/xen/git/xen.git#master _______________________________________________ Xen-changelog mailing list Xen-changelog@xxxxxxxxxxxxx http://lists.xensource.com/xen-changelog
|
Lists.xenproject.org is hosted with RackSpace, monitoring our |