mirror of
https://github.com/xen-project/xen.git
synced 2026-10-28 02:01:24 +01:00
x86/mm: split out pv grant table code
Move the code to pv/grant_table.c. Nothing needs to be done with regard to headers. Signed-off-by: Wei Liu <wei.liu2@citrix.com> Acked-by: Jan Beulich <jbeulich@suse.com>
This commit is contained in:
1 parent
39061c6099
commit
0bf001d21b
3 files changed
+328
-283
No files matched your search
@@ -3631,289 +3631,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)
|
||||
{
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -0,0 +1,327 @@
|
||||
/*
|
||||
* pv/grant_table.c
|
||||
*
|
||||
* Grant table interfaces for PV guests
|
||||
*
|
||||
* Copyright (C) 2017 Wei Liu <wei.liu2@citrix.com>
|
||||
*
|
||||
* 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 <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#include <xen/types.h>
|
||||
|
||||
#include <public/grant_table.h>
|
||||
|
||||
#include <asm/p2m.h>
|
||||
#include <asm/pv/mm.h>
|
||||
|
||||
#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:
|
||||
*/
|
||||