[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index] [Xen-devel] [PATCH 1 of 5] mem_access: hvm changes to page faults
Changes the nested page fault to send memory access failures to the event handler, if there is one. Also adds HVMOPs to set and get memory access. Signed-off-by: Joe Epstein <jepstein98@xxxxxxxxx> diff -r 4e108cf56d07 xen/arch/x86/hvm/hvm.c --- a/xen/arch/x86/hvm/hvm.c Mon Dec 27 08:00:09 2010 +0000 +++ b/xen/arch/x86/hvm/hvm.c Tue Dec 28 22:35:35 2010 -0800 @@ -1086,61 +1086,91 @@ domain_shutdown(v->domain, SHUTDOWN_reboot); } -bool_t hvm_hap_nested_page_fault(unsigned long gfn) +bool_t hvm_hap_nested_page_fault(unsigned long gpa, + bool_t gla_valid, + unsigned long gla, + bool_t access_r, + bool_t access_w, + bool_t access_x) { + unsigned long gfn = gpa >> PAGE_SHIFT; p2m_type_t p2mt; mfn_t mfn; struct vcpu *v = current; struct p2m_domain *p2m = p2m_get_hostp2m(v->domain); + int guest_fault = 0; mfn = gfn_to_mfn_guest(p2m, gfn, &p2mt); - /* - * If this GFN is emulated MMIO or marked as read-only, pass the fault - * to the mmio handler. - */ - if ( (p2mt == p2m_mmio_dm) || (p2mt == p2m_ram_ro) ) +#ifdef __x86_64__ + /* Check if the page has been paged out */ + if ( p2m_is_paged(p2mt) || (p2mt == p2m_ram_paging_out) ) { - if ( !handle_mmio() ) - hvm_inject_exception(TRAP_gp_fault, 0, 0); + p2m_mem_paging_populate(p2m, gfn); return 1; } -#ifdef __x86_64__ - /* Check if the page has been paged out */ - if ( p2m_is_paged(p2mt) || (p2mt == p2m_ram_paging_out) ) - p2m_mem_paging_populate(p2m, gfn); - /* Mem sharing: unshare the page and try again */ - if ( p2mt == p2m_ram_shared ) + if ( p2mt == p2m_ram_shared && access_w ) { mem_sharing_unshare_page(p2m, gfn, 0); return 1; } #endif - - /* Spurious fault? PoD and log-dirty also take this path. */ - if ( p2m_is_ram(p2mt) ) + + /* + * If this GFN is emulated MMIO or marked as read-only (which old MMIO is), + * pass the fault to the mmio handler first. + */ + if ( (p2mt == p2m_mmio_dm) || (p2mt == p2m_ram_ro) ) { - /* - * Page log dirty is always done with order 0. If this mfn resides in - * a large page, we do not change other pages type within that large - * page. - */ - paging_mark_dirty(v->domain, mfn_x(mfn)); - p2m_change_type(p2m, gfn, p2m_ram_logdirty, p2m_ram_rw); + if ( !handle_mmio() ) + { + guest_fault = 1; + goto check_access_handler; + } return 1; } - /* Shouldn't happen: Maybe the guest was writing to a r/o grant mapping? */ - if ( p2mt == p2m_grant_map_ro ) + /* Was it a write access: log-dirty, etc... */ + if ( access_w ) { + /* PoD and log-dirty also take this path. */ + if ( p2mt != p2m_ram_rw && p2m_is_ram(p2mt) ) + { + /* + * Page log dirty is always done with order 0. If this mfn resides in + * a large page, we do not change other pages type within that large + * page. + */ + paging_mark_dirty(v->domain, mfn_x(mfn)); + p2m_change_type(p2m, gfn, p2m_ram_logdirty, p2m_ram_rw); + return 1; + } + + /* Shouldn't happen: Maybe the guest was writing to a r/o grant mapping? */ + if ( p2mt == p2m_grant_map_ro ) + { + gdprintk(XENLOG_WARNING, + "trying to write to read-only grant mapping\n"); + guest_fault = 1; + goto check_access_handler; + } + } /* end access_w */ + + check_access_handler: + /* Even if it is the guest's "fault", check with the mem_event interface instead if + * one is there */ + if ( p2m_mem_access_check(gpa, gla_valid, gla, access_r, access_w, access_x) ) + return 1; + + /* If there is no handler, then fault if guest_fault = 1 */ + if ( guest_fault ) { - gdprintk(XENLOG_WARNING, - "trying to write to read-only grant mapping\n"); hvm_inject_exception(TRAP_gp_fault, 0, 0); return 1; } + /* Nothing handled it: it must be an access error with no memory handler, so fail */ return 0; } @@ -3412,6 +3442,143 @@ break; } + case HVMOP_set_mem_access: + { + struct xen_hvm_set_mem_access a; + struct domain *d; + struct p2m_domain *p2m; + unsigned long pfn; + + p2m_access_t memaccess[] = { + p2m_access_n, + p2m_access_r, + p2m_access_w, + p2m_access_rw, + p2m_access_x, + p2m_access_rx, + p2m_access_wx, + p2m_access_rwx, + p2m_access_rx2rw, + 0, /* HVMMEM_access_default -- will get set below */ + }; + + if ( copy_from_guest(&a, arg, 1) ) + return -EFAULT; + + rc = rcu_lock_target_domain_by_id(a.domid, &d); + if ( rc != 0 ) + return rc; + + rc = -EINVAL; + if ( !is_hvm_domain(d) ) + goto param_fail5; + + p2m = p2m_get_hostp2m(d); + memaccess[HVMMEM_access_default] = p2m->default_access; + + /* If request to set default access */ + if ( a.first_pfn == ~0ull ) + { + rc = 0; + p2m->default_access = memaccess[a.hvmmem_access]; + goto param_fail5; + } + + rc = -EINVAL; + if ( (a.first_pfn > domain_get_maximum_gpfn(d)) || + ((a.first_pfn + a.nr - 1) < a.first_pfn) || + ((a.first_pfn + a.nr - 1) > domain_get_maximum_gpfn(d)) ) + goto param_fail5; + + if ( a.hvmmem_access >= ARRAY_SIZE(memaccess) ) + goto param_fail5; + + for ( pfn = a.first_pfn; pfn < a.first_pfn + a.nr; pfn++ ) + { + p2m_type_t t; + mfn_t mfn; + int success; + + mfn = gfn_to_mfn_unshare(p2m, pfn, &t, 0); + + p2m_lock(p2m); + success = p2m->set_entry(p2m, pfn, mfn, 0, t, memaccess[a.hvmmem_access]); + p2m_unlock(p2m); + if ( !success ) + goto param_fail5; + } + + rc = 0; + + param_fail5: + rcu_unlock_domain(d); + break; + } + + case HVMOP_get_mem_access: + { + struct xen_hvm_get_mem_access a; + struct domain *d; + struct p2m_domain *p2m; + p2m_type_t t; + p2m_access_t ac; + mfn_t mfn; + + /* Interface access to internal p2m accesses */ + hvmmem_access_t memaccess[] = { + HVMMEM_access_n, + HVMMEM_access_r, + HVMMEM_access_w, + HVMMEM_access_rw, + HVMMEM_access_x, + HVMMEM_access_rx, + HVMMEM_access_wx, + HVMMEM_access_rwx, + HVMMEM_access_rx2rw + }; + + if ( copy_from_guest(&a, arg, 1) ) + return -EFAULT; + + rc = rcu_lock_target_domain_by_id(a.domid, &d); + if ( rc != 0 ) + return rc; + + rc = -EINVAL; + if ( !is_hvm_domain(d) ) + goto param_fail6; + + p2m = p2m_get_hostp2m(d); + + if ( a.pfn == ~0ull ) + { + a.hvmmem_access = memaccess[p2m->default_access]; + } + else { + rc = -EINVAL; + if ( (a.pfn > domain_get_maximum_gpfn(d)) ) + goto param_fail6; + + rc = -ESRCH; + mfn = p2m->get_entry(p2m, a.pfn, &t, &ac, p2m_query); + + if ( mfn_x(mfn) == INVALID_MFN ) + goto param_fail6; + + rc = -ERANGE; + if ( ac >= ARRAY_SIZE(memaccess) ) + goto param_fail6; + + a.hvmmem_access = memaccess[ac]; + } + + rc = copy_to_guest(arg, &a, 1) ? -EFAULT : 0; + + param_fail6: + rcu_unlock_domain(d); + break; + } + case HVMOP_pagetable_dying: { struct xen_hvm_pagetable_dying a; @@ -3426,12 +3593,12 @@ rc = -EINVAL; if ( !is_hvm_domain(d) || !paging_mode_shadow(d) ) - goto param_fail5; + goto param_fail7; rc = 0; pagetable_dying(d, a.gpa); - param_fail5: + param_fail7: rcu_unlock_domain(d); break; } diff -r 4e108cf56d07 xen/arch/x86/hvm/svm/svm.c --- a/xen/arch/x86/hvm/svm/svm.c Mon Dec 27 08:00:09 2010 +0000 +++ b/xen/arch/x86/hvm/svm/svm.c Tue Dec 28 22:35:35 2010 -0800 @@ -979,7 +979,7 @@ __trace_var(TRC_HVM_NPF, 0, sizeof(_d), &_d); } - if ( hvm_hap_nested_page_fault(gfn) ) + if ( hvm_hap_nested_page_fault(gpa, 0, ~0ull, 0, 0, 0) ) return; /* Everything else is an error. */ diff -r 4e108cf56d07 xen/arch/x86/hvm/vmx/vmx.c --- a/xen/arch/x86/hvm/vmx/vmx.c Mon Dec 27 08:00:09 2010 +0000 +++ b/xen/arch/x86/hvm/vmx/vmx.c Tue Dec 28 22:35:35 2010 -0800 @@ -2079,7 +2079,13 @@ __trace_var(TRC_HVM_NPF, 0, sizeof(_d), &_d); } - if ( hvm_hap_nested_page_fault(gfn) ) + if ( hvm_hap_nested_page_fault(gpa, + qualification & EPT_GLA_VALID ? 1 : 0, + qualification & EPT_GLA_VALID + ? __vmread(GUEST_LINEAR_ADDRESS) : ~0ull, + qualification & EPT_READ_VIOLATION ? 1 : 0, + qualification & EPT_WRITE_VIOLATION ? 1 : 0, + qualification & EPT_EXEC_VIOLATION ? 1 : 0) ) return; /* Everything else is an error. */ diff -r 4e108cf56d07 xen/arch/ia64/vmx/vmx_hypercall.c --- a/xen/arch/ia64/vmx/vmx_hypercall.c Mon Dec 27 08:00:09 2010 +0000 +++ b/xen/arch/ia64/vmx/vmx_hypercall.c Tue Dec 28 22:38:13 2010 -0800 @@ -218,6 +218,9 @@ } case HVMOP_set_mem_type: + case HVMOP_set_mem_access: + case HVMOP_get_mem_access: + rc = -ENOSYS; break; _______________________________________________ Xen-devel mailing list Xen-devel@xxxxxxxxxxxxxxxxxxx http://lists.xensource.com/xen-devel
|
Lists.xenproject.org is hosted with RackSpace, monitoring our |