]> xenbits.xensource.com Git - people/royger/xen.git/commitdiff
x86/pv: set/clear guest GDT mappings using {populate,destroy}_perdomain_mapping()
authorRoger Pau Monne <roger.pau@citrix.com>
Tue, 26 Nov 2024 15:29:13 +0000 (16:29 +0100)
committerRoger Pau Monne <roger.pau@citrix.com>
Tue, 10 Dec 2024 17:42:33 +0000 (18:42 +0100)
The pv_{set,destroy}_gdt() functions rely on the L1 table(s) that contain such
mappings being stashed in the domain structure, and thus such mappings being
modified by merely updating the L1 entries.

Switch both pv_{set,destroy}_gdt() to instead use
{populate,destory}_perdomain_mapping().

Note that this requires moving the pv_set_gdt() call in arch_set_info_guest()
strictly after update_cr3(), so v->arch.cr3 is valid when
populate__perdomain_mapping() is called.

Signed-off-by: Roger Pau Monné <roger.pau@citrix.com>
xen/arch/x86/domain.c
xen/arch/x86/pv/descriptor-tables.c

index 0bd0ef7e40f424eef60c30f0ac8c3512372d0d42..0481164f37274cfa7b7d34fa43f1cad5d57edec1 100644 (file)
@@ -1376,22 +1376,6 @@ int arch_set_info_guest(
     if ( rc )
         return rc;
 
-    if ( !compat )
-        rc = pv_set_gdt(v, c.nat->gdt_frames, c.nat->gdt_ents);
-#ifdef CONFIG_COMPAT
-    else
-    {
-        unsigned long gdt_frames[ARRAY_SIZE(v->arch.pv.gdt_frames)];
-
-        for ( i = 0; i < nr_gdt_frames; ++i )
-            gdt_frames[i] = c.cmp->gdt_frames[i];
-
-        rc = pv_set_gdt(v, gdt_frames, c.cmp->gdt_ents);
-    }
-#endif
-    if ( rc != 0 )
-        return rc;
-
     set_bit(_VPF_in_reset, &v->pause_flags);
 
 #ifdef CONFIG_COMPAT
@@ -1492,7 +1476,6 @@ int arch_set_info_guest(
     {
         if ( cr3_page )
             put_page(cr3_page);
-        pv_destroy_gdt(v);
         return rc;
     }
 
@@ -1508,6 +1491,22 @@ int arch_set_info_guest(
         paging_update_paging_modes(v);
     else
         update_cr3(v);
+
+    if ( !compat )
+        rc = pv_set_gdt(v, c.nat->gdt_frames, c.nat->gdt_ents);
+#ifdef CONFIG_COMPAT
+    else
+    {
+        unsigned long gdt_frames[ARRAY_SIZE(v->arch.pv.gdt_frames)];
+
+        for ( i = 0; i < nr_gdt_frames; ++i )
+            gdt_frames[i] = c.cmp->gdt_frames[i];
+
+        rc = pv_set_gdt(v, gdt_frames, c.cmp->gdt_ents);
+    }
+#endif
+    if ( rc != 0 )
+        return rc;
 #endif /* CONFIG_PV */
 
  out:
index 02647a2c50476ade54ae58c1019592c481a6aeab..5a79f022ce132fc0928778320f3b1246ecb0be67 100644 (file)
@@ -49,23 +49,20 @@ bool pv_destroy_ldt(struct vcpu *v)
 
 void pv_destroy_gdt(struct vcpu *v)
 {
-    l1_pgentry_t *pl1e = pv_gdt_ptes(v);
-    mfn_t zero_mfn = _mfn(virt_to_mfn(zero_page));
-    l1_pgentry_t zero_l1e = l1e_from_mfn(zero_mfn, __PAGE_HYPERVISOR_RO);
     unsigned int i;
 
     ASSERT(v == current || !vcpu_cpu_dirty(v));
 
-    v->arch.pv.gdt_ents = 0;
-    for ( i = 0; i < FIRST_RESERVED_GDT_PAGE; i++ )
-    {
-        mfn_t mfn = l1e_get_mfn(pl1e[i]);
+    if ( v->arch.cr3 )
+        destroy_perdomain_mapping(v, GDT_VIRT_START(v),
+                                  ARRAY_SIZE(v->arch.pv.gdt_frames));
 
-        if ( (l1e_get_flags(pl1e[i]) & _PAGE_PRESENT) &&
-             !mfn_eq(mfn, zero_mfn) )
-            put_page_and_type(mfn_to_page(mfn));
+    for ( i = 0; i < ARRAY_SIZE(v->arch.pv.gdt_frames); i++)
+    {
+        if ( !v->arch.pv.gdt_frames[i] )
+            break;
 
-        l1e_write(&pl1e[i], zero_l1e);
+        put_page_and_type(mfn_to_page(_mfn(v->arch.pv.gdt_frames[i])));
         v->arch.pv.gdt_frames[i] = 0;
     }
 }
@@ -74,8 +71,8 @@ int pv_set_gdt(struct vcpu *v, const unsigned long frames[],
                unsigned int entries)
 {
     struct domain *d = v->domain;
-    l1_pgentry_t *pl1e;
     unsigned int i, nr_frames = DIV_ROUND_UP(entries, 512);
+    mfn_t mfns[ARRAY_SIZE(v->arch.pv.gdt_frames)];
 
     ASSERT(v == current || !vcpu_cpu_dirty(v));
 
@@ -90,6 +87,8 @@ int pv_set_gdt(struct vcpu *v, const unsigned long frames[],
         if ( !mfn_valid(mfn) ||
              !get_page_and_type(mfn_to_page(mfn), d, PGT_seg_desc_page) )
             goto fail;
+
+        mfns[i] = mfn;
     }
 
     /* Tear down the old GDT. */
@@ -97,12 +96,9 @@ int pv_set_gdt(struct vcpu *v, const unsigned long frames[],
 
     /* Install the new GDT. */
     v->arch.pv.gdt_ents = entries;
-    pl1e = pv_gdt_ptes(v);
     for ( i = 0; i < nr_frames; i++ )
-    {
         v->arch.pv.gdt_frames[i] = frames[i];
-        l1e_write(&pl1e[i], l1e_from_pfn(frames[i], __PAGE_HYPERVISOR_RW));
-    }
+    populate_perdomain_mapping(v, GDT_VIRT_START(v), mfns, nr_frames);
 
     return 0;