|
[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index] [PATCH v6 14/44] x86/mm: let Xen's page-table walker operate on a given root
map_pages_to_xen() and modify_xen_mappings() maintain Xen's own
mappings, walking from idle_pg_table, whose Xen slots every other root
page-table copies. A later patch introduces a second, sparse directmap
hierarchy: page tables for the directmap virtual address range that some
guest contexts use in place of idle_pg_table's. It needs the same
maintenance at the same virtual addresses.
Give virt_to_xen_l{3,2,1}e() the L4 to walk from, and move the bodies of
map_pages_to_xen() and modify_xen_mappings() into map_pages_in() and
modify_mappings_in(), which take the root as well. The public functions
pass idle_pg_table. The EFI runtime-services page-tables mirror
idle_pg_table's L4 entries only, so a newly allocated L3 is propagated
to them only when the root is idle_pg_table.
map_pages_in() and modify_mappings_in() free page-table pages through
free_pagetable_in(), which takes the root too and for now only calls
free_xen_pagetable().
TLB flushing is unaffected: flushes are by virtual address and go to
every online CPU, which covers both hierarchies.
No functional change.
Assisted-by: Claude Code:claude-opus-5-5
Signed-off-by: George Dunlap <gwd@xxxxxxxxxxxxxx>
---
Changes in v5:
- Free page-table pages through free_pagetable_in(), for now a plain
wrapper, split out of "x86/mm: build and maintain a sparse view of the
directmap".
Changes in v4:
- Message: name the second hierarchy as sparse; flushes reach every CPU
(Roger).
Changes in v3:
- New in this version.
---
xen/arch/x86/mm.c | 78 ++++++++++++++++++++++++++++++++++-------------
1 file changed, 56 insertions(+), 22 deletions(-)
diff --git a/xen/arch/x86/mm.c b/xen/arch/x86/mm.c
index f52c72a605..39c6fa3d56 100644
--- a/xen/arch/x86/mm.c
+++ b/xen/arch/x86/mm.c
@@ -5247,13 +5247,14 @@ static DEFINE_SPINLOCK(map_pgdir_lock);
/*
* For virt_to_xen_lXe() functions, they take a linear address and return a
- * pointer to Xen's LX entry. Caller needs to unmap the pointer.
+ * pointer to Xen's LX entry in the page-table hierarchy rooted at @root
+ * (idle_pg_table for Xen's own mappings). Caller needs to unmap the pointer.
*/
-static l3_pgentry_t *virt_to_xen_l3e(unsigned long v)
+static l3_pgentry_t *virt_to_xen_l3e(l4_pgentry_t *root, unsigned long v)
{
l4_pgentry_t *pl4e;
- pl4e = &idle_pg_table[l4_table_offset(v)];
+ pl4e = &root[l4_table_offset(v)];
if ( !(l4e_get_flags(*pl4e) & _PAGE_PRESENT) )
{
bool locking = system_state > SYS_STATE_boot;
@@ -5269,7 +5270,8 @@ static l3_pgentry_t *virt_to_xen_l3e(unsigned long v)
l4_pgentry_t l4e = l4e_from_mfn(l3mfn, __PAGE_HYPERVISOR);
l4e_write(pl4e, l4e);
- efi_update_l4_pgtable(l4_table_offset(v), l4e);
+ if ( root == idle_pg_table )
+ efi_update_l4_pgtable(l4_table_offset(v), l4e);
l3mfn = INVALID_MFN;
}
if ( locking )
@@ -5280,11 +5282,11 @@ static l3_pgentry_t *virt_to_xen_l3e(unsigned long v)
return map_l3t_from_l4e(*pl4e) + l3_table_offset(v);
}
-static l2_pgentry_t *virt_to_xen_l2e(unsigned long v)
+static l2_pgentry_t *virt_to_xen_l2e(l4_pgentry_t *root, unsigned long v)
{
l3_pgentry_t *pl3e, l3e;
- pl3e = virt_to_xen_l3e(v);
+ pl3e = virt_to_xen_l3e(root, v);
if ( !pl3e )
return NULL;
@@ -5318,11 +5320,11 @@ static l2_pgentry_t *virt_to_xen_l2e(unsigned long v)
return map_l2t_from_l3e(l3e) + l2_table_offset(v);
}
-static l1_pgentry_t *virt_to_xen_l1e(unsigned long v)
+static l1_pgentry_t *virt_to_xen_l1e(l4_pgentry_t *root, unsigned long v)
{
l2_pgentry_t *pl2e, l2e;
- pl2e = virt_to_xen_l2e(v);
+ pl2e = virt_to_xen_l2e(root, v);
if ( !pl2e )
return NULL;
@@ -5398,7 +5400,7 @@ mfn_t xen_map_to_mfn(unsigned long va)
bool locking = system_state > SYS_STATE_boot;
unsigned int l2_offset = l2_table_offset(va);
unsigned int l1_offset = l1_table_offset(va);
- const l3_pgentry_t *pl3e = virt_to_xen_l3e(va);
+ const l3_pgentry_t *pl3e = virt_to_xen_l3e(idle_pg_table, va);
const l2_pgentry_t *pl2e = NULL;
const l1_pgentry_t *pl1e = NULL;
struct page_info *l3page;
@@ -5438,7 +5440,21 @@ mfn_t xen_map_to_mfn(unsigned long va)
return ret;
}
-int map_pages_to_xen(
+/*
+ * Free a page-table page that the hierarchy rooted at @root has stopped
+ * using.
+ */
+static void free_pagetable_in(const l4_pgentry_t *root, mfn_t mfn)
+{
+ free_xen_pagetable(mfn);
+}
+
+/*
+ * map_pages_to_xen() in the hierarchy rooted at @root: idle_pg_table's, or
+ * another hierarchy sharing its virtual addresses.
+ */
+static int map_pages_in(
+ l4_pgentry_t *root,
unsigned long virt,
mfn_t mfn,
unsigned long nr_mfns,
@@ -5489,7 +5505,7 @@ int map_pages_to_xen(
UNMAP_DOMAIN_PAGE(pl3e);
UNMAP_DOMAIN_PAGE(pl2e);
- pl3e = virt_to_xen_l3e(virt);
+ pl3e = virt_to_xen_l3e(root, virt);
if ( !pl3e )
goto out;
@@ -5542,10 +5558,10 @@ int map_pages_to_xen(
ol2e = l2t[i];
if ( (l2e_get_flags(ol2e) & _PAGE_PRESENT) &&
!(l2e_get_flags(ol2e) & _PAGE_PSE) )
- free_xen_pagetable(l2e_get_mfn(ol2e));
+ free_pagetable_in(root, l2e_get_mfn(ol2e));
}
unmap_domain_page(l2t);
- free_xen_pagetable(l3e_get_mfn(ol3e));
+ free_pagetable_in(root, l3e_get_mfn(ol3e));
}
}
@@ -5613,7 +5629,7 @@ int map_pages_to_xen(
free_xen_pagetable(l2mfn);
}
- pl2e = virt_to_xen_l2e(virt);
+ pl2e = virt_to_xen_l2e(root, virt);
if ( !pl2e )
goto out;
@@ -5643,7 +5659,7 @@ int map_pages_to_xen(
flush_flags(l1e_get_flags(l1t[i]));
flush_area(virt, flush_flags);
unmap_domain_page(l1t);
- free_xen_pagetable(l2e_get_mfn(ol2e));
+ free_pagetable_in(root, l2e_get_mfn(ol2e));
}
}
@@ -5658,7 +5674,7 @@ int map_pages_to_xen(
/* Normal page mapping. */
if ( !(l2e_get_flags(*pl2e) & _PAGE_PRESENT) )
{
- pl1e = virt_to_xen_l1e(virt);
+ pl1e = virt_to_xen_l1e(root, virt);
if ( pl1e == NULL )
goto out;
}
@@ -5775,7 +5791,7 @@ int map_pages_to_xen(
flush_area(virt - PAGE_SIZE,
FLUSH_TLB_GLOBAL |
FLUSH_ORDER(PAGETABLE_ORDER));
- free_xen_pagetable(l2e_get_mfn(ol2e));
+ free_pagetable_in(root, l2e_get_mfn(ol2e));
}
else if ( locking )
spin_unlock(&map_pgdir_lock);
@@ -5822,7 +5838,7 @@ int map_pages_to_xen(
flush_area(virt - PAGE_SIZE,
FLUSH_TLB_GLOBAL |
FLUSH_ORDER(2*PAGETABLE_ORDER));
- free_xen_pagetable(l3e_get_mfn(ol3e));
+ free_pagetable_in(root, l3e_get_mfn(ol3e));
}
else if ( locking )
spin_unlock(&map_pgdir_lock);
@@ -5843,6 +5859,15 @@ int map_pages_to_xen(
return rc;
}
+int map_pages_to_xen(
+ unsigned long virt,
+ mfn_t mfn,
+ unsigned long nr_mfns,
+ pte_attr_t flags)
+{
+ return map_pages_in(idle_pg_table, virt, mfn, nr_mfns, flags);
+}
+
int __init populate_pt_range(unsigned long virt, unsigned long nr_mfns)
{
return map_pages_to_xen(virt, INVALID_MFN, nr_mfns, MAP_SMALL_PAGES);
@@ -5859,8 +5884,12 @@ int __init populate_pt_range(unsigned long virt,
unsigned long nr_mfns)
* flags are ignored.
*
* It is an error to call with present flags over an unpopulated range.
+ *
+ * modify_mappings_in() does so in the hierarchy rooted at @root, as
+ * map_pages_in() does.
*/
-int modify_xen_mappings(unsigned long s, unsigned long e, pte_attr_t nf)
+static int modify_mappings_in(l4_pgentry_t *root, unsigned long s,
+ unsigned long e, pte_attr_t nf)
{
bool locking = system_state > SYS_STATE_boot;
l3_pgentry_t *pl3e = NULL;
@@ -5887,7 +5916,7 @@ int modify_xen_mappings(unsigned long s, unsigned long e,
pte_attr_t nf)
UNMAP_DOMAIN_PAGE(pl2e);
UNMAP_DOMAIN_PAGE(pl3e);
- pl3e = virt_to_xen_l3e(v);
+ pl3e = virt_to_xen_l3e(root, v);
if ( !pl3e )
goto out;
@@ -6070,7 +6099,7 @@ int modify_xen_mappings(unsigned long s, unsigned long e,
pte_attr_t nf)
if ( locking )
spin_unlock(&map_pgdir_lock);
flush_area(NULL, FLUSH_TLB_GLOBAL); /* flush before free */
- free_xen_pagetable(l1mfn);
+ free_pagetable_in(root, l1mfn);
}
else if ( locking )
spin_unlock(&map_pgdir_lock);
@@ -6114,7 +6143,7 @@ int modify_xen_mappings(unsigned long s, unsigned long e,
pte_attr_t nf)
if ( locking )
spin_unlock(&map_pgdir_lock);
flush_area(NULL, FLUSH_TLB_GLOBAL); /* flush before free */
- free_xen_pagetable(l2mfn);
+ free_pagetable_in(root, l2mfn);
}
else if ( locking )
spin_unlock(&map_pgdir_lock);
@@ -6138,6 +6167,11 @@ int modify_xen_mappings(unsigned long s, unsigned long
e, pte_attr_t nf)
#undef flush_area
+int modify_xen_mappings(unsigned long s, unsigned long e, pte_attr_t nf)
+{
+ return modify_mappings_in(idle_pg_table, s, e, nf);
+}
+
int destroy_xen_mappings(unsigned long s, unsigned long e)
{
return modify_xen_mappings(s, e, _PAGE_NONE);
--
2.56.0
|
![]() |
Lists.xenproject.org is hosted with RackSpace, monitoring our |