[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index] [Xen-changelog] [xen-unstable] hvm: Clean up EPT/NPT 'nested page fault' handling.
# HG changeset patch # User Keir Fraser <keir.fraser@xxxxxxxxxx> # Date 1256563173 0 # Node ID b27f85b54ecc7276f43cdcd669bda269c0715373 # Parent 9c49133434cb920a0593e07e5970d1381086a4db hvm: Clean up EPT/NPT 'nested page fault' handling. Share most of the code. Signed-off-by: Keir Fraser <keir.fraser@xxxxxxxxxx> --- xen/arch/x86/hvm/hvm.c | 38 +++++++++++++++++++ xen/arch/x86/hvm/svm/svm.c | 52 ++++++-------------------- xen/arch/x86/hvm/vmx/vmx.c | 75 ++++++++------------------------------ xen/include/asm-x86/hvm/hvm.h | 2 + xen/include/asm-x86/hvm/vmx/vmx.h | 29 ++------------ 5 files changed, 73 insertions(+), 123 deletions(-) diff -r 9c49133434cb -r b27f85b54ecc xen/arch/x86/hvm/hvm.c --- a/xen/arch/x86/hvm/hvm.c Mon Oct 26 12:20:07 2009 +0000 +++ b/xen/arch/x86/hvm/hvm.c Mon Oct 26 13:19:33 2009 +0000 @@ -916,6 +916,44 @@ void hvm_triple_fault(void) domain_shutdown(v->domain, SHUTDOWN_reboot); } +bool_t hvm_hap_nested_page_fault(unsigned long gfn) +{ + p2m_type_t p2mt; + mfn_t mfn; + + mfn = gfn_to_mfn_type_current(gfn, &p2mt, p2m_guest); + + /* + * If this GFN is emulated MMIO or marked as read-only, pass the fault + * to the mmio handler. + */ + if ( p2m_is_mmio(p2mt) || (p2mt == p2m_ram_ro) ) + { + if ( !handle_mmio() ) + hvm_inject_exception(TRAP_gp_fault, 0, 0); + return 1; + } + + /* Log-dirty: mark the page dirty and let the guest write it again */ + if ( p2mt == p2m_ram_logdirty ) + { + paging_mark_dirty(current->domain, mfn_x(mfn)); + p2m_change_type(current->domain, 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"); + hvm_inject_exception(TRAP_gp_fault, 0, 0); + return 1; + } + + return 0; +} + int hvm_set_efer(uint64_t value) { struct vcpu *v = current; diff -r 9c49133434cb -r b27f85b54ecc xen/arch/x86/hvm/svm/svm.c --- a/xen/arch/x86/hvm/svm/svm.c Mon Oct 26 12:20:07 2009 +0000 +++ b/xen/arch/x86/hvm/svm/svm.c Mon Oct 26 13:19:33 2009 +0000 @@ -884,46 +884,20 @@ void start_svm(struct cpuinfo_x86 *c) hvm_enable(&svm_function_table); } -static void svm_do_nested_pgfault(paddr_t gpa, struct cpu_user_regs *regs) -{ +static void svm_do_nested_pgfault(paddr_t gpa) +{ + unsigned long gfn = gpa >> PAGE_SHIFT; + mfn_t mfn; p2m_type_t p2mt; - mfn_t mfn; - unsigned long gfn = gpa >> PAGE_SHIFT; - - /* - * If this GFN is emulated MMIO or marked as read-only, pass the fault - * to the mmio handler. - */ + + if ( hvm_hap_nested_page_fault(gfn) ) + return; + + /* Everything else is an error. */ mfn = gfn_to_mfn_type_current(gfn, &p2mt, p2m_guest); - if ( (p2mt == p2m_mmio_dm) || (p2mt == p2m_ram_ro) ) - { - if ( !handle_mmio() ) - hvm_inject_exception(TRAP_gp_fault, 0, 0); - return; - } - - /* Log-dirty: mark the page dirty and let the guest write it again */ - if ( p2mt == p2m_ram_logdirty ) - { - paging_mark_dirty(current->domain, mfn_x(mfn)); - p2m_change_type(current->domain, gfn, p2m_ram_logdirty, p2m_ram_rw); - return; - } - - /* Okay, this shouldn't happen. Maybe the guest was writing to a - read-only grant mapping? */ - if ( p2mt == p2m_grant_map_ro ) - { - /* Naughty... */ - gdprintk(XENLOG_WARNING, - "trying to write to read-only grant mapping\n"); - hvm_inject_exception(TRAP_gp_fault, 0, 0); - return; - } - - /* Something bad has happened; either Xen or the hardware have - screwed up. */ - gdprintk(XENLOG_WARNING, "unexpected SVM nested page fault\n"); + gdprintk(XENLOG_ERR, "SVM violation gpa %#"PRIpaddr", mfn %#lx, type %i\n", + gpa, mfn_x(mfn), p2mt); + domain_crash(current->domain); } static void svm_fpu_dirty_intercept(void) @@ -1511,7 +1485,7 @@ asmlinkage void svm_vmexit_handler(struc case VMEXIT_NPF: perfc_incra(svmexits, VMEXIT_NPF_PERFC); regs->error_code = vmcb->exitinfo1; - svm_do_nested_pgfault(vmcb->exitinfo2, regs); + svm_do_nested_pgfault(vmcb->exitinfo2); break; case VMEXIT_IRET: diff -r 9c49133434cb -r b27f85b54ecc xen/arch/x86/hvm/vmx/vmx.c --- a/xen/arch/x86/hvm/vmx/vmx.c Mon Oct 26 12:20:07 2009 +0000 +++ b/xen/arch/x86/hvm/vmx/vmx.c Mon Oct 26 13:19:33 2009 +0000 @@ -2153,50 +2153,16 @@ static void vmx_wbinvd_intercept(void) static void ept_handle_violation(unsigned long qualification, paddr_t gpa) { - unsigned long gla_validity = qualification & EPT_GLA_VALIDITY_MASK; - struct domain *d = current->domain; unsigned long gla, gfn = gpa >> PAGE_SHIFT; mfn_t mfn; - p2m_type_t t; - - mfn = gfn_to_mfn_guest(d, gfn, &t); - - /* There are three legitimate reasons for taking an EPT violation. - * One is a guest access to MMIO space. */ - if ( gla_validity == EPT_GLA_VALIDITY_MATCH && p2m_is_mmio(t) ) - { - handle_mmio(); + p2m_type_t p2mt; + + if ( (qualification & EPT_GLA_VALID) && + hvm_hap_nested_page_fault(gfn) ) return; - } - - /* The second is log-dirty mode, writing to a read-only page; - * The third is populating a populate-on-demand page. */ - if ( (gla_validity == EPT_GLA_VALIDITY_MATCH - || gla_validity == EPT_GLA_VALIDITY_GPT_WALK) - && p2m_is_ram(t) && (t != p2m_ram_ro) ) - { - if ( paging_mode_log_dirty(d) ) - { - paging_mark_dirty(d, mfn_x(mfn)); - p2m_change_type(d, gfn, p2m_ram_logdirty, p2m_ram_rw); - flush_tlb_mask(&d->domain_dirty_cpumask); - } - return; - } - - /* Ignore writes to: - * 1. read only memory regions; - * 2. memory holes. */ - if ( (qualification & EPT_WRITE_VIOLATION) - && (((gla_validity == EPT_GLA_VALIDITY_MATCH) && (t == p2m_ram_ro)) - || (mfn_x(mfn) == INVALID_MFN)) ) { - int inst_len = __get_instruction_length(); - __update_guest_eip(inst_len); - return; - } /* Everything else is an error. */ - gla = __vmread(GUEST_LINEAR_ADDRESS); + mfn = gfn_to_mfn_type_current(gfn, &p2mt, p2m_guest); gdprintk(XENLOG_ERR, "EPT violation %#lx (%c%c%c/%c%c%c), " "gpa %#"PRIpaddr", mfn %#lx, type %i.\n", qualification, @@ -2206,29 +2172,20 @@ static void ept_handle_violation(unsigne (qualification & EPT_EFFECTIVE_READ) ? 'r' : '-', (qualification & EPT_EFFECTIVE_WRITE) ? 'w' : '-', (qualification & EPT_EFFECTIVE_EXEC) ? 'x' : '-', - gpa, mfn_x(mfn), t); + gpa, mfn_x(mfn), p2mt); + + if ( qualification & EPT_GLA_VALID ) + { + gla = __vmread(GUEST_LINEAR_ADDRESS); + gdprintk(XENLOG_ERR, " --- GLA %#lx\n", gla); + } if ( qualification & EPT_GAW_VIOLATION ) gdprintk(XENLOG_ERR, " --- GPA too wide (max %u bits)\n", - 9 * (unsigned) d->arch.hvm_domain.vmx.ept_control.gaw + 21); - - switch ( gla_validity ) - { - case EPT_GLA_VALIDITY_PDPTR_LOAD: - gdprintk(XENLOG_ERR, " --- PDPTR load failed\n"); - break; - case EPT_GLA_VALIDITY_GPT_WALK: - gdprintk(XENLOG_ERR, " --- guest PT walk to %#lx failed\n", gla); - break; - case EPT_GLA_VALIDITY_RSVD: - gdprintk(XENLOG_ERR, " --- GLA_validity 2 (reserved)\n"); - break; - case EPT_GLA_VALIDITY_MATCH: - gdprintk(XENLOG_ERR, " --- guest access to %#lx failed\n", gla); - break; - } - - domain_crash(d); + 9 * (unsigned int)current->domain->arch.hvm_domain. + vmx.ept_control.gaw + 21); + + domain_crash(current->domain); } static void vmx_failed_vmentry(unsigned int exit_reason, diff -r 9c49133434cb -r b27f85b54ecc xen/include/asm-x86/hvm/hvm.h --- a/xen/include/asm-x86/hvm/hvm.h Mon Oct 26 12:20:07 2009 +0000 +++ b/xen/include/asm-x86/hvm/hvm.h Mon Oct 26 13:19:33 2009 +0000 @@ -333,4 +333,6 @@ static inline void hvm_set_info_guest(st int hvm_debug_op(struct vcpu *v, int32_t op); +bool_t hvm_hap_nested_page_fault(unsigned long gfn); + #endif /* __ASM_X86_HVM_HVM_H__ */ diff -r 9c49133434cb -r b27f85b54ecc xen/include/asm-x86/hvm/vmx/vmx.h --- a/xen/include/asm-x86/hvm/vmx/vmx.h Mon Oct 26 12:20:07 2009 +0000 +++ b/xen/include/asm-x86/hvm/vmx/vmx.h Mon Oct 26 13:19:33 2009 +0000 @@ -366,45 +366,24 @@ void ept_p2m_init(struct domain *d); void ept_p2m_init(struct domain *d); /* EPT violation qualifications definitions */ -/* bit offset 0 in exit qualification */ #define _EPT_READ_VIOLATION 0 #define EPT_READ_VIOLATION (1UL<<_EPT_READ_VIOLATION) -/* bit offset 1 in exit qualification */ #define _EPT_WRITE_VIOLATION 1 #define EPT_WRITE_VIOLATION (1UL<<_EPT_WRITE_VIOLATION) -/* bit offset 2 in exit qualification */ #define _EPT_EXEC_VIOLATION 2 #define EPT_EXEC_VIOLATION (1UL<<_EPT_EXEC_VIOLATION) - -/* bit offset 3 in exit qualification */ #define _EPT_EFFECTIVE_READ 3 #define EPT_EFFECTIVE_READ (1UL<<_EPT_EFFECTIVE_READ) -/* bit offset 4 in exit qualification */ #define _EPT_EFFECTIVE_WRITE 4 #define EPT_EFFECTIVE_WRITE (1UL<<_EPT_EFFECTIVE_WRITE) -/* bit offset 5 in exit qualification */ #define _EPT_EFFECTIVE_EXEC 5 #define EPT_EFFECTIVE_EXEC (1UL<<_EPT_EFFECTIVE_EXEC) - -/* bit offset 6 in exit qualification */ #define _EPT_GAW_VIOLATION 6 #define EPT_GAW_VIOLATION (1UL<<_EPT_GAW_VIOLATION) - -/* bits offset 7 & 8 in exit qualification */ -#define _EPT_GLA_VALIDITY 7 -#define EPT_GLA_VALIDITY_MASK (3UL<<_EPT_GLA_VALIDITY) -/* gla != gpa, when load PDPTR */ -#define EPT_GLA_VALIDITY_PDPTR_LOAD (0UL<<_EPT_GLA_VALIDITY) -/* gla != gpa, during guest page table walking */ -#define EPT_GLA_VALIDITY_GPT_WALK (1UL<<_EPT_GLA_VALIDITY) -/* reserved */ -#define EPT_GLA_VALIDITY_RSVD (2UL<<_EPT_GLA_VALIDITY) -/* gla == gpa, normal case */ -#define EPT_GLA_VALIDITY_MATCH (3UL<<_EPT_GLA_VALIDITY) - -#define EPT_EFFECTIVE_MASK (EPT_EFFECTIVE_READ | \ - EPT_EFFECTIVE_WRITE | \ - EPT_EFFECTIVE_EXEC) +#define _EPT_GLA_VALID 7 +#define EPT_GLA_VALID (1UL<<_EPT_GLA_VALID) +#define _EPT_GLA_FAULT 8 +#define EPT_GLA_FAULT (1UL<<_EPT_GLA_FAULT) #define EPT_PAGETABLE_ENTRIES 512 _______________________________________________ Xen-changelog mailing list Xen-changelog@xxxxxxxxxxxxxxxxxxx http://lists.xensource.com/xen-changelog
|
Lists.xenproject.org is hosted with RackSpace, monitoring our |