From patchwork Thu Jul 20 16:04:20 2017 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Wei Liu X-Patchwork-Id: 9855335 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 B2FF560393 for ; Thu, 20 Jul 2017 16:18:48 +0000 (UTC) Received: from mail.wl.linuxfoundation.org (localhost [127.0.0.1]) by mail.wl.linuxfoundation.org (Postfix) with ESMTP id A213B286E6 for ; Thu, 20 Jul 2017 16:18:48 +0000 (UTC) Received: by mail.wl.linuxfoundation.org (Postfix, from userid 486) id 96ED02870D; Thu, 20 Jul 2017 16:18:48 +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 878EC286E6 for ; Thu, 20 Jul 2017 16:18:47 +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 1dYE7q-0002rW-M6; Thu, 20 Jul 2017 16:16:30 +0000 Received: from mail6.bemta5.messagelabs.com ([195.245.231.135]) by lists.xenproject.org with esmtp (Exim 4.84_2) (envelope-from ) id 1dYE7p-0002pU-8x for xen-devel@lists.xenproject.org; Thu, 20 Jul 2017 16:16:29 +0000 Received: from [85.158.139.211] by server-4.bemta-5.messagelabs.com id F4/D9-02184-C57D0795; Thu, 20 Jul 2017 16:16:28 +0000 X-Brightmail-Tracker: H4sIAAAAAAAAA+NgFlrKIsWRWlGSWpSXmKPExsXitHSDvW709YJ Ig8P39C2+b5nM5MDocfjDFZYAxijWzLyk/IoE1oyFW6cxF5xbxFixZdt1pgbGm2VdjJwcEgL+ Eldm7GEGsdkElCV+dvaygdgiAnoSTQeeM3YxcnEwC8xhlJg6t4sRJCEsYC+xuLGXBcRmEVCVW HuziR3E5hWwkNiy+A07xFB5iV1tF1lBbE6g+JpfX5lAbCEBc4nN++ezQNgKEh3TjzFB9ApKnJ z5BCzOLCAhcfDFC+YJjLyzkKRmIUktYGRaxahRnFpUllqka2Sgl1SUmZ5RkpuYmaNraGCql5t aXJyYnpqTmFSsl5yfu4kRGED1DAyMOxgbZ/sdYpTkYFIS5WUJLIgU4kvKT6nMSCzOiC8qzUkt PsSowcEh0Ldm9QVGKZa8/LxUJQlehmtAdYJFqempFWmZOcAQhymV4OBREuEVBEnzFhck5hZnp kOkTjEacyzo2fCFiePVhP/fmITAJkmJ89qAlAqAlGaU5sENgsXeJUZZKWFeRgYGBiGegtSi3M wSVPlXjOIcjErCvPEgU3gy80rg9r0COoUJ6JRHbmCnlCQipKQaGP0LTXxStdcwXH4e9z3X+9p +03tfffYvf7zh6rH5Yt5c1inTVOT4t2t1mwVd3+0vsnlm+3Uz710cl1Wvvpj2+hdLwOnVMny7 9VOyWxkyq1f17LDuu/L6RJKWfEWG4MJf96dPFKhYn9UV5Pir9NBNHXajN+f/t8qnPI4y1Phn8 kpDetPOuVdFtimxFGckGmoxFxUnAgCVBFIQuAIAAA== X-Env-Sender: prvs=3674d857a=wei.liu2@citrix.com X-Msg-Ref: server-4.tower-206.messagelabs.com!1500567381!103772445!3 X-Originating-IP: [66.165.176.63] X-SpamReason: No, hits=0.0 required=7.0 tests=sa_preprocessor: VHJ1c3RlZCBJUDogNjYuMTY1LjE3Ni42MyA9PiAzMDYwNDg=\n, received_headers: No Received headers X-StarScan-Received: X-StarScan-Version: 9.4.25; banners=-,-,- X-VirusChecked: Checked Received: (qmail 64311 invoked from network); 20 Jul 2017 16:16:27 -0000 Received: from smtp02.citrix.com (HELO SMTP02.CITRIX.COM) (66.165.176.63) by server-4.tower-206.messagelabs.com with RC4-SHA encrypted SMTP; 20 Jul 2017 16:16:27 -0000 X-IronPort-AV: E=Sophos;i="5.40,384,1496102400"; d="scan'208";a="440670506" From: Wei Liu To: Xen-devel Date: Thu, 20 Jul 2017 17:04:20 +0100 Message-ID: <20170720160426.2343-16-wei.liu2@citrix.com> X-Mailer: git-send-email 2.11.0 In-Reply-To: <20170720160426.2343-1-wei.liu2@citrix.com> References: <20170720160426.2343-1-wei.liu2@citrix.com> MIME-Version: 1.0 Cc: George Dunlap , Andrew Cooper , Wei Liu , Jan Beulich Subject: [Xen-devel] [PATCH v3 15/21] 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 Signed-off-by: Wei Liu --- xen/arch/x86/mm.c | 349 -------------------------------------- xen/arch/x86/pv/Makefile | 1 + xen/arch/x86/pv/grant_table.c | 386 ++++++++++++++++++++++++++++++++++++++++++ 3 files changed, 387 insertions(+), 349 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 5a9cc7173a..897db4cfb9 100644 --- a/xen/arch/x86/mm.c +++ b/xen/arch/x86/mm.c @@ -3844,355 +3844,6 @@ long do_mmu_update( } -static int create_grant_pte_mapping( - uint64_t pte_addr, l1_pgentry_t nl1e, struct vcpu *v) -{ - int rc = GNTST_okay; - void *va; - unsigned long gmfn, mfn; - struct page_info *page; - l1_pgentry_t ol1e; - struct domain *d = v->domain; - - adjust_guest_l1e(nl1e, d); - - gmfn = pte_addr >> PAGE_SHIFT; - page = get_page_from_gfn(d, gmfn, NULL, P2M_ALLOC); - - if ( unlikely(!page) ) - { - gdprintk(XENLOG_WARNING, "Could not get page for normal update\n"); - return GNTST_general_error; - } - - mfn = page_to_mfn(page); - va = map_domain_page(_mfn(mfn)); - va = (void *)((unsigned long)va + ((unsigned long)pte_addr & ~PAGE_MASK)); - - if ( !page_lock(page) ) - { - rc = GNTST_general_error; - goto failed; - } - - if ( (page->u.inuse.type_info & PGT_type_mask) != PGT_l1_page_table ) - { - page_unlock(page); - rc = GNTST_general_error; - goto failed; - } - - ol1e = *(l1_pgentry_t *)va; - if ( !UPDATE_ENTRY(l1, (l1_pgentry_t *)va, ol1e, nl1e, mfn, v, 0) ) - { - page_unlock(page); - rc = GNTST_general_error; - goto failed; - } - - page_unlock(page); - - put_page_from_l1e(ol1e, d); - - failed: - unmap_domain_page(va); - put_page(page); - - return rc; -} - -static int destroy_grant_pte_mapping( - uint64_t addr, unsigned long frame, struct domain *d) -{ - int rc = GNTST_okay; - void *va; - unsigned long gmfn, mfn; - struct page_info *page; - l1_pgentry_t ol1e; - - gmfn = addr >> PAGE_SHIFT; - page = get_page_from_gfn(d, gmfn, NULL, P2M_ALLOC); - - if ( unlikely(!page) ) - { - gdprintk(XENLOG_WARNING, "Could not get page for normal update\n"); - return GNTST_general_error; - } - - mfn = page_to_mfn(page); - va = map_domain_page(_mfn(mfn)); - va = (void *)((unsigned long)va + ((unsigned long)addr & ~PAGE_MASK)); - - if ( !page_lock(page) ) - { - rc = GNTST_general_error; - goto failed; - } - - if ( (page->u.inuse.type_info & PGT_type_mask) != PGT_l1_page_table ) - { - page_unlock(page); - rc = GNTST_general_error; - goto failed; - } - - ol1e = *(l1_pgentry_t *)va; - - /* Check that the virtual address supplied is actually mapped to frame. */ - if ( unlikely(l1e_get_pfn(ol1e) != frame) ) - { - page_unlock(page); - gdprintk(XENLOG_WARNING, - "PTE entry %"PRIpte" for address %"PRIx64" doesn't match frame %lx\n", - l1e_get_intpte(ol1e), addr, frame); - rc = GNTST_general_error; - goto failed; - } - - /* Delete pagetable entry. */ - if ( unlikely(!UPDATE_ENTRY(l1, - (l1_pgentry_t *)va, ol1e, l1e_empty(), mfn, - d->vcpu[0] /* Change if we go to per-vcpu shadows. */, - 0)) ) - { - page_unlock(page); - gdprintk(XENLOG_WARNING, "Cannot delete PTE entry at %p\n", va); - rc = GNTST_general_error; - goto failed; - } - - page_unlock(page); - - failed: - unmap_domain_page(va); - put_page(page); - return rc; -} - - -static int create_grant_va_mapping( - unsigned long va, l1_pgentry_t nl1e, struct vcpu *v) -{ - l1_pgentry_t *pl1e, ol1e; - struct domain *d = v->domain; - unsigned long gl1mfn; - struct page_info *l1pg; - int okay; - - adjust_guest_l1e(nl1e, d); - - pl1e = pv_map_guest_l1e(va, &gl1mfn); - if ( !pl1e ) - { - gdprintk(XENLOG_WARNING, "Could not find L1 PTE for address %lx\n", va); - return GNTST_general_error; - } - - if ( get_page_from_pagenr(gl1mfn, current->domain) ) - { - pv_unmap_guest_l1e(pl1e); - return GNTST_general_error; - } - - l1pg = mfn_to_page(gl1mfn); - if ( !page_lock(l1pg) ) - { - put_page(l1pg); - pv_unmap_guest_l1e(pl1e); - return GNTST_general_error; - } - - if ( (l1pg->u.inuse.type_info & PGT_type_mask) != PGT_l1_page_table ) - { - page_unlock(l1pg); - put_page(l1pg); - pv_unmap_guest_l1e(pl1e); - return GNTST_general_error; - } - - ol1e = *pl1e; - okay = UPDATE_ENTRY(l1, pl1e, ol1e, nl1e, gl1mfn, v, 0); - - page_unlock(l1pg); - put_page(l1pg); - pv_unmap_guest_l1e(pl1e); - - if ( okay ) - put_page_from_l1e(ol1e, d); - - return okay ? GNTST_okay : GNTST_general_error; -} - -static int replace_grant_va_mapping( - unsigned long addr, unsigned long frame, l1_pgentry_t nl1e, struct vcpu *v) -{ - l1_pgentry_t *pl1e, ol1e; - unsigned long gl1mfn; - struct page_info *l1pg; - int rc = 0; - - pl1e = pv_map_guest_l1e(addr, &gl1mfn); - if ( !pl1e ) - { - gdprintk(XENLOG_WARNING, "Could not find L1 PTE for address %lx\n", addr); - return GNTST_general_error; - } - - if ( get_page_from_pagenr(gl1mfn, current->domain) ) - { - rc = GNTST_general_error; - goto out; - } - - l1pg = mfn_to_page(gl1mfn); - if ( !page_lock(l1pg) ) - { - rc = GNTST_general_error; - put_page(l1pg); - goto out; - } - - if ( (l1pg->u.inuse.type_info & PGT_type_mask) != PGT_l1_page_table ) - { - rc = GNTST_general_error; - goto unlock_and_out; - } - - ol1e = *pl1e; - - /* Check that the virtual address supplied is actually mapped to frame. */ - if ( unlikely(l1e_get_pfn(ol1e) != frame) ) - { - gdprintk(XENLOG_WARNING, - "PTE entry %lx for address %lx doesn't match frame %lx\n", - l1e_get_pfn(ol1e), addr, frame); - rc = GNTST_general_error; - goto unlock_and_out; - } - - /* Delete pagetable entry. */ - if ( unlikely(!UPDATE_ENTRY(l1, pl1e, ol1e, nl1e, gl1mfn, v, 0)) ) - { - gdprintk(XENLOG_WARNING, "Cannot delete PTE entry at %p\n", pl1e); - rc = GNTST_general_error; - goto unlock_and_out; - } - - unlock_and_out: - page_unlock(l1pg); - put_page(l1pg); - out: - pv_unmap_guest_l1e(pl1e); - return rc; -} - -static int destroy_grant_va_mapping( - unsigned long addr, unsigned long frame, struct vcpu *v) -{ - return replace_grant_va_mapping(addr, frame, l1e_empty(), v); -} - -int create_grant_pv_mapping(uint64_t addr, unsigned long frame, - unsigned int flags, unsigned int cache_flags) -{ - l1_pgentry_t pte; - uint32_t grant_pte_flags; - - grant_pte_flags = - _PAGE_PRESENT | _PAGE_ACCESSED | _PAGE_DIRTY | _PAGE_GNTTAB; - if ( cpu_has_nx ) - grant_pte_flags |= _PAGE_NX_BIT; - - pte = l1e_from_pfn(frame, grant_pte_flags); - if ( (flags & GNTMAP_application_map) ) - l1e_add_flags(pte,_PAGE_USER); - if ( !(flags & GNTMAP_readonly) ) - l1e_add_flags(pte,_PAGE_RW); - - l1e_add_flags(pte, - ((flags >> _GNTMAP_guest_avail0) * _PAGE_AVAIL0) - & _PAGE_AVAIL); - - l1e_add_flags(pte, cacheattr_to_pte_flags(cache_flags >> 5)); - - if ( flags & GNTMAP_contains_pte ) - return create_grant_pte_mapping(addr, pte, current); - return create_grant_va_mapping(addr, pte, current); -} - -int replace_grant_pv_mapping(uint64_t addr, unsigned long frame, - uint64_t new_addr, unsigned int flags) -{ - struct vcpu *curr = current; - l1_pgentry_t *pl1e, ol1e; - unsigned long gl1mfn; - struct page_info *l1pg; - int rc; - - if ( flags & GNTMAP_contains_pte ) - { - if ( !new_addr ) - return destroy_grant_pte_mapping(addr, frame, curr->domain); - - return GNTST_general_error; - } - - if ( !new_addr ) - return destroy_grant_va_mapping(addr, frame, curr); - - pl1e = pv_map_guest_l1e(new_addr, &gl1mfn); - if ( !pl1e ) - { - gdprintk(XENLOG_WARNING, - "Could not find L1 PTE for address %"PRIx64"\n", new_addr); - return GNTST_general_error; - } - - if ( get_page_from_pagenr(gl1mfn, current->domain) ) - { - pv_unmap_guest_l1e(pl1e); - return GNTST_general_error; - } - - l1pg = mfn_to_page(gl1mfn); - if ( !page_lock(l1pg) ) - { - put_page(l1pg); - pv_unmap_guest_l1e(pl1e); - return GNTST_general_error; - } - - if ( (l1pg->u.inuse.type_info & PGT_type_mask) != PGT_l1_page_table ) - { - page_unlock(l1pg); - put_page(l1pg); - pv_unmap_guest_l1e(pl1e); - return GNTST_general_error; - } - - ol1e = *pl1e; - - if ( unlikely(!UPDATE_ENTRY(l1, pl1e, ol1e, l1e_empty(), - gl1mfn, curr, 0)) ) - { - page_unlock(l1pg); - put_page(l1pg); - gdprintk(XENLOG_WARNING, "Cannot delete PTE entry at %p\n", pl1e); - pv_unmap_guest_l1e(pl1e); - return GNTST_general_error; - } - - page_unlock(l1pg); - put_page(l1pg); - pv_unmap_guest_l1e(pl1e); - - rc = replace_grant_va_mapping(addr, frame, ol1e, curr); - if ( rc ) - put_page_from_l1e(ol1e, curr->domain); - - 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 016b1b6e8f..501c766cc2 100644 --- a/xen/arch/x86/pv/Makefile +++ b/xen/arch/x86/pv/Makefile @@ -6,6 +6,7 @@ obj-y += emul-inv-op.o obj-y += emul-mmio-op.o obj-y += emul-priv-op.o obj-y += emul-ptwr-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..6c22cd01a7 --- /dev/null +++ b/xen/arch/x86/pv/grant_table.c @@ -0,0 +1,386 @@ +/****************************************************************************** + * arch/x86/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 of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * 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 + +static int create_grant_pte_mapping(uint64_t pte_addr, l1_pgentry_t nl1e, + struct vcpu *v) +{ + int rc = GNTST_okay; + void *va; + unsigned long gmfn, mfn; + struct page_info *page; + l1_pgentry_t ol1e; + struct domain *d = v->domain; + + adjust_guest_l1e(nl1e, d); + + gmfn = pte_addr >> PAGE_SHIFT; + page = get_page_from_gfn(d, gmfn, NULL, P2M_ALLOC); + + if ( unlikely(!page) ) + { + gdprintk(XENLOG_WARNING, "Could not get page for normal update\n"); + return GNTST_general_error; + } + + mfn = page_to_mfn(page); + va = map_domain_page(_mfn(mfn)); + va = (void *)((unsigned long)va + ((unsigned long)pte_addr & ~PAGE_MASK)); + + if ( !page_lock(page) ) + { + rc = GNTST_general_error; + goto failed; + } + + if ( (page->u.inuse.type_info & PGT_type_mask) != PGT_l1_page_table ) + { + page_unlock(page); + rc = GNTST_general_error; + goto failed; + } + + ol1e = *(l1_pgentry_t *)va; + if ( !UPDATE_ENTRY(l1, (l1_pgentry_t *)va, ol1e, nl1e, mfn, v, 0) ) + { + page_unlock(page); + rc = GNTST_general_error; + goto failed; + } + + page_unlock(page); + + put_page_from_l1e(ol1e, d); + + failed: + unmap_domain_page(va); + put_page(page); + + return rc; +} + +static int destroy_grant_pte_mapping(uint64_t addr, unsigned long frame, + struct domain *d) +{ + int rc = GNTST_okay; + void *va; + unsigned long gmfn, mfn; + struct page_info *page; + l1_pgentry_t ol1e; + + gmfn = addr >> PAGE_SHIFT; + page = get_page_from_gfn(d, gmfn, NULL, P2M_ALLOC); + + if ( unlikely(!page) ) + { + gdprintk(XENLOG_WARNING, "Could not get page for normal update\n"); + return GNTST_general_error; + } + + mfn = page_to_mfn(page); + va = map_domain_page(_mfn(mfn)); + va = (void *)((unsigned long)va + ((unsigned long)addr & ~PAGE_MASK)); + + if ( !page_lock(page) ) + { + rc = GNTST_general_error; + goto failed; + } + + if ( (page->u.inuse.type_info & PGT_type_mask) != PGT_l1_page_table ) + { + page_unlock(page); + rc = GNTST_general_error; + goto failed; + } + + ol1e = *(l1_pgentry_t *)va; + + /* Check that the virtual address supplied is actually mapped to frame. */ + if ( unlikely(l1e_get_pfn(ol1e) != frame) ) + { + page_unlock(page); + gdprintk(XENLOG_WARNING, + "PTE entry %"PRIpte" for address %"PRIx64" doesn't match frame %lx\n", + l1e_get_intpte(ol1e), addr, frame); + rc = GNTST_general_error; + goto failed; + } + + /* Delete pagetable entry. */ + if ( unlikely(!UPDATE_ENTRY(l1, + (l1_pgentry_t *)va, ol1e, l1e_empty(), mfn, + d->vcpu[0] /* Change if we go to per-vcpu shadows. */, + 0)) ) + { + page_unlock(page); + gdprintk(XENLOG_WARNING, "Cannot delete PTE entry at %p\n", va); + rc = GNTST_general_error; + goto failed; + } + + page_unlock(page); + + failed: + unmap_domain_page(va); + put_page(page); + return rc; +} + + +static int create_grant_va_mapping(unsigned long va, l1_pgentry_t nl1e, + struct vcpu *v) +{ + l1_pgentry_t *pl1e, ol1e; + struct domain *d = v->domain; + unsigned long gl1mfn; + struct page_info *l1pg; + int okay; + + adjust_guest_l1e(nl1e, d); + + pl1e = pv_map_guest_l1e(va, &gl1mfn); + if ( !pl1e ) + { + gdprintk(XENLOG_WARNING, "Could not find L1 PTE for address %lx\n", va); + return GNTST_general_error; + } + + if ( get_page_from_pagenr(gl1mfn, current->domain) ) + { + pv_unmap_guest_l1e(pl1e); + return GNTST_general_error; + } + + l1pg = mfn_to_page(gl1mfn); + if ( !page_lock(l1pg) ) + { + put_page(l1pg); + pv_unmap_guest_l1e(pl1e); + return GNTST_general_error; + } + + if ( (l1pg->u.inuse.type_info & PGT_type_mask) != PGT_l1_page_table ) + { + page_unlock(l1pg); + put_page(l1pg); + pv_unmap_guest_l1e(pl1e); + return GNTST_general_error; + } + + ol1e = *pl1e; + okay = UPDATE_ENTRY(l1, pl1e, ol1e, nl1e, gl1mfn, v, 0); + + page_unlock(l1pg); + put_page(l1pg); + pv_unmap_guest_l1e(pl1e); + + if ( okay ) + put_page_from_l1e(ol1e, d); + + return okay ? GNTST_okay : GNTST_general_error; +} + +static int replace_grant_va_mapping(unsigned long addr, unsigned long frame, + l1_pgentry_t nl1e, struct vcpu *v) +{ + l1_pgentry_t *pl1e, ol1e; + unsigned long gl1mfn; + struct page_info *l1pg; + int rc = 0; + + pl1e = pv_map_guest_l1e(addr, &gl1mfn); + if ( !pl1e ) + { + gdprintk(XENLOG_WARNING, "Could not find L1 PTE for address %lx\n", addr); + return GNTST_general_error; + } + + if ( get_page_from_pagenr(gl1mfn, current->domain) ) + { + rc = GNTST_general_error; + goto out; + } + + l1pg = mfn_to_page(gl1mfn); + if ( !page_lock(l1pg) ) + { + rc = GNTST_general_error; + put_page(l1pg); + goto out; + } + + if ( (l1pg->u.inuse.type_info & PGT_type_mask) != PGT_l1_page_table ) + { + rc = GNTST_general_error; + goto unlock_and_out; + } + + ol1e = *pl1e; + + /* Check that the virtual address supplied is actually mapped to frame. */ + if ( unlikely(l1e_get_pfn(ol1e) != frame) ) + { + gdprintk(XENLOG_WARNING, + "PTE entry %lx for address %lx doesn't match frame %lx\n", + l1e_get_pfn(ol1e), addr, frame); + rc = GNTST_general_error; + goto unlock_and_out; + } + + /* Delete pagetable entry. */ + if ( unlikely(!UPDATE_ENTRY(l1, pl1e, ol1e, nl1e, gl1mfn, v, 0)) ) + { + gdprintk(XENLOG_WARNING, "Cannot delete PTE entry at %p\n", pl1e); + rc = GNTST_general_error; + goto unlock_and_out; + } + + unlock_and_out: + page_unlock(l1pg); + put_page(l1pg); + out: + pv_unmap_guest_l1e(pl1e); + return rc; +} + +static int destroy_grant_va_mapping(unsigned long addr, unsigned long frame, + struct vcpu *v) +{ + return replace_grant_va_mapping(addr, frame, l1e_empty(), v); +} + +int create_grant_pv_mapping(uint64_t addr, unsigned long frame, + unsigned int flags, unsigned int cache_flags) +{ + l1_pgentry_t pte; + uint32_t grant_pte_flags; + + grant_pte_flags = + _PAGE_PRESENT | _PAGE_ACCESSED | _PAGE_DIRTY | _PAGE_GNTTAB; + if ( cpu_has_nx ) + grant_pte_flags |= _PAGE_NX_BIT; + + pte = l1e_from_pfn(frame, grant_pte_flags); + if ( (flags & GNTMAP_application_map) ) + l1e_add_flags(pte,_PAGE_USER); + if ( !(flags & GNTMAP_readonly) ) + l1e_add_flags(pte,_PAGE_RW); + + l1e_add_flags(pte, + ((flags >> _GNTMAP_guest_avail0) * _PAGE_AVAIL0) + & _PAGE_AVAIL); + + l1e_add_flags(pte, cacheattr_to_pte_flags(cache_flags >> 5)); + + if ( flags & GNTMAP_contains_pte ) + return create_grant_pte_mapping(addr, pte, current); + return create_grant_va_mapping(addr, pte, current); +} + +int replace_grant_pv_mapping(uint64_t addr, unsigned long frame, + uint64_t new_addr, unsigned int flags) +{ + struct vcpu *curr = current; + l1_pgentry_t *pl1e, ol1e; + unsigned long gl1mfn; + struct page_info *l1pg; + int rc; + + if ( flags & GNTMAP_contains_pte ) + { + if ( !new_addr ) + return destroy_grant_pte_mapping(addr, frame, curr->domain); + + return GNTST_general_error; + } + + if ( !new_addr ) + return destroy_grant_va_mapping(addr, frame, curr); + + pl1e = pv_map_guest_l1e(new_addr, &gl1mfn); + if ( !pl1e ) + { + gdprintk(XENLOG_WARNING, + "Could not find L1 PTE for address %"PRIx64"\n", new_addr); + return GNTST_general_error; + } + + if ( get_page_from_pagenr(gl1mfn, current->domain) ) + { + pv_unmap_guest_l1e(pl1e); + return GNTST_general_error; + } + + l1pg = mfn_to_page(gl1mfn); + if ( !page_lock(l1pg) ) + { + put_page(l1pg); + pv_unmap_guest_l1e(pl1e); + return GNTST_general_error; + } + + if ( (l1pg->u.inuse.type_info & PGT_type_mask) != PGT_l1_page_table ) + { + page_unlock(l1pg); + put_page(l1pg); + pv_unmap_guest_l1e(pl1e); + return GNTST_general_error; + } + + ol1e = *pl1e; + + if ( unlikely(!UPDATE_ENTRY(l1, pl1e, ol1e, l1e_empty(), + gl1mfn, curr, 0)) ) + { + page_unlock(l1pg); + put_page(l1pg); + gdprintk(XENLOG_WARNING, "Cannot delete PTE entry at %p\n", pl1e); + pv_unmap_guest_l1e(pl1e); + return GNTST_general_error; + } + + page_unlock(l1pg); + put_page(l1pg); + pv_unmap_guest_l1e(pl1e); + + rc = replace_grant_va_mapping(addr, frame, ol1e, curr); + if ( rc ) + put_page_from_l1e(ol1e, curr->domain); + + return rc; +} + +/* + * Local variables: + * mode: C + * c-file-style: "BSD" + * c-basic-offset: 4 + * tab-width: 4 + * indent-tabs-mode: nil + * End: + */