[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