From mboxrd@z Thu Jan 1 00:00:00 1970 From: Ed White Subject: [PATCH v3 10/13] x86/altp2m: add remaining support routines. Date: Wed, 1 Jul 2015 11:09:34 -0700 Message-ID: <1435774177-6345-11-git-send-email-edmund.h.white@intel.com> References: <1435774177-6345-1-git-send-email-edmund.h.white@intel.com> Mime-Version: 1.0 Content-Type: text/plain; charset="us-ascii" Content-Transfer-Encoding: 7bit Return-path: In-Reply-To: <1435774177-6345-1-git-send-email-edmund.h.white@intel.com> List-Unsubscribe: , List-Post: List-Help: List-Subscribe: , Sender: xen-devel-bounces@lists.xen.org Errors-To: xen-devel-bounces@lists.xen.org To: xen-devel@lists.xen.org Cc: Ravi Sahita , Wei Liu , George Dunlap , Ian Jackson , Tim Deegan , Ed White , Jan Beulich , Andrew Cooper , tlengyel@novetta.com, Daniel De Graaf List-Id: xen-devel@lists.xenproject.org Add the remaining routines required to support enabling the alternate p2m functionality. Signed-off-by: Ed White --- xen/arch/x86/hvm/hvm.c | 58 +++++- xen/arch/x86/mm/hap/Makefile | 1 + xen/arch/x86/mm/hap/altp2m_hap.c | 98 ++++++++++ xen/arch/x86/mm/p2m-ept.c | 3 + xen/arch/x86/mm/p2m.c | 385 +++++++++++++++++++++++++++++++++++++++ xen/include/asm-x86/hvm/altp2m.h | 4 + xen/include/asm-x86/p2m.h | 33 ++++ 7 files changed, 576 insertions(+), 6 deletions(-) create mode 100644 xen/arch/x86/mm/hap/altp2m_hap.c diff --git a/xen/arch/x86/hvm/hvm.c b/xen/arch/x86/hvm/hvm.c index f21d34d..d2d90c8 100644 --- a/xen/arch/x86/hvm/hvm.c +++ b/xen/arch/x86/hvm/hvm.c @@ -2806,10 +2806,11 @@ int hvm_hap_nested_page_fault(paddr_t gpa, unsigned long gla, mfn_t mfn; struct vcpu *curr = current; struct domain *currd = curr->domain; - struct p2m_domain *p2m; + struct p2m_domain *p2m, *hostp2m; int rc, fall_through = 0, paged = 0; int sharing_enomem = 0; vm_event_request_t *req_ptr = NULL; + bool_t ap2m_active = 0; /* On Nested Virtualization, walk the guest page table. * If this succeeds, all is fine. @@ -2869,11 +2870,31 @@ int hvm_hap_nested_page_fault(paddr_t gpa, unsigned long gla, goto out; } - p2m = p2m_get_hostp2m(currd); - mfn = get_gfn_type_access(p2m, gfn, &p2mt, &p2ma, + ap2m_active = altp2m_active(currd); + + /* Take a lock on the host p2m speculatively, to avoid potential + * locking order problems later and to handle unshare etc. + */ + hostp2m = p2m_get_hostp2m(currd); + mfn = get_gfn_type_access(hostp2m, gfn, &p2mt, &p2ma, P2M_ALLOC | (npfec.write_access ? P2M_UNSHARE : 0), NULL); + if ( ap2m_active ) + { + if ( altp2m_hap_nested_page_fault(curr, gpa, gla, npfec, &p2m) == 1 ) + { + /* entry was lazily copied from host -- retry */ + __put_gfn(hostp2m, gfn); + rc = 1; + goto out; + } + + mfn = get_gfn_type_access(p2m, gfn, &p2mt, &p2ma, 0, NULL); + } + else + p2m = hostp2m; + /* Check access permissions first, then handle faults */ if ( mfn_x(mfn) != INVALID_MFN ) { @@ -2913,6 +2934,20 @@ int hvm_hap_nested_page_fault(paddr_t gpa, unsigned long gla, if ( violation ) { + /* Should #VE be emulated for this fault? */ + if ( p2m_is_altp2m(p2m) && !cpu_has_vmx_virt_exceptions ) + { + bool_t sve; + + p2m->get_entry_full(p2m, gfn, &p2mt, &p2ma, 0, NULL, &sve); + + if ( !sve && ap2m_vcpu_emulate_ve(curr) ) + { + rc = 1; + goto out_put_gfn; + } + } + if ( p2m_mem_access_check(gpa, gla, npfec, &req_ptr) ) { fall_through = 1; @@ -2932,7 +2967,9 @@ int hvm_hap_nested_page_fault(paddr_t gpa, unsigned long gla, (npfec.write_access && (p2m_is_discard_write(p2mt) || (p2mt == p2m_mmio_write_dm))) ) { - put_gfn(currd, gfn); + __put_gfn(p2m, gfn); + if ( ap2m_active ) + __put_gfn(hostp2m, gfn); rc = 0; if ( unlikely(is_pvh_domain(currd)) ) @@ -2961,6 +2998,7 @@ int hvm_hap_nested_page_fault(paddr_t gpa, unsigned long gla, /* Spurious fault? PoD and log-dirty also take this path. */ if ( p2m_is_ram(p2mt) ) { + rc = 1; /* * Page log dirty is always done with order 0. If this mfn resides in * a large page, we do not change other pages type within that large @@ -2969,9 +3007,15 @@ int hvm_hap_nested_page_fault(paddr_t gpa, unsigned long gla, if ( npfec.write_access ) { paging_mark_dirty(currd, mfn_x(mfn)); + /* If p2m is really an altp2m, unlock here to avoid lock ordering + * violation when the change below is propagated from host p2m */ + if ( ap2m_active ) + __put_gfn(p2m, gfn); p2m_change_type_one(currd, gfn, p2m_ram_logdirty, p2m_ram_rw); + __put_gfn(ap2m_active ? hostp2m : p2m, gfn); + + goto out; } - rc = 1; goto out_put_gfn; } @@ -2981,7 +3025,9 @@ int hvm_hap_nested_page_fault(paddr_t gpa, unsigned long gla, rc = fall_through; out_put_gfn: - put_gfn(currd, gfn); + __put_gfn(p2m, gfn); + if ( ap2m_active ) + __put_gfn(hostp2m, gfn); out: /* All of these are delayed until we exit, since we might * sleep on event ring wait queues, and we must not hold diff --git a/xen/arch/x86/mm/hap/Makefile b/xen/arch/x86/mm/hap/Makefile index 68f2bb5..216cd90 100644 --- a/xen/arch/x86/mm/hap/Makefile +++ b/xen/arch/x86/mm/hap/Makefile @@ -4,6 +4,7 @@ obj-y += guest_walk_3level.o obj-$(x86_64) += guest_walk_4level.o obj-y += nested_hap.o obj-y += nested_ept.o +obj-y += altp2m_hap.o guest_walk_%level.o: guest_walk.c Makefile $(CC) $(CFLAGS) -DGUEST_PAGING_LEVELS=$* -c $< -o $@ diff --git a/xen/arch/x86/mm/hap/altp2m_hap.c b/xen/arch/x86/mm/hap/altp2m_hap.c new file mode 100644 index 0000000..52c7877 --- /dev/null +++ b/xen/arch/x86/mm/hap/altp2m_hap.c @@ -0,0 +1,98 @@ +/****************************************************************************** + * arch/x86/mm/hap/altp2m_hap.c + * + * Copyright (c) 2014 Intel Corporation. + * + * 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, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +#include +#include +#include +#include +#include +#include + +#include "private.h" + +/* + * If the fault is for a not present entry: + * if the entry in the host p2m has a valid mfn, copy it and retry + * else indicate that outer handler should handle fault + * + * If the fault is for a present entry: + * indicate that outer handler should handle fault + */ + +int +altp2m_hap_nested_page_fault(struct vcpu *v, paddr_t gpa, + unsigned long gla, struct npfec npfec, + struct p2m_domain **ap2m) +{ + struct p2m_domain *hp2m = p2m_get_hostp2m(v->domain); + p2m_type_t p2mt; + p2m_access_t p2ma; + unsigned int page_order; + gfn_t gfn = _gfn(paddr_to_pfn(gpa)); + unsigned long mask; + mfn_t mfn; + int rv; + + *ap2m = p2m_get_altp2m(v); + + mfn = get_gfn_type_access(*ap2m, gfn_x(gfn), &p2mt, &p2ma, + 0, &page_order); + __put_gfn(*ap2m, gfn_x(gfn)); + + if ( mfn_x(mfn) != INVALID_MFN ) + return 0; + + mfn = get_gfn_type_access(hp2m, gfn_x(gfn), &p2mt, &p2ma, + P2M_ALLOC | P2M_UNSHARE, &page_order); + put_gfn(hp2m->domain, gfn_x(gfn)); + + if ( mfn_x(mfn) == INVALID_MFN ) + return 0; + + p2m_lock(*ap2m); + + /* If this is a superpage mapping, round down both frame numbers + * to the start of the superpage. */ + mask = ~((1UL << page_order) - 1); + mfn = _mfn(mfn_x(mfn) & mask); + + rv = p2m_set_entry(*ap2m, gfn_x(gfn) & mask, mfn, page_order, p2mt, p2ma); + p2m_unlock(*ap2m); + + if ( rv ) + { + gdprintk(XENLOG_ERR, + "failed to set entry for %#"PRIx64" -> %#"PRIx64" p2m %#"PRIx64"\n", + gfn_x(gfn), mfn_x(mfn), (unsigned long)*ap2m); + domain_crash(hp2m->domain); + } + + return 1; +} + +/* + * Local variables: + * mode: C + * c-file-style: "BSD" + * c-basic-offset: 4 + * tab-width: 4 + * indent-tabs-mode: nil + * End: + */ diff --git a/xen/arch/x86/mm/p2m-ept.c b/xen/arch/x86/mm/p2m-ept.c index bcb9381..36fb6a4 100644 --- a/xen/arch/x86/mm/p2m-ept.c +++ b/xen/arch/x86/mm/p2m-ept.c @@ -850,6 +850,9 @@ out: if ( is_epte_present(&old_entry) ) ept_free_entry(p2m, &old_entry, target); + if ( rc == 0 && p2m_is_hostp2m(p2m) ) + p2m_altp2m_propagate_change(d, _gfn(gfn), mfn, order, p2mt, p2ma); + return rc; } diff --git a/xen/arch/x86/mm/p2m.c b/xen/arch/x86/mm/p2m.c index 576b28d..1d062e7 100644 --- a/xen/arch/x86/mm/p2m.c +++ b/xen/arch/x86/mm/p2m.c @@ -2036,6 +2036,391 @@ bool_t p2m_switch_vcpu_altp2m_by_id(struct vcpu *v, uint16_t idx) return rc; } +void p2m_flush_altp2m(struct domain *d) +{ + uint16_t i; + + altp2m_lock(d); + + for ( i = 0; i < MAX_ALTP2M; i++ ) + { + p2m_flush_table(d->arch.altp2m_p2m[i]); + /* Uninit and reinit ept to force TLB shootdown */ + ept_p2m_uninit(d->arch.altp2m_p2m[i]); + ept_p2m_init(d->arch.altp2m_p2m[i]); + d->arch.altp2m_eptp[i] = INVALID_MFN; + } + + altp2m_unlock(d); +} + +static void p2m_init_altp2m_helper(struct domain *d, uint16_t i) +{ + struct p2m_domain *p2m = d->arch.altp2m_p2m[i]; + struct ept_data *ept; + + p2m->min_remapped_gfn = INVALID_GFN; + p2m->max_remapped_gfn = INVALID_GFN; + ept = &p2m->ept; + ept->asr = pagetable_get_pfn(p2m_get_pagetable(p2m)); + d->arch.altp2m_eptp[i] = ept_get_eptp(ept); +} + +long p2m_init_altp2m_by_id(struct domain *d, uint16_t idx) +{ + long rc = -EINVAL; + + if ( idx > MAX_ALTP2M ) + return rc; + + altp2m_lock(d); + + if ( d->arch.altp2m_eptp[idx] == INVALID_MFN ) + { + p2m_init_altp2m_helper(d, idx); + rc = 0; + } + + altp2m_unlock(d); + return rc; +} + +long p2m_init_next_altp2m(struct domain *d, uint16_t *idx) +{ + long rc = -EINVAL; + uint16_t i; + + altp2m_lock(d); + + for ( i = 0; i < MAX_ALTP2M; i++ ) + { + if ( d->arch.altp2m_eptp[i] != INVALID_MFN ) + continue; + + p2m_init_altp2m_helper(d, i); + *idx = i; + rc = 0; + + break; + } + + altp2m_unlock(d); + return rc; +} + +long p2m_destroy_altp2m_by_id(struct domain *d, uint16_t idx) +{ + struct p2m_domain *p2m; + long rc = -EINVAL; + + if ( !idx || idx > MAX_ALTP2M ) + return rc; + + domain_pause_except_self(d); + + altp2m_lock(d); + + if ( d->arch.altp2m_eptp[idx] != INVALID_MFN ) + { + p2m = d->arch.altp2m_p2m[idx]; + + if ( !_atomic_read(p2m->active_vcpus) ) + { + p2m_flush_table(d->arch.altp2m_p2m[idx]); + /* Uninit and reinit ept to force TLB shootdown */ + ept_p2m_uninit(d->arch.altp2m_p2m[idx]); + ept_p2m_init(d->arch.altp2m_p2m[idx]); + d->arch.altp2m_eptp[idx] = INVALID_MFN; + rc = 0; + } + } + + altp2m_unlock(d); + + domain_unpause_except_self(d); + + return rc; +} + +long p2m_switch_domain_altp2m_by_id(struct domain *d, uint16_t idx) +{ + struct vcpu *v; + long rc = -EINVAL; + + if ( idx > MAX_ALTP2M ) + return rc; + + domain_pause_except_self(d); + + altp2m_lock(d); + + if ( d->arch.altp2m_eptp[idx] != INVALID_MFN ) + { + for_each_vcpu( d, v ) + if ( idx != vcpu_altp2m(v).p2midx ) + { + atomic_dec(&p2m_get_altp2m(v)->active_vcpus); + vcpu_altp2m(v).p2midx = idx; + atomic_inc(&p2m_get_altp2m(v)->active_vcpus); + ap2m_vcpu_update_eptp(v); + } + + rc = 0; + } + + altp2m_unlock(d); + + domain_unpause_except_self(d); + + return rc; +} + +long p2m_set_altp2m_mem_access(struct domain *d, uint16_t idx, + gfn_t gfn, xenmem_access_t access) +{ + struct p2m_domain *hp2m, *ap2m; + p2m_access_t req_a, old_a; + p2m_type_t t; + mfn_t mfn; + unsigned int page_order; + long rc = -EINVAL; + + static const p2m_access_t memaccess[] = { +#define ACCESS(ac) [XENMEM_access_##ac] = p2m_access_##ac + ACCESS(n), + ACCESS(r), + ACCESS(w), + ACCESS(rw), + ACCESS(x), + ACCESS(rx), + ACCESS(wx), + ACCESS(rwx), +#undef ACCESS + }; + + if ( idx > MAX_ALTP2M || d->arch.altp2m_eptp[idx] == INVALID_MFN ) + return rc; + + ap2m = d->arch.altp2m_p2m[idx]; + + switch ( access ) + { + case 0 ... ARRAY_SIZE(memaccess) - 1: + req_a = memaccess[access]; + break; + case XENMEM_access_default: + req_a = ap2m->default_access; + break; + default: + return rc; + } + + /* If request to set default access */ + if ( gfn_x(gfn) == INVALID_GFN ) + { + ap2m->default_access = req_a; + return 0; + } + + hp2m = p2m_get_hostp2m(d); + + p2m_lock(ap2m); + + mfn = ap2m->get_entry(ap2m, gfn_x(gfn), &t, &old_a, 0, NULL); + + /* Check host p2m if no valid entry in alternate */ + if ( !mfn_valid(mfn) ) + { + mfn = hp2m->get_entry(hp2m, gfn_x(gfn), &t, &old_a, + P2M_ALLOC | P2M_UNSHARE, &page_order); + + if ( !mfn_valid(mfn) || t != p2m_ram_rw ) + goto out; + + /* If this is a superpage, copy that first */ + if ( page_order != PAGE_ORDER_4K ) + { + gfn_t gfn2; + unsigned long mask; + mfn_t mfn2; + + mask = ~((1UL << page_order) - 1); + gfn2 = _gfn(gfn_x(gfn) & mask); + mfn2 = _mfn(mfn_x(mfn) & mask); + + if ( ap2m->set_entry(ap2m, gfn_x(gfn2), mfn2, page_order, t, old_a) ) + goto out; + } + } + + if ( !ap2m->set_entry_full(ap2m, gfn_x(gfn), mfn, PAGE_ORDER_4K, t, req_a, + (current->domain != d)) ) + rc = 0; + +out: + p2m_unlock(ap2m); + return rc; +} + +long p2m_change_altp2m_gfn(struct domain *d, uint16_t idx, + gfn_t old_gfn, gfn_t new_gfn) +{ + struct p2m_domain *hp2m, *ap2m; + p2m_access_t a; + p2m_type_t t; + mfn_t mfn; + unsigned int page_order; + long rc = -EINVAL; + + if ( idx > MAX_ALTP2M || d->arch.altp2m_eptp[idx] == INVALID_MFN ) + return rc; + + hp2m = p2m_get_hostp2m(d); + ap2m = d->arch.altp2m_p2m[idx]; + + p2m_lock(ap2m); + + mfn = ap2m->get_entry(ap2m, gfn_x(old_gfn), &t, &a, 0, NULL); + + if ( gfn_x(new_gfn) == INVALID_GFN ) + { + if ( mfn_valid(mfn) ) + p2m_remove_page(ap2m, gfn_x(old_gfn), mfn_x(mfn), PAGE_ORDER_4K); + rc = 0; + goto out; + } + + /* Check host p2m if no valid entry in alternate */ + if ( !mfn_valid(mfn) ) + { + mfn = hp2m->get_entry(hp2m, gfn_x(old_gfn), &t, &a, + P2M_ALLOC | P2M_UNSHARE, &page_order); + + if ( !mfn_valid(mfn) || t != p2m_ram_rw ) + goto out; + + /* If this is a superpage, copy that first */ + if ( page_order != PAGE_ORDER_4K ) + { + gfn_t gfn; + unsigned long mask; + + mask = ~((1UL << page_order) - 1); + gfn = _gfn(gfn_x(old_gfn) & mask); + mfn = _mfn(mfn_x(mfn) & mask); + + if ( ap2m->set_entry(ap2m, gfn_x(gfn), mfn, page_order, t, a) ) + goto out; + } + } + + mfn = ap2m->get_entry(ap2m, gfn_x(new_gfn), &t, &a, 0, NULL); + + if ( !mfn_valid(mfn) ) + mfn = hp2m->get_entry(hp2m, gfn_x(new_gfn), &t, &a, 0, NULL); + + if ( !mfn_valid(mfn) || (t != p2m_ram_rw) ) + goto out; + + if ( !ap2m->set_entry_full(ap2m, gfn_x(old_gfn), mfn, PAGE_ORDER_4K, t, a, + (current->domain != d)) ) + { + rc = 0; + + if ( ap2m->min_remapped_gfn == INVALID_GFN || + gfn_x(new_gfn) < ap2m->min_remapped_gfn ) + ap2m->min_remapped_gfn = gfn_x(new_gfn); + if ( ap2m->max_remapped_gfn == INVALID_GFN || + gfn_x(new_gfn) > ap2m->max_remapped_gfn ) + ap2m->max_remapped_gfn = gfn_x(new_gfn); + } + +out: + p2m_unlock(ap2m); + return rc; +} + +static void p2m_reset_altp2m(struct p2m_domain *p2m) +{ + p2m_flush_table(p2m); + /* Uninit and reinit ept to force TLB shootdown */ + ept_p2m_uninit(p2m); + ept_p2m_init(p2m); + p2m->min_remapped_gfn = INVALID_GFN; + p2m->max_remapped_gfn = INVALID_GFN; +} + +void p2m_altp2m_propagate_change(struct domain *d, gfn_t gfn, + mfn_t mfn, unsigned int page_order, + p2m_type_t p2mt, p2m_access_t p2ma) +{ + struct p2m_domain *p2m; + p2m_access_t a; + p2m_type_t t; + mfn_t m; + uint16_t i; + bool_t reset_p2m; + unsigned int reset_count = 0; + uint16_t last_reset_idx = ~0; + + if ( !altp2m_active(d) ) + return; + + altp2m_lock(d); + + for ( i = 0; i < MAX_ALTP2M; i++ ) + { + if ( d->arch.altp2m_eptp[i] == INVALID_MFN ) + continue; + + p2m = d->arch.altp2m_p2m[i]; + m = get_gfn_type_access(p2m, gfn_x(gfn), &t, &a, 0, NULL); + + reset_p2m = 0; + + /* Check for a dropped page that may impact this altp2m */ + if ( mfn_x(mfn) == INVALID_MFN && + gfn_x(gfn) >= p2m->min_remapped_gfn && + gfn_x(gfn) <= p2m->max_remapped_gfn ) + reset_p2m = 1; + + if ( reset_p2m ) + { + if ( !reset_count++ ) + { + p2m_reset_altp2m(p2m); + last_reset_idx = i; + } + else + { + /* At least 2 altp2m's impacted, so reset everything */ + __put_gfn(p2m, gfn_x(gfn)); + + for ( i = 0; i < MAX_ALTP2M; i++ ) + { + if ( i == last_reset_idx || + d->arch.altp2m_eptp[i] == INVALID_MFN ) + continue; + + p2m = d->arch.altp2m_p2m[i]; + p2m_lock(p2m); + p2m_reset_altp2m(p2m); + p2m_unlock(p2m); + } + + goto out; + } + } + else if ( mfn_x(m) != INVALID_MFN ) + p2m_set_entry(p2m, gfn_x(gfn), mfn, page_order, p2mt, p2ma); + + __put_gfn(p2m, gfn_x(gfn)); + } + +out: + altp2m_unlock(d); +} + /*** Audit ***/ #if P2M_AUDIT diff --git a/xen/include/asm-x86/hvm/altp2m.h b/xen/include/asm-x86/hvm/altp2m.h index 1a6f22b..f90b5af 100644 --- a/xen/include/asm-x86/hvm/altp2m.h +++ b/xen/include/asm-x86/hvm/altp2m.h @@ -34,5 +34,9 @@ int altp2m_vcpu_initialise(struct vcpu *v); void altp2m_vcpu_destroy(struct vcpu *v); void altp2m_vcpu_reset(struct vcpu *v); +/* Alternate p2m paging */ +int altp2m_hap_nested_page_fault(struct vcpu *v, paddr_t gpa, + unsigned long gla, struct npfec npfec, struct p2m_domain **ap2m); + #endif /* _ALTP2M_H */ diff --git a/xen/include/asm-x86/p2m.h b/xen/include/asm-x86/p2m.h index 5689f40..2159c5b 100644 --- a/xen/include/asm-x86/p2m.h +++ b/xen/include/asm-x86/p2m.h @@ -279,6 +279,11 @@ struct p2m_domain { /* Highest guest frame that's ever been mapped in the p2m */ unsigned long max_mapped_pfn; + /* Alternate p2m's only: range of gfn's for which underlying + * mfn may have duplicate mappings */ + unsigned long min_remapped_gfn; + unsigned long max_remapped_gfn; + /* When releasing shared gfn's in a preemptible manner, recall where * to resume the search */ unsigned long next_shared_gfn_to_relinquish; @@ -765,6 +770,34 @@ bool_t p2m_switch_vcpu_altp2m_by_id(struct vcpu *v, uint16_t idx); /* Check to see if vcpu should be switched to a different p2m. */ void p2m_altp2m_check(struct vcpu *v, const vm_event_response_t *rsp); +/* Flush all the alternate p2m's for a domain */ +void p2m_flush_altp2m(struct domain *d); + +/* Make a specific alternate p2m valid */ +long p2m_init_altp2m_by_id(struct domain *d, uint16_t idx); + +/* Find an available alternate p2m and make it valid */ +long p2m_init_next_altp2m(struct domain *d, uint16_t *idx); + +/* Make a specific alternate p2m invalid */ +long p2m_destroy_altp2m_by_id(struct domain *d, uint16_t idx); + +/* Switch alternate p2m for entire domain */ +long p2m_switch_domain_altp2m_by_id(struct domain *d, uint16_t idx); + +/* Set access type for a gfn */ +long p2m_set_altp2m_mem_access(struct domain *d, uint16_t idx, + gfn_t gfn, xenmem_access_t access); + +/* Change a gfn->mfn mapping */ +long p2m_change_altp2m_gfn(struct domain *d, uint16_t idx, + gfn_t old_gfn, gfn_t new_gfn); + +/* Propagate a host p2m change to all alternate p2m's */ +void p2m_altp2m_propagate_change(struct domain *d, gfn_t gfn, + mfn_t mfn, unsigned int page_order, + p2m_type_t p2mt, p2m_access_t p2ma); + /* * p2m type to IOMMU flags */ -- 1.9.1