|
[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index] [PATCH 3/4] x86: extend do_mmu_update() to support returning the old PTE value
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 <kevin.lampis@xxxxxxxxxx>
---
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
|
![]() |
Lists.xenproject.org is hosted with RackSpace, monitoring our |