[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index] [Xen-devel] [PATCH v5 08/23] 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@xxxxxxxxxx> --- 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 <wei.liu2@xxxxxxxxxx> + * + * 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: + */ -- 2.11.0 _______________________________________________ Xen-devel mailing list Xen-devel@xxxxxxxxxxxxx https://lists.xen.org/xen-devel
|
Lists.xenproject.org is hosted with RackSpace, monitoring our |