[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index] [Xen-changelog] [xen-unstable] Intel EPT: Add page shattering logic for EPT when a super-page gets partially freed.
# HG changeset patch # User Keir Fraser <keir.fraser@xxxxxxxxxx> # Date 1211364171 -3600 # Node ID ff23c9a11085dce8c5b2e3b692cde86cd87698a7 # Parent ef019d230080cc1c85a3a9a79c170f898db6be53 Intel EPT: Add page shattering logic for EPT when a super-page gets partially freed. Signed-off-by: Xin Xiaohui <xiaohui.xin@xxxxxxxxx> --- xen/arch/x86/mm/hap/p2m-ept.c | 172 +++++++++++++++++++++++++++++------------- 1 files changed, 120 insertions(+), 52 deletions(-) diff -r ef019d230080 -r ff23c9a11085 xen/arch/x86/mm/hap/p2m-ept.c --- a/xen/arch/x86/mm/hap/p2m-ept.c Wed May 21 10:59:49 2008 +0100 +++ b/xen/arch/x86/mm/hap/p2m-ept.c Wed May 21 11:02:51 2008 +0100 @@ -49,10 +49,35 @@ static void ept_p2m_type_to_flags(ept_en #define GUEST_TABLE_NORMAL_PAGE 1 #define GUEST_TABLE_SUPER_PAGE 2 +#define GUEST_TABLE_SPLIT_PAGE 3 + +static int ept_set_middle_entry(struct domain *d, ept_entry_t *ept_entry) +{ + struct page_info *pg; + + pg = d->arch.p2m->alloc_page(d); + if ( pg == NULL ) + return 0; + + pg->count_info = 1; + pg->u.inuse.type_info = 1 | PGT_validated; + list_add_tail(&pg->list, &d->arch.p2m->pages); + + ept_entry->emt = 0; + ept_entry->sp_avail = 0; + ept_entry->avail1 = 0; + ept_entry->mfn = page_to_mfn(pg); + ept_entry->rsvd = 0; + ept_entry->avail2 = 0; + /* last step */ + ept_entry->r = ept_entry->w = ept_entry->x = 1; + + return 1; +} static int ept_next_level(struct domain *d, bool_t read_only, ept_entry_t **table, unsigned long *gfn_remainder, - u32 shift) + u32 shift, int order) { ept_entry_t *ept_entry, *next; u32 index; @@ -63,27 +88,11 @@ static int ept_next_level(struct domain if ( !(ept_entry->epte & 0x7) ) { - struct page_info *pg; - if ( read_only ) return 0; - pg = d->arch.p2m->alloc_page(d); - if ( pg == NULL ) + if ( !ept_set_middle_entry(d, ept_entry) ) return 0; - - pg->count_info = 1; - pg->u.inuse.type_info = 1 | PGT_validated; - list_add_tail(&pg->list, &d->arch.p2m->pages); - - ept_entry->emt = 0; - ept_entry->sp_avail = 0; - ept_entry->avail1 = 0; - ept_entry->mfn = page_to_mfn(pg); - ept_entry->rsvd = 0; - ept_entry->avail2 = 0; - /* last step */ - ept_entry->r = ept_entry->w = ept_entry->x = 1; } if ( !ept_entry->sp_avail ) @@ -95,7 +104,12 @@ static int ept_next_level(struct domain return GUEST_TABLE_NORMAL_PAGE; } else - return GUEST_TABLE_SUPER_PAGE; + { + if ( order == shift || read_only ) + return GUEST_TABLE_SUPER_PAGE; + else + return GUEST_TABLE_SPLIT_PAGE; + } } static int @@ -109,7 +123,9 @@ ept_set_entry(struct domain *d, unsigned int i, rv = 0, ret = 0; int walk_level = order / EPT_TABLE_ORDER; - /* Should check if gfn obeys GAW here */ + /* we only support 4k and 2m pages now */ + + BUG_ON(order && order != EPT_TABLE_ORDER); if ( order != 0 ) if ( (gfn & ((1UL << order) - 1)) ) @@ -122,10 +138,10 @@ ept_set_entry(struct domain *d, unsigned for ( i = EPT_DEFAULT_GAW; i > walk_level; i-- ) { ret = ept_next_level(d, 0, &table, &gfn_remainder, - i * EPT_TABLE_ORDER); + i * EPT_TABLE_ORDER, order); if ( !ret ) goto out; - else if ( ret == GUEST_TABLE_SUPER_PAGE ) + else if ( ret != GUEST_TABLE_NORMAL_PAGE ) break; } @@ -135,35 +151,87 @@ ept_set_entry(struct domain *d, unsigned ept_entry = table + index; - if ( mfn_valid(mfn_x(mfn)) || (p2mt == p2m_mmio_direct) ) - { - /* 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->sp_avail = walk_level ? 1 : 0; - - if ( ret == GUEST_TABLE_SUPER_PAGE ) - { - ept_entry->mfn = mfn_x(mfn) - offset; - if ( ept_entry->avail1 == p2m_ram_logdirty && - p2mt == p2m_ram_rw ) - for ( i = 0; i < 512; i++ ) - paging_mark_dirty(d, mfn_x(mfn)-offset+i); + if ( ret != GUEST_TABLE_SPLIT_PAGE ) + { + if ( mfn_valid(mfn_x(mfn)) || (p2mt == p2m_mmio_direct) ) + { + /* 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->sp_avail = walk_level ? 1 : 0; + + if ( ret == GUEST_TABLE_SUPER_PAGE ) + { + ept_entry->mfn = mfn_x(mfn) - offset; + if ( ept_entry->avail1 == p2m_ram_logdirty && + p2mt == p2m_ram_rw ) + for ( i = 0; i < 512; i++ ) + paging_mark_dirty(d, mfn_x(mfn)-offset+i); + } + else + ept_entry->mfn = mfn_x(mfn); + + ept_entry->avail1 = p2mt; + ept_entry->rsvd = 0; + 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->mfn = mfn_x(mfn); - - ept_entry->avail1 = p2mt; - ept_entry->rsvd = 0; - ept_entry->avail2 = 0; - /* last step */ - ept_entry->r = ept_entry->w = ept_entry->x = 1; - ept_p2m_type_to_flags(ept_entry, p2mt); + ept_entry->epte = 0; } else - ept_entry->epte = 0; + { + /* It's super page before, now set one of the 4k pages, so + * we should split the 2m page to 4k pages now. + */ + + ept_entry_t *split_table = NULL; + ept_entry_t *split_ept_entry = NULL; + unsigned long split_mfn = ept_entry->mfn; + p2m_type_t split_p2mt = ept_entry->avail1; + + /* alloc new page for new ept middle level entry which is + * before a leaf super entry + */ + + if ( !ept_set_middle_entry(d, ept_entry) ) + goto out; + + /* split the super page before to 4k pages */ + + split_table = map_domain_page(ept_entry->mfn); + + for ( i = 0; i < 512; i++ ) + { + split_ept_entry = split_table + i; + split_ept_entry->emt = EPT_DEFAULT_MT; + split_ept_entry->sp_avail = 0; + + split_ept_entry->mfn = split_mfn+i; + + split_ept_entry->avail1 = split_p2mt; + split_ept_entry->rsvd = 0; + split_ept_entry->avail2 = 0; + /* last step */ + split_ept_entry->r = split_ept_entry->w = split_ept_entry->x = 1; + ept_p2m_type_to_flags(split_ept_entry, split_p2mt); + } + + /* Set the destinated 4k page as normal */ + + offset = gfn & ((1 << EPT_TABLE_ORDER) - 1); + split_ept_entry = split_table + offset; + 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 */ rv = 1; @@ -179,22 +247,22 @@ out: { if ( p2mt == p2m_ram_rw ) { - if ( ret == GUEST_TABLE_SUPER_PAGE ) + if ( order == EPT_TABLE_ORDER ) { for ( i = 0; i < 512; i++ ) iommu_map_page(d, gfn-offset+i, mfn_x(mfn)-offset+i); } - else if ( ret ) + else if ( !order ) iommu_map_page(d, gfn, mfn_x(mfn)); } else { - if ( ret == GUEST_TABLE_SUPER_PAGE ) + if ( order == EPT_TABLE_ORDER ) { for ( i = 0; i < 512; i++ ) iommu_unmap_page(d, gfn-offset+i); } - else if ( ret ) + else if ( !order ) iommu_unmap_page(d, gfn); } } @@ -230,7 +298,7 @@ static mfn_t ept_get_entry(struct domain for ( i = EPT_DEFAULT_GAW; i > 0; i-- ) { ret = ept_next_level(d, 1, &table, &gfn_remainder, - i * EPT_TABLE_ORDER); + i * EPT_TABLE_ORDER, 0); if ( !ret ) goto out; else if ( ret == GUEST_TABLE_SUPER_PAGE ) _______________________________________________ Xen-changelog mailing list Xen-changelog@xxxxxxxxxxxxxxxxxxx http://lists.xensource.com/xen-changelog
|
Lists.xenproject.org is hosted with RackSpace, monitoring our |