[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index] [Xen-changelog] [xen-unstable] MTRR virtualization for Intel EPT
# HG changeset patch # User Keir Fraser <keir.fraser@xxxxxxxxxx> # Date 1215423950 -3600 # Node ID 9b35ae586cb8587186f08be9acff2b76024ae65e # Parent abd84464c09c1a43f3c756bdc7934ea9e99f375a MTRR virtualization for Intel EPT Signed-off-by: Xiaohui Xin <xiaohui.xin@xxxxxxxxx> --- xen/arch/x86/hvm/hvm.c | 19 ++++--- xen/arch/x86/hvm/mtrr.c | 27 ++++++++++ xen/arch/x86/hvm/vmx/vmx.c | 11 ++++ xen/arch/x86/mm/hap/p2m-ept.c | 95 ++++++++++++++++++++++++++++++++++---- xen/include/asm-x86/hvm/hvm.h | 1 xen/include/asm-x86/hvm/vmx/vmx.h | 4 + xen/include/asm-x86/mtrr.h | 3 + 7 files changed, 143 insertions(+), 17 deletions(-) diff -r abd84464c09c -r 9b35ae586cb8 xen/arch/x86/hvm/hvm.c --- a/xen/arch/x86/hvm/hvm.c Mon Jul 07 10:29:56 2008 +0100 +++ b/xen/arch/x86/hvm/hvm.c Mon Jul 07 10:45:50 2008 +0100 @@ -836,6 +836,14 @@ static void local_flush_cache(void *info wbinvd(); } +static void hvm_set_uc_mode(struct vcpu *v, bool_t is_in_uc_mode) +{ + v->domain->arch.hvm_domain.is_in_uc_mode = is_in_uc_mode; + shadow_blow_tables_per_domain(v->domain); + if ( hvm_funcs.set_uc_mode ) + return hvm_funcs.set_uc_mode(v); +} + int hvm_set_cr0(unsigned long value) { struct vcpu *v = current; @@ -923,9 +931,7 @@ int hvm_set_cr0(unsigned long value) { /* Flush physical caches. */ on_each_cpu(local_flush_cache, NULL, 1, 1); - /* Shadow pagetables must recognise UC mode. */ - v->domain->arch.hvm_domain.is_in_uc_mode = 1; - shadow_blow_tables_per_domain(v->domain); + hvm_set_uc_mode(v, 1); } spin_unlock(&v->domain->arch.hvm_domain.uc_lock); } @@ -937,11 +943,8 @@ int hvm_set_cr0(unsigned long value) v->arch.hvm_vcpu.cache_mode = NORMAL_CACHE_MODE; if ( domain_exit_uc_mode(v) ) - { - /* Shadow pagetables must recognise normal caching mode. */ - v->domain->arch.hvm_domain.is_in_uc_mode = 0; - shadow_blow_tables_per_domain(v->domain); - } + hvm_set_uc_mode(v, 0); + spin_unlock(&v->domain->arch.hvm_domain.uc_lock); } } diff -r abd84464c09c -r 9b35ae586cb8 xen/arch/x86/hvm/mtrr.c --- a/xen/arch/x86/hvm/mtrr.c Mon Jul 07 10:29:56 2008 +0100 +++ b/xen/arch/x86/hvm/mtrr.c Mon Jul 07 10:45:50 2008 +0100 @@ -696,3 +696,30 @@ static int hvm_load_mtrr_msr(struct doma HVM_REGISTER_SAVE_RESTORE(MTRR, hvm_save_mtrr_msr, hvm_load_mtrr_msr, 1, HVMSR_PER_VCPU); + +uint8_t epte_get_entry_emt( + struct domain *d, unsigned long gfn, unsigned long mfn) +{ + uint8_t gmtrr_mtype, hmtrr_mtype; + uint32_t type; + struct vcpu *v = current; + + if ( (current->domain != d) && ((v = d->vcpu[0]) == NULL) ) + return MTRR_TYPE_WRBACK; + + if ( !v->domain->arch.hvm_domain.params[HVM_PARAM_IDENT_PT] ) + return MTRR_TYPE_WRBACK; + + if ( (v == current) && v->domain->arch.hvm_domain.is_in_uc_mode ) + return MTRR_TYPE_UNCACHABLE; + + if ( !mfn_valid(mfn) ) + return MTRR_TYPE_UNCACHABLE; + + if ( hvm_get_mem_pinned_cacheattr(d, gfn, &type) ) + return type; + + gmtrr_mtype = get_mtrr_type(&v->arch.hvm_vcpu.mtrr, (gfn << PAGE_SHIFT)); + hmtrr_mtype = get_mtrr_type(&mtrr_state, (mfn << PAGE_SHIFT)); + return ((gmtrr_mtype <= hmtrr_mtype) ? gmtrr_mtype : hmtrr_mtype); +} diff -r abd84464c09c -r 9b35ae586cb8 xen/arch/x86/hvm/vmx/vmx.c --- a/xen/arch/x86/hvm/vmx/vmx.c Mon Jul 07 10:29:56 2008 +0100 +++ b/xen/arch/x86/hvm/vmx/vmx.c Mon Jul 07 10:45:50 2008 +0100 @@ -1173,6 +1173,14 @@ static int vmx_do_pmu_interrupt(struct c return vpmu_do_interrupt(regs); } +static void vmx_set_uc_mode(struct vcpu *v) +{ + if ( paging_mode_hap(v->domain) ) + ept_change_entry_emt_with_range( + v->domain, 0, v->domain->arch.p2m->max_mapped_pfn); + vpid_sync_all(); +} + static struct hvm_function_table vmx_function_table = { .name = "VMX", .domain_initialise = vmx_domain_initialise, @@ -1202,7 +1210,8 @@ static struct hvm_function_table vmx_fun .fpu_dirty_intercept = vmx_fpu_dirty_intercept, .msr_read_intercept = vmx_msr_read_intercept, .msr_write_intercept = vmx_msr_write_intercept, - .invlpg_intercept = vmx_invlpg_intercept + .invlpg_intercept = vmx_invlpg_intercept, + .set_uc_mode = vmx_set_uc_mode }; static unsigned long *vpid_bitmap; diff -r abd84464c09c -r 9b35ae586cb8 xen/arch/x86/mm/hap/p2m-ept.c --- a/xen/arch/x86/mm/hap/p2m-ept.c Mon Jul 07 10:29:56 2008 +0100 +++ b/xen/arch/x86/mm/hap/p2m-ept.c Mon Jul 07 10:45:50 2008 +0100 @@ -26,6 +26,8 @@ #include <asm/p2m.h> #include <asm/hvm/vmx/vmx.h> #include <xen/iommu.h> +#include <asm/mtrr.h> +#include <asm/hvm/cacheattr.h> static void ept_p2m_type_to_flags(ept_entry_t *entry, p2m_type_t type) { @@ -158,8 +160,7 @@ ept_set_entry(struct domain *d, unsigned /* Track the highest gfn for which we have ever had a valid mapping */ if ( gfn > d->arch.p2m->max_mapped_pfn ) d->arch.p2m->max_mapped_pfn = gfn; - - ept_entry->emt = EPT_DEFAULT_MT; + ept_entry->emt = epte_get_entry_emt(d, gfn, mfn_x(mfn)); ept_entry->sp_avail = walk_level ? 1 : 0; if ( ret == GUEST_TABLE_SUPER_PAGE ) @@ -204,11 +205,13 @@ ept_set_entry(struct domain *d, unsigned /* split the super page before to 4k pages */ split_table = map_domain_page(ept_entry->mfn); + offset = gfn & ((1 << EPT_TABLE_ORDER) - 1); for ( i = 0; i < 512; i++ ) { split_ept_entry = split_table + i; - split_ept_entry->emt = EPT_DEFAULT_MT; + split_ept_entry->emt = epte_get_entry_emt(d, + gfn-offset+i, split_mfn+i); split_ept_entry->sp_avail = 0; split_ept_entry->mfn = split_mfn+i; @@ -222,15 +225,13 @@ ept_set_entry(struct domain *d, unsigned } /* Set the destinated 4k page as normal */ - - offset = gfn & ((1 << EPT_TABLE_ORDER) - 1); split_ept_entry = split_table + offset; + split_ept_entry->emt = epte_get_entry_emt(d, gfn, mfn_x(mfn)); split_ept_entry->mfn = mfn_x(mfn); split_ept_entry->avail1 = p2mt; ept_p2m_type_to_flags(split_ept_entry, p2mt); unmap_domain_page(split_table); - } /* Success */ @@ -249,7 +250,7 @@ out: { if ( order == EPT_TABLE_ORDER ) { - for ( i = 0; i < 512; i++ ) + for ( i = 0; i < ( 1 << order ); i++ ) iommu_map_page(d, gfn-offset+i, mfn_x(mfn)-offset+i); } else if ( !order ) @@ -259,7 +260,7 @@ out: { if ( order == EPT_TABLE_ORDER ) { - for ( i = 0; i < 512; i++ ) + for ( i = 0; i < ( 1 << order ); i++ ) iommu_unmap_page(d, gfn-offset+i); } else if ( !order ) @@ -322,9 +323,87 @@ static mfn_t ept_get_entry(struct domain return mfn; } +static uint64_t ept_get_entry_content(struct domain *d, unsigned long gfn) +{ + ept_entry_t *table = + map_domain_page(mfn_x(pagetable_get_mfn(d->arch.phys_table))); + unsigned long gfn_remainder = gfn; + ept_entry_t *ept_entry; + uint64_t content = 0; + + u32 index; + int i, ret=0; + + /* This pfn is higher than the highest the p2m map currently holds */ + if ( gfn > d->arch.p2m->max_mapped_pfn ) + goto out; + + for ( i = EPT_DEFAULT_GAW; i > 0; i-- ) + { + ret = ept_next_level(d, 1, &table, &gfn_remainder, + i * EPT_TABLE_ORDER, 0); + if ( !ret ) + goto out; + else if ( ret == GUEST_TABLE_SUPER_PAGE ) + break; + } + + index = gfn_remainder >> ( i * EPT_TABLE_ORDER); + ept_entry = table + index; + content = ept_entry->epte; + + out: + unmap_domain_page(table); + return content; +} + static mfn_t ept_get_entry_current(unsigned long gfn, p2m_type_t *t) { return ept_get_entry(current->domain, gfn, t); +} + +void ept_change_entry_emt_with_range(struct domain *d, unsigned long start_gfn, + unsigned long end_gfn) +{ + unsigned long gfn; + p2m_type_t p2mt; + uint64_t epte; + int order = 0; + unsigned long mfn; + + for ( gfn = start_gfn; gfn <= end_gfn; gfn++ ) + { + epte = ept_get_entry_content(d, gfn); + if ( epte == 0 ) + continue; + mfn = (epte & EPTE_MFN_MASK) >> PAGE_SHIFT; + if ( !mfn_valid(mfn) ) + continue; + p2mt = (epte & EPTE_AVAIL1_MASK) >> 8; + order = 0; + + if ( epte & EPTE_SUPER_PAGE_MASK ) + { + if ( !(gfn & ( (1 << EPT_TABLE_ORDER) - 1)) && + ((gfn + 0x1FF) <= end_gfn) ) + { + /* gfn assigned with 2M, and the end covers more than 2m areas. + * Set emt for super page. + */ + order = EPT_TABLE_ORDER; + ept_set_entry(d, gfn, _mfn(mfn), order, p2mt); + gfn += 0x1FF; + } + else + { + /* change emt for partial entries of the 2m area */ + ept_set_entry(d, gfn, _mfn(mfn), order, p2mt); + gfn = ((gfn >> EPT_TABLE_ORDER) << EPT_TABLE_ORDER) + 0x1FF; + } + } + else /* gfn assigned with 4k */ + ept_set_entry(d, gfn, _mfn(mfn), order, p2mt); + } } /* Walk the whole p2m table, changing any entries of the old type diff -r abd84464c09c -r 9b35ae586cb8 xen/include/asm-x86/hvm/hvm.h --- a/xen/include/asm-x86/hvm/hvm.h Mon Jul 07 10:29:56 2008 +0100 +++ b/xen/include/asm-x86/hvm/hvm.h Mon Jul 07 10:45:50 2008 +0100 @@ -127,6 +127,7 @@ struct hvm_function_table { int (*msr_read_intercept)(struct cpu_user_regs *regs); int (*msr_write_intercept)(struct cpu_user_regs *regs); void (*invlpg_intercept)(unsigned long vaddr); + void (*set_uc_mode)(struct vcpu *v); }; extern struct hvm_function_table hvm_funcs; diff -r abd84464c09c -r 9b35ae586cb8 xen/include/asm-x86/hvm/vmx/vmx.h --- a/xen/include/asm-x86/hvm/vmx/vmx.h Mon Jul 07 10:29:56 2008 +0100 +++ b/xen/include/asm-x86/hvm/vmx/vmx.h Mon Jul 07 10:45:50 2008 +0100 @@ -44,6 +44,10 @@ typedef union { } ept_entry_t; #define EPT_TABLE_ORDER 9 +#define EPTE_SUPER_PAGE_MASK 0x80 +#define EPTE_MFN_MASK 0x1fffffffffff000 +#define EPTE_AVAIL1_MASK 0xF00 +#define EPTE_EMT_MASK 0x78 void vmx_asm_vmexit_handler(struct cpu_user_regs); void vmx_asm_do_vmentry(void); diff -r abd84464c09c -r 9b35ae586cb8 xen/include/asm-x86/mtrr.h --- a/xen/include/asm-x86/mtrr.h Mon Jul 07 10:29:56 2008 +0100 +++ b/xen/include/asm-x86/mtrr.h Mon Jul 07 10:45:50 2008 +0100 @@ -64,6 +64,9 @@ extern void mtrr_centaur_report_mcr(int extern void mtrr_centaur_report_mcr(int mcr, u32 lo, u32 hi); extern u32 get_pat_flags(struct vcpu *v, u32 gl1e_flags, paddr_t gpaddr, paddr_t spaddr); +extern uint8_t epte_get_entry_emt(struct domain *d, unsigned long gfn, unsigned long mfn); +extern void ept_change_entry_emt_with_range(struct domain *d, unsigned long start_gfn, + unsigned long end_gfn); extern unsigned char pat_type_2_pte_flags(unsigned char pat_type); #endif /* __ASM_X86_MTRR_H__ */ _______________________________________________ Xen-changelog mailing list Xen-changelog@xxxxxxxxxxxxxxxxxxx http://lists.xensource.com/xen-changelog
|
Lists.xenproject.org is hosted with RackSpace, monitoring our |