From patchwork Thu Sep 14 12:58:37 2017 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Wei Liu X-Patchwork-Id: 9953017 Return-Path: Received: from mail.wl.linuxfoundation.org (pdx-wl-mail.web.codeaurora.org [172.30.200.125]) by pdx-korg-patchwork.web.codeaurora.org (Postfix) with ESMTP id 57134602C9 for ; Thu, 14 Sep 2017 13:01:43 +0000 (UTC) Received: from mail.wl.linuxfoundation.org (localhost [127.0.0.1]) by mail.wl.linuxfoundation.org (Postfix) with ESMTP id 225DE290BB for ; Thu, 14 Sep 2017 13:01:43 +0000 (UTC) Received: by mail.wl.linuxfoundation.org (Postfix, from userid 486) id 16F9E290D4; Thu, 14 Sep 2017 13:01:43 +0000 (UTC) X-Spam-Checker-Version: SpamAssassin 3.3.1 (2010-03-16) on pdx-wl-mail.web.codeaurora.org X-Spam-Level: X-Spam-Status: No, score=-4.2 required=2.0 tests=BAYES_00, RCVD_IN_DNSWL_MED autolearn=ham version=3.3.1 Received: from lists.xenproject.org (lists.xenproject.org [192.237.175.120]) (using TLSv1.2 with cipher AES128-GCM-SHA256 (128/128 bits)) (No client certificate requested) by mail.wl.linuxfoundation.org (Postfix) with ESMTPS id E6E4F290BB for ; Thu, 14 Sep 2017 13:01:41 +0000 (UTC) Received: from localhost ([127.0.0.1] helo=lists.xenproject.org) by lists.xenproject.org with esmtp (Exim 4.84_2) (envelope-from ) id 1dsTjR-0004Km-FD; Thu, 14 Sep 2017 12:59:01 +0000 Received: from mail6.bemta3.messagelabs.com ([195.245.230.39]) by lists.xenproject.org with esmtp (Exim 4.84_2) (envelope-from ) id 1dsTjQ-0004Jt-9u for xen-devel@lists.xenproject.org; Thu, 14 Sep 2017 12:59:00 +0000 Received: from [85.158.137.68] by server-2.bemta-3.messagelabs.com id CA/FF-02041-31D7AB95; Thu, 14 Sep 2017 12:58:59 +0000 X-Brightmail-Tracker: H4sIAAAAAAAAA+NgFlrKIsWRWlGSWpSXmKPExsXitHRDpK5Q7a5 IgyXLDSy+b5nM5MDocfjDFZYAxijWzLyk/IoE1oy3Bw4wF8yYzlhx5tZ2lgbGjbldjJwcEgL+ Elc2f2QDsdkElCV+dvaC2SICehJNB54zdjFycTALzGGUmDq3ixEkISxgL3GveSmYzSKgKjHj9 DMmEJtXwELi2/xuJoih8hK72i6ygticApYSXR9egsWFgGp6L+1nh7AVJDqmH4PqFZQ4OfMJC4 jNLCAhcfDFC+YJjLyzkKRmIUktYGRaxahRnFpUllqka2ygl1SUmZ5RkpuYmaNraGCsl5taXJy YnpqTmFSsl5yfu4kRGED1DAyMOxg7T/gdYpTkYFIS5d2ruzNSiC8pP6UyI7E4I76oNCe1+BCj BgeHQN+a1RcYpVjy8vNSlSR4dWt2RQoJFqWmp1akZeYAQxymVIKDR0mE1wckzVtckJhbnJkOk TrFaMxxYMKVP0wcHTfv/mESApskJc57oxqoVACkNKM0D24QLPYuMcpKCfMyMjAwCPEUpBblZp agyr9iFOdgVBLm/QMyhSczrwRu3yugU5iATjlzegfIKSWJCCmpBkaxnFnd5TK6Py54+T/XbMi ufNb5XbHZ/sCDLYllpuEPNVO7Mh+Wriu5/tSo4Uv97/TE7F/HOioufpuWGvDT1/O4sRbf/K2/ pz51+pZYs2fa+oMb/gc8SamMf/V+19TDtw/tFc9ZrNeh2D5rQ2hp5MMDMtskmCT9bvbeqwnif nd++8NDSuLsV+yUWIozEg21mIuKEwGdrVO+uAIAAA== X-Env-Sender: prvs=423b67c62=wei.liu2@citrix.com X-Msg-Ref: server-8.tower-31.messagelabs.com!1505393934!114872936!3 X-Originating-IP: [66.165.176.89] X-SpamReason: No, hits=0.0 required=7.0 tests=sa_preprocessor: VHJ1c3RlZCBJUDogNjYuMTY1LjE3Ni44OSA9PiAyMDMwMDc=\n, received_headers: No Received headers X-StarScan-Received: X-StarScan-Version: 9.4.45; banners=-,-,- X-VirusChecked: Checked Received: (qmail 16492 invoked from network); 14 Sep 2017 12:58:58 -0000 Received: from smtp.citrix.com (HELO SMTP.CITRIX.COM) (66.165.176.89) by server-8.tower-31.messagelabs.com with RC4-SHA encrypted SMTP; 14 Sep 2017 12:58:58 -0000 X-IronPort-AV: E=Sophos;i="5.42,393,1500940800"; d="scan'208";a="439751166" From: Wei Liu To: Xen-devel Date: Thu, 14 Sep 2017 13:58:37 +0100 Message-ID: <20170914125852.22129-9-wei.liu2@citrix.com> X-Mailer: git-send-email 2.11.0 In-Reply-To: <20170914125852.22129-1-wei.liu2@citrix.com> References: <20170914125852.22129-1-wei.liu2@citrix.com> MIME-Version: 1.0 Cc: George Dunlap , Andrew Cooper , Wei Liu , Jan Beulich Subject: [Xen-devel] [PATCH v5 08/23] x86/mm: split out pv grant table code X-BeenThere: xen-devel@lists.xen.org X-Mailman-Version: 2.1.18 Precedence: list List-Id: Xen developer discussion List-Unsubscribe: , List-Post: List-Help: List-Subscribe: , Errors-To: xen-devel-bounces@lists.xen.org Sender: "Xen-devel" X-Virus-Scanned: ClamAV using ClamSMTP Move the code to pv/grant_table.c. Nothing needs to be done with regard to headers. Signed-off-by: Wei Liu Acked-by: Jan Beulich --- xen/arch/x86/mm.c | 283 ------------------------------------ xen/arch/x86/pv/Makefile | 1 + xen/arch/x86/pv/grant_table.c | 327 ++++++++++++++++++++++++++++++++++++++++++ 3 files changed, 328 insertions(+), 283 deletions(-) create mode 100644 xen/arch/x86/pv/grant_table.c diff --git a/xen/arch/x86/mm.c b/xen/arch/x86/mm.c index 29d8e18819..69a47d87d6 100644 --- a/xen/arch/x86/mm.c +++ b/xen/arch/x86/mm.c @@ -3630,289 +3630,6 @@ long do_mmu_update( return rc; } -static unsigned int grant_to_pte_flags(unsigned int grant_flags, - unsigned int cache_flags) -{ - unsigned int pte_flags = - _PAGE_PRESENT | _PAGE_ACCESSED | _PAGE_DIRTY | _PAGE_GNTTAB | _PAGE_NX; - - if ( grant_flags & GNTMAP_application_map ) - pte_flags |= _PAGE_USER; - if ( !(grant_flags & GNTMAP_readonly) ) - pte_flags |= _PAGE_RW; - - pte_flags |= MASK_INSR((grant_flags >> _GNTMAP_guest_avail0), _PAGE_AVAIL); - pte_flags |= cacheattr_to_pte_flags(cache_flags >> 5); - - return pte_flags; -} - -int create_grant_pv_mapping(uint64_t addr, unsigned long frame, - unsigned int flags, unsigned int cache_flags) -{ - struct vcpu *curr = current; - struct domain *currd = curr->domain; - l1_pgentry_t nl1e, ol1e, *pl1e; - struct page_info *page; - mfn_t gl1mfn; - int rc = GNTST_general_error; - - nl1e = l1e_from_pfn(frame, grant_to_pte_flags(flags, cache_flags)); - nl1e = adjust_guest_l1e(nl1e, currd); - - /* - * The meaning of addr depends on GNTMAP_contains_pte. It is either a - * machine address of an L1e the guest has nominated to be altered, or a - * linear address we need to look up the appropriate L1e for. - */ - if ( flags & GNTMAP_contains_pte ) - { - /* addr must be suitably aligned, or we will corrupt adjacent ptes. */ - if ( !IS_ALIGNED(addr, sizeof(nl1e)) ) - { - gdprintk(XENLOG_WARNING, - "Misaligned PTE address %"PRIx64"\n", addr); - goto out; - } - - gl1mfn = _mfn(addr >> PAGE_SHIFT); - - if ( !get_page_from_mfn(gl1mfn, currd) ) - goto out; - - pl1e = map_domain_page(gl1mfn) + (addr & ~PAGE_MASK); - } - else - { - /* Guest trying to pass an out-of-range linear address? */ - if ( is_pv_32bit_domain(currd) && addr != (uint32_t)addr ) - goto out; - - pl1e = map_guest_l1e(addr, &gl1mfn); - - if ( !pl1e ) - { - gdprintk(XENLOG_WARNING, - "Could not find L1 PTE for linear address %"PRIx64"\n", - addr); - goto out; - } - - if ( !get_page_from_mfn(gl1mfn, currd) ) - goto out_unmap; - } - - page = mfn_to_page(gl1mfn); - if ( !page_lock(page) ) - goto out_put; - - if ( (page->u.inuse.type_info & PGT_type_mask) != PGT_l1_page_table ) - goto out_unlock; - - ol1e = *pl1e; - if ( UPDATE_ENTRY(l1, pl1e, ol1e, nl1e, mfn_x(gl1mfn), curr, 0) ) - rc = GNTST_okay; - - out_unlock: - page_unlock(page); - out_put: - put_page(page); - out_unmap: - unmap_domain_page(pl1e); - - if ( rc == GNTST_okay ) - put_page_from_l1e(ol1e, currd); - - out: - return rc; -} - -/* - * This exists soley for implementing GNTABOP_unmap_and_replace, the ABI of - * which is bizarre. This GNTTABOP isn't used any more, but was used by - * classic-xen kernels and PVOps Linux before the M2P_OVERRIDE infrastructure - * was replaced with something which actually worked. - * - * Look up the L1e mapping linear, and zap it. Return the L1e via *out. - * Returns a boolean indicating success. If success, the caller is - * responsible for calling put_page_from_l1e(). - */ -static bool steal_linear_address(unsigned long linear, l1_pgentry_t *out) -{ - struct vcpu *curr = current; - struct domain *currd = curr->domain; - l1_pgentry_t *pl1e, ol1e; - struct page_info *page; - mfn_t gl1mfn; - bool okay = false; - - ASSERT(is_pv_domain(currd)); - - pl1e = map_guest_l1e(linear, &gl1mfn); - if ( !pl1e ) - { - gdprintk(XENLOG_WARNING, - "Could not find L1 PTE for linear %"PRIx64"\n", linear); - goto out; - } - - if ( !get_page_from_mfn(gl1mfn, currd) ) - goto out_unmap; - - page = mfn_to_page(gl1mfn); - if ( !page_lock(page) ) - goto out_put; - - if ( (page->u.inuse.type_info & PGT_type_mask) != PGT_l1_page_table ) - goto out_unlock; - - ol1e = *pl1e; - okay = UPDATE_ENTRY(l1, pl1e, ol1e, l1e_empty(), mfn_x(gl1mfn), curr, 0); - - out_unlock: - page_unlock(page); - out_put: - put_page(page); - out_unmap: - unmap_domain_page(pl1e); - - if ( okay ) - *out = ol1e; - - out: - return okay; -} - -/* - * Passing a new_addr of zero is taken to mean destroy. Passing a non-zero - * new_addr has only ever been available via GNTABOP_unmap_and_replace, and - * only when !(flags & GNTMAP_contains_pte). - */ -int replace_grant_pv_mapping(uint64_t addr, unsigned long frame, - uint64_t new_addr, unsigned int flags) -{ - struct vcpu *curr = current; - struct domain *currd = curr->domain; - l1_pgentry_t nl1e = l1e_empty(), ol1e, *pl1e; - struct page_info *page; - mfn_t gl1mfn; - int rc = GNTST_general_error; - unsigned int grant_pte_flags = grant_to_pte_flags(flags, 0); - - /* - * On top of the explicit settings done by create_grant_pv_mapping() - * also open-code relevant parts of adjust_guest_l1e(). Don't mirror - * available and cachability flags, though. - */ - if ( !is_pv_32bit_domain(currd) ) - grant_pte_flags |= (grant_pte_flags & _PAGE_USER) - ? _PAGE_GLOBAL - : _PAGE_GUEST_KERNEL | _PAGE_USER; - - /* - * addr comes from Xen's active_entry tracking, and was used successfully - * to create a grant. - * - * The meaning of addr depends on GNTMAP_contains_pte. It is either a - * machine address of an L1e the guest has nominated to be altered, or a - * linear address we need to look up the appropriate L1e for. - */ - if ( flags & GNTMAP_contains_pte ) - { - /* Replace not available in this addressing mode. */ - if ( new_addr ) - goto out; - - /* Sanity check that we won't clobber the pagetable. */ - if ( !IS_ALIGNED(addr, sizeof(nl1e)) ) - { - ASSERT_UNREACHABLE(); - goto out; - } - - gl1mfn = _mfn(addr >> PAGE_SHIFT); - - if ( !get_page_from_mfn(gl1mfn, currd) ) - goto out; - - pl1e = map_domain_page(gl1mfn) + (addr & ~PAGE_MASK); - } - else - { - if ( is_pv_32bit_domain(currd) ) - { - if ( addr != (uint32_t)addr ) - { - ASSERT_UNREACHABLE(); - goto out; - } - - /* Guest trying to pass an out-of-range linear address? */ - if ( new_addr != (uint32_t)new_addr ) - goto out; - } - - if ( new_addr && !steal_linear_address(new_addr, &nl1e) ) - goto out; - - pl1e = map_guest_l1e(addr, &gl1mfn); - - if ( !pl1e ) - goto out; - - if ( !get_page_from_mfn(gl1mfn, currd) ) - goto out_unmap; - } - - page = mfn_to_page(gl1mfn); - - if ( !page_lock(page) ) - goto out_put; - - if ( (page->u.inuse.type_info & PGT_type_mask) != PGT_l1_page_table ) - goto out_unlock; - - ol1e = *pl1e; - - /* - * Check that the address supplied is actually mapped to frame (with - * appropriate permissions). - */ - if ( unlikely(l1e_get_pfn(ol1e) != frame) || - unlikely((l1e_get_flags(ol1e) ^ grant_pte_flags) & - (_PAGE_PRESENT | _PAGE_RW)) ) - { - gdprintk(XENLOG_ERR, - "PTE %"PRIpte" for %"PRIx64" doesn't match grant (%"PRIpte")\n", - l1e_get_intpte(ol1e), addr, - l1e_get_intpte(l1e_from_pfn(frame, grant_pte_flags))); - goto out_unlock; - } - - if ( unlikely((l1e_get_flags(ol1e) ^ grant_pte_flags) & - ~(_PAGE_AVAIL | PAGE_CACHE_ATTRS)) ) - gdprintk(XENLOG_WARNING, - "PTE flags %x for %"PRIx64" don't match grant (%x)\n", - l1e_get_flags(ol1e), addr, grant_pte_flags); - - if ( UPDATE_ENTRY(l1, pl1e, ol1e, nl1e, mfn_x(gl1mfn), curr, 0) ) - rc = GNTST_okay; - - out_unlock: - page_unlock(page); - out_put: - put_page(page); - out_unmap: - unmap_domain_page(pl1e); - - out: - /* If there was an error, we are still responsible for the stolen pte. */ - if ( rc ) - put_page_from_l1e(nl1e, currd); - - return rc; -} - int donate_page( struct domain *d, struct page_info *page, unsigned int memflags) { diff --git a/xen/arch/x86/pv/Makefile b/xen/arch/x86/pv/Makefile index d4fcc2ab94..a692ee6432 100644 --- a/xen/arch/x86/pv/Makefile +++ b/xen/arch/x86/pv/Makefile @@ -4,6 +4,7 @@ obj-y += emulate.o obj-y += emul-gate-op.o obj-y += emul-inv-op.o obj-y += emul-priv-op.o +obj-y += grant_table.o obj-y += hypercall.o obj-y += iret.o obj-y += misc-hypercalls.o diff --git a/xen/arch/x86/pv/grant_table.c b/xen/arch/x86/pv/grant_table.c new file mode 100644 index 0000000000..81988a3b57 --- /dev/null +++ b/xen/arch/x86/pv/grant_table.c @@ -0,0 +1,327 @@ +/* + * pv/grant_table.c + * + * Grant table interfaces for PV guests + * + * Copyright (C) 2017 Wei Liu + * + * This program is free software; you can redistribute it and/or + * modify it under the terms and conditions of the GNU General Public + * License, version 2, as published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public + * License along with this program; If not, see . + */ + +#include + +#include + +#include +#include + +#include "mm.h" + +/* Override macros from asm/page.h to make them work with mfn_t */ +#undef mfn_to_page +#define mfn_to_page(mfn) __mfn_to_page(mfn_x(mfn)) +#undef page_to_mfn +#define page_to_mfn(pg) _mfn(__page_to_mfn(pg)) + +static unsigned int grant_to_pte_flags(unsigned int grant_flags, + unsigned int cache_flags) +{ + unsigned int pte_flags = + _PAGE_PRESENT | _PAGE_ACCESSED | _PAGE_DIRTY | _PAGE_GNTTAB | _PAGE_NX; + + if ( grant_flags & GNTMAP_application_map ) + pte_flags |= _PAGE_USER; + if ( !(grant_flags & GNTMAP_readonly) ) + pte_flags |= _PAGE_RW; + + pte_flags |= MASK_INSR((grant_flags >> _GNTMAP_guest_avail0), _PAGE_AVAIL); + pte_flags |= cacheattr_to_pte_flags(cache_flags >> 5); + + return pte_flags; +} + +int create_grant_pv_mapping(uint64_t addr, unsigned long frame, + unsigned int flags, unsigned int cache_flags) +{ + struct vcpu *curr = current; + struct domain *currd = curr->domain; + l1_pgentry_t nl1e, ol1e, *pl1e; + struct page_info *page; + mfn_t gl1mfn; + int rc = GNTST_general_error; + + nl1e = l1e_from_pfn(frame, grant_to_pte_flags(flags, cache_flags)); + nl1e = adjust_guest_l1e(nl1e, currd); + + /* + * The meaning of addr depends on GNTMAP_contains_pte. It is either a + * machine address of an L1e the guest has nominated to be altered, or a + * linear address we need to look up the appropriate L1e for. + */ + if ( flags & GNTMAP_contains_pte ) + { + /* addr must be suitably aligned, or we will corrupt adjacent ptes. */ + if ( !IS_ALIGNED(addr, sizeof(nl1e)) ) + { + gdprintk(XENLOG_WARNING, + "Misaligned PTE address %"PRIx64"\n", addr); + goto out; + } + + gl1mfn = _mfn(addr >> PAGE_SHIFT); + + if ( !get_page_from_mfn(gl1mfn, currd) ) + goto out; + + pl1e = map_domain_page(gl1mfn) + (addr & ~PAGE_MASK); + } + else + { + /* Guest trying to pass an out-of-range linear address? */ + if ( is_pv_32bit_domain(currd) && addr != (uint32_t)addr ) + goto out; + + pl1e = map_guest_l1e(addr, &gl1mfn); + + if ( !pl1e ) + { + gdprintk(XENLOG_WARNING, + "Could not find L1 PTE for linear address %"PRIx64"\n", + addr); + goto out; + } + + if ( !get_page_from_mfn(gl1mfn, currd) ) + goto out_unmap; + } + + page = mfn_to_page(gl1mfn); + if ( !page_lock(page) ) + goto out_put; + + if ( (page->u.inuse.type_info & PGT_type_mask) != PGT_l1_page_table ) + goto out_unlock; + + ol1e = *pl1e; + if ( UPDATE_ENTRY(l1, pl1e, ol1e, nl1e, mfn_x(gl1mfn), curr, 0) ) + rc = GNTST_okay; + + out_unlock: + page_unlock(page); + out_put: + put_page(page); + out_unmap: + unmap_domain_page(pl1e); + + if ( rc == GNTST_okay ) + put_page_from_l1e(ol1e, currd); + + out: + return rc; +} + +/* + * This exists soley for implementing GNTABOP_unmap_and_replace, the ABI of + * which is bizarre. This GNTTABOP isn't used any more, but was used by + * classic-xen kernels and PVOps Linux before the M2P_OVERRIDE infrastructure + * was replaced with something which actually worked. + * + * Look up the L1e mapping linear, and zap it. Return the L1e via *out. + * Returns a boolean indicating success. If success, the caller is + * responsible for calling put_page_from_l1e(). + */ +static bool steal_linear_address(unsigned long linear, l1_pgentry_t *out) +{ + struct vcpu *curr = current; + struct domain *currd = curr->domain; + l1_pgentry_t *pl1e, ol1e; + struct page_info *page; + mfn_t gl1mfn; + bool okay = false; + + ASSERT(is_pv_domain(currd)); + + pl1e = map_guest_l1e(linear, &gl1mfn); + if ( !pl1e ) + { + gdprintk(XENLOG_WARNING, + "Could not find L1 PTE for linear %"PRIx64"\n", linear); + goto out; + } + + if ( !get_page_from_mfn(gl1mfn, currd) ) + goto out_unmap; + + page = mfn_to_page(gl1mfn); + if ( !page_lock(page) ) + goto out_put; + + if ( (page->u.inuse.type_info & PGT_type_mask) != PGT_l1_page_table ) + goto out_unlock; + + ol1e = *pl1e; + okay = UPDATE_ENTRY(l1, pl1e, ol1e, l1e_empty(), mfn_x(gl1mfn), curr, 0); + + out_unlock: + page_unlock(page); + out_put: + put_page(page); + out_unmap: + unmap_domain_page(pl1e); + + if ( okay ) + *out = ol1e; + + out: + return okay; +} + +/* + * Passing a new_addr of zero is taken to mean destroy. Passing a non-zero + * new_addr has only ever been available via GNTABOP_unmap_and_replace, and + * only when !(flags & GNTMAP_contains_pte). + */ +int replace_grant_pv_mapping(uint64_t addr, unsigned long frame, + uint64_t new_addr, unsigned int flags) +{ + struct vcpu *curr = current; + struct domain *currd = curr->domain; + l1_pgentry_t nl1e = l1e_empty(), ol1e, *pl1e; + struct page_info *page; + mfn_t gl1mfn; + int rc = GNTST_general_error; + unsigned int grant_pte_flags = grant_to_pte_flags(flags, 0); + + /* + * On top of the explicit settings done by create_grant_pv_mapping() + * also open-code relevant parts of adjust_guest_l1e(). Don't mirror + * available and cachability flags, though. + */ + if ( !is_pv_32bit_domain(currd) ) + grant_pte_flags |= (grant_pte_flags & _PAGE_USER) + ? _PAGE_GLOBAL + : _PAGE_GUEST_KERNEL | _PAGE_USER; + + /* + * addr comes from Xen's active_entry tracking, and was used successfully + * to create a grant. + * + * The meaning of addr depends on GNTMAP_contains_pte. It is either a + * machine address of an L1e the guest has nominated to be altered, or a + * linear address we need to look up the appropriate L1e for. + */ + if ( flags & GNTMAP_contains_pte ) + { + /* Replace not available in this addressing mode. */ + if ( new_addr ) + goto out; + + /* Sanity check that we won't clobber the pagetable. */ + if ( !IS_ALIGNED(addr, sizeof(nl1e)) ) + { + ASSERT_UNREACHABLE(); + goto out; + } + + gl1mfn = _mfn(addr >> PAGE_SHIFT); + + if ( !get_page_from_mfn(gl1mfn, currd) ) + goto out; + + pl1e = map_domain_page(gl1mfn) + (addr & ~PAGE_MASK); + } + else + { + if ( is_pv_32bit_domain(currd) ) + { + if ( addr != (uint32_t)addr ) + { + ASSERT_UNREACHABLE(); + goto out; + } + + /* Guest trying to pass an out-of-range linear address? */ + if ( new_addr != (uint32_t)new_addr ) + goto out; + } + + if ( new_addr && !steal_linear_address(new_addr, &nl1e) ) + goto out; + + pl1e = map_guest_l1e(addr, &gl1mfn); + + if ( !pl1e ) + goto out; + + if ( !get_page_from_mfn(gl1mfn, currd) ) + goto out_unmap; + } + + page = mfn_to_page(gl1mfn); + + if ( !page_lock(page) ) + goto out_put; + + if ( (page->u.inuse.type_info & PGT_type_mask) != PGT_l1_page_table ) + goto out_unlock; + + ol1e = *pl1e; + + /* + * Check that the address supplied is actually mapped to frame (with + * appropriate permissions). + */ + if ( unlikely(l1e_get_pfn(ol1e) != frame) || + unlikely((l1e_get_flags(ol1e) ^ grant_pte_flags) & + (_PAGE_PRESENT | _PAGE_RW)) ) + { + gdprintk(XENLOG_ERR, + "PTE %"PRIpte" for %"PRIx64" doesn't match grant (%"PRIpte")\n", + l1e_get_intpte(ol1e), addr, + l1e_get_intpte(l1e_from_pfn(frame, grant_pte_flags))); + goto out_unlock; + } + + if ( unlikely((l1e_get_flags(ol1e) ^ grant_pte_flags) & + ~(_PAGE_AVAIL | PAGE_CACHE_ATTRS)) ) + gdprintk(XENLOG_WARNING, + "PTE flags %x for %"PRIx64" don't match grant (%x)\n", + l1e_get_flags(ol1e), addr, grant_pte_flags); + + if ( UPDATE_ENTRY(l1, pl1e, ol1e, nl1e, mfn_x(gl1mfn), curr, 0) ) + rc = GNTST_okay; + + out_unlock: + page_unlock(page); + out_put: + put_page(page); + out_unmap: + unmap_domain_page(pl1e); + + out: + /* If there was an error, we are still responsible for the stolen pte. */ + if ( rc ) + put_page_from_l1e(nl1e, currd); + + return rc; +} + +/* + * Local variables: + * mode: C + * c-file-style: "BSD" + * c-basic-offset: 4 + * tab-width: 4 + * indent-tabs-mode: nil + * End: + */