# 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
|