[PATCH 3/4] x86: extend do_mmu_update() to support returning the old PTE value

Kevin Lampis <[email protected]>
Newsgroups org.xenproject.lists.xen-devel
Message-ID <[email protected]>
A new parameter write_back_old when set will return the old PTE value.

- The new PTE value in req.val must be 0, this is for clearing only.

- The PRESERVE_AD flag is rejected with -EINVAL because preserving
  Accessed/Dirty bits into a zero'ed PTE doesn't make sense.

- Only l1 PTEs are supported because they are the most frequent and have the
  biggest performance impact.

- The old PTE value is passed back to the guest through the req.val field

If the write_back_old flag is not set then the old behavior is preserved
  do_mmu_update -> mod_l1_entry -> UPDATE_ENTRY -> paging_write_guest_entry

The new get_and_clear call chain looks like this
  do_mmu_update -> mod_l1_entry -> update_intpte -> paging_cmpxchg_guest_entry

Signed-off-by: Kevin Lampis <[email protected]>
---
 xen/arch/x86/mm.c | 62 ++++++++++++++++++++++++++++++++++++++++++++---
 1 file changed, 58 insertions(+), 4 deletions(-)

diff --git a/xen/arch/x86/mm.c b/xen/arch/x86/mm.c
index 500549c8e036..278b992aca5c 100644
--- a/xen/arch/x86/mm.c
+++ b/xen/arch/x86/mm.c
@@ -3988,11 +3988,12 @@ long do_mmuext_op(
     return rc;
 }
 
-long do_mmu_update(
+static long __do_mmu_update(
     XEN_GUEST_HANDLE_PARAM(mmu_update_t) ureqs,
     unsigned int count,
     XEN_GUEST_HANDLE_PARAM(uint) pdone,
-    unsigned int foreigndom)
+    unsigned int foreigndom,
+    bool write_back_old)
 {
     struct mmu_update req;
     void *va = NULL;
@@ -4144,13 +4145,41 @@ long do_mmu_update(
                 switch ( page->u.inuse.type_info & PGT_type_mask )
                 {
                 case PGT_l1_page_table:
-                    rc = mod_l1_entry(va, l1e_from_intpte(req.val), mfn,
-                                      cmd, v, pg_owner, NULL);
+                {
+                    if ( !write_back_old )
+                        rc = mod_l1_entry(va, l1e_from_intpte(req.val), mfn,
+                                          cmd, v, pg_owner, NULL);
+                    else
+                    {
+                        l1_pgentry_t ol1e;
+                        if ( unlikely(req.val != 0 ||
+                                      cmd == MMU_PT_UPDATE_PRESERVE_AD) )
+                        {
+                            rc = -EINVAL;
+                            break;
+                        }
+
+                        rc = mod_l1_entry(va, l1e_from_intpte(req.val), mfn,
+                                          cmd, v, pg_owner, &ol1e);
+
+                        if ( !rc )
+                        {
+                            req.val = ol1e.l1;
+                            if ( unlikely(copy_to_guest(ureqs, &req, 1)) )
+                                rc = -EFAULT;
+                        }
+                    }
                     break;
+                }
 
                 case PGT_l2_page_table:
                     if ( unlikely(pg_owner != pt_owner) )
                         break;
+                    if ( unlikely(write_back_old) )
+                    {
+                        rc = -EINVAL;
+                        break;
+                    }
                     rc = mod_l2_entry(va, l2e_from_intpte(req.val), mfn,
                                       cmd == MMU_PT_UPDATE_PRESERVE_AD, v);
                     if ( !rc )
@@ -4160,6 +4189,11 @@ long do_mmu_update(
                 case PGT_l3_page_table:
                     if ( unlikely(pg_owner != pt_owner) )
                         break;
+                    if ( unlikely(write_back_old) )
+                    {
+                        rc = -EINVAL;
+                        break;
+                    }
                     rc = mod_l3_entry(va, l3e_from_intpte(req.val), mfn,
                                       cmd == MMU_PT_UPDATE_PRESERVE_AD, v);
                     if ( !rc )
@@ -4169,6 +4203,11 @@ long do_mmu_update(
                 case PGT_l4_page_table:
                     if ( unlikely(pg_owner != pt_owner) )
                         break;
+                    if ( unlikely(write_back_old) )
+                    {
+                        rc = -EINVAL;
+                        break;
+                    }
                     rc = mod_l4_entry(va, l4e_from_intpte(req.val), mfn,
                                       cmd == MMU_PT_UPDATE_PRESERVE_AD, v);
                     if ( !rc )
@@ -4198,6 +4237,11 @@ long do_mmu_update(
                     break;
 
                 case PGT_writable_page:
+                    if ( unlikely(write_back_old) )
+                    {
+                        rc = -EINVAL;
+                        break;
+                    }
                     perfc_incr(writable_mmu_updates);
                     paging_write_guest_entry(v, va, req.val, mfn);
                     rc = 0;
@@ -4366,6 +4410,16 @@ long do_mmu_update(
 
     return rc;
 }
+
+long do_mmu_update(
+    XEN_GUEST_HANDLE_PARAM(mmu_update_t) ureqs,
+    unsigned int count,
+    XEN_GUEST_HANDLE_PARAM(uint) pdone,
+    unsigned int foreigndom)
+{
+    return __do_mmu_update(ureqs, count, pdone, foreigndom, false);
+}
+
 #endif /* CONFIG_PV */
 
 /*
-- 
2.52.0
lmpx.com only provides a reader for public news (NNTP) servers. It is not affiliated with the servers or forums shown here and is not responsible for the content of articles, which is written by their respective authors.