[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index] [Xen-changelog] [xen-unstable] vmx: Enable live-migration with EPT
# HG changeset patch # User Keir Fraser <keir.fraser@xxxxxxxxxx> # Date 1207818041 -3600 # Node ID 9153b99a7066b6b5098f61483e3147e81ad7258e # Parent 1d3aaa6a8b870805e16dcf162223fb2edd9de26d vmx: Enable live-migration with EPT Signed-off-by: Xin Li <xin.b.li@xxxxxxxxx> Signed-off-by: Jun Nakajima <jun.nakajima@xxxxxxxxx> Signed-off-by: Xiaohui Xin <Xiaohui.xin@xxxxxxxxx> Signed-off-by: Keir Fraser <keir.fraser@xxxxxxxxxx> --- xen/arch/x86/hvm/vmx/vmx.c | 40 ++++++++++++++++-- xen/arch/x86/mm/hap/hap.c | 6 +- xen/arch/x86/mm/hap/p2m-ept.c | 84 ++++++++++++++++++++++++++++++++++---- xen/arch/x86/mm/p2m.c | 16 ++++++- xen/include/asm-x86/hvm/vmx/vmx.h | 43 +++++++++++++++++++ xen/include/asm-x86/p2m.h | 4 + 6 files changed, 178 insertions(+), 15 deletions(-) diff -r 1d3aaa6a8b87 -r 9153b99a7066 xen/arch/x86/hvm/vmx/vmx.c --- a/xen/arch/x86/hvm/vmx/vmx.c Thu Apr 10 09:22:38 2008 +0100 +++ b/xen/arch/x86/hvm/vmx/vmx.c Thu Apr 10 10:00:41 2008 +0100 @@ -2053,13 +2053,47 @@ static void vmx_wbinvd_intercept(void) static void ept_handle_violation(unsigned long qualification, paddr_t gpa) { - if ( unlikely(((qualification >> 7) & 0x3) != 0x3) ) - { - domain_crash(current->domain); + unsigned long gla_validity = qualification & EPT_GLA_VALIDITY_MASK; + struct domain *d = current->domain; + unsigned long gfn = gpa >> PAGE_SHIFT; + mfn_t mfn; + p2m_type_t t; + + if ( unlikely(qualification & EPT_GAW_VIOLATION) ) + { + gdprintk(XENLOG_ERR, "EPT violation: guest physical address %"PRIpaddr + " exceeded its width limit.\n", gpa); + goto crash; + } + + if ( unlikely(gla_validity == EPT_GLA_VALIDITY_RSVD) || + unlikely(gla_validity == EPT_GLA_VALIDITY_PDPTR_LOAD) ) + { + gdprintk(XENLOG_ERR, "EPT violation: reserved bit or " + "pdptr load violation.\n"); + goto crash; + } + + mfn = gfn_to_mfn(d, gfn, &t); + if ( p2m_is_ram(t) && 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; } + /* This can only happen in log-dirty mode, writing back A/D bits. */ + if ( unlikely(gla_validity == EPT_GLA_VALIDITY_GPT_WALK) ) + goto crash; + + ASSERT(gla_validity == EPT_GLA_VALIDITY_MATCH); handle_mmio(); + + return; + + crash: + domain_crash(d); } static void vmx_failed_vmentry(unsigned int exit_reason, diff -r 1d3aaa6a8b87 -r 9153b99a7066 xen/arch/x86/mm/hap/hap.c --- a/xen/arch/x86/mm/hap/hap.c Thu Apr 10 09:22:38 2008 +0100 +++ b/xen/arch/x86/mm/hap/hap.c Thu Apr 10 10:00:41 2008 +0100 @@ -62,7 +62,7 @@ int hap_enable_log_dirty(struct domain * hap_unlock(d); /* set l1e entries of P2M table to be read-only. */ - p2m_change_type_global(d, p2m_ram_rw, p2m_ram_logdirty); + p2m_change_entry_type_global(d, p2m_ram_rw, p2m_ram_logdirty); flush_tlb_mask(d->domain_dirty_cpumask); return 0; } @@ -74,14 +74,14 @@ int hap_disable_log_dirty(struct domain hap_unlock(d); /* set l1e entries of P2M table with normal mode */ - p2m_change_type_global(d, p2m_ram_logdirty, p2m_ram_rw); + p2m_change_entry_type_global(d, p2m_ram_logdirty, p2m_ram_rw); return 0; } void hap_clean_dirty_bitmap(struct domain *d) { /* set l1e entries of P2M table to be read-only. */ - p2m_change_type_global(d, p2m_ram_rw, p2m_ram_logdirty); + p2m_change_entry_type_global(d, p2m_ram_rw, p2m_ram_logdirty); flush_tlb_mask(d->domain_dirty_cpumask); } diff -r 1d3aaa6a8b87 -r 9153b99a7066 xen/arch/x86/mm/hap/p2m-ept.c --- a/xen/arch/x86/mm/hap/p2m-ept.c Thu Apr 10 09:22:38 2008 +0100 +++ b/xen/arch/x86/mm/hap/p2m-ept.c Thu Apr 10 10:00:41 2008 +0100 @@ -26,6 +26,26 @@ #include <asm/hvm/vmx/vmx.h> #include <xen/iommu.h> +static void ept_p2m_type_to_flags(ept_entry_t *entry, p2m_type_t type) +{ + switch(type) + { + case p2m_invalid: + case p2m_mmio_dm: + default: + return; + case p2m_ram_rw: + case p2m_mmio_direct: + entry->r = entry->w = entry->x = 1; + return; + case p2m_ram_logdirty: + case p2m_ram_ro: + entry->r = entry->x = 1; + entry->w = 0; + return; + } +} + static int ept_next_level(struct domain *d, bool_t read_only, ept_entry_t **table, unsigned long *gfn_remainder, u32 shift) @@ -104,6 +124,7 @@ ept_set_entry(struct domain *d, unsigned ept_entry->avail2 = 0; /* last step */ ept_entry->r = ept_entry->w = ept_entry->x = 1; + ept_p2m_type_to_flags(ept_entry, p2mt); } else ept_entry->epte = 0; @@ -150,13 +171,10 @@ static mfn_t ept_get_entry(struct domain index = gfn_remainder; ept_entry = table + index; - if ( (ept_entry->epte & 0x7) == 0x7 ) - { - if ( ept_entry->avail1 != p2m_invalid ) - { - *t = ept_entry->avail1; - mfn = _mfn(ept_entry->mfn); - } + if ( ept_entry->avail1 != p2m_invalid ) + { + *t = ept_entry->avail1; + mfn = _mfn(ept_entry->mfn); } out: @@ -169,11 +187,63 @@ static mfn_t ept_get_entry_current(unsig return ept_get_entry(current->domain, gfn, t); } +/* Walk the whole p2m table, changing any entries of the old type + * to the new type. This is used in hardware-assisted paging to + * quickly enable or diable log-dirty tracking */ + +static void ept_change_entry_type_global(struct domain *d, + p2m_type_t ot, p2m_type_t nt) +{ + ept_entry_t *l4e, *l3e, *l2e, *l1e; + int i4, i3, i2, i1; + + if ( pagetable_get_pfn(d->arch.phys_table) == 0 ) + return; + + BUG_ON(EPT_DEFAULT_GAW != 3); + + l4e = map_domain_page(mfn_x(pagetable_get_mfn(d->arch.phys_table))); + for (i4 = 0; i4 < EPT_PAGETABLE_ENTRIES; i4++ ) + { + if ( !l4e[i4].epte || l4e[i4].sp_avail ) + continue; + l3e = map_domain_page(l4e[i4].mfn); + for ( i3 = 0; i3 < EPT_PAGETABLE_ENTRIES; i3++ ) + { + if ( !l3e[i3].epte || l3e[i3].sp_avail ) + continue; + l2e = map_domain_page(l3e[i3].mfn); + for ( i2 = 0; i2 < EPT_PAGETABLE_ENTRIES; i2++ ) + { + if ( !l2e[i2].epte || l2e[i2].sp_avail ) + continue; + l1e = map_domain_page(l2e[i2].mfn); + for ( i1 = 0; i1 < EPT_PAGETABLE_ENTRIES; i1++ ) + { + if ( !l1e[i1].epte ) + continue; + if ( l1e[i1].avail1 != ot ) + continue; + l1e[i1].avail1 = nt; + ept_p2m_type_to_flags(l1e+i1, nt); + } + unmap_domain_page(l1e); + } + unmap_domain_page(l2e); + } + unmap_domain_page(l3e); + } + unmap_domain_page(l4e); + + ept_sync_domain(d); +} + void ept_p2m_init(struct domain *d) { d->arch.p2m->set_entry = ept_set_entry; d->arch.p2m->get_entry = ept_get_entry; d->arch.p2m->get_entry_current = ept_get_entry_current; + d->arch.p2m->change_entry_type_global = ept_change_entry_type_global; } /* diff -r 1d3aaa6a8b87 -r 9153b99a7066 xen/arch/x86/mm/p2m.c --- a/xen/arch/x86/mm/p2m.c Thu Apr 10 09:22:38 2008 +0100 +++ b/xen/arch/x86/mm/p2m.c Thu Apr 10 10:00:41 2008 +0100 @@ -71,6 +71,8 @@ spin_unlock(&(_p2m)->lock); \ } while (0) +#define p2m_locked_by_me(_p2m) \ + (current->processor == (_p2m)->locker) /* Printouts */ #define P2M_PRINTK(_f, _a...) \ @@ -418,12 +420,23 @@ int p2m_init(struct domain *d) p2m->set_entry = p2m_set_entry; p2m->get_entry = p2m_gfn_to_mfn; p2m->get_entry_current = p2m_gfn_to_mfn_current; + p2m->change_entry_type_global = p2m_change_type_global; if ( is_hvm_domain(d) && d->arch.hvm_domain.hap_enabled && (boot_cpu_data.x86_vendor == X86_VENDOR_INTEL) ) ept_p2m_init(d); return 0; +} + +void p2m_change_entry_type_global(struct domain *d, + p2m_type_t ot, p2m_type_t nt) +{ + struct p2m_domain *p2m = d->arch.p2m; + + p2m_lock(p2m); + p2m->change_entry_type_global(d, ot, nt); + p2m_unlock(p2m); } static inline @@ -880,7 +893,7 @@ void p2m_change_type_global(struct domai if ( pagetable_get_pfn(d->arch.phys_table) == 0 ) return; - p2m_lock(d->arch.p2m); + ASSERT(p2m_locked_by_me(d->arch.p2m)); #if CONFIG_PAGING_LEVELS == 4 l4e = map_domain_page(mfn_x(pagetable_get_mfn(d->arch.phys_table))); @@ -952,7 +965,6 @@ void p2m_change_type_global(struct domai unmap_domain_page(l2e); #endif - p2m_unlock(d->arch.p2m); } /* Modify the p2m type of a single gfn from ot to nt, returning the diff -r 1d3aaa6a8b87 -r 9153b99a7066 xen/include/asm-x86/hvm/vmx/vmx.h --- a/xen/include/asm-x86/hvm/vmx/vmx.h Thu Apr 10 09:22:38 2008 +0100 +++ b/xen/include/asm-x86/hvm/vmx/vmx.h Thu Apr 10 10:00:41 2008 +0100 @@ -344,4 +344,47 @@ void vmx_inject_nmi(struct vcpu *v); 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_PAGETABLE_ENTRIES 512 + #endif /* __ASM_X86_HVM_VMX_VMX_H__ */ diff -r 1d3aaa6a8b87 -r 9153b99a7066 xen/include/asm-x86/p2m.h --- a/xen/include/asm-x86/p2m.h Thu Apr 10 09:22:38 2008 +0100 +++ b/xen/include/asm-x86/p2m.h Thu Apr 10 10:00:41 2008 +0100 @@ -107,6 +107,9 @@ struct p2m_domain { p2m_type_t *p2mt); mfn_t (*get_entry_current)(unsigned long gfn, p2m_type_t *p2mt); + void (*change_entry_type_global)(struct domain *d, + p2m_type_t ot, + p2m_type_t nt); /* Highest guest frame that's ever been mapped in the p2m */ unsigned long max_mapped_pfn; @@ -218,6 +221,7 @@ void guest_physmap_remove_page(struct do /* Change types across all p2m entries in a domain */ void p2m_change_type_global(struct domain *d, p2m_type_t ot, p2m_type_t nt); +void p2m_change_entry_type_global(struct domain *d, p2m_type_t ot, p2m_type_t nt); /* Compare-exchange the type of a single p2m entry */ p2m_type_t p2m_change_type(struct domain *d, unsigned long gfn, _______________________________________________ Xen-changelog mailing list Xen-changelog@xxxxxxxxxxxxxxxxxxx http://lists.xensource.com/xen-changelog
|
Lists.xenproject.org is hosted with RackSpace, monitoring our |