|
[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index] [RFC 3/4] Add xen superpage splitting support to arm
Updates xen_pt_update_entry function from xen/arch/arm/mm.c to
automatically split superpages as needed.
---
xen/arch/arm/mm.c | 91 +++++++++++++++++++++++++++++++++++++++++++++++--------
1 file changed, 78 insertions(+), 13 deletions(-)
diff --git a/xen/arch/arm/mm.c b/xen/arch/arm/mm.c
index 6301752..91b9c2b 100644
--- a/xen/arch/arm/mm.c
+++ b/xen/arch/arm/mm.c
@@ -753,8 +753,78 @@ static int create_xen_table(lpae_t *entry)
}
#define XEN_TABLE_MAP_FAILED 0
-#define XEN_TABLE_SUPER_PAGE 1
-#define XEN_TABLE_NORMAL_PAGE 2
+#define XEN_TABLE_NORMAL_PAGE 1
+
+/* More or less taken from p2m_split_superpage, without the p2m stuff */
+static bool xen_split_superpage(lpae_t *entry, unsigned int level,
+ unsigned int target, const unsigned int
*offsets)
+{
+ struct page_info *page;
+ lpae_t pte, *table;
+ unsigned int i;
+ bool rv = true;
+
+ mfn_t mfn = lpae_get_mfn(*entry);
+ unsigned int next_level = level + 1;
+ unsigned int level_order = XEN_PT_LEVEL_ORDER(next_level);
+
+ ASSERT(level < target);
+ ASSERT(lpae_is_superpage(*entry, level));
+
+ page = alloc_domheap_page(NULL, 0);
+ if ( !page )
+ return false;
+
+ table = __map_domain_page(page);
+
+ /*
+ * We are either splitting a first level 1G page into 512 second level
+ * 2M pages, or a second level 2M page into 512 third level 4K pages.
+ */
+ for ( i = 0; i < XEN_PT_LPAE_ENTRIES; i++ )
+ {
+ lpae_t *new_entry = table + i;
+
+ /*
+ * Use the content of the superpage entry and override
+ * the necessary fields. So the correct permission are kept.
+ */
+ pte = *entry;
+ lpae_set_mfn(pte, mfn_add(mfn, i << level_order));
+
+ /*
+ * First and second level pages set walk.table = 0, but third
+ * level entries set walk.table = 1.
+ */
+ pte.walk.table = (next_level == 3);
+
+ write_pte(new_entry, pte);
+ }
+
+ /*
+ * Shatter superpage in the page to the level we want to make the
+ * changes.
+ * This is done outside the loop to avoid checking the offset to
+ * know whether the entry should be shattered for every entry.
+ */
+ if ( next_level != target )
+ rv = xen_split_superpage(table + offsets[next_level],
+ level + 1, target, offsets);
+
+ clean_dcache_va_range(table, PAGE_SIZE);
+ unmap_domain_page(table);
+
+ /*
+ * Generate the entry for this new table we created,
+ * and write it back in place of the superpage entry.
+ */
+ pte = mfn_to_xen_entry(page_to_mfn(page), MT_NORMAL);
+ pte.pt.table = 1;
+ write_pte(entry, pte);
+ clean_dcache(*entry);
+
+ return rv;
+}
/*
* Take the currently mapped table, find the corresponding entry,
@@ -767,16 +837,15 @@ static int create_xen_table(lpae_t *entry)
* XEN_TABLE_MAP_FAILED: Either read_only was set and the entry
* was empty, or allocating a new page failed.
* XEN_TABLE_NORMAL_PAGE: next level mapped normally
- * XEN_TABLE_SUPER_PAGE: The next entry points to a superpage.
*/
static int xen_pt_next_level(bool read_only, unsigned int level,
- lpae_t **table, unsigned int offset)
+ lpae_t **table, const unsigned int *offsets)
{
lpae_t *entry;
int ret;
mfn_t mfn;
- entry = *table + offset;
+ entry = *table + offsets[level];
if ( !lpae_is_valid(*entry) )
{
@@ -790,7 +859,8 @@ static int xen_pt_next_level(bool read_only, unsigned int
level,
/* The function xen_pt_next_level is never called at the 3rd level */
if ( lpae_is_mapping(*entry, level) )
- return XEN_TABLE_SUPER_PAGE;
+ /* Shatter the superpage before continuing */
+ xen_split_superpage(entry, level, level + 1, offsets);
mfn = lpae_get_mfn(*entry);
@@ -915,7 +985,7 @@ static int xen_pt_update_entry(mfn_t root, unsigned long
virt,
table = xen_map_table(root);
for ( level = HYP_PT_ROOT_LEVEL; level < target; level++ )
{
- rc = xen_pt_next_level(read_only, level, &table, offsets[level]);
+ rc = xen_pt_next_level(read_only, level, &table, offsets);
if ( rc == XEN_TABLE_MAP_FAILED )
{
/*
@@ -941,12 +1011,7 @@ static int xen_pt_update_entry(mfn_t root, unsigned long
virt,
break;
}
- if ( level != target )
- {
- mm_printk("%s: Shattering superpage is not supported\n", __func__);
- rc = -EOPNOTSUPP;
- goto out;
- }
+ BUG_ON( level != target );
entry = table + offsets[level];
--
2.7.4
|
![]() |
Lists.xenproject.org is hosted with RackSpace, monitoring our |