[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

[PATCH v6 07/44] x86/mm: have init_xen_l4_slots() take a vCPU in place of the domain



A later change gives the vCPUs of some domains per-domain areas of
their own, and slot 260 of a table private to one vCPU must then hold
that vCPU's L3.  Eventually, all guest types may be able to support
either per-domain L3s or per-vCPU L3s.

HVM domains always have one root page table per vCPU; this does not
change.  So init_xen_l4_slots() needs the appropriate L3 at vCPU
creation, either the domain-wide L3 or the per-vCPU L3.

PV domains with a domain-wide L3 should behave as now: the Xen slots
of guest root pagetables need the domain-wide L3 installed.  But PV
guests with per-vCPU page tables can never run directly on guest
pagetables; they will always need some separate page table, which can
be initialized with the per-vCPU L3.

So, create two versions of init_xen_l4_slots(). The first is used in
contexts where we may be initializing a non-guest root, and must have
a vCPU L3 if per-vCPU L3s are in use; this takes a vCPU as an
argument.  The second is used for roots that all of a domain's vCPUs
share (a PV guest's own L4s, and their shadows), which only need an
L3 if domain-wide L3s are in use; this takes a domain as an argument.

Both wrap an internal function, which takes a domain and an L3
pointer, and leaves the slot empty if this pointer is NULL.  At the
moment, both always pass on the domain-wide L3, but in the future this
will change if the guest is using per-vCPU pagetables.

Otherwise no functional change: slot 260 still gets the domain's
per-domain L3.

Assisted-by: Claude Code:claude-opus-5-5
Signed-off-by: George Dunlap <gwd@xxxxxxxxxxxxxx>
---
Changes in v6:
- Add init_xen_l4_slots_pv() form, which only takes a domain as an
  argument; promote_l4_table(), the PV dom0 builder and the shadows of
  PV guests' L4s use it, so promote_l4_table() no longer needs vCPU 0.

Changes in v5:
- promote_l4_table() checks for vCPU 0 itself, now that "x86/mm: refuse
  to promote an L4 while the domain has no per-domain L3" tests for the
  L3 instead.

Changes in v4:
- New in this version, split out of "x86/hvm: introduce per-vCPU L3
  page-table": init_xen_l4_slots() takes a vCPU in place of the domain
  (Roger, Jan).
- Reflow promote_l4_table()'s call to init_xen_l4_slots() (Jan).
---
 xen/arch/x86/include/asm/mm.h  |  4 +++-
 xen/arch/x86/mm.c              | 35 +++++++++++++++++++++++++++++-----
 xen/arch/x86/mm/hap/hap.c      |  2 +-
 xen/arch/x86/mm/shadow/hvm.c   |  2 +-
 xen/arch/x86/mm/shadow/multi.c |  5 +++--
 xen/arch/x86/pv/dom0_build.c   |  4 ++--
 xen/arch/x86/pv/domain.c       |  2 +-
 7 files changed, 41 insertions(+), 13 deletions(-)

diff --git a/xen/arch/x86/include/asm/mm.h b/xen/arch/x86/include/asm/mm.h
index e85a6db203..0d2cecf1c7 100644
--- a/xen/arch/x86/include/asm/mm.h
+++ b/xen/arch/x86/include/asm/mm.h
@@ -370,7 +370,9 @@ int devalidate_page(struct page_info *page, unsigned long 
type,
 
 void init_xen_pae_l2_slots(l2_pgentry_t *l2t, const struct domain *d);
 void init_xen_l4_slots(l4_pgentry_t *l4t, mfn_t l4mfn,
-                       const struct domain *d, mfn_t sl4mfn, bool ro_mpt);
+                       const struct vcpu *v, mfn_t sl4mfn, bool ro_mpt);
+void init_xen_l4_slots_pv(l4_pgentry_t *l4t, mfn_t l4mfn,
+                          const struct domain *d, mfn_t sl4mfn, bool ro_mpt);
 bool fill_ro_mpt(mfn_t mfn);
 void zap_ro_mpt(mfn_t mfn);
 
diff --git a/xen/arch/x86/mm.c b/xen/arch/x86/mm.c
index 61bd4aa02a..10106d9f03 100644
--- a/xen/arch/x86/mm.c
+++ b/xen/arch/x86/mm.c
@@ -1693,8 +1693,10 @@ static int promote_l3_table(struct page_info *page)
  * appropriate slots.  Pagetables not shared with guests will gain the
  * extended directmap.
  */
-void init_xen_l4_slots(l4_pgentry_t *l4t, mfn_t l4mfn,
-                       const struct domain *d, mfn_t sl4mfn, bool ro_mpt)
+static void _init_xen_l4_slots(l4_pgentry_t *l4t, mfn_t l4mfn,
+                               const struct domain *d,
+                               const struct page_info *l3_pg,
+                               mfn_t sl4mfn, bool ro_mpt)
 {
     /*
      * PV vcpus need a shortened directmap.  HVM and Idle vcpus get the full
@@ -1723,7 +1725,7 @@ void init_xen_l4_slots(l4_pgentry_t *l4t, mfn_t l4mfn,
 
     /* Slot 260: Per-domain mappings. */
     l4t[l4_table_offset(PERDOMAIN_VIRT_START)] =
-        l4e_from_page(d->arch.perdomain_l3_pg, __PAGE_HYPERVISOR_RW);
+        l3_pg ? l4e_from_page(l3_pg, __PAGE_HYPERVISOR_RW) : l4e_empty();
 
     /* Slot 4: Per-domain mappings mirror. */
     BUILD_BUG_ON(IS_ENABLED(CONFIG_PV32) &&
@@ -1770,6 +1772,29 @@ void init_xen_l4_slots(l4_pgentry_t *l4t, mfn_t l4mfn,
     }
 }
 
+/*
+ * v is the vCPU the table is private to.  For shared root pagetables, use
+ * init_xen_l4_slots_pv().
+ */
+void init_xen_l4_slots(l4_pgentry_t *l4t, mfn_t l4mfn,
+                       const struct vcpu *v, mfn_t sl4mfn, bool ro_mpt)
+{
+    const struct domain *d = v->domain;
+
+    _init_xen_l4_slots(l4t, l4mfn, d, d->arch.perdomain_l3_pg, sl4mfn, ro_mpt);
+}
+
+/*
+ * This is a version of init_xen_l4_slots for shared root pagetables;
+ * it only propagates domain-wide perdomain L3s, and so only needs a
+ * domain pointer.
+ */
+void init_xen_l4_slots_pv(l4_pgentry_t *l4t, mfn_t l4mfn,
+                          const struct domain *d, mfn_t sl4mfn, bool ro_mpt)
+{
+    _init_xen_l4_slots(l4t, l4mfn, d, d->arch.perdomain_l3_pg, sl4mfn, ro_mpt);
+}
+
 bool fill_ro_mpt(mfn_t mfn)
 {
     l4_pgentry_t *l4tab = map_domain_page(mfn);
@@ -1878,8 +1903,8 @@ static int promote_l4_table(struct page_info *page)
 
     if ( !rc )
     {
-        init_xen_l4_slots(pl4e, l4mfn,
-                          d, INVALID_MFN, VM_ASSIST(d, m2p_strict));
+        init_xen_l4_slots_pv(pl4e, l4mfn, d, INVALID_MFN,
+                             VM_ASSIST(d, m2p_strict));
         atomic_inc(&d->arch.pv.nr_l4_pages);
     }
     unmap_domain_page(pl4e);
diff --git a/xen/arch/x86/mm/hap/hap.c b/xen/arch/x86/mm/hap/hap.c
index 0ede4181a0..aba4f77df9 100644
--- a/xen/arch/x86/mm/hap/hap.c
+++ b/xen/arch/x86/mm/hap/hap.c
@@ -407,7 +407,7 @@ static mfn_t hap_make_monitor_table(struct vcpu *v)
     m4mfn = page_to_mfn(pg);
     l4e = map_domain_page(m4mfn);
 
-    init_xen_l4_slots(l4e, m4mfn, d, INVALID_MFN, false);
+    init_xen_l4_slots(l4e, m4mfn, v, INVALID_MFN, false);
     unmap_domain_page(l4e);
 
     return m4mfn;
diff --git a/xen/arch/x86/mm/shadow/hvm.c b/xen/arch/x86/mm/shadow/hvm.c
index e6fb97c4b6..0b23326214 100644
--- a/xen/arch/x86/mm/shadow/hvm.c
+++ b/xen/arch/x86/mm/shadow/hvm.c
@@ -760,7 +760,7 @@ mfn_t sh_make_monitor_table(const struct vcpu *v, unsigned 
int shadow_levels)
      * shadow-linear mapping will either be inserted below when creating
      * lower level monitor tables, or later in sh_update_cr3().
      */
-    init_xen_l4_slots(l4e, m4mfn, d, INVALID_MFN, false);
+    init_xen_l4_slots(l4e, m4mfn, v, INVALID_MFN, false);
 
     if ( shadow_levels < 4 )
     {
diff --git a/xen/arch/x86/mm/shadow/multi.c b/xen/arch/x86/mm/shadow/multi.c
index 7f72b4b7b2..1831091b95 100644
--- a/xen/arch/x86/mm/shadow/multi.c
+++ b/xen/arch/x86/mm/shadow/multi.c
@@ -974,8 +974,9 @@ sh_make_shadow(struct vcpu *v, mfn_t gmfn, u32 shadow_type)
 
             BUILD_BUG_ON(sizeof(l4_pgentry_t) != sizeof(shadow_l4e_t));
 
-            init_xen_l4_slots(l4t, gmfn, d, smfn, (!is_pv_32bit_domain(d) &&
-                                                   VM_ASSIST(d, m2p_strict)));
+            init_xen_l4_slots_pv(l4t, gmfn, d, smfn,
+                                 (!is_pv_32bit_domain(d) &&
+                                  VM_ASSIST(d, m2p_strict)));
             unmap_domain_page(l4t);
         }
         break;
diff --git a/xen/arch/x86/pv/dom0_build.c b/xen/arch/x86/pv/dom0_build.c
index 24f2fa0b7f..dd64af5616 100644
--- a/xen/arch/x86/pv/dom0_build.c
+++ b/xen/arch/x86/pv/dom0_build.c
@@ -724,8 +724,8 @@ static int __init dom0_construct(const struct boot_domain 
*bd)
         maddr_to_page(mpt_alloc)->u.inuse.type_info = PGT_l4_page_table;
         l4start = l4tab = __va(mpt_alloc); mpt_alloc += PAGE_SIZE;
         clear_page(l4tab);
-        init_xen_l4_slots(l4tab, _mfn(virt_to_mfn(l4start)),
-                          d, INVALID_MFN, true);
+        init_xen_l4_slots_pv(l4tab, _mfn(virt_to_mfn(l4start)),
+                             d, INVALID_MFN, true);
         v->arch.guest_table = pagetable_from_paddr(__pa(l4start));
     }
     else
diff --git a/xen/arch/x86/pv/domain.c b/xen/arch/x86/pv/domain.c
index f3c711b85b..f139d8f83c 100644
--- a/xen/arch/x86/pv/domain.c
+++ b/xen/arch/x86/pv/domain.c
@@ -127,7 +127,7 @@ static int setup_compat_l4(struct vcpu *v)
     mfn = page_to_mfn(pg);
     l4tab = map_domain_page(mfn);
     clear_page(l4tab);
-    init_xen_l4_slots(l4tab, mfn, v->domain, INVALID_MFN, false);
+    init_xen_l4_slots(l4tab, mfn, v, INVALID_MFN, false);
     unmap_domain_page(l4tab);
 
     /* This page needs to look like a pagetable so that it can be shadowed */
-- 
2.56.0




 


Rackspace

Lists.xenproject.org is hosted with RackSpace, monitoring our
servers 24x7x365 and backed by RackSpace's Fanatical Support®.