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

[PATCH v3 3/6] x86: extend mod_l*_entry() to optionally return the old PTE value


  • To: xen-devel@xxxxxxxxxxxxxxxxxxxx
  • From: Kevin Lampis <kevin.lampis@xxxxxxxxxx>
  • Date: Thu, 1 Oct 2026 18:47:46 +0100
  • Arc-authentication-results: i=1; mx.microsoft.com 1; spf=pass smtp.mailfrom=citrix.com; dmarc=pass action=none header.from=citrix.com; dkim=pass header.d=citrix.com; arc=none
  • Arc-message-signature: i=1; a=rsa-sha256; c=relaxed/relaxed; d=microsoft.com; s=arcselector10001; h=From:Date:Subject:Message-ID:Content-Type:MIME-Version:X-MS-Exchange-AntiSpam-MessageData-ChunkCount:X-MS-Exchange-AntiSpam-MessageData-0:X-MS-Exchange-AntiSpam-MessageData-1; bh=pQ+J3wc2JXd52VnbMqfcY5c0kIzjo5Lek38sZL8Kkbo=; b=pfywxmhFDceI9qd7CH2gUdQilTwyipyc6qnT9rzC1iSr0cUUgLUmK4+6930yJEVfdAMVUqH6eqqGQQpVGX+bBfyQn2TPhPsIXrxFEYhtmvTodHTD4tLFJ5Kohrmge33G2Tmebwcn5IQspmNXRGfd1BufuIyQrx7LvPiYCl826pwzNUvoA14ui6isIpShZpj55lRjWVJQSoa7lO7j/DZ4zRvKHjp6xZte2zUJbC3jQqYqY7A4Tf+lgorgJ+nIka0QVLLFr8KgBexwXOsMR4WxgKqF1xh+ZSy95lWRbpmm7xs62jBe7WakY0ooWEDCUejXqmnuVEupsG/YPjzgoDXqwQ==
  • Arc-seal: i=1; a=rsa-sha256; s=arcselector10001; d=microsoft.com; cv=none; b=XGHpgIzMzfDZSQzPJnE++QRrzIaLi0BdGN/7DYH8rjVFnVZVSKMrwhQjzbvoID5s50ahPRffp8WWvPNNJ65XY5LBwk9ur/0++oJcX35FIFnITi1g7Id4U3/O5+UpJuhWn0NIK0wzUcubWIV18J9ijMoztg60AiZue24eqQkSClcN+uJvnMCXVfZis7CXTRK9BkjhOpFmhlkuhcQzeqnoyon0bOaYzI8ZOXED6l0A9Et5Sht3jySiSzwUz+q4GxM282uFeAzdJarqAqon+hOMLnPBCQowY4d3wBbXx70gXF0wxLLOcRkQR7uJZUvisG8Be2CPWeTHExcRj2t3xE6RvQ==
  • Authentication-results: eu.smtp.expurgate.cloud; dkim=pass header.s=selector1 header.d=citrix.com header.i="@citrix.com" header.h="From:Date:Subject:Message-ID:Content-Type:MIME-Version:X-MS-Exchange-SenderADCheck"
  • Authentication-results: mx.microsoft.com 1; dkim=none (message not signed) header.d=none;dmarc=none action=none header.from=citrix.com;
  • Cc: jbeulich@xxxxxxxx, andrew.cooper3@xxxxxxxxxx, teddy.astie@xxxxxxxxxx, Kevin Lampis <kevin.lampis@xxxxxxxxxx>
  • Delivery-date: Thu, 01 Oct 2026 17:46:21 +0000
  • List-id: Xen developer discussion <xen-devel.lists.xenproject.org>

Calling mod_l*_entry() with a valid ol*e_out pointer will do an atomic
xchg to set the new pte value and return the old pte value through the
ol*e_out pointer. If the ol*e_out pointer is NULL then old behavior is
preserved.

Signed-off-by: Kevin Lampis <kevin.lampis@xxxxxxxxxx>
---
Changes in v3:
- Add swap to mod_l{2,3,4}_entry()

Changes in v2:
- UPDATE_ENTRY now returns the old pte value instead of using an out
  pointer
---
 xen/arch/x86/mm.c | 107 ++++++++++++++++++++++++++++++++++++----------
 1 file changed, 85 insertions(+), 22 deletions(-)

diff --git a/xen/arch/x86/mm.c b/xen/arch/x86/mm.c
index 1ddb8b71469a..535a62139cad 100644
--- a/xen/arch/x86/mm.c
+++ b/xen/arch/x86/mm.c
@@ -2154,7 +2154,8 @@ static void l3t_unlock(struct page_info *page)
 /* Update the L1 entry at pl1e to new value nl1e. */
 static int mod_l1_entry(l1_pgentry_t *pl1e, l1_pgentry_t nl1e,
                         mfn_t gl1mfn, unsigned int update_flags,
-                        struct vcpu *pt_vcpu, struct domain *pg_dom)
+                        struct vcpu *pt_vcpu, struct domain *pg_dom,
+                        l1_pgentry_t *ol1e_out)
 {
     l1_pgentry_t ol1e = l1e_read(pl1e);
     struct domain *pt_dom = pt_vcpu->domain;
@@ -2215,7 +2216,12 @@ static int mod_l1_entry(l1_pgentry_t *pl1e, l1_pgentry_t 
nl1e,
         /* Fast path for sufficiently-similar mappings. */
         if ( !l1e_has_changed(ol1e, nl1e, ~FASTPATH_FLAG_WHITELIST) )
         {
-            UPDATE_ENTRY(l1, pl1e, ol1e, nl1e, gl1mfn, pt_vcpu, update_flags);
+            if ( ol1e_out )
+                *ol1e_out = UPDATE_ENTRY_SWAP(l1, pl1e, ol1e, nl1e, gl1mfn,
+                                              pt_vcpu, update_flags);
+            else
+                UPDATE_ENTRY(l1, pl1e, ol1e, nl1e, gl1mfn, pt_vcpu, 
update_flags);
+
             if ( page )
                 put_page(page);
             return 0;
@@ -2238,14 +2244,25 @@ static int mod_l1_entry(l1_pgentry_t *pl1e, 
l1_pgentry_t nl1e,
         if ( page )
             put_page(page);
 
-        UPDATE_ENTRY(l1, pl1e, ol1e, nl1e, gl1mfn, pt_vcpu, update_flags);
+        if ( ol1e_out )
+            *ol1e_out = UPDATE_ENTRY_SWAP(l1, pl1e, ol1e, nl1e, gl1mfn,
+                                          pt_vcpu, update_flags);
+        else
+            UPDATE_ENTRY(l1, pl1e, ol1e, nl1e, gl1mfn, pt_vcpu, update_flags);
     }
     else if ( pv_l1tf_check_l1e(pt_dom, nl1e) )
         return -ERESTART;
     else
-        UPDATE_ENTRY(l1, pl1e, ol1e, nl1e, gl1mfn, pt_vcpu, update_flags);
+    {
+        if ( ol1e_out )
+            *ol1e_out = UPDATE_ENTRY_SWAP(l1, pl1e, ol1e, nl1e, gl1mfn,
+                                          pt_vcpu, update_flags);
+        else
+            UPDATE_ENTRY(l1, pl1e, ol1e, nl1e, gl1mfn, pt_vcpu, update_flags);
+    }
 
     put_page_from_l1e(ol1e, pt_dom);
+
     return rc;
 }
 
@@ -2255,7 +2272,8 @@ static int mod_l2_entry(l2_pgentry_t *pl2e,
                         l2_pgentry_t nl2e,
                         mfn_t mfn,
                         unsigned int update_flags,
-                        struct vcpu *vcpu)
+                        struct vcpu *vcpu,
+                        l2_pgentry_t *ol2e_out)
 {
     l2_pgentry_t ol2e;
     struct domain *d = vcpu->domain;
@@ -2286,19 +2304,33 @@ static int mod_l2_entry(l2_pgentry_t *pl2e,
         /* Fast path for sufficiently-similar mappings. */
         if ( !l2e_has_changed(ol2e, nl2e, ~FASTPATH_PDE_FLAG_WHITELIST) )
         {
-            UPDATE_ENTRY(l2, pl2e, ol2e, nl2e, mfn, vcpu, update_flags);
+            if ( ol2e_out )
+                *ol2e_out = UPDATE_ENTRY_SWAP(l2, pl2e, ol2e, nl2e, mfn,
+                                              vcpu, update_flags);
+            else
+                UPDATE_ENTRY(l2, pl2e, ol2e, nl2e, mfn, vcpu, update_flags);
             return 0;
         }
 
         if ( unlikely((rc = get_page_from_l2e(nl2e, mfn, d, 0)) < 0) )
             return rc;
 
-        UPDATE_ENTRY(l2, pl2e, ol2e, nl2e, mfn, vcpu, update_flags);
+        if ( ol2e_out )
+            *ol2e_out = UPDATE_ENTRY_SWAP(l2, pl2e, ol2e, nl2e, mfn,
+                                          vcpu, update_flags);
+        else
+            UPDATE_ENTRY(l2, pl2e, ol2e, nl2e, mfn, vcpu, update_flags);
     }
     else if ( pv_l1tf_check_l2e(d, nl2e) )
         return -ERESTART;
     else
-        UPDATE_ENTRY(l2, pl2e, ol2e, nl2e, mfn, vcpu, update_flags);
+    {
+        if ( ol2e_out )
+            *ol2e_out = UPDATE_ENTRY_SWAP(l2, pl2e, ol2e, nl2e, mfn,
+                                          vcpu, update_flags);
+        else
+            UPDATE_ENTRY(l2, pl2e, ol2e, nl2e, mfn, vcpu, update_flags);
+    }
 
     put_page_from_l2e(ol2e, mfn, PTF_defer);
 
@@ -2310,7 +2342,8 @@ static int mod_l3_entry(l3_pgentry_t *pl3e,
                         l3_pgentry_t nl3e,
                         mfn_t mfn,
                         unsigned int update_flags,
-                        struct vcpu *vcpu)
+                        struct vcpu *vcpu,
+                        l3_pgentry_t *ol3e_out)
 {
     l3_pgentry_t ol3e;
     struct domain *d = vcpu->domain;
@@ -2339,7 +2372,11 @@ static int mod_l3_entry(l3_pgentry_t *pl3e,
         /* Fast path for sufficiently-similar mappings. */
         if ( !l3e_has_changed(ol3e, nl3e, ~FASTPATH_PDE_FLAG_WHITELIST) )
         {
-            UPDATE_ENTRY(l3, pl3e, ol3e, nl3e, mfn, vcpu, update_flags);
+            if ( ol3e_out )
+                *ol3e_out = UPDATE_ENTRY_SWAP(l3, pl3e, ol3e, nl3e, mfn, vcpu,
+                                              update_flags);
+            else
+                UPDATE_ENTRY(l3, pl3e, ol3e, nl3e, mfn, vcpu, update_flags);
             return 0;
         }
 
@@ -2348,12 +2385,22 @@ static int mod_l3_entry(l3_pgentry_t *pl3e,
             return rc;
         rc = 0;
 
-        UPDATE_ENTRY(l3, pl3e, ol3e, nl3e, mfn, vcpu, update_flags);
+        if ( ol3e_out )
+            *ol3e_out = UPDATE_ENTRY_SWAP(l3, pl3e, ol3e, nl3e, mfn, vcpu,
+                                          update_flags);
+        else
+            UPDATE_ENTRY(l3, pl3e, ol3e, nl3e, mfn, vcpu, update_flags);
     }
     else if ( pv_l1tf_check_l3e(d, nl3e) )
         return -ERESTART;
     else
-        UPDATE_ENTRY(l3, pl3e, ol3e, nl3e, mfn, vcpu, update_flags);
+    {
+        if ( ol3e_out )
+            *ol3e_out = UPDATE_ENTRY_SWAP(l3, pl3e, ol3e, nl3e, mfn, vcpu,
+                                          update_flags);
+        else
+            UPDATE_ENTRY(l3, pl3e, ol3e, nl3e, mfn, vcpu, update_flags);
+    }
 
     put_page_from_l3e(ol3e, mfn, PTF_defer);
     return rc;
@@ -2364,7 +2411,8 @@ static int mod_l4_entry(l4_pgentry_t *pl4e,
                         l4_pgentry_t nl4e,
                         mfn_t mfn,
                         unsigned int update_flags,
-                        struct vcpu *vcpu)
+                        struct vcpu *vcpu,
+                        l4_pgentry_t *ol4e_out)
 {
     struct domain *d = vcpu->domain;
     l4_pgentry_t ol4e;
@@ -2393,7 +2441,11 @@ static int mod_l4_entry(l4_pgentry_t *pl4e,
         /* Fast path for sufficiently-similar mappings. */
         if ( !l4e_has_changed(ol4e, nl4e, ~FASTPATH_PDE_FLAG_WHITELIST) )
         {
-            UPDATE_ENTRY(l4, pl4e, ol4e, nl4e, mfn, vcpu, update_flags);
+            if ( ol4e_out )
+                *ol4e_out = UPDATE_ENTRY_SWAP(l4, pl4e, ol4e, nl4e, mfn, vcpu,
+                                              update_flags);
+            else
+                UPDATE_ENTRY(l4, pl4e, ol4e, nl4e, mfn, vcpu, update_flags);
             return 0;
         }
 
@@ -2402,12 +2454,22 @@ static int mod_l4_entry(l4_pgentry_t *pl4e,
             return rc;
         rc = 0;
 
-        UPDATE_ENTRY(l4, pl4e, ol4e, nl4e, mfn, vcpu, update_flags);
+        if ( ol4e_out )
+            *ol4e_out = UPDATE_ENTRY_SWAP(l4, pl4e, ol4e, nl4e, mfn, vcpu,
+                                          update_flags);
+        else
+            UPDATE_ENTRY(l4, pl4e, ol4e, nl4e, mfn, vcpu, update_flags);
     }
     else if ( pv_l1tf_check_l4e(d, nl4e) )
         return -ERESTART;
     else
-        UPDATE_ENTRY(l4, pl4e, ol4e, nl4e, mfn, vcpu, update_flags);
+    {
+        if ( ol4e_out )
+            *ol4e_out = UPDATE_ENTRY_SWAP(l4, pl4e, ol4e, nl4e, mfn, vcpu,
+                                          update_flags);
+        else
+            UPDATE_ENTRY(l4, pl4e, ol4e, nl4e, mfn, vcpu, update_flags);
+    }
 
     put_page_from_l4e(ol4e, mfn, PTF_defer);
     return rc;
@@ -3277,7 +3339,7 @@ int new_guest_cr3(mfn_t mfn)
                           l4e_from_mfn(mfn,
                                        (_PAGE_PRESENT | _PAGE_RW |
                                         _PAGE_USER | _PAGE_ACCESSED)),
-                          gt_mfn, 0, curr);
+                          gt_mfn, 0, curr, NULL);
         unmap_domain_page(pl4e);
         switch ( rc )
         {
@@ -4115,14 +4177,14 @@ long do_mmu_update(
                 {
                 case PGT_l1_page_table:
                     rc = mod_l1_entry(va, l1e_from_intpte(req.val), mfn,
-                                      update_flags, v, pg_owner);
+                                      update_flags, v, pg_owner, NULL);
                     break;
 
                 case PGT_l2_page_table:
                     if ( unlikely(pg_owner != pt_owner) )
                         break;
                     rc = mod_l2_entry(va, l2e_from_intpte(req.val), mfn,
-                                      update_flags, v);
+                                      update_flags, v, NULL);
                     if ( !rc )
                         flush_linear_pt = true;
                     break;
@@ -4131,7 +4193,7 @@ long do_mmu_update(
                     if ( unlikely(pg_owner != pt_owner) )
                         break;
                     rc = mod_l3_entry(va, l3e_from_intpte(req.val), mfn,
-                                      update_flags, v);
+                                      update_flags, v, NULL);
                     if ( !rc )
                         flush_linear_pt = true;
                     break;
@@ -4140,7 +4202,7 @@ long do_mmu_update(
                     if ( unlikely(pg_owner != pt_owner) )
                         break;
                     rc = mod_l4_entry(va, l4e_from_intpte(req.val), mfn,
-                                      update_flags, v);
+                                      update_flags, v, NULL);
                     if ( !rc )
                         flush_linear_pt = true;
                     if ( !rc && pt_owner->arch.pv.xpti )
@@ -4480,7 +4542,8 @@ static int __do_update_va_mapping(
         goto out;
     }
 
-    rc = mod_l1_entry(pl1e, val, gl1mfn, MMU_NORMAL_PT_UPDATE, v, pg_owner);
+    rc = mod_l1_entry(pl1e, val, gl1mfn, MMU_NORMAL_PT_UPDATE, v, pg_owner,
+                      NULL);
 
     page_unlock(gl1pg);
     put_page(gl1pg);
-- 
2.52.0




 


Rackspace

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