xen/arch/x86/cpu/mcheck/vmce.c | 9 +-
xen/arch/x86/debug.c | 17 ++-
xen/arch/x86/domain.c | 27 +++++-
xen/arch/x86/domctl.c | 15 ++-
xen/arch/x86/hvm/emulate.c | 29 ++++++-
xen/arch/x86/hvm/hvm.c | 113 ++++++++++++++++++++-------
xen/arch/x86/hvm/mtrr.c | 2 +-
xen/arch/x86/hvm/stdvga.c | 4 +-
xen/arch/x86/hvm/svm/nestedsvm.c | 13 ++-
xen/arch/x86/hvm/svm/svm.c | 12 ++-
xen/arch/x86/hvm/viridian.c | 8 +-
xen/arch/x86/hvm/vmx/vmx.c | 15 ++-
xen/arch/x86/hvm/vmx/vvmx.c | 13 ++-
xen/arch/x86/mm.c | 153 +++++++++++++++++++++++++++++++-------
xen/arch/x86/mm/guest_walk.c | 31 ++++++-
xen/arch/x86/mm/hap/guest_walk.c | 15 +++-
xen/arch/x86/mm/hap/nested_hap.c | 17 +++-
xen/arch/x86/mm/mem_event.c | 23 ++++-
xen/arch/x86/mm/mem_sharing.c | 27 +++++-
xen/arch/x86/mm/p2m-pod.c | 19 +++-
xen/arch/x86/mm/p2m.c | 40 +++++----
xen/arch/x86/mm/shadow/common.c | 6 +-
xen/arch/x86/mm/shadow/multi.c | 85 +++++++++++++++------
xen/arch/x86/mm/shadow/types.h | 10 +-
xen/arch/x86/physdev.c | 8 +-
xen/arch/x86/traps.c | 19 +++-
xen/common/grant_table.c | 30 ++++++-
xen/common/memory.c | 19 ++++-
xen/common/tmem_xen.c | 21 +++-
xen/include/asm-ia64/mm.h | 2 +
xen/include/asm-x86/guest_pt.h | 6 +-
xen/include/asm-x86/p2m.h | 45 ++++++++---
32 files changed, 636 insertions(+), 217 deletions(-)
Callers of lookups into the p2m code are now variants of get_gfn. All
callers need to call put_gfn. The code behind it is a no-op at the
moment, but will change to proper locking in a later patch.
This patch does not change functionality. Only naming, and adds
put_gfn's.
set_p2m_entry retains its name because it is always called with
p2m_lock held.
This patch is humongous, unfortunately, given the dozens of call sites
involved.
After this patch, anyone using old style gfn_to_mfn will not succeed
in compiling their code. This is on purpose: adapt to the new API.
Signed-off-by: Andres Lagar-Cavilla <andres@xxxxxxxxxxxxxxxx>
Acked-by: Tim Deegan <tim@xxxxxxx>
diff -r 4699decb8424 -r 7461834954c8 xen/arch/x86/cpu/mcheck/vmce.c
--- a/xen/arch/x86/cpu/mcheck/vmce.c
+++ b/xen/arch/x86/cpu/mcheck/vmce.c
@@ -574,6 +574,7 @@ int unmmap_broken_page(struct domain *d,
{
mfn_t r_mfn;
p2m_type_t pt;
+ int rc;
/* Always trust dom0's MCE handler will prevent future access */
if ( d == dom0 )
@@ -585,14 +586,16 @@ int unmmap_broken_page(struct domain *d,
if ( !is_hvm_domain(d) || !paging_mode_hap(d) )
return -ENOSYS;
- r_mfn = gfn_to_mfn_query(d, gfn, &pt);
+ rc = -1;
+ r_mfn = get_gfn_query(d, gfn, &pt);
if ( p2m_to_mask(pt) & P2M_UNMAP_TYPES)
{
ASSERT(mfn_x(r_mfn) == mfn_x(mfn));
p2m_change_type(d, gfn, pt, p2m_ram_broken);
- return 0;
+ rc = 0;
}
+ put_gfn(d, gfn);
- return -1;
+ return rc;
}
diff -r 4699decb8424 -r 7461834954c8 xen/arch/x86/debug.c
--- a/xen/arch/x86/debug.c
+++ b/xen/arch/x86/debug.c
@@ -43,22 +43,23 @@
/* Returns: mfn for the given (hvm guest) vaddr */
static unsigned long
-dbg_hvm_va2mfn(dbgva_t vaddr, struct domain *dp, int toaddr)
+dbg_hvm_va2mfn(dbgva_t vaddr, struct domain *dp, int toaddr,
+ unsigned long *gfn)
{
- unsigned long mfn, gfn;
+ unsigned long mfn;
uint32_t pfec = PFEC_page_present;
p2m_type_t gfntype;
DBGP2("vaddr:%lx domid:%d\n", vaddr, dp->domain_id);
- gfn = paging_gva_to_gfn(dp->vcpu[0], vaddr, &pfec);
- if ( gfn == INVALID_GFN )
+ *gfn = paging_gva_to_gfn(dp->vcpu[0], vaddr, &pfec);
+ if ( *gfn == INVALID_GFN )
{
DBGP2("kdb:bad gfn from gva_to_gfn\n");
return INVALID_MFN;
}
- mfn = mfn_x(gfn_to_mfn(dp, gfn, &gfntype));
+ mfn = mfn_x(get_gfn(dp, *gfn, &gfntype));
if ( p2m_is_readonly(gfntype) && toaddr )
{
DBGP2("kdb:p2m_is_readonly: gfntype:%x\n", gfntype);
@@ -193,12 +194,12 @@ dbg_rw_guest_mem(dbgva_t addr, dbgbyte_t
while ( len > 0 )
{
char *va;
- unsigned long mfn, pagecnt;
+ unsigned long mfn, gfn = INVALID_GFN, pagecnt;
pagecnt = min_t(long, PAGE_SIZE - (addr & ~PAGE_MASK), len);
mfn = (dp->is_hvm
- ? dbg_hvm_va2mfn(addr, dp, toaddr)
+ ? dbg_hvm_va2mfn(addr, dp, toaddr, &gfn)
: dbg_pv_va2mfn(addr, dp, pgd3));
if ( mfn == INVALID_MFN )
break;
@@ -217,6 +218,8 @@ dbg_rw_guest_mem(dbgva_t addr, dbgbyte_t
}
unmap_domain_page(va);
+ if ( gfn != INVALID_GFN )
+ put_gfn(dp, gfn);
addr += pagecnt;
buf += pagecnt;
diff -r 4699decb8424 -r 7461834954c8 xen/arch/x86/domain.c
--- a/xen/arch/x86/domain.c
+++ b/xen/arch/x86/domain.c
@@ -720,6 +720,7 @@ int arch_set_info_guest(
struct vcpu *v, vcpu_guest_context_u c)
{
struct domain *d = v->domain;
+ unsigned long cr3_gfn;
unsigned long cr3_pfn = INVALID_MFN;
unsigned long flags, cr4;
unsigned int i;
@@ -931,7 +932,8 @@ int arch_set_info_guest(
if ( !compat )
{
- cr3_pfn = gmfn_to_mfn(d, xen_cr3_to_pfn(c.nat->ctrlreg[3]));
+ cr3_gfn = xen_cr3_to_pfn(c.nat->ctrlreg[3]);
+ cr3_pfn = get_gfn_untyped(d, cr3_gfn);
if ( !mfn_valid(cr3_pfn) ||
(paging_mode_refcounts(d)
@@ -939,16 +941,18 @@ int arch_set_info_guest(
: !get_page_and_type(mfn_to_page(cr3_pfn), d,
PGT_base_page_table)) )
{
+ put_gfn(d, cr3_gfn);
destroy_gdt(v);
return -EINVAL;
}
v->arch.guest_table = pagetable_from_pfn(cr3_pfn);
-
+ put_gfn(d, cr3_gfn);
#ifdef __x86_64__
if ( c.nat->ctrlreg[1] )
{
- cr3_pfn = gmfn_to_mfn(d, xen_cr3_to_pfn(c.nat->ctrlreg[1]));
+ cr3_gfn = xen_cr3_to_pfn(c.nat->ctrlreg[1]);
+ cr3_pfn = get_gfn_untyped(d, cr3_gfn);
if ( !mfn_valid(cr3_pfn) ||
(paging_mode_refcounts(d)
@@ -962,11 +966,13 @@ int arch_set_info_guest(
put_page(mfn_to_page(cr3_pfn));
else
put_page_and_type(mfn_to_page(cr3_pfn));
+ put_gfn(d, cr3_gfn);
destroy_gdt(v);
return -EINVAL;
}
v->arch.guest_table_user = pagetable_from_pfn(cr3_pfn);
+ put_gfn(d, cr3_gfn);
}
else if ( !(flags & VGCF_in_kernel) )
{
@@ -978,7 +984,8 @@ int arch_set_info_guest(
{
l4_pgentry_t *l4tab;
- cr3_pfn = gmfn_to_mfn(d, compat_cr3_to_pfn(c.cmp->ctrlreg[3]));
+ cr3_gfn = compat_cr3_to_pfn(c.cmp->ctrlreg[3]);
+ cr3_pfn = get_gfn_untyped(d, cr3_gfn);
if ( !mfn_valid(cr3_pfn) ||
(paging_mode_refcounts(d)
@@ -986,6 +993,7 @@ int arch_set_info_guest(
: !get_page_and_type(mfn_to_page(cr3_pfn), d,
PGT_l3_page_table)) )
{
+ put_gfn(d, cr3_gfn);
destroy_gdt(v);
return -EINVAL;
}
@@ -993,6 +1001,7 @@ int arch_set_info_guest(
l4tab = __va(pagetable_get_paddr(v->arch.guest_table));
*l4tab = l4e_from_pfn(
cr3_pfn, _PAGE_PRESENT|_PAGE_RW|_PAGE_USER|_PAGE_ACCESSED);
+ put_gfn(d, cr3_gfn);
#endif
}
@@ -1058,11 +1067,12 @@ unmap_vcpu_info(struct vcpu *v)
* event doesn't get missed.
*/
static int
-map_vcpu_info(struct vcpu *v, unsigned long mfn, unsigned offset)
+map_vcpu_info(struct vcpu *v, unsigned long gfn, unsigned offset)
{
struct domain *d = v->domain;
void *mapping;
vcpu_info_t *new_info;
+ unsigned long mfn;
int i;
if ( offset > (PAGE_SIZE - sizeof(vcpu_info_t)) )
@@ -1075,15 +1085,19 @@ map_vcpu_info(struct vcpu *v, unsigned l
if ( (v != current) && !test_bit(_VPF_down, &v->pause_flags) )
return -EINVAL;
- mfn = gmfn_to_mfn(d, mfn);
+ mfn = get_gfn_untyped(d, gfn);
if ( !mfn_valid(mfn) ||
!get_page_and_type(mfn_to_page(mfn), d, PGT_writable_page) )
+ {
+ put_gfn(d, gfn);
return -EINVAL;
+ }
mapping = map_domain_page_global(mfn);
if ( mapping == NULL )
{
put_page_and_type(mfn_to_page(mfn));
+ put_gfn(d, gfn);
return -ENOMEM;
}
@@ -1113,6 +1127,7 @@ map_vcpu_info(struct vcpu *v, unsigned l
for ( i = 0; i < BITS_PER_EVTCHN_WORD(d); i++ )
set_bit(i, &vcpu_info(v, evtchn_pending_sel));
+ put_gfn(d, gfn);
return 0;
}
diff -r 4699decb8424 -r 7461834954c8 xen/arch/x86/domctl.c
--- a/xen/arch/x86/domctl.c
+++ b/xen/arch/x86/domctl.c
@@ -199,7 +199,7 @@ long arch_do_domctl(
for ( j = 0; j < k; j++ )
{
- unsigned long type = 0, mfn = gmfn_to_mfn(d, arr[j]);
+ unsigned long type = 0, mfn = get_gfn_untyped(d, arr[j]);
page = mfn_to_page(mfn);
@@ -235,6 +235,7 @@ long arch_do_domctl(
type = XEN_DOMCTL_PFINFO_XTAB;
arr[j] = type;
+ put_gfn(d, arr[j]);
}
if ( copy_to_guest_offset(domctl->u.getpageframeinfo3.array,
@@ -299,7 +300,8 @@ long arch_do_domctl(
for ( j = 0; j < k; j++ )
{
struct page_info *page;
- unsigned long mfn = gmfn_to_mfn(d, arr32[j]);
+ unsigned long gfn = arr32[j];
+ unsigned long mfn = get_gfn_untyped(d, gfn);
page = mfn_to_page(mfn);
@@ -310,8 +312,10 @@ long arch_do_domctl(
unlikely(is_xen_heap_mfn(mfn)) )
arr32[j] |= XEN_DOMCTL_PFINFO_XTAB;
else if ( xsm_getpageframeinfo(page) != 0 )
+ {
+ put_gfn(d, gfn);
continue;
- else if ( likely(get_page(page, d)) )
+ } else if ( likely(get_page(page, d)) )
{
unsigned long type = 0;
@@ -339,6 +343,7 @@ long arch_do_domctl(
else
arr32[j] |= XEN_DOMCTL_PFINFO_XTAB;
+ put_gfn(d, gfn);
}
if ( copy_to_guest_offset(domctl->u.getpageframeinfo2.array,
@@ -425,12 +430,13 @@ long arch_do_domctl(
break;
}
- mfn = gmfn_to_mfn(d, gmfn);
+ mfn = get_gfn_untyped(d, gmfn);
ret = -EACCES;
if ( !mfn_valid(mfn) ||
!get_page_and_type(mfn_to_page(mfn), d, PGT_writable_page) )
{
+ put_gfn(d, gmfn);
rcu_unlock_domain(d);
break;
}
@@ -443,6 +449,7 @@ long arch_do_domctl(
put_page_and_type(mfn_to_page(mfn));
+ put_gfn(d, gmfn);
rcu_unlock_domain(d);
}
break;
diff -r 4699decb8424 -r 7461834954c8 xen/arch/x86/hvm/emulate.c
--- a/xen/arch/x86/hvm/emulate.c
+++ b/xen/arch/x86/hvm/emulate.c
@@ -63,14 +63,18 @@ static int hvmemul_do_io(
int rc;
/* Check for paged out page */
- ram_mfn = gfn_to_mfn_unshare(curr->domain, ram_gfn, &p2mt);
+ ram_mfn = get_gfn_unshare(curr->domain, ram_gfn, &p2mt);
if ( p2m_is_paging(p2mt) )
{
p2m_mem_paging_populate(curr->domain, ram_gfn);
+ put_gfn(curr->domain, ram_gfn);
return X86EMUL_RETRY;
}
if ( p2m_is_shared(p2mt) )
+ {
+ put_gfn(curr->domain, ram_gfn);
return X86EMUL_RETRY;
+ }
/*
* Weird-sized accesses have undefined behaviour: we discard writes
@@ -82,6 +86,7 @@ static int hvmemul_do_io(
ASSERT(p_data != NULL); /* cannot happen with a REP prefix */
if ( dir == IOREQ_READ )
memset(p_data, ~0, size);
+ put_gfn(curr->domain, ram_gfn);
return X86EMUL_UNHANDLEABLE;
}
@@ -101,7 +106,10 @@ static int hvmemul_do_io(
paddr_t pa = vio->mmio_large_write_pa;
unsigned int bytes = vio->mmio_large_write_bytes;
if ( (addr >= pa) && ((addr + size) <= (pa + bytes)) )
+ {
+ put_gfn(curr->domain, ram_gfn);
return X86EMUL_OKAY;
+ }
}
else
{
@@ -111,6 +119,7 @@ static int hvmemul_do_io(
{
memcpy(p_data, &vio->mmio_large_read[addr - pa],
size);
+ put_gfn(curr->domain, ram_gfn);
return X86EMUL_OKAY;
}
}
@@ -123,15 +132,22 @@ static int hvmemul_do_io(
case HVMIO_completed:
vio->io_state = HVMIO_none;
if ( p_data == NULL )
+ {
+ put_gfn(curr->domain, ram_gfn);
return X86EMUL_UNHANDLEABLE;
+ }
goto finish_access;
case HVMIO_dispatched:
/* May have to wait for previous cycle of a multi-write to complete. */
if ( is_mmio && !value_is_ptr && (dir == IOREQ_WRITE) &&
(addr == (vio->mmio_large_write_pa +
vio->mmio_large_write_bytes)) )
+ {
+ put_gfn(curr->domain, ram_gfn);
return X86EMUL_RETRY;
+ }
default:
+ put_gfn(curr->domain, ram_gfn);
return X86EMUL_UNHANDLEABLE;
}
@@ -139,6 +155,7 @@ static int hvmemul_do_io(
{
gdprintk(XENLOG_WARNING, "WARNING: io already pending (%d)?\n",
p->state);
+ put_gfn(curr->domain, ram_gfn);
return X86EMUL_UNHANDLEABLE;
}
@@ -189,7 +206,10 @@ static int hvmemul_do_io(
}
if ( rc != X86EMUL_OKAY )
+ {
+ put_gfn(curr->domain, ram_gfn);
return rc;
+ }
finish_access:
if ( p_data != NULL )
@@ -223,6 +243,7 @@ static int hvmemul_do_io(
}
}
+ put_gfn(curr->domain, ram_gfn);
return X86EMUL_OKAY;
}
@@ -671,12 +692,14 @@ static int hvmemul_rep_movs(
if ( rc != X86EMUL_OKAY )
return rc;
- (void)gfn_to_mfn(current->domain, sgpa >> PAGE_SHIFT, &p2mt);
+ /* Unlocked works here because we get_gfn for real in whatever
+ * we call later. */
+ (void)get_gfn_unlocked(current->domain, sgpa >> PAGE_SHIFT, &p2mt);
if ( !p2m_is_ram(p2mt) && !p2m_is_grant(p2mt) )
return hvmemul_do_mmio(
sgpa, reps, bytes_per_rep, dgpa, IOREQ_READ, df, NULL);
- (void)gfn_to_mfn(current->domain, dgpa >> PAGE_SHIFT, &p2mt);
+ (void)get_gfn_unlocked(current->domain, dgpa >> PAGE_SHIFT, &p2mt);
if ( !p2m_is_ram(p2mt) && !p2m_is_grant(p2mt) )
return hvmemul_do_mmio(
dgpa, reps, bytes_per_rep, sgpa, IOREQ_WRITE, df, NULL);
diff -r 4699decb8424 -r 7461834954c8 xen/arch/x86/hvm/hvm.c
--- a/xen/arch/x86/hvm/hvm.c
+++ b/xen/arch/x86/hvm/hvm.c
@@ -355,26 +355,37 @@ static int hvm_set_ioreq_page(
unsigned long mfn;
void *va;
- mfn = mfn_x(gfn_to_mfn_unshare(d, gmfn, &p2mt));
+ mfn = mfn_x(get_gfn_unshare(d, gmfn, &p2mt));
if ( !p2m_is_ram(p2mt) )
+ {
+ put_gfn(d, gmfn);
return -EINVAL;
+ }
if ( p2m_is_paging(p2mt) )
{
p2m_mem_paging_populate(d, gmfn);
+ put_gfn(d, gmfn);
return -ENOENT;
}
if ( p2m_is_shared(p2mt) )
+ {
+ put_gfn(d, gmfn);
return -ENOENT;
+ }
ASSERT(mfn_valid(mfn));
page = mfn_to_page(mfn);
if ( !get_page_and_type(page, d, PGT_writable_page) )
+ {
+ put_gfn(d, gmfn);
return -EINVAL;
+ }
va = map_domain_page_global(mfn);
if ( va == NULL )
{
put_page_and_type(page);
+ put_gfn(d, gmfn);
return -ENOMEM;
}
@@ -385,6 +396,7 @@ static int hvm_set_ioreq_page(
spin_unlock(&iorp->lock);
unmap_domain_page_global(va);
put_page_and_type(mfn_to_page(mfn));
+ put_gfn(d, gmfn);
return -EINVAL;
}
@@ -392,6 +404,7 @@ static int hvm_set_ioreq_page(
iorp->page = page;
spin_unlock(&iorp->lock);
+ put_gfn(d, gmfn);
domain_unpause(d);
@@ -1182,6 +1195,7 @@ int hvm_hap_nested_page_fault(unsigned l
mfn_t mfn;
struct vcpu *v = current;
struct p2m_domain *p2m;
+ int rc;
/* On Nested Virtualization, walk the guest page table.
* If this succeeds, all is fine.
@@ -1216,7 +1230,7 @@ int hvm_hap_nested_page_fault(unsigned l
}
p2m = p2m_get_hostp2m(v->domain);
- mfn = gfn_to_mfn_type_p2m(p2m, gfn, &p2mt, &p2ma, p2m_guest, NULL);
+ mfn = get_gfn_type_access(p2m, gfn, &p2mt, &p2ma, p2m_guest, NULL);
/* Check access permissions first, then handle faults */
if ( access_valid && (mfn_x(mfn) != INVALID_MFN) )
@@ -1255,8 +1269,8 @@ int hvm_hap_nested_page_fault(unsigned l
if ( violation )
{
p2m_mem_access_check(gpa, gla_valid, gla, access_r, access_w,
access_x);
-
- return 1;
+ rc = 1;
+ goto out_put_gfn;
}
}
@@ -1268,7 +1282,8 @@ int hvm_hap_nested_page_fault(unsigned l
{
if ( !handle_mmio() )
hvm_inject_exception(TRAP_gp_fault, 0, 0);
- return 1;
+ rc = 1;
+ goto out_put_gfn;
}
#ifdef __x86_64__
@@ -1281,7 +1296,8 @@ int hvm_hap_nested_page_fault(unsigned l
{
ASSERT(!p2m_is_nestedp2m(p2m));
mem_sharing_unshare_page(p2m->domain, gfn, 0);
- return 1;
+ rc = 1;
+ goto out_put_gfn;
}
#endif
@@ -1295,7 +1311,8 @@ int hvm_hap_nested_page_fault(unsigned l
*/
paging_mark_dirty(v->domain, mfn_x(mfn));
p2m_change_type(v->domain, gfn, p2m_ram_logdirty, p2m_ram_rw);
- return 1;
+ rc = 1;
+ goto out_put_gfn;
}
/* Shouldn't happen: Maybe the guest was writing to a r/o grant mapping? */
@@ -1304,10 +1321,14 @@ int hvm_hap_nested_page_fault(unsigned l
gdprintk(XENLOG_WARNING,
"trying to write to read-only grant mapping\n");
hvm_inject_exception(TRAP_gp_fault, 0, 0);
- return 1;
+ rc = 1;
+ goto out_put_gfn;
}
- return 0;
+ rc = 0;
+out_put_gfn:
+ put_gfn(p2m->domain, gfn);
+ return rc;
}
int hvm_handle_xsetbv(u64 new_bv)
@@ -1530,10 +1551,11 @@ int hvm_set_cr0(unsigned long value)
{
/* The guest CR3 must be pointing to the guest physical. */
gfn = v->arch.hvm_vcpu.guest_cr[3]>>PAGE_SHIFT;
- mfn = mfn_x(gfn_to_mfn(v->domain, gfn, &p2mt));
+ mfn = mfn_x(get_gfn(v->domain, gfn, &p2mt));
if ( !p2m_is_ram(p2mt) || !mfn_valid(mfn) ||
!get_page(mfn_to_page(mfn), v->domain))
{
+ put_gfn(v->domain, gfn);
gdprintk(XENLOG_ERR, "Invalid CR3 value = %lx (mfn=%lx)\n",
v->arch.hvm_vcpu.guest_cr[3], mfn);
domain_crash(v->domain);
@@ -1545,6 +1567,7 @@ int hvm_set_cr0(unsigned long value)
HVM_DBG_LOG(DBG_LEVEL_VMMU, "Update CR3 value = %lx, mfn = %lx",
v->arch.hvm_vcpu.guest_cr[3], mfn);
+ put_gfn(v->domain, gfn);
}
}
else if ( !(value & X86_CR0_PG) && (old_value & X86_CR0_PG) )
@@ -1621,13 +1644,17 @@ int hvm_set_cr3(unsigned long value)
{
/* Shadow-mode CR3 change. Check PDBR and update refcounts. */
HVM_DBG_LOG(DBG_LEVEL_VMMU, "CR3 value = %lx", value);
- mfn = mfn_x(gfn_to_mfn(v->domain, value >> PAGE_SHIFT, &p2mt));
+ mfn = mfn_x(get_gfn(v->domain, value >> PAGE_SHIFT, &p2mt));
if ( !p2m_is_ram(p2mt) || !mfn_valid(mfn) ||
!get_page(mfn_to_page(mfn), v->domain) )
+ {
+ put_gfn(v->domain, value >> PAGE_SHIFT);
goto bad_cr3;
+ }
put_page(pagetable_get_page(v->arch.guest_table));
v->arch.guest_table = pagetable_from_pfn(mfn);
+ put_gfn(v->domain, value >> PAGE_SHIFT);
HVM_DBG_LOG(DBG_LEVEL_VMMU, "Update CR3 value = %lx", value);
}
@@ -1764,6 +1791,7 @@ int hvm_virtual_to_linear_addr(
return 0;
}
+/* We leave this function holding a lock on the p2m entry */
static void *__hvm_map_guest_frame(unsigned long gfn, bool_t writable)
{
unsigned long mfn;
@@ -1771,13 +1799,17 @@ static void *__hvm_map_guest_frame(unsig
struct domain *d = current->domain;
mfn = mfn_x(writable
- ? gfn_to_mfn_unshare(d, gfn, &p2mt)
- : gfn_to_mfn(d, gfn, &p2mt));
+ ? get_gfn_unshare(d, gfn, &p2mt)
+ : get_gfn(d, gfn, &p2mt));
if ( (p2m_is_shared(p2mt) && writable) || !p2m_is_ram(p2mt) )
+ {
+ put_gfn(d, gfn);
return NULL;
+ }
if ( p2m_is_paging(p2mt) )
{
p2m_mem_paging_populate(d, gfn);
+ put_gfn(d, gfn);
return NULL;
}
@@ -1805,9 +1837,8 @@ void hvm_unmap_guest_frame(void *p)
unmap_domain_page(p);
}
-static void *hvm_map_entry(unsigned long va)
+static void *hvm_map_entry(unsigned long va, unsigned long *gfn)
{
- unsigned long gfn;
uint32_t pfec;
char *v;
@@ -1824,11 +1855,11 @@ static void *hvm_map_entry(unsigned long
* treat it as a kernel-mode read (i.e. no access checks).
*/
pfec = PFEC_page_present;
- gfn = paging_gva_to_gfn(current, va, &pfec);
+ *gfn = paging_gva_to_gfn(current, va, &pfec);
if ( (pfec == PFEC_page_paged) || (pfec == PFEC_page_shared) )
goto fail;
- v = hvm_map_guest_frame_rw(gfn);
+ v = hvm_map_guest_frame_rw(*gfn);
if ( v == NULL )
goto fail;
@@ -1839,9 +1870,11 @@ static void *hvm_map_entry(unsigned long
return NULL;
}
-static void hvm_unmap_entry(void *p)
+static void hvm_unmap_entry(void *p, unsigned long gfn)
{
hvm_unmap_guest_frame(p);
+ if ( p && (gfn != INVALID_GFN) )
+ put_gfn(current->domain, gfn);
}
static int hvm_load_segment_selector(
@@ -1853,6 +1886,7 @@ static int hvm_load_segment_selector(
int fault_type = TRAP_invalid_tss;
struct cpu_user_regs *regs = guest_cpu_user_regs();
struct vcpu *v = current;
+ unsigned long pdesc_gfn = INVALID_GFN;
if ( regs->eflags & X86_EFLAGS_VM )
{
@@ -1886,7 +1920,7 @@ static int hvm_load_segment_selector(
if ( ((sel & 0xfff8) + 7) > desctab.limit )
goto fail;
- pdesc = hvm_map_entry(desctab.base + (sel & 0xfff8));
+ pdesc = hvm_map_entry(desctab.base + (sel & 0xfff8), &pdesc_gfn);
if ( pdesc == NULL )
goto hvm_map_fail;
@@ -1946,7 +1980,7 @@ static int hvm_load_segment_selector(
desc.b |= 0x100;
skip_accessed_flag:
- hvm_unmap_entry(pdesc);
+ hvm_unmap_entry(pdesc, pdesc_gfn);
segr.base = (((desc.b << 0) & 0xff000000u) |
((desc.b << 16) & 0x00ff0000u) |
@@ -1962,7 +1996,7 @@ static int hvm_load_segment_selector(
return 0;
unmap_and_fail:
- hvm_unmap_entry(pdesc);
+ hvm_unmap_entry(pdesc, pdesc_gfn);
fail:
hvm_inject_exception(fault_type, sel & 0xfffc, 0);
hvm_map_fail:
@@ -1977,7 +2011,7 @@ void hvm_task_switch(
struct cpu_user_regs *regs = guest_cpu_user_regs();
struct segment_register gdt, tr, prev_tr, segr;
struct desc_struct *optss_desc = NULL, *nptss_desc = NULL, tss_desc;
- unsigned long eflags;
+ unsigned long eflags, optss_gfn = INVALID_GFN, nptss_gfn = INVALID_GFN;
int exn_raised, rc;
struct {
u16 back_link,__blh;
@@ -2003,11 +2037,11 @@ void hvm_task_switch(
goto out;
}
- optss_desc = hvm_map_entry(gdt.base + (prev_tr.sel & 0xfff8));
+ optss_desc = hvm_map_entry(gdt.base + (prev_tr.sel & 0xfff8), &optss_gfn);
if ( optss_desc == NULL )
goto out;
- nptss_desc = hvm_map_entry(gdt.base + (tss_sel & 0xfff8));
+ nptss_desc = hvm_map_entry(gdt.base + (tss_sel & 0xfff8), &nptss_gfn);
if ( nptss_desc == NULL )
goto out;
@@ -2172,8 +2206,8 @@ void hvm_task_switch(
}
out:
- hvm_unmap_entry(optss_desc);
- hvm_unmap_entry(nptss_desc);
+ hvm_unmap_entry(optss_desc, optss_gfn);
+ hvm_unmap_entry(nptss_desc, nptss_gfn);
}
#define HVMCOPY_from_guest (0u<<0)
@@ -2230,19 +2264,29 @@ static enum hvm_copy_result __hvm_copy(
gfn = addr >> PAGE_SHIFT;
}
- mfn = mfn_x(gfn_to_mfn_unshare(curr->domain, gfn, &p2mt));
+ mfn = mfn_x(get_gfn_unshare(curr->domain, gfn, &p2mt));
if ( p2m_is_paging(p2mt) )
{
p2m_mem_paging_populate(curr->domain, gfn);
+ put_gfn(curr->domain, gfn);
return HVMCOPY_gfn_paged_out;
}
if ( p2m_is_shared(p2mt) )
+ {
+ put_gfn(curr->domain, gfn);
return HVMCOPY_gfn_shared;
+ }
if ( p2m_is_grant(p2mt) )
+ {
+ put_gfn(curr->domain, gfn);
return HVMCOPY_unhandleable;
+ }
if ( !p2m_is_ram(p2mt) )
+ {
+ put_gfn(curr->domain, gfn);
return HVMCOPY_bad_gfn_to_mfn;
+ }
ASSERT(mfn_valid(mfn));
p = (char *)map_domain_page(mfn) + (addr & ~PAGE_MASK);
@@ -2273,6 +2317,7 @@ static enum hvm_copy_result __hvm_copy(
addr += count;
buf += count;
todo -= count;
+ put_gfn(curr->domain, gfn);
}
return HVMCOPY_okay;
@@ -3697,11 +3742,11 @@ long do_hvm_op(unsigned long op, XEN_GUE
for ( pfn = a.first_pfn; pfn < a.first_pfn + a.nr; pfn++ )
{
p2m_type_t t;
- mfn_t mfn = gfn_to_mfn(d, pfn, &t);
+ mfn_t mfn = get_gfn(d, pfn, &t);
if ( p2m_is_paging(t) )
{
p2m_mem_paging_populate(d, pfn);
-
+ put_gfn(d, pfn);
rc = -EINVAL;
goto param_fail3;
}
@@ -3716,6 +3761,7 @@ long do_hvm_op(unsigned long op, XEN_GUE
/* don't take a long time and don't die either */
sh_remove_shadows(d->vcpu[0], mfn, 1, 0);
}
+ put_gfn(d, pfn);
}
param_fail3:
@@ -3739,7 +3785,7 @@ long do_hvm_op(unsigned long op, XEN_GUE
rc = -EINVAL;
if ( is_hvm_domain(d) )
{
- gfn_to_mfn_unshare(d, a.pfn, &t);
+ get_gfn_unshare_unlocked(d, a.pfn, &t);
if ( p2m_is_mmio(t) )
a.mem_type = HVMMEM_mmio_dm;
else if ( p2m_is_readonly(t) )
@@ -3792,20 +3838,23 @@ long do_hvm_op(unsigned long op, XEN_GUE
p2m_type_t t;
p2m_type_t nt;
mfn_t mfn;
- mfn = gfn_to_mfn_unshare(d, pfn, &t);
+ mfn = get_gfn_unshare(d, pfn, &t);
if ( p2m_is_paging(t) )
{
p2m_mem_paging_populate(d, pfn);
+ put_gfn(d, pfn);
rc = -EINVAL;
goto param_fail4;
}
if ( p2m_is_shared(t) )
{
+ put_gfn(d, pfn);
rc = -EINVAL;
goto param_fail4;
}
if ( p2m_is_grant(t) )
{
+ put_gfn(d, pfn);
gdprintk(XENLOG_WARNING,
"type for pfn 0x%lx changed to grant while "
"we were working?\n", pfn);
@@ -3816,6 +3865,7 @@ long do_hvm_op(unsigned long op, XEN_GUE
nt = p2m_change_type(d, pfn, t, memtype[a.hvmmem_type]);
if ( nt != t )
{
+ put_gfn(d, pfn);
gdprintk(XENLOG_WARNING,
"type of pfn 0x%lx changed from %d to %d while "
"we were trying to change it to %d\n",
@@ -3823,6 +3873,7 @@ long do_hvm_op(unsigned long op, XEN_GUE
goto param_fail4;
}
}
+ put_gfn(d, pfn);
}
rc = 0;
diff -r 4699decb8424 -r 7461834954c8 xen/arch/x86/hvm/mtrr.c
--- a/xen/arch/x86/hvm/mtrr.c
+++ b/xen/arch/x86/hvm/mtrr.c
@@ -389,7 +389,7 @@ uint32_t get_pat_flags(struct vcpu *v,
{
struct domain *d = v->domain;
p2m_type_t p2mt;
- gfn_to_mfn_query(d, paddr_to_pfn(gpaddr), &p2mt);
+ get_gfn_query_unlocked(d, paddr_to_pfn(gpaddr), &p2mt);
if (p2m_is_ram(p2mt))
gdprintk(XENLOG_WARNING,
"Conflict occurs for a given guest l1e flags:%x "
diff -r 4699decb8424 -r 7461834954c8 xen/arch/x86/hvm/stdvga.c
--- a/xen/arch/x86/hvm/stdvga.c
+++ b/xen/arch/x86/hvm/stdvga.c
@@ -482,7 +482,7 @@ static int mmio_move(struct hvm_hw_stdvg
if ( hvm_copy_to_guest_phys(data, &tmp, p->size) !=
HVMCOPY_okay )
{
- (void)gfn_to_mfn(d, data >> PAGE_SHIFT, &p2mt);
+ (void)get_gfn_unlocked(d, data >> PAGE_SHIFT, &p2mt);
/*
* The only case we handle is vga_mem <-> vga_mem.
* Anything else disables caching and leaves it to qemu-dm.
@@ -504,7 +504,7 @@ static int mmio_move(struct hvm_hw_stdvg
if ( hvm_copy_from_guest_phys(&tmp, data, p->size) !=
HVMCOPY_okay )
{
- (void)gfn_to_mfn(d, data >> PAGE_SHIFT, &p2mt);
+ (void)get_gfn_unlocked(d, data >> PAGE_SHIFT, &p2mt);
if ( (p2mt != p2m_mmio_dm) || (data < VGA_MEM_BASE) ||
((data + p->size) > (VGA_MEM_BASE + VGA_MEM_SIZE)) )
return 0;
diff -r 4699decb8424 -r 7461834954c8 xen/arch/x86/hvm/svm/nestedsvm.c
--- a/xen/arch/x86/hvm/svm/nestedsvm.c
+++ b/xen/arch/x86/hvm/svm/nestedsvm.c
@@ -81,6 +81,10 @@ int nestedsvm_vmcb_map(struct vcpu *v, u
if (nv->nv_vvmcx == NULL)
return 0;
nv->nv_vvmcxaddr = vmcbaddr;
+ /* put_gfn here even though the map survives beyond this caller.
+ * The map can likely survive beyond a hypervisor exit, thus we
+ * need to put the gfn */
+ put_gfn(current->domain, vmcbaddr >> PAGE_SHIFT);
}
return 1;
@@ -354,6 +358,7 @@ static int nsvm_vmrun_permissionmap(stru
ioport_80 = test_bit(0x80, ns_viomap);
ioport_ed = test_bit(0xed, ns_viomap);
hvm_unmap_guest_frame(ns_viomap);
+ put_gfn(current->domain, svm->ns_iomap_pa >> PAGE_SHIFT);
svm->ns_iomap = nestedhvm_vcpu_iomap_get(ioport_80, ioport_ed);
@@ -857,23 +862,25 @@ nsvm_vmcb_guest_intercepts_ioio(paddr_t
ioio_info_t ioinfo;
uint16_t port;
bool_t enabled;
+ unsigned long gfn = 0; /* gcc ... */
ioinfo.bytes = exitinfo1;
port = ioinfo.fields.port;
switch (port) {
case 0 ... 32767: /* first 4KB page */
- io_bitmap = hvm_map_guest_frame_ro(iopm_gfn);
+ gfn = iopm_gfn;
break;
case 32768 ... 65535: /* second 4KB page */
port -= 32768;
- io_bitmap = hvm_map_guest_frame_ro(iopm_gfn+1);
+ gfn = iopm_gfn + 1;
break;
default:
BUG();
break;
}
+ io_bitmap = hvm_map_guest_frame_ro(gfn);
if (io_bitmap == NULL) {
gdprintk(XENLOG_ERR,
"IOIO intercept: mapping of permission map failed\n");
@@ -882,6 +889,8 @@ nsvm_vmcb_guest_intercepts_ioio(paddr_t
enabled = test_bit(port, io_bitmap);
hvm_unmap_guest_frame(io_bitmap);
+ put_gfn(current->domain, gfn);
+
if (!enabled)
return NESTEDHVM_VMEXIT_HOST;
diff -r 4699decb8424 -r 7461834954c8 xen/arch/x86/hvm/svm/svm.c
--- a/xen/arch/x86/hvm/svm/svm.c
+++ b/xen/arch/x86/hvm/svm/svm.c
@@ -244,9 +244,10 @@ static int svm_vmcb_restore(struct vcpu
{
if ( c->cr0 & X86_CR0_PG )
{
- mfn = mfn_x(gfn_to_mfn(v->domain, c->cr3 >> PAGE_SHIFT, &p2mt));
+ mfn = mfn_x(get_gfn(v->domain, c->cr3 >> PAGE_SHIFT, &p2mt));
if ( !p2m_is_ram(p2mt) || !get_page(mfn_to_page(mfn), v->domain) )
{
+ put_gfn(v->domain, c->cr3 >> PAGE_SHIFT);
gdprintk(XENLOG_ERR, "Invalid CR3 value=0x%"PRIx64"\n",
c->cr3);
return -EINVAL;
@@ -257,6 +258,8 @@ static int svm_vmcb_restore(struct vcpu
put_page(pagetable_get_page(v->arch.guest_table));
v->arch.guest_table = pagetable_from_pfn(mfn);
+ if ( c->cr0 & X86_CR0_PG )
+ put_gfn(v->domain, c->cr3 >> PAGE_SHIFT);
}
v->arch.hvm_vcpu.guest_cr[0] = c->cr0 | X86_CR0_ET;
@@ -1161,7 +1164,9 @@ static void svm_do_nested_pgfault(struct
p2m = p2m_get_p2m(v);
_d.gpa = gpa;
_d.qualification = 0;
- _d.mfn = mfn_x(gfn_to_mfn_type_p2m(p2m, gfn, &_d.p2mt, &p2ma,
p2m_query, NULL));
+ mfn = get_gfn_type_access(p2m, gfn, &_d.p2mt, &p2ma, p2m_query, NULL);
+ __put_gfn(p2m, gfn);
+ _d.mfn = mfn_x(mfn);
__trace_var(TRC_HVM_NPF, 0, sizeof(_d), &_d);
}
@@ -1181,7 +1186,8 @@ static void svm_do_nested_pgfault(struct
if ( p2m == NULL )
p2m = p2m_get_p2m(v);
/* Everything else is an error. */
- mfn = gfn_to_mfn_type_p2m(p2m, gfn, &p2mt, &p2ma, p2m_guest, NULL);
+ mfn = get_gfn_type_access(p2m, gfn, &p2mt, &p2ma, p2m_guest, NULL);
+ __put_gfn(p2m, gfn);
gdprintk(XENLOG_ERR,
"SVM violation gpa %#"PRIpaddr", mfn %#lx, type %i\n",
gpa, mfn_x(mfn), p2mt);
diff -r 4699decb8424 -r 7461834954c8 xen/arch/x86/hvm/viridian.c
--- a/xen/arch/x86/hvm/viridian.c
+++ b/xen/arch/x86/hvm/viridian.c
@@ -134,12 +134,13 @@ void dump_apic_assist(struct vcpu *v)
static void enable_hypercall_page(struct domain *d)
{
unsigned long gmfn = d->arch.hvm_domain.viridian.hypercall_gpa.fields.pfn;
- unsigned long mfn = gmfn_to_mfn(d, gmfn);
+ unsigned long mfn = get_gfn_untyped(d, gmfn);
uint8_t *p;
if ( !mfn_valid(mfn) ||
!get_page_and_type(mfn_to_page(mfn), d, PGT_writable_page) )
{
+ put_gfn(d, gmfn);
gdprintk(XENLOG_WARNING, "Bad GMFN %lx (MFN %lx)\n", gmfn, mfn);
return;
}
@@ -162,13 +163,14 @@ static void enable_hypercall_page(struct
unmap_domain_page(p);
put_page_and_type(mfn_to_page(mfn));
+ put_gfn(d, gmfn);
}
void initialize_apic_assist(struct vcpu *v)
{
struct domain *d = v->domain;
unsigned long gmfn = v->arch.hvm_vcpu.viridian.apic_assist.fields.pfn;
- unsigned long mfn = gmfn_to_mfn(d, gmfn);
+ unsigned long mfn = get_gfn_untyped(d, gmfn);
uint8_t *p;
/*
@@ -184,6 +186,7 @@ void initialize_apic_assist(struct vcpu
if ( !mfn_valid(mfn) ||
!get_page_and_type(mfn_to_page(mfn), d, PGT_writable_page) )
{
+ put_gfn(d, gmfn);
gdprintk(XENLOG_WARNING, "Bad GMFN %lx (MFN %lx)\n", gmfn, mfn);
return;
}
@@ -195,6 +198,7 @@ void initialize_apic_assist(struct vcpu
unmap_domain_page(p);
put_page_and_type(mfn_to_page(mfn));
+ put_gfn(d, gmfn);
}
int wrmsr_viridian_regs(uint32_t idx, uint64_t val)
diff -r 4699decb8424 -r 7461834954c8 xen/arch/x86/hvm/vmx/vmx.c
--- a/xen/arch/x86/hvm/vmx/vmx.c
+++ b/xen/arch/x86/hvm/vmx/vmx.c
@@ -487,9 +487,10 @@ static int vmx_restore_cr0_cr3(
{
if ( cr0 & X86_CR0_PG )
{
- mfn = mfn_x(gfn_to_mfn(v->domain, cr3 >> PAGE_SHIFT, &p2mt));
+ mfn = mfn_x(get_gfn(v->domain, cr3 >> PAGE_SHIFT, &p2mt));
if ( !p2m_is_ram(p2mt) || !get_page(mfn_to_page(mfn), v->domain) )
{
+ put_gfn(v->domain, cr3 >> PAGE_SHIFT);
gdprintk(XENLOG_ERR, "Invalid CR3 value=0x%lx\n", cr3);
return -EINVAL;
}
@@ -499,6 +500,8 @@ static int vmx_restore_cr0_cr3(
put_page(pagetable_get_page(v->arch.guest_table));
v->arch.guest_table = pagetable_from_pfn(mfn);
+ if ( cr0 & X86_CR0_PG )
+ put_gfn(v->domain, cr3 >> PAGE_SHIFT);
}
v->arch.hvm_vcpu.guest_cr[0] = cr0 | X86_CR0_ET;
@@ -1007,9 +1010,12 @@ static void vmx_load_pdptrs(struct vcpu
if ( cr3 & 0x1fUL )
goto crash;
- mfn = mfn_x(gfn_to_mfn(v->domain, cr3 >> PAGE_SHIFT, &p2mt));
+ mfn = mfn_x(get_gfn(v->domain, cr3 >> PAGE_SHIFT, &p2mt));
if ( !p2m_is_ram(p2mt) )
+ {
+ put_gfn(v->domain, cr3 >> PAGE_SHIFT);
goto crash;
+ }
p = map_domain_page(mfn);
@@ -1037,6 +1043,7 @@ static void vmx_load_pdptrs(struct vcpu
vmx_vmcs_exit(v);
unmap_domain_page(p);
+ put_gfn(v->domain, cr3 >> PAGE_SHIFT);
return;
crash:
@@ -2090,7 +2097,7 @@ static void ept_handle_violation(unsigne
_d.gpa = gpa;
_d.qualification = qualification;
- _d.mfn = mfn_x(gfn_to_mfn_query(d, gfn, &_d.p2mt));
+ _d.mfn = mfn_x(get_gfn_query_unlocked(d, gfn, &_d.p2mt));
__trace_var(TRC_HVM_NPF, 0, sizeof(_d), &_d);
}
@@ -2106,7 +2113,7 @@ static void ept_handle_violation(unsigne
return;
/* Everything else is an error. */
- mfn = gfn_to_mfn_guest(d, gfn, &p2mt);
+ mfn = get_gfn_guest_unlocked(d, gfn, &p2mt);
gdprintk(XENLOG_ERR, "EPT violation %#lx (%c%c%c/%c%c%c), "
"gpa %#"PRIpaddr", mfn %#lx, type %i.\n",
qualification,
diff -r 4699decb8424 -r 7461834954c8 xen/arch/x86/hvm/vmx/vvmx.c
--- a/xen/arch/x86/hvm/vmx/vvmx.c
+++ b/xen/arch/x86/hvm/vmx/vvmx.c
@@ -558,9 +558,12 @@ static void __map_io_bitmap(struct vcpu
index = vmcs_reg == IO_BITMAP_A ? 0 : 1;
if (nvmx->iobitmap[index])
- hvm_unmap_guest_frame (nvmx->iobitmap[index]);
+ hvm_unmap_guest_frame (nvmx->iobitmap[index]);
gpa = __get_vvmcs(vcpu_nestedhvm(v).nv_vvmcx, vmcs_reg);
nvmx->iobitmap[index] = hvm_map_guest_frame_ro (gpa >> PAGE_SHIFT);
+ /* See comment in nestedsvm_vmcb_map re putting this gfn and
+ * liveness of the map it backs */
+ put_gfn(current->domain, gpa >> PAGE_SHIFT);
}
static inline void map_io_bitmap_all(struct vcpu *v)
@@ -577,12 +580,12 @@ static void nvmx_purge_vvmcs(struct vcpu
__clear_current_vvmcs(v);
if ( nvcpu->nv_vvmcxaddr != VMCX_EADDR )
- hvm_unmap_guest_frame (nvcpu->nv_vvmcx);
+ hvm_unmap_guest_frame(nvcpu->nv_vvmcx);
nvcpu->nv_vvmcx == NULL;
nvcpu->nv_vvmcxaddr = VMCX_EADDR;
for (i=0; i<2; i++) {
if ( nvmx->iobitmap[i] ) {
- hvm_unmap_guest_frame (nvmx->iobitmap[i]);
+ hvm_unmap_guest_frame(nvmx->iobitmap[i]);
nvmx->iobitmap[i] = NULL;
}
}
@@ -1138,6 +1141,9 @@ int nvmx_handle_vmptrld(struct cpu_user_
nvcpu->nv_vvmcx = hvm_map_guest_frame_rw (gpa >> PAGE_SHIFT);
nvcpu->nv_vvmcxaddr = gpa;
map_io_bitmap_all (v);
+ /* See comment in nestedsvm_vmcb_map regarding putting this
+ * gfn and liveness of the map that uses it */
+ put_gfn(current->domain, gpa >> PAGE_SHIFT);
}
vmreturn(regs, VMSUCCEED);
@@ -1199,6 +1205,7 @@ int nvmx_handle_vmclear(struct cpu_user_
if ( vvmcs )
__set_vvmcs(vvmcs, NVMX_LAUNCH_STATE, 0);
hvm_unmap_guest_frame(vvmcs);
+ put_gfn(current->domain, gpa >> PAGE_SHIFT);
}
vmreturn(regs, VMSUCCEED);
diff -r 4699decb8424 -r 7461834954c8 xen/arch/x86/mm.c
--- a/xen/arch/x86/mm.c
+++ b/xen/arch/x86/mm.c
@@ -663,13 +663,19 @@ int map_ldt_shadow_page(unsigned int off
return 0;
gmfn = l1e_get_pfn(l1e);
- mfn = gmfn_to_mfn(d, gmfn);
+ mfn = get_gfn_untyped(d, gmfn);
if ( unlikely(!mfn_valid(mfn)) )
+ {
+ put_gfn(d, gmfn);
return 0;
+ }
okay = get_page_and_type(mfn_to_page(mfn), d, PGT_seg_desc_page);
if ( unlikely(!okay) )
+ {
+ put_gfn(d, gmfn);
return 0;
+ }
nl1e = l1e_from_pfn(mfn, l1e_get_flags(l1e) | _PAGE_RW);
@@ -678,6 +684,7 @@ int map_ldt_shadow_page(unsigned int off
v->arch.pv_vcpu.shadow_ldt_mapcnt++;
spin_unlock(&v->arch.pv_vcpu.shadow_ldt_lock);
+ put_gfn(d, gmfn);
return 1;
}
@@ -1798,7 +1805,6 @@ static int mod_l1_entry(l1_pgentry_t *pl
{
l1_pgentry_t ol1e;
struct domain *pt_dom = pt_vcpu->domain;
- unsigned long mfn;
p2m_type_t p2mt;
int rc = 0;
@@ -1815,9 +1821,14 @@ static int mod_l1_entry(l1_pgentry_t *pl
if ( l1e_get_flags(nl1e) & _PAGE_PRESENT )
{
/* Translate foreign guest addresses. */
- mfn = mfn_x(gfn_to_mfn(pg_dom, l1e_get_pfn(nl1e), &p2mt));
+ unsigned long mfn, gfn;
+ gfn = l1e_get_pfn(nl1e);
+ mfn = mfn_x(get_gfn(pg_dom, gfn, &p2mt));
if ( !p2m_is_ram(p2mt) || unlikely(mfn == INVALID_MFN) )
+ {
+ put_gfn(pg_dom, gfn);
return -EINVAL;
+ }
ASSERT((mfn & ~(PADDR_MASK >> PAGE_SHIFT)) == 0);
nl1e = l1e_from_pfn(mfn, l1e_get_flags(nl1e));
@@ -1825,6 +1836,7 @@ static int mod_l1_entry(l1_pgentry_t *pl
{
MEM_LOG("Bad L1 flags %x",
l1e_get_flags(nl1e) & l1_disallow_mask(pt_dom));
+ put_gfn(pg_dom, gfn);
return -EINVAL;
}
@@ -1835,12 +1847,14 @@ static int mod_l1_entry(l1_pgentry_t *pl
if ( UPDATE_ENTRY(l1, pl1e, ol1e, nl1e, gl1mfn, pt_vcpu,
preserve_ad) )
return 0;
+ put_gfn(pg_dom, gfn);
return -EBUSY;
}
switch ( rc = get_page_from_l1e(nl1e, pt_dom, pg_dom) )
{
default:
+ put_gfn(pg_dom, gfn);
return rc;
case 0:
break;
@@ -1856,6 +1870,7 @@ static int mod_l1_entry(l1_pgentry_t *pl
ol1e = nl1e;
rc = -EBUSY;
}
+ put_gfn(pg_dom, gfn);
}
else if ( unlikely(!UPDATE_ENTRY(l1, pl1e, ol1e, nl1e, gl1mfn, pt_vcpu,
preserve_ad)) )
@@ -3023,7 +3038,7 @@ int do_mmuext_op(
if ( paging_mode_refcounts(pg_owner) )
break;
- mfn = gmfn_to_mfn(pg_owner, op.arg1.mfn);
+ mfn = get_gfn_untyped(pg_owner, op.arg1.mfn);
rc = get_page_and_type_from_pagenr(mfn, type, pg_owner, 0, 1);
okay = !rc;
if ( unlikely(!okay) )
@@ -3032,6 +3047,7 @@ int do_mmuext_op(
rc = -EAGAIN;
else if ( rc != -EAGAIN )
MEM_LOG("Error while pinning mfn %lx", mfn);
+ put_gfn(pg_owner, op.arg1.mfn);
break;
}
@@ -3040,6 +3056,7 @@ int do_mmuext_op(
if ( (rc = xsm_memory_pin_page(d, page)) != 0 )
{
put_page_and_type(page);
+ put_gfn(pg_owner, op.arg1.mfn);
okay = 0;
break;
}
@@ -3049,6 +3066,7 @@ int do_mmuext_op(
{
MEM_LOG("Mfn %lx already pinned", mfn);
put_page_and_type(page);
+ put_gfn(pg_owner, op.arg1.mfn);
okay = 0;
break;
}
@@ -3067,6 +3085,7 @@ int do_mmuext_op(
spin_unlock(&pg_owner->page_alloc_lock);
if ( drop_ref )
put_page_and_type(page);
+ put_gfn(pg_owner, op.arg1.mfn);
}
break;
@@ -3079,9 +3098,10 @@ int do_mmuext_op(
if ( paging_mode_refcounts(pg_owner) )
break;
- mfn = gmfn_to_mfn(pg_owner, op.arg1.mfn);
+ mfn = get_gfn_untyped(pg_owner, op.arg1.mfn);
if ( unlikely(!(okay = get_page_from_pagenr(mfn, pg_owner))) )
{
+ put_gfn(pg_owner, op.arg1.mfn);
MEM_LOG("Mfn %lx bad domain", mfn);
break;
}
@@ -3092,6 +3112,7 @@ int do_mmuext_op(
{
okay = 0;
put_page(page);
+ put_gfn(pg_owner, op.arg1.mfn);
MEM_LOG("Mfn %lx not pinned", mfn);
break;
}
@@ -3102,18 +3123,20 @@ int do_mmuext_op(
/* A page is dirtied when its pin status is cleared. */
paging_mark_dirty(pg_owner, mfn);
+ put_gfn(pg_owner, op.arg1.mfn);
break;
}
case MMUEXT_NEW_BASEPTR:
- okay = new_guest_cr3(gmfn_to_mfn(d, op.arg1.mfn));
+ okay = new_guest_cr3(get_gfn_untyped(d, op.arg1.mfn));
+ put_gfn(d, op.arg1.mfn);
break;
#ifdef __x86_64__
case MMUEXT_NEW_USER_BASEPTR: {
unsigned long old_mfn, mfn;
- mfn = gmfn_to_mfn(d, op.arg1.mfn);
+ mfn = get_gfn_untyped(d, op.arg1.mfn);
if ( mfn != 0 )
{
if ( paging_mode_refcounts(d) )
@@ -3123,6 +3146,7 @@ int do_mmuext_op(
mfn, PGT_root_page_table, d, 0, 0);
if ( unlikely(!okay) )
{
+ put_gfn(d, op.arg1.mfn);
MEM_LOG("Error while installing new mfn %lx", mfn);
break;
}
@@ -3130,6 +3154,7 @@ int do_mmuext_op(
old_mfn = pagetable_get_pfn(curr->arch.guest_table_user);
curr->arch.guest_table_user = pagetable_from_pfn(mfn);
+ put_gfn(d, op.arg1.mfn);
if ( old_mfn != 0 )
{
@@ -3247,11 +3272,12 @@ int do_mmuext_op(
unsigned long mfn;
unsigned char *ptr;
- mfn = gmfn_to_mfn(d, op.arg1.mfn);
+ mfn = get_gfn_untyped(d, op.arg1.mfn);
okay = !get_page_and_type_from_pagenr(
mfn, PGT_writable_page, d, 0, 0);
if ( unlikely(!okay) )
{
+ put_gfn(d, op.arg1.mfn);
MEM_LOG("Error while clearing mfn %lx", mfn);
break;
}
@@ -3264,6 +3290,7 @@ int do_mmuext_op(
fixunmap_domain_page(ptr);
put_page_and_type(mfn_to_page(mfn));
+ put_gfn(d, op.arg1.mfn);
break;
}
@@ -3273,20 +3300,23 @@ int do_mmuext_op(
unsigned char *dst;
unsigned long src_mfn, mfn;
- src_mfn = gmfn_to_mfn(d, op.arg2.src_mfn);
+ src_mfn = get_gfn_untyped(d, op.arg2.src_mfn);
okay = get_page_from_pagenr(src_mfn, d);
if ( unlikely(!okay) )
{
+ put_gfn(d, op.arg2.src_mfn);
MEM_LOG("Error while copying from mfn %lx", src_mfn);
break;
}
- mfn = gmfn_to_mfn(d, op.arg1.mfn);
+ mfn = get_gfn_untyped(d, op.arg1.mfn);
okay = !get_page_and_type_from_pagenr(
mfn, PGT_writable_page, d, 0, 0);
if ( unlikely(!okay) )
{
+ put_gfn(d, op.arg1.mfn);
put_page(mfn_to_page(src_mfn));
+ put_gfn(d, op.arg2.src_mfn);
MEM_LOG("Error while copying to mfn %lx", mfn);
break;
}
@@ -3301,7 +3331,9 @@ int do_mmuext_op(
unmap_domain_page(src);
put_page_and_type(mfn_to_page(mfn));
+ put_gfn(d, op.arg1.mfn);
put_page(mfn_to_page(src_mfn));
+ put_gfn(d, op.arg2.src_mfn);
break;
}
@@ -3489,14 +3521,14 @@ int do_mmu_update(
req.ptr -= cmd;
gmfn = req.ptr >> PAGE_SHIFT;
- mfn = mfn_x(gfn_to_mfn(pt_owner, gmfn, &p2mt));
+ mfn = mfn_x(get_gfn(pt_owner, gmfn, &p2mt));
if ( !p2m_is_valid(p2mt) )
- mfn = INVALID_MFN;
+ mfn = INVALID_MFN;
if ( p2m_is_paged(p2mt) )
{
p2m_mem_paging_populate(pg_owner, gmfn);
-
+ put_gfn(pt_owner, gmfn);
rc = -ENOENT;
break;
}
@@ -3504,6 +3536,7 @@ int do_mmu_update(
if ( unlikely(!get_page_from_pagenr(mfn, pt_owner)) )
{
MEM_LOG("Could not get page for normal update");
+ put_gfn(pt_owner, gmfn);
break;
}
@@ -3516,6 +3549,7 @@ int do_mmu_update(
if ( rc ) {
unmap_domain_page_with_cache(va, &mapcache);
put_page(page);
+ put_gfn(pt_owner, gmfn);
break;
}
@@ -3527,16 +3561,20 @@ int do_mmu_update(
{
l1_pgentry_t l1e = l1e_from_intpte(req.val);
p2m_type_t l1e_p2mt;
- gfn_to_mfn(pg_owner, l1e_get_pfn(l1e), &l1e_p2mt);
+ unsigned long l1egfn = l1e_get_pfn(l1e), l1emfn;
+
+ l1emfn = mfn_x(get_gfn(pg_owner, l1egfn, &l1e_p2mt));
if ( p2m_is_paged(l1e_p2mt) )
{
p2m_mem_paging_populate(pg_owner, l1e_get_pfn(l1e));
+ put_gfn(pg_owner, l1egfn);
rc = -ENOENT;
break;
}
else if ( p2m_ram_paging_in_start == l1e_p2mt &&
!mfn_valid(mfn) )
{
+ put_gfn(pg_owner, l1egfn);
rc = -ENOENT;
break;
}
@@ -3553,7 +3591,10 @@ int do_mmu_update(
l1e_get_pfn(l1e),
0);
if ( rc )
+ {
+ put_gfn(pg_owner, l1egfn);
break;
+ }
}
}
#endif
@@ -3561,27 +3602,33 @@ int do_mmu_update(
rc = mod_l1_entry(va, l1e, mfn,
cmd == MMU_PT_UPDATE_PRESERVE_AD, v,
pg_owner);
+ put_gfn(pg_owner, l1egfn);
}
break;
case PGT_l2_page_table:
{
l2_pgentry_t l2e = l2e_from_intpte(req.val);
p2m_type_t l2e_p2mt;
- gfn_to_mfn(pg_owner, l2e_get_pfn(l2e), &l2e_p2mt);
+ unsigned long l2egfn = l2e_get_pfn(l2e), l2emfn;
+
+ l2emfn = mfn_x(get_gfn(pg_owner, l2egfn, &l2e_p2mt));
if ( p2m_is_paged(l2e_p2mt) )
{
- p2m_mem_paging_populate(pg_owner, l2e_get_pfn(l2e));
+ p2m_mem_paging_populate(pg_owner, l2egfn);
+ put_gfn(pg_owner, l2egfn);
rc = -ENOENT;
break;
}
else if ( p2m_ram_paging_in_start == l2e_p2mt &&
!mfn_valid(mfn) )
{
+ put_gfn(pg_owner, l2egfn);
rc = -ENOENT;
break;
}
else if ( p2m_ram_shared == l2e_p2mt )
{
+ put_gfn(pg_owner, l2egfn);
MEM_LOG("Unexpected attempt to map shared page.\n");
break;
}
@@ -3589,33 +3636,40 @@ int do_mmu_update(
rc = mod_l2_entry(va, l2e, mfn,
cmd == MMU_PT_UPDATE_PRESERVE_AD, v);
+ put_gfn(pg_owner, l2egfn);
}
break;
case PGT_l3_page_table:
{
l3_pgentry_t l3e = l3e_from_intpte(req.val);
p2m_type_t l3e_p2mt;
- gfn_to_mfn(pg_owner, l3e_get_pfn(l3e), &l3e_p2mt);
+ unsigned long l3egfn = l3e_get_pfn(l3e), l3emfn;
+
+ l3emfn = mfn_x(get_gfn(pg_owner, l3egfn, &l3e_p2mt));
if ( p2m_is_paged(l3e_p2mt) )
{
- p2m_mem_paging_populate(pg_owner, l3e_get_pfn(l3e));
+ p2m_mem_paging_populate(pg_owner, l3egfn);
+ put_gfn(pg_owner, l3egfn);
rc = -ENOENT;
break;
}
else if ( p2m_ram_paging_in_start == l3e_p2mt &&
!mfn_valid(mfn) )
{
+ put_gfn(pg_owner, l3egfn);
rc = -ENOENT;
break;
}
else if ( p2m_ram_shared == l3e_p2mt )
{
+ put_gfn(pg_owner, l3egfn);
MEM_LOG("Unexpected attempt to map shared page.\n");
break;
}
rc = mod_l3_entry(va, l3e, mfn,
cmd == MMU_PT_UPDATE_PRESERVE_AD, 1, v);
+ put_gfn(pg_owner, l3egfn);
}
break;
#if CONFIG_PAGING_LEVELS >= 4
@@ -3623,27 +3677,33 @@ int do_mmu_update(
{
l4_pgentry_t l4e = l4e_from_intpte(req.val);
p2m_type_t l4e_p2mt;
- gfn_to_mfn(pg_owner, l4e_get_pfn(l4e), &l4e_p2mt);
+ unsigned long l4egfn = l4e_get_pfn(l4e), l4emfn;
+
+ l4emfn = mfn_x(get_gfn(pg_owner, l4egfn, &l4e_p2mt));
if ( p2m_is_paged(l4e_p2mt) )
{
- p2m_mem_paging_populate(pg_owner, l4e_get_pfn(l4e));
+ p2m_mem_paging_populate(pg_owner, l4egfn);
+ put_gfn(pg_owner, l4egfn);
rc = -ENOENT;
break;
}
else if ( p2m_ram_paging_in_start == l4e_p2mt &&
!mfn_valid(mfn) )
{
+ put_gfn(pg_owner, l4egfn);
rc = -ENOENT;
break;
}
else if ( p2m_ram_shared == l4e_p2mt )
{
+ put_gfn(pg_owner, l4egfn);
MEM_LOG("Unexpected attempt to map shared page.\n");
break;
}
rc = mod_l4_entry(va, l4e, mfn,
cmd == MMU_PT_UPDATE_PRESERVE_AD, 1, v);
+ put_gfn(pg_owner, l4egfn);
}
break;
#endif
@@ -3667,6 +3727,7 @@ int do_mmu_update(
unmap_domain_page_with_cache(va, &mapcache);
put_page(page);
+ put_gfn(pt_owner, gmfn);
}
break;
@@ -3753,10 +3814,11 @@ static int create_grant_pte_mapping(
adjust_guest_l1e(nl1e, d);
gmfn = pte_addr >> PAGE_SHIFT;
- mfn = gmfn_to_mfn(d, gmfn);
+ mfn = get_gfn_untyped(d, gmfn);
if ( unlikely(!get_page_from_pagenr(mfn, current->domain)) )
{
+ put_gfn(d, gmfn);
MEM_LOG("Could not get page for normal update");
return GNTST_general_error;
}
@@ -3794,6 +3856,7 @@ static int create_grant_pte_mapping(
failed:
unmap_domain_page(va);
put_page(page);
+ put_gfn(d, gmfn);
return rc;
}
@@ -3808,10 +3871,11 @@ static int destroy_grant_pte_mapping(
l1_pgentry_t ol1e;
gmfn = addr >> PAGE_SHIFT;
- mfn = gmfn_to_mfn(d, gmfn);
+ mfn = get_gfn_untyped(d, gmfn);
if ( unlikely(!get_page_from_pagenr(mfn, current->domain)) )
{
+ put_gfn(d, gmfn);
MEM_LOG("Could not get page for normal update");
return GNTST_general_error;
}
@@ -3863,6 +3927,7 @@ static int destroy_grant_pte_mapping(
failed:
unmap_domain_page(va);
put_page(page);
+ put_gfn(d, gmfn);
return rc;
}
@@ -4054,9 +4119,10 @@ static int replace_grant_p2m_mapping(
if ( new_addr != 0 || (flags & GNTMAP_contains_pte) )
return GNTST_general_error;
- old_mfn = gfn_to_mfn(d, gfn, &type);
+ old_mfn = get_gfn(d, gfn, &type);
if ( !p2m_is_grant(type) || mfn_x(old_mfn) != frame )
{
+ put_gfn(d, gfn);
gdprintk(XENLOG_WARNING,
"replace_grant_p2m_mapping: old mapping invalid (type %d, mfn
%lx, frame %lx)\n",
type, mfn_x(old_mfn), frame);
@@ -4064,6 +4130,7 @@ static int replace_grant_p2m_mapping(
}
guest_physmap_remove_page(d, gfn, frame, PAGE_ORDER_4K);
+ put_gfn(d, gfn);
return GNTST_okay;
}
@@ -4444,15 +4511,20 @@ long set_gdt(struct vcpu *v,
struct domain *d = v->domain;
/* NB. There are 512 8-byte entries per GDT page. */
int i, nr_pages = (entries + 511) / 512;
- unsigned long mfn;
+ unsigned long mfn, *pfns;
if ( entries > FIRST_RESERVED_GDT_ENTRY )
return -EINVAL;
+ pfns = xmalloc_array(unsigned long, nr_pages);
+ if ( !pfns )
+ return -ENOMEM;
+
/* Check the pages in the new GDT. */
for ( i = 0; i < nr_pages; i++ )
{
- mfn = frames[i] = gmfn_to_mfn(d, frames[i]);
+ pfns[i] = frames[i];
+ mfn = frames[i] = get_gfn_untyped(d, frames[i]);
if ( !mfn_valid(mfn) ||
!get_page_and_type(mfn_to_page(mfn), d, PGT_seg_desc_page) )
goto fail;
@@ -4468,13 +4540,19 @@ long set_gdt(struct vcpu *v,
v->arch.pv_vcpu.gdt_frames[i] = frames[i];
l1e_write(&v->arch.perdomain_ptes[i],
l1e_from_pfn(frames[i], __PAGE_HYPERVISOR));
+ put_gfn(d, pfns[i]);
}
+ xfree(pfns);
return 0;
fail:
while ( i-- > 0 )
+ {
put_page_and_type(mfn_to_page(frames[i]));
+ put_gfn(d, pfns[i]);
+ }
+ xfree(pfns);
return -EINVAL;
}
@@ -4518,15 +4596,21 @@ long do_update_descriptor(u64 pa, u64 de
*(u64 *)&d = desc;
- mfn = gmfn_to_mfn(dom, gmfn);
+ mfn = get_gfn_untyped(dom, gmfn);
if ( (((unsigned int)pa % sizeof(struct desc_struct)) != 0) ||
!mfn_valid(mfn) ||
!check_descriptor(dom, &d) )
+ {
+ put_gfn(dom, gmfn);
return -EINVAL;
+ }
page = mfn_to_page(mfn);
if ( unlikely(!get_page(page, dom)) )
+ {
+ put_gfn(dom, gmfn);
return -EINVAL;
+ }
/* Check if the given frame is in use in an unsafe context. */
switch ( page->u.inuse.type_info & PGT_type_mask )
@@ -4554,6 +4638,7 @@ long do_update_descriptor(u64 pa, u64 de
out:
put_page(page);
+ put_gfn(dom, gmfn);
return ret;
}
@@ -4595,6 +4680,7 @@ static int handle_iomem_range(unsigned l
long arch_memory_op(int op, XEN_GUEST_HANDLE(void) arg)
{
struct page_info *page = NULL;
+ unsigned long gfn = 0; /* gcc ... */
int rc;
switch ( op )
@@ -4652,11 +4738,13 @@ long arch_memory_op(int op, XEN_GUEST_HA
case XENMAPSPACE_gmfn:
{
p2m_type_t p2mt;
-
- xatp.idx = mfn_x(gfn_to_mfn_unshare(d, xatp.idx, &p2mt));
+ gfn = xatp.idx;
+
+ xatp.idx = mfn_x(get_gfn_unshare(d, xatp.idx, &p2mt));
/* If the page is still shared, exit early */
if ( p2m_is_shared(p2mt) )
{
+ put_gfn(d, gfn);
rcu_unlock_domain(d);
return -ENOMEM;
}
@@ -4674,6 +4762,8 @@ long arch_memory_op(int op, XEN_GUEST_HA
{
if ( page )
put_page(page);
+ if ( xatp.space == XENMAPSPACE_gmfn )
+ put_gfn(d, gfn);
rcu_unlock_domain(d);
return -EINVAL;
}
@@ -4684,7 +4774,7 @@ long arch_memory_op(int op, XEN_GUEST_HA
put_page(page);
/* Remove previously mapped page if it was present. */
- prev_mfn = gmfn_to_mfn(d, xatp.gpfn);
+ prev_mfn = get_gfn_untyped(d, xatp.gpfn);
if ( mfn_valid(prev_mfn) )
{
if ( is_xen_heap_mfn(prev_mfn) )
@@ -4694,6 +4784,8 @@ long arch_memory_op(int op, XEN_GUEST_HA
/* Normal domain memory is freed, to avoid leaking memory. */
guest_remove_page(d, xatp.gpfn);
}
+ /* In the XENMAPSPACE_gmfn case we still hold a ref on the old page. */
+ put_gfn(d, xatp.gpfn);
/* Unmap from old location, if any. */
gpfn = get_gpfn_from_mfn(mfn);
@@ -4704,6 +4796,9 @@ long arch_memory_op(int op, XEN_GUEST_HA
/* Map at new location. */
rc = guest_physmap_add_page(d, xatp.gpfn, mfn, PAGE_ORDER_4K);
+ /* In the XENMAPSPACE_gmfn, we took a ref and locked the p2m at the
top */
+ if ( xatp.space == XENMAPSPACE_gmfn )
+ put_gfn(d, gfn);
domain_unlock(d);
rcu_unlock_domain(d);
diff -r 4699decb8424 -r 7461834954c8 xen/arch/x86/mm/guest_walk.c
--- a/xen/arch/x86/mm/guest_walk.c
+++ b/xen/arch/x86/mm/guest_walk.c
@@ -86,30 +86,35 @@ static uint32_t set_ad_bits(void *guest_
return 0;
}
+/* If the map is non-NULL, we leave this function having
+ * called get_gfn, you need to call put_gfn. */
static inline void *map_domain_gfn(struct p2m_domain *p2m,
gfn_t gfn,
mfn_t *mfn,
p2m_type_t *p2mt,
uint32_t *rc)
{
- p2m_access_t a;
+ p2m_access_t p2ma;
/* Translate the gfn, unsharing if shared */
- *mfn = gfn_to_mfn_type_p2m(p2m, gfn_x(gfn), p2mt, &a, p2m_unshare, NULL);
+ *mfn = get_gfn_type_access(p2m, gfn_x(gfn), p2mt, &p2ma, p2m_unshare,
NULL);
if ( p2m_is_paging(*p2mt) )
{
ASSERT(!p2m_is_nestedp2m(p2m));
p2m_mem_paging_populate(p2m->domain, gfn_x(gfn));
+ __put_gfn(p2m, gfn_x(gfn));
*rc = _PAGE_PAGED;
return NULL;
}
if ( p2m_is_shared(*p2mt) )
{
+ __put_gfn(p2m, gfn_x(gfn));
*rc = _PAGE_SHARED;
return NULL;
}
if ( !p2m_is_ram(*p2mt) )
{
+ __put_gfn(p2m, gfn_x(gfn));
*rc |= _PAGE_PRESENT;
return NULL;
}
@@ -120,6 +125,9 @@ static inline void *map_domain_gfn(struc
/* Walk the guest pagetables, after the manner of a hardware walker. */
+/* Because the walk is essentially random, it can cause a deadlock
+ * warning in the p2m locking code. Highly unlikely this is an actual
+ * deadlock, because who would walk page table in the opposite order? */
uint32_t
guest_walk_tables(struct vcpu *v, struct p2m_domain *p2m,
unsigned long va, walk_t *gw,
@@ -288,7 +296,6 @@ guest_walk_tables(struct vcpu *v, struct
#endif
rc |= _PAGE_INVALID_BITS;
}
-
/* Increment the pfn by the right number of 4k pages.
* Mask out PAT and invalid bits. */
start = _gfn((gfn_x(start) & ~GUEST_L2_GFN_MASK) +
@@ -347,12 +354,24 @@ set_ad:
out:
#if GUEST_PAGING_LEVELS == 4
- if ( l3p ) unmap_domain_page(l3p);
+ if ( l3p )
+ {
+ unmap_domain_page(l3p);
+ __put_gfn(p2m, gfn_x(guest_l4e_get_gfn(gw->l4e)));
+ }
#endif
#if GUEST_PAGING_LEVELS >= 3
- if ( l2p ) unmap_domain_page(l2p);
+ if ( l2p )
+ {
+ unmap_domain_page(l2p);
+ __put_gfn(p2m, gfn_x(guest_l3e_get_gfn(gw->l3e)));
+ }
#endif
- if ( l1p ) unmap_domain_page(l1p);
+ if ( l1p )
+ {
+ unmap_domain_page(l1p);
+ __put_gfn(p2m, gfn_x(guest_l2e_get_gfn(gw->l2e)));
+ }
return rc;
}
diff -r 4699decb8424 -r 7461834954c8 xen/arch/x86/mm/hap/guest_walk.c
--- a/xen/arch/x86/mm/hap/guest_walk.c
+++ b/xen/arch/x86/mm/hap/guest_walk.c
@@ -56,26 +56,30 @@ unsigned long hap_p2m_ga_to_gfn(GUEST_PA
p2m_type_t p2mt;
p2m_access_t p2ma;
walk_t gw;
+ unsigned long top_gfn;
/* Get the top-level table's MFN */
- top_mfn = gfn_to_mfn_type_p2m(p2m, cr3 >> PAGE_SHIFT,
- &p2mt, &p2ma, p2m_unshare, NULL);
+ top_gfn = cr3 >> PAGE_SHIFT;
+ top_mfn = get_gfn_type_access(p2m, top_gfn, &p2mt, &p2ma, p2m_unshare,
NULL);
if ( p2m_is_paging(p2mt) )
{
ASSERT(!p2m_is_nestedp2m(p2m));
p2m_mem_paging_populate(p2m->domain, cr3 >> PAGE_SHIFT);
pfec[0] = PFEC_page_paged;
+ __put_gfn(p2m, top_gfn);
return INVALID_GFN;
}
if ( p2m_is_shared(p2mt) )
{
pfec[0] = PFEC_page_shared;
+ __put_gfn(p2m, top_gfn);
return INVALID_GFN;
}
if ( !p2m_is_ram(p2mt) )
{
pfec[0] &= ~PFEC_page_present;
+ __put_gfn(p2m, top_gfn);
return INVALID_GFN;
}
@@ -87,26 +91,31 @@ unsigned long hap_p2m_ga_to_gfn(GUEST_PA
#endif
missing = guest_walk_tables(v, p2m, ga, &gw, pfec[0], top_mfn, top_map);
unmap_domain_page(top_map);
+ __put_gfn(p2m, top_gfn);
/* Interpret the answer */
if ( missing == 0 )
{
gfn_t gfn = guest_l1e_get_gfn(gw.l1e);
- gfn_to_mfn_type_p2m(p2m, gfn_x(gfn), &p2mt, &p2ma, p2m_unshare, NULL);
+ (void)get_gfn_type_access(p2m, gfn_x(gfn), &p2mt, &p2ma, p2m_unshare,
NULL);
if ( p2m_is_paging(p2mt) )
{
ASSERT(!p2m_is_nestedp2m(p2m));
p2m_mem_paging_populate(p2m->domain, gfn_x(gfn));
pfec[0] = PFEC_page_paged;
+ __put_gfn(p2m, gfn_x(gfn));
return INVALID_GFN;
}
if ( p2m_is_shared(p2mt) )
{
pfec[0] = PFEC_page_shared;
+ __put_gfn(p2m, gfn_x(gfn));
return INVALID_GFN;
}
+ __put_gfn(p2m, gfn_x(gfn));
+
if ( page_order )
*page_order = guest_walk_to_page_order(&gw);
diff -r 4699decb8424 -r 7461834954c8 xen/arch/x86/mm/hap/nested_hap.c
--- a/xen/arch/x86/mm/hap/nested_hap.c
+++ b/xen/arch/x86/mm/hap/nested_hap.c
@@ -146,22 +146,29 @@ nestedhap_walk_L0_p2m(struct p2m_domain
mfn_t mfn;
p2m_type_t p2mt;
p2m_access_t p2ma;
+ int rc;
/* walk L0 P2M table */
- mfn = gfn_to_mfn_type_p2m(p2m, L1_gpa >> PAGE_SHIFT, &p2mt, &p2ma,
+ mfn = get_gfn_type_access(p2m, L1_gpa >> PAGE_SHIFT, &p2mt, &p2ma,
p2m_query, page_order);
+ rc = NESTEDHVM_PAGEFAULT_MMIO;
if ( p2m_is_mmio(p2mt) )
- return NESTEDHVM_PAGEFAULT_MMIO;
+ goto out;
+ rc = NESTEDHVM_PAGEFAULT_ERROR;
if ( p2m_is_paging(p2mt) || p2m_is_shared(p2mt) || !p2m_is_ram(p2mt) )
- return NESTEDHVM_PAGEFAULT_ERROR;
+ goto out;
+ rc = NESTEDHVM_PAGEFAULT_ERROR;
if ( !mfn_valid(mfn) )
- return NESTEDHVM_PAGEFAULT_ERROR;
+ goto out;
*L0_gpa = (mfn_x(mfn) << PAGE_SHIFT) + (L1_gpa & ~PAGE_MASK);
- return NESTEDHVM_PAGEFAULT_DONE;
+ rc = NESTEDHVM_PAGEFAULT_DONE;
+out:
+ __put_gfn(p2m, L1_gpa >> PAGE_SHIFT);
+ return rc;
}
/* This function uses L2_gpa to walk the P2M page table in L1. If the
diff -r 4699decb8424 -r 7461834954c8 xen/arch/x86/mm/mem_event.c
--- a/xen/arch/x86/mm/mem_event.c
+++ b/xen/arch/x86/mm/mem_event.c
@@ -47,7 +47,7 @@ static int mem_event_enable(struct domai
unsigned long ring_addr = mec->ring_addr;
unsigned long shared_addr = mec->shared_addr;
l1_pgentry_t l1e;
- unsigned long gfn;
+ unsigned long shared_gfn = 0, ring_gfn = 0; /* gcc ... */
p2m_type_t p2mt;
mfn_t ring_mfn;
mfn_t shared_mfn;
@@ -60,23 +60,36 @@ static int mem_event_enable(struct domai
/* Get MFN of ring page */
guest_get_eff_l1e(v, ring_addr, &l1e);
- gfn = l1e_get_pfn(l1e);
- ring_mfn = gfn_to_mfn(dom_mem_event, gfn, &p2mt);
+ ring_gfn = l1e_get_pfn(l1e);
+ /* We're grabbing these two in an order that could deadlock
+ * dom0 if 1. it were an hvm 2. there were two concurrent
+ * enables 3. the two gfn's in each enable criss-crossed
+ * 2MB regions. Duly noted.... */
+ ring_mfn = get_gfn(dom_mem_event, ring_gfn, &p2mt);
if ( unlikely(!mfn_valid(mfn_x(ring_mfn))) )
+ {
+ put_gfn(dom_mem_event, ring_gfn);
return -EINVAL;
+ }
/* Get MFN of shared page */
guest_get_eff_l1e(v, shared_addr, &l1e);
- gfn = l1e_get_pfn(l1e);
- shared_mfn = gfn_to_mfn(dom_mem_event, gfn, &p2mt);
+ shared_gfn = l1e_get_pfn(l1e);
+ shared_mfn = get_gfn(dom_mem_event, shared_gfn, &p2mt);
if ( unlikely(!mfn_valid(mfn_x(shared_mfn))) )
+ {
+ put_gfn(dom_mem_event, ring_gfn);
+ put_gfn(dom_mem_event, shared_gfn);
return -EINVAL;
+ }
/* Map ring and shared pages */
med->ring_page = map_domain_page(mfn_x(ring_mfn));
med->shared_page = map_domain_page(mfn_x(shared_mfn));
+ put_gfn(dom_mem_event, ring_gfn);
+ put_gfn(dom_mem_event, shared_gfn);
/* Allocate event channel */
rc = alloc_unbound_xen_event_channel(d->vcpu[0],
diff -r 4699decb8424 -r 7461834954c8 xen/arch/x86/mm/mem_sharing.c
--- a/xen/arch/x86/mm/mem_sharing.c
+++ b/xen/arch/x86/mm/mem_sharing.c
@@ -227,7 +227,7 @@ static void mem_sharing_audit(void)
g->domain, g->gfn, mfn_x(e->mfn));
continue;
}
- mfn = gfn_to_mfn(d, g->gfn, &t);
+ mfn = get_gfn_unlocked(d, g->gfn, &t);
if(mfn_x(mfn) != mfn_x(e->mfn))
MEM_SHARING_DEBUG("Incorrect P2M for d=%d, PFN=%lx."
"Expecting MFN=%ld, got %ld\n",
@@ -335,7 +335,7 @@ int mem_sharing_debug_gfn(struct domain
p2m_type_t p2mt;
mfn_t mfn;
- mfn = gfn_to_mfn(d, gfn, &p2mt);
+ mfn = get_gfn_unlocked(d, gfn, &p2mt);
printk("Debug for domain=%d, gfn=%lx, ",
d->domain_id,
@@ -460,7 +460,7 @@ int mem_sharing_nominate_page(struct dom
*phandle = 0UL;
shr_lock();
- mfn = gfn_to_mfn(d, gfn, &p2mt);
+ mfn = get_gfn(d, gfn, &p2mt);
/* Check if mfn is valid */
ret = -EINVAL;
@@ -524,6 +524,7 @@ int mem_sharing_nominate_page(struct dom
ret = 0;
out:
+ put_gfn(d, gfn);
shr_unlock();
return ret;
}
@@ -593,14 +594,18 @@ int mem_sharing_unshare_page(struct doma
shr_handle_t handle;
struct list_head *le;
+ /* Remove the gfn_info from the list */
+
+ /* This is one of the reasons why we can't enforce ordering
+ * between shr_lock and p2m fine-grained locks in mm-lock.
+ * Callers may walk in here already holding the lock for this gfn */
shr_lock();
mem_sharing_audit();
-
- /* Remove the gfn_info from the list */
- mfn = gfn_to_mfn(d, gfn, &p2mt);
+ mfn = get_gfn(d, gfn, &p2mt);
/* Has someone already unshared it? */
if (!p2m_is_shared(p2mt)) {
+ put_gfn(d, gfn);
shr_unlock();
return 0;
}
@@ -634,6 +639,7 @@ gfn_found:
/* Even though we don't allocate a private page, we have to account
* for the MFN that originally backed this PFN. */
atomic_dec(&nr_saved_mfns);
+ put_gfn(d, gfn);
shr_unlock();
put_page_and_type(page);
if(last_gfn &&
@@ -653,6 +659,7 @@ gfn_found:
/* We've failed to obtain memory for private page. Need to re-add the
* gfn_info to relevant list */
list_add(&gfn_info->list, &hash_entry->gfns);
+ put_gfn(d, gfn);
shr_unlock();
return -ENOMEM;
}
@@ -663,6 +670,13 @@ gfn_found:
unmap_domain_page(s);
unmap_domain_page(t);
+ /* NOTE: set_shared_p2m_entry will switch the underlying mfn. If
+ * we do get_page withing get_gfn, the correct sequence here
+ * should be
+ get_page(page);
+ put_page(old_page);
+ * so that the ref to the old page is dropped, and a ref to
+ * the new page is obtained to later be dropped in put_gfn */
BUG_ON(set_shared_p2m_entry(d, gfn, page_to_mfn(page)) == 0);
put_page_and_type(old_page);
@@ -683,6 +697,7 @@ private_page_found:
/* Update m2p entry */
set_gpfn_from_mfn(mfn_x(page_to_mfn(page)), gfn);
+ put_gfn(d, gfn);
shr_unlock();
return 0;
}
diff -r 4699decb8424 -r 7461834954c8 xen/arch/x86/mm/p2m-pod.c
--- a/xen/arch/x86/mm/p2m-pod.c
+++ b/xen/arch/x86/mm/p2m-pod.c
@@ -531,9 +531,10 @@ p2m_pod_decrease_reservation(struct doma
/* FIXME: Add contiguous; query for PSE entries? */
for ( i=0; i<(1<<order); i++)
{
+ p2m_access_t a;
p2m_type_t t;
- gfn_to_mfn_query(d, gpfn + i, &t);
+ (void)p2m->get_entry(p2m, gpfn + i, &t, &a, p2m_query, NULL);
if ( t == p2m_populate_on_demand )
pod++;
@@ -572,8 +573,9 @@ p2m_pod_decrease_reservation(struct doma
{
mfn_t mfn;
p2m_type_t t;
+ p2m_access_t a;
- mfn = gfn_to_mfn_query(d, gpfn + i, &t);
+ mfn = p2m->get_entry(p2m, gpfn + i, &t, &a, p2m_query, NULL);
if ( t == p2m_populate_on_demand )
{
set_p2m_entry(p2m, gpfn + i, _mfn(INVALID_MFN), 0, p2m_invalid,
p2m->default_access);
@@ -653,8 +655,8 @@ p2m_pod_zero_check_superpage(struct p2m_
* and aligned, and mapping them. */
for ( i=0; i<SUPERPAGE_PAGES; i++ )
{
-
- mfn = gfn_to_mfn_query(d, gfn + i, &type);
+ p2m_access_t a;
+ mfn = p2m->get_entry(p2m, gfn + i, &type, &a, p2m_query, NULL);
if ( i == 0 )
{
@@ -782,7 +784,8 @@ p2m_pod_zero_check(struct p2m_domain *p2
/* First, get the gfn list, translate to mfns, and map the pages. */
for ( i=0; i<count; i++ )
{
- mfns[i] = gfn_to_mfn_query(d, gfns[i], types + i);
+ p2m_access_t a;
+ mfns[i] = p2m->get_entry(p2m, gfns[i], types + i, &a, p2m_query, NULL);
/* If this is ram, and not a pagetable or from the xen heap, and
probably not mapped
elsewhere, map it; otherwise, skip. */
if ( p2m_is_ram(types[i])
@@ -923,7 +926,8 @@ p2m_pod_emergency_sweep(struct p2m_domai
/* FIXME: Figure out how to avoid superpages */
for ( i=p2m->pod.reclaim_single; i > 0 ; i-- )
{
- gfn_to_mfn_query(p2m->domain, i, &t );
+ p2m_access_t a;
+ (void)p2m->get_entry(p2m, i, &t, &a, p2m_query, NULL);
if ( p2m_is_ram(t) )
{
gfns[j] = i;
@@ -1112,7 +1116,8 @@ guest_physmap_mark_populate_on_demand(st
/* Make sure all gpfns are unused */
for ( i = 0; i < (1UL << order); i++ )
{
- omfn = gfn_to_mfn_query(d, gfn + i, &ot);
+ p2m_access_t a;
+ omfn = p2m->get_entry(p2m, gfn + i, &ot, &a, p2m_query, NULL);
if ( p2m_is_ram(ot) )
{
printk("%s: gfn_to_mfn returned type %d!\n",
diff -r 4699decb8424 -r 7461834954c8 xen/arch/x86/mm/p2m.c
--- a/xen/arch/x86/mm/p2m.c
+++ b/xen/arch/x86/mm/p2m.c
@@ -144,7 +144,7 @@ void p2m_change_entry_type_global(struct
p2m_unlock(p2m);
}
-mfn_t gfn_to_mfn_type_p2m(struct p2m_domain *p2m, unsigned long gfn,
+mfn_t get_gfn_type_access(struct p2m_domain *p2m, unsigned long gfn,
p2m_type_t *t, p2m_access_t *a, p2m_query_t q,
unsigned int *page_order)
{
@@ -343,28 +343,27 @@ void p2m_teardown(struct p2m_domain *p2m
#ifdef __x86_64__
unsigned long gfn;
p2m_type_t t;
- p2m_access_t a;
mfn_t mfn;
#endif
if (p2m == NULL)
return;
+ p2m_lock(p2m);
+
#ifdef __x86_64__
for ( gfn=0; gfn < p2m->max_mapped_pfn; gfn++ )
{
- mfn = gfn_to_mfn_type_p2m(p2m, gfn, &t, &a, p2m_query, NULL);
+ p2m_access_t a;
+ mfn = p2m->get_entry(p2m, gfn, &t, &a, p2m_query, NULL);
if ( mfn_valid(mfn) && (t == p2m_ram_shared) )
{
ASSERT(!p2m_is_nestedp2m(p2m));
BUG_ON(mem_sharing_unshare_page(d, gfn, MEM_SHARING_DESTROY_GFN));
}
-
}
#endif
- p2m_lock(p2m);
-
p2m->phys_table = pagetable_null();
while ( (pg = page_list_remove_head(&p2m->pages)) )
@@ -454,6 +453,7 @@ guest_physmap_add_entry(struct domain *d
struct p2m_domain *p2m = p2m_get_hostp2m(d);
unsigned long i, ogfn;
p2m_type_t ot;
+ p2m_access_t a;
mfn_t omfn;
int pod_count = 0;
int rc = 0;
@@ -489,12 +489,13 @@ guest_physmap_add_entry(struct domain *d
/* First, remove m->p mappings for existing p->m mappings */
for ( i = 0; i < (1UL << page_order); i++ )
{
- omfn = gfn_to_mfn_query(d, gfn + i, &ot);
+ omfn = p2m->get_entry(p2m, gfn + i, &ot, &a, p2m_query, NULL);
if ( p2m_is_grant(ot) )
{
/* Really shouldn't be unmapping grant maps this way */
domain_crash(d);
p2m_unlock(p2m);
+
return -EINVAL;
}
else if ( p2m_is_ram(ot) )
@@ -528,7 +529,7 @@ guest_physmap_add_entry(struct domain *d
* address */
P2M_DEBUG("aliased! mfn=%#lx, old gfn=%#lx, new gfn=%#lx\n",
mfn + i, ogfn, gfn + i);
- omfn = gfn_to_mfn_query(d, ogfn, &ot);
+ omfn = p2m->get_entry(p2m, ogfn, &ot, &a, p2m_query, NULL);
if ( p2m_is_ram(ot) )
{
ASSERT(mfn_valid(omfn));
@@ -577,6 +578,7 @@ guest_physmap_add_entry(struct domain *d
p2m_type_t p2m_change_type(struct domain *d, unsigned long gfn,
p2m_type_t ot, p2m_type_t nt)
{
+ p2m_access_t a;
p2m_type_t pt;
mfn_t mfn;
struct p2m_domain *p2m = p2m_get_hostp2m(d);
@@ -585,7 +587,7 @@ p2m_type_t p2m_change_type(struct domain
p2m_lock(p2m);
- mfn = gfn_to_mfn_query(d, gfn, &pt);
+ mfn = p2m->get_entry(p2m, gfn, &pt, &a, p2m_query, NULL);
if ( pt == ot )
set_p2m_entry(p2m, gfn, mfn, PAGE_ORDER_4K, nt, p2m->default_access);
@@ -600,6 +602,7 @@ void p2m_change_type_range(struct domain
unsigned long start, unsigned long end,
p2m_type_t ot, p2m_type_t nt)
{
+ p2m_access_t a;
p2m_type_t pt;
unsigned long gfn;
mfn_t mfn;
@@ -612,7 +615,7 @@ void p2m_change_type_range(struct domain
for ( gfn = start; gfn < end; gfn++ )
{
- mfn = gfn_to_mfn_query(d, gfn, &pt);
+ mfn = p2m->get_entry(p2m, gfn, &pt, &a, p2m_query, NULL);
if ( pt == ot )
set_p2m_entry(p2m, gfn, mfn, PAGE_ORDER_4K, nt,
p2m->default_access);
}
@@ -629,6 +632,7 @@ int
set_mmio_p2m_entry(struct domain *d, unsigned long gfn, mfn_t mfn)
{
int rc = 0;
+ p2m_access_t a;
p2m_type_t ot;
mfn_t omfn;
struct p2m_domain *p2m = p2m_get_hostp2m(d);
@@ -637,7 +641,7 @@ set_mmio_p2m_entry(struct domain *d, uns
return 0;
p2m_lock(p2m);
- omfn = gfn_to_mfn_query(d, gfn, &ot);
+ omfn = p2m->get_entry(p2m, gfn, &ot, &a, p2m_query, NULL);
if ( p2m_is_grant(ot) )
{
p2m_unlock(p2m);
@@ -657,7 +661,7 @@ set_mmio_p2m_entry(struct domain *d, uns
if ( 0 == rc )
gdprintk(XENLOG_ERR,
"set_mmio_p2m_entry: set_p2m_entry failed! mfn=%08lx\n",
- mfn_x(gfn_to_mfn_query(d, gfn, &ot)));
+ mfn_x(get_gfn_query_unlocked(p2m->domain, gfn, &ot)));
return rc;
}
@@ -666,6 +670,7 @@ clear_mmio_p2m_entry(struct domain *d, u
{
int rc = 0;
mfn_t mfn;
+ p2m_access_t a;
p2m_type_t t;
struct p2m_domain *p2m = p2m_get_hostp2m(d);
@@ -673,7 +678,7 @@ clear_mmio_p2m_entry(struct domain *d, u
return 0;
p2m_lock(p2m);
- mfn = gfn_to_mfn_query(d, gfn, &t);
+ mfn = p2m->get_entry(p2m, gfn, &t, &a, p2m_query, NULL);
/* Do not use mfn_valid() here as it will usually fail for MMIO pages. */
if ( (INVALID_MFN == mfn_x(mfn)) || (t != p2m_mmio_direct) )
@@ -696,6 +701,7 @@ set_shared_p2m_entry(struct domain *d, u
{
struct p2m_domain *p2m = p2m_get_hostp2m(d);
int rc = 0;
+ p2m_access_t a;
p2m_type_t ot;
mfn_t omfn;
@@ -703,7 +709,7 @@ set_shared_p2m_entry(struct domain *d, u
return 0;
p2m_lock(p2m);
- omfn = gfn_to_mfn_query(p2m->domain, gfn, &ot);
+ omfn = p2m->get_entry(p2m, gfn, &ot, &a, p2m_query, NULL);
/* At the moment we only allow p2m change if gfn has already been made
* sharable first */
ASSERT(p2m_is_shared(ot));
@@ -717,7 +723,7 @@ set_shared_p2m_entry(struct domain *d, u
if ( 0 == rc )
gdprintk(XENLOG_ERR,
"set_shared_p2m_entry: set_p2m_entry failed! mfn=%08lx\n",
- mfn_x(gfn_to_mfn_query(d, gfn, &ot)));
+ mfn_x(get_gfn_query_unlocked(p2m->domain, gfn, &ot)));
return rc;
}
@@ -1168,7 +1174,7 @@ int p2m_set_mem_access(struct domain *d,
{
struct p2m_domain *p2m = p2m_get_hostp2m(d);
unsigned long pfn;
- p2m_access_t a;
+ p2m_access_t a, _a;
p2m_type_t t;
mfn_t mfn;
int rc = 0;
@@ -1202,7 +1208,7 @@ int p2m_set_mem_access(struct domain *d,
p2m_lock(p2m);
for ( pfn = start_pfn; pfn < start_pfn + nr; pfn++ )
{
- mfn = gfn_to_mfn_query(d, pfn, &t);
+ mfn = p2m->get_entry(p2m, pfn, &t, &_a, p2m_query, NULL);
if ( p2m->set_entry(p2m, pfn, mfn, PAGE_ORDER_4K, t, a) == 0 )
{
rc = -ENOMEM;
diff -r 4699decb8424 -r 7461834954c8 xen/arch/x86/mm/shadow/common.c
--- a/xen/arch/x86/mm/shadow/common.c
+++ b/xen/arch/x86/mm/shadow/common.c
@@ -3676,7 +3676,7 @@ int shadow_track_dirty_vram(struct domai
/* Iterate over VRAM to track dirty bits. */
for ( i = 0; i < nr; i++ ) {
- mfn_t mfn = gfn_to_mfn_query(d, begin_pfn + i, &t);
+ mfn_t mfn = get_gfn_query(d, begin_pfn + i, &t);
struct page_info *page;
int dirty = 0;
paddr_t sl1ma = dirty_vram->sl1ma[i];
@@ -3741,6 +3741,8 @@ int shadow_track_dirty_vram(struct domai
}
}
+ put_gfn(d, begin_pfn + i);
+
if ( dirty )
{
dirty_vram->dirty_bitmap[i / 8] |= 1 << (i % 8);
@@ -3761,7 +3763,7 @@ int shadow_track_dirty_vram(struct domai
/* was clean for more than two seconds, try to disable guest
* write access */
for ( i = begin_pfn; i < end_pfn; i++ ) {
- mfn_t mfn = gfn_to_mfn_query(d, i, &t);
+ mfn_t mfn = get_gfn_query_unlocked(d, i, &t);
if (mfn_x(mfn) != INVALID_MFN)
flush_tlb |= sh_remove_write_access(d->vcpu[0], mfn,
1, 0);
}
diff -r 4699decb8424 -r 7461834954c8 xen/arch/x86/mm/shadow/multi.c
--- a/xen/arch/x86/mm/shadow/multi.c
+++ b/xen/arch/x86/mm/shadow/multi.c
@@ -2265,7 +2265,7 @@ static int validate_gl4e(struct vcpu *v,
if ( guest_l4e_get_flags(new_gl4e) & _PAGE_PRESENT )
{
gfn_t gl3gfn = guest_l4e_get_gfn(new_gl4e);
- mfn_t gl3mfn = gfn_to_mfn_query(d, gl3gfn, &p2mt);
+ mfn_t gl3mfn = get_gfn_query(d, gl3gfn, &p2mt);
if ( p2m_is_ram(p2mt) )
sl3mfn = get_shadow_status(v, gl3mfn, SH_type_l3_shadow);
else if ( p2mt != p2m_populate_on_demand )
@@ -2275,6 +2275,7 @@ static int validate_gl4e(struct vcpu *v,
if ( mfn_valid(sl3mfn) )
shadow_resync_all(v);
#endif
+ put_gfn(d, gfn_x(gl3gfn));
}
l4e_propagate_from_guest(v, new_gl4e, sl3mfn, &new_sl4e, ft_prefetch);
@@ -2322,7 +2323,7 @@ static int validate_gl3e(struct vcpu *v,
if ( guest_l3e_get_flags(new_gl3e) & _PAGE_PRESENT )
{
gfn_t gl2gfn = guest_l3e_get_gfn(new_gl3e);
- mfn_t gl2mfn = gfn_to_mfn_query(v->domain, gl2gfn, &p2mt);
+ mfn_t gl2mfn = get_gfn_query(v->domain, gl2gfn, &p2mt);
if ( p2m_is_ram(p2mt) )
sl2mfn = get_shadow_status(v, gl2mfn, SH_type_l2_shadow);
else if ( p2mt != p2m_populate_on_demand )
@@ -2332,6 +2333,7 @@ static int validate_gl3e(struct vcpu *v,
if ( mfn_valid(sl2mfn) )
shadow_resync_all(v);
#endif
+ put_gfn(v->domain, gfn_x(gl2gfn));
}
l3e_propagate_from_guest(v, new_gl3e, sl2mfn, &new_sl3e, ft_prefetch);
result |= shadow_set_l3e(v, sl3p, new_sl3e, sl3mfn);
@@ -2371,11 +2373,12 @@ static int validate_gl2e(struct vcpu *v,
}
else
{
- mfn_t gl1mfn = gfn_to_mfn_query(v->domain, gl1gfn, &p2mt);
+ mfn_t gl1mfn = get_gfn_query(v->domain, gl1gfn, &p2mt);
if ( p2m_is_ram(p2mt) )
sl1mfn = get_shadow_status(v, gl1mfn, SH_type_l1_shadow);
else if ( p2mt != p2m_populate_on_demand )
result |= SHADOW_SET_ERROR;
+ put_gfn(v->domain, gfn_x(gl1gfn));
}
}
l2e_propagate_from_guest(v, new_gl2e, sl1mfn, &new_sl2e, ft_prefetch);
@@ -2441,7 +2444,7 @@ static int validate_gl1e(struct vcpu *v,
perfc_incr(shadow_validate_gl1e_calls);
gfn = guest_l1e_get_gfn(new_gl1e);
- gmfn = gfn_to_mfn_query(v->domain, gfn, &p2mt);
+ gmfn = get_gfn_query(v->domain, gfn, &p2mt);
l1e_propagate_from_guest(v, new_gl1e, gmfn, &new_sl1e, ft_prefetch, p2mt);
result |= shadow_set_l1e(v, sl1p, new_sl1e, p2mt, sl1mfn);
@@ -2463,6 +2466,7 @@ static int validate_gl1e(struct vcpu *v,
}
#endif /* OOS */
+ put_gfn(v->domain, gfn_x(gfn));
return result;
}
@@ -2501,10 +2505,11 @@ void sh_resync_l1(struct vcpu *v, mfn_t
shadow_l1e_t nsl1e;
gfn = guest_l1e_get_gfn(gl1e);
- gmfn = gfn_to_mfn_query(v->domain, gfn, &p2mt);
+ gmfn = get_gfn_query(v->domain, gfn, &p2mt);
l1e_propagate_from_guest(v, gl1e, gmfn, &nsl1e, ft_prefetch, p2mt);
rc |= shadow_set_l1e(v, sl1p, nsl1e, p2mt, sl1mfn);
+ put_gfn(v->domain, gfn_x(gfn));
*snpl1p = gl1e;
}
});
@@ -2824,7 +2829,7 @@ static void sh_prefetch(struct vcpu *v,
/* Look at the gfn that the l1e is pointing at */
gfn = guest_l1e_get_gfn(gl1e);
- gmfn = gfn_to_mfn_query(v->domain, gfn, &p2mt);
+ gmfn = get_gfn_query(v->domain, gfn, &p2mt);
/* Propagate the entry. */
l1e_propagate_from_guest(v, gl1e, gmfn, &sl1e, ft_prefetch, p2mt);
@@ -2834,6 +2839,8 @@ static void sh_prefetch(struct vcpu *v,
if ( snpl1p != NULL )
snpl1p[i] = gl1e;
#endif /* OOS */
+
+ put_gfn(v->domain, gfn_x(gfn));
}
if ( gl1p != NULL )
sh_unmap_domain_page(gl1p);
@@ -3182,7 +3189,7 @@ static int sh_page_fault(struct vcpu *v,
/* What mfn is the guest trying to access? */
gfn = guest_l1e_get_gfn(gw.l1e);
- gmfn = gfn_to_mfn_guest(d, gfn, &p2mt);
+ gmfn = get_gfn_guest(d, gfn, &p2mt);
if ( shadow_mode_refcounts(d) &&
((!p2m_is_valid(p2mt) && !p2m_is_grant(p2mt)) ||
@@ -3192,6 +3199,7 @@ static int sh_page_fault(struct vcpu *v,
SHADOW_PRINTK("BAD gfn=%"SH_PRI_gfn" gmfn=%"PRI_mfn"\n",
gfn_x(gfn), mfn_x(gmfn));
reset_early_unshadow(v);
+ put_gfn(d, gfn_x(gfn));
goto propagate;
}
@@ -3236,6 +3244,7 @@ static int sh_page_fault(struct vcpu *v,
if ( rc & GW_RMWR_REWALK )
{
paging_unlock(d);
+ put_gfn(d, gfn_x(gfn));
goto rewalk;
}
#endif /* OOS */
@@ -3244,6 +3253,7 @@ static int sh_page_fault(struct vcpu *v,
{
perfc_incr(shadow_inconsistent_gwalk);
paging_unlock(d);
+ put_gfn(d, gfn_x(gfn));
goto rewalk;
}
@@ -3270,6 +3280,7 @@ static int sh_page_fault(struct vcpu *v,
ASSERT(d->is_shutting_down);
#endif
paging_unlock(d);
+ put_gfn(d, gfn_x(gfn));
trace_shadow_gen(TRC_SHADOW_DOMF_DYING, va);
return 0;
}
@@ -3287,6 +3298,7 @@ static int sh_page_fault(struct vcpu *v,
* failed. We cannot safely continue since some page is still
* OOS but not in the hash table anymore. */
paging_unlock(d);
+ put_gfn(d, gfn_x(gfn));
return 0;
}
@@ -3296,6 +3308,7 @@ static int sh_page_fault(struct vcpu *v,
{
perfc_incr(shadow_inconsistent_gwalk);
paging_unlock(d);
+ put_gfn(d, gfn_x(gfn));
goto rewalk;
}
#endif /* OOS */
@@ -3389,6 +3402,7 @@ static int sh_page_fault(struct vcpu *v,
SHADOW_PRINTK("fixed\n");
shadow_audit_tables(v);
paging_unlock(d);
+ put_gfn(d, gfn_x(gfn));
return EXCRET_fault_fixed;
emulate:
@@ -3457,6 +3471,7 @@ static int sh_page_fault(struct vcpu *v,
sh_audit_gw(v, &gw);
shadow_audit_tables(v);
paging_unlock(d);
+ put_gfn(d, gfn_x(gfn));
this_cpu(trace_emulate_write_val) = 0;
@@ -3595,6 +3610,7 @@ static int sh_page_fault(struct vcpu *v,
shadow_audit_tables(v);
reset_early_unshadow(v);
paging_unlock(d);
+ put_gfn(d, gfn_x(gfn));
trace_shadow_gen(TRC_SHADOW_MMIO, va);
return (handle_mmio_with_translation(va, gpa >> PAGE_SHIFT)
? EXCRET_fault_fixed : 0);
@@ -3605,6 +3621,7 @@ static int sh_page_fault(struct vcpu *v,
shadow_audit_tables(v);
reset_early_unshadow(v);
paging_unlock(d);
+ put_gfn(d, gfn_x(gfn));
propagate:
trace_not_shadow_fault(gw.l1e, va);
@@ -4292,7 +4309,7 @@ sh_update_cr3(struct vcpu *v, int do_loc
if ( guest_l3e_get_flags(gl3e[i]) & _PAGE_PRESENT )
{
gl2gfn = guest_l3e_get_gfn(gl3e[i]);
- gl2mfn = gfn_to_mfn_query(d, gl2gfn, &p2mt);
+ gl2mfn = get_gfn_query_unlocked(d, gfn_x(gl2gfn), &p2mt);
if ( p2m_is_ram(p2mt) )
flush |= sh_remove_write_access(v, gl2mfn, 2, 0);
}
@@ -4305,13 +4322,14 @@ sh_update_cr3(struct vcpu *v, int do_loc
if ( guest_l3e_get_flags(gl3e[i]) & _PAGE_PRESENT )
{
gl2gfn = guest_l3e_get_gfn(gl3e[i]);
- gl2mfn = gfn_to_mfn_query(d, gl2gfn, &p2mt);
+ gl2mfn = get_gfn_query(d, gl2gfn, &p2mt);
if ( p2m_is_ram(p2mt) )
sh_set_toplevel_shadow(v, i, gl2mfn, (i == 3)
? SH_type_l2h_shadow
: SH_type_l2_shadow);
else
sh_set_toplevel_shadow(v, i, _mfn(INVALID_MFN), 0);
+ put_gfn(d, gfn_x(gl2gfn));
}
else
sh_set_toplevel_shadow(v, i, _mfn(INVALID_MFN), 0);
@@ -4689,11 +4707,12 @@ static void sh_pagetable_dying(struct vc
int flush = 0;
int fast_path = 0;
paddr_t gcr3 = 0;
- mfn_t smfn, gmfn;
p2m_type_t p2mt;
char *gl3pa = NULL;
guest_l3e_t *gl3e = NULL;
paddr_t gl2a = 0;
+ unsigned long l3gfn;
+ mfn_t l3mfn;
paging_lock(v->domain);
@@ -4702,8 +4721,9 @@ static void sh_pagetable_dying(struct vc
if ( gcr3 == gpa )
fast_path = 1;
- gmfn = gfn_to_mfn_query(v->domain, _gfn(gpa >> PAGE_SHIFT), &p2mt);
- if ( !mfn_valid(gmfn) || !p2m_is_ram(p2mt) )
+ l3gfn = gpa >> PAGE_SHIFT;
+ l3mfn = get_gfn_query(v->domain, _gfn(l3gfn), &p2mt);
+ if ( !mfn_valid(l3mfn) || !p2m_is_ram(p2mt) )
{
printk(XENLOG_DEBUG "sh_pagetable_dying: gpa not valid %"PRIpaddr"\n",
gpa);
@@ -4711,19 +4731,24 @@ static void sh_pagetable_dying(struct vc
}
if ( !fast_path )
{
- gl3pa = sh_map_domain_page(gmfn);
+ gl3pa = sh_map_domain_page(l3mfn);
gl3e = (guest_l3e_t *)(gl3pa + ((unsigned long)gpa & ~PAGE_MASK));
}
for ( i = 0; i < 4; i++ )
{
+ unsigned long gfn;
+ mfn_t smfn, gmfn;
+
if ( fast_path )
smfn = _mfn(pagetable_get_pfn(v->arch.shadow_table[i]));
else
{
/* retrieving the l2s */
gl2a = guest_l3e_get_paddr(gl3e[i]);
- gmfn = gfn_to_mfn_query(v->domain, _gfn(gl2a >> PAGE_SHIFT),
&p2mt);
+ gfn = gl2a >> PAGE_SHIFT;
+ gmfn = get_gfn_query(v->domain, _gfn(gfn), &p2mt);
smfn = shadow_hash_lookup(v, mfn_x(gmfn), SH_type_l2_pae_shadow);
+ put_gfn(v->domain, gfn);
}
if ( mfn_valid(smfn) )
@@ -4747,6 +4772,7 @@ static void sh_pagetable_dying(struct vc
out:
if ( !fast_path )
unmap_domain_page(gl3pa);
+ put_gfn(v->domain, l3gfn);
paging_unlock(v->domain);
}
#else
@@ -4757,12 +4783,14 @@ static void sh_pagetable_dying(struct vc
paging_lock(v->domain);
- gmfn = gfn_to_mfn_query(v->domain, _gfn(gpa >> PAGE_SHIFT), &p2mt);
+ gmfn = get_gfn_query(v->domain, _gfn(gpa >> PAGE_SHIFT), &p2mt);
#if GUEST_PAGING_LEVELS == 2
smfn = shadow_hash_lookup(v, mfn_x(gmfn), SH_type_l2_32_shadow);
#else
smfn = shadow_hash_lookup(v, mfn_x(gmfn), SH_type_l4_64_shadow);
#endif
+ put_gfn(v->domain, gpa >> PAGE_SHIFT);
+
if ( mfn_valid(smfn) )
{
mfn_to_page(gmfn)->shadow_flags |= SHF_pagetable_dying;
@@ -4811,15 +4839,22 @@ static mfn_t emulate_gva_to_mfn(struct v
/* Translate the GFN to an MFN */
ASSERT(!paging_locked_by_me(v->domain));
- mfn = gfn_to_mfn_guest(v->domain, _gfn(gfn), &p2mt);
+ mfn = get_gfn_guest(v->domain, _gfn(gfn), &p2mt);
if ( p2m_is_readonly(p2mt) )
+ {
+ put_gfn(v->domain, gfn);
return _mfn(READONLY_GFN);
+ }
if ( !p2m_is_ram(p2mt) )
+ {
+ put_gfn(v->domain, gfn);
return _mfn(BAD_GFN_TO_MFN);
+ }
ASSERT(mfn_valid(mfn));
v->arch.paging.last_write_was_pt = !!sh_mfn_is_a_page_table(mfn);
+ put_gfn(v->domain, gfn);
return mfn;
}
@@ -5220,7 +5255,7 @@ int sh_audit_l1_table(struct vcpu *v, mf
{
gfn = guest_l1e_get_gfn(*gl1e);
mfn = shadow_l1e_get_mfn(*sl1e);
- gmfn = gfn_to_mfn_query(v->domain, gfn, &p2mt);
+ gmfn = get_gfn_query_unlocked(v->domain, gfn_x(gfn), &p2mt);
if ( !p2m_is_grant(p2mt) && mfn_x(gmfn) != mfn_x(mfn) )
AUDIT_FAIL(1, "bad translation: gfn %" SH_PRI_gfn
" --> %" PRI_mfn " != mfn %" PRI_mfn,
@@ -5291,16 +5326,17 @@ int sh_audit_l2_table(struct vcpu *v, mf
mfn = shadow_l2e_get_mfn(*sl2e);
gmfn = (guest_l2e_get_flags(*gl2e) & _PAGE_PSE)
? get_fl1_shadow_status(v, gfn)
- : get_shadow_status(v, gfn_to_mfn_query(v->domain, gfn, &p2mt),
- SH_type_l1_shadow);
+ : get_shadow_status(v,
+ get_gfn_query_unlocked(v->domain, gfn_x(gfn),
+ &p2mt), SH_type_l1_shadow);
if ( mfn_x(gmfn) != mfn_x(mfn) )
AUDIT_FAIL(2, "bad translation: gfn %" SH_PRI_gfn
" (--> %" PRI_mfn ")"
" --> %" PRI_mfn " != mfn %" PRI_mfn,
gfn_x(gfn),
(guest_l2e_get_flags(*gl2e) & _PAGE_PSE) ? 0
- : mfn_x(gfn_to_mfn_query(v->domain,
- gfn, &p2mt)), mfn_x(gmfn), mfn_x(mfn));
+ : mfn_x(get_gfn_query_unlocked(v->domain,
+ gfn_x(gfn), &p2mt)), mfn_x(gmfn),
mfn_x(mfn));
}
});
sh_unmap_domain_page(gp);
@@ -5339,7 +5375,8 @@ int sh_audit_l3_table(struct vcpu *v, mf
{
gfn = guest_l3e_get_gfn(*gl3e);
mfn = shadow_l3e_get_mfn(*sl3e);
- gmfn = get_shadow_status(v, gfn_to_mfn_query(v->domain, gfn,
&p2mt),
+ gmfn = get_shadow_status(v, get_gfn_query_unlocked(
+ v->domain, gfn_x(gfn), &p2mt),
((GUEST_PAGING_LEVELS == 3 ||
is_pv_32on64_vcpu(v))
&& !shadow_mode_external(v->domain)
@@ -5387,8 +5424,8 @@ int sh_audit_l4_table(struct vcpu *v, mf
{
gfn = guest_l4e_get_gfn(*gl4e);
mfn = shadow_l4e_get_mfn(*sl4e);
- gmfn = get_shadow_status(v, gfn_to_mfn_query(v->domain,
- gfn, &p2mt),
+ gmfn = get_shadow_status(v, get_gfn_query_unlocked(
+ v->domain, gfn_x(gfn), &p2mt),
SH_type_l3_shadow);
if ( mfn_x(gmfn) != mfn_x(mfn) )
AUDIT_FAIL(4, "bad translation: gfn %" SH_PRI_gfn
diff -r 4699decb8424 -r 7461834954c8 xen/arch/x86/mm/shadow/types.h
--- a/xen/arch/x86/mm/shadow/types.h
+++ b/xen/arch/x86/mm/shadow/types.h
@@ -191,11 +191,11 @@ static inline shadow_l4e_t shadow_l4e_fr
})
#endif
- /* Override gfn_to_mfn to work with gfn_t */
-#undef gfn_to_mfn_query
-#define gfn_to_mfn_query(d, g, t) gfn_to_mfn_type((d), gfn_x(g), (t),
p2m_query)
-#undef gfn_to_mfn_guest
-#define gfn_to_mfn_guest(d, g, t) gfn_to_mfn_type((d), gfn_x(g), (t),
p2m_guest)
+ /* Override get_gfn to work with gfn_t */
+#undef get_gfn_query
+#define get_gfn_query(d, g, t) get_gfn_type((d), gfn_x(g), (t), p2m_query)
+#undef get_gfn_guest
+#define get_gfn_guest(d, g, t) get_gfn_type((d), gfn_x(g), (t), p2m_guest)
/* The shadow types needed for the various levels. */
diff -r 4699decb8424 -r 7461834954c8 xen/arch/x86/physdev.c
--- a/xen/arch/x86/physdev.c
+++ b/xen/arch/x86/physdev.c
@@ -297,16 +297,20 @@ ret_t do_physdev_op(int cmd, XEN_GUEST_H
break;
ret = -EINVAL;
- mfn = gmfn_to_mfn(current->domain, info.gmfn);
+ mfn = get_gfn_untyped(current->domain, info.gmfn);
if ( !mfn_valid(mfn) ||
!get_page_and_type(mfn_to_page(mfn), v->domain,
PGT_writable_page) )
+ {
+ put_gfn(current->domain, info.gmfn);
break;
+ }
if ( cmpxchg(&v->domain->arch.pv_domain.pirq_eoi_map_mfn,
0, mfn) != 0 )
{
put_page_and_type(mfn_to_page(mfn));
+ put_gfn(current->domain, info.gmfn);
ret = -EBUSY;
break;
}
@@ -316,10 +320,12 @@ ret_t do_physdev_op(int cmd, XEN_GUEST_H
{
v->domain->arch.pv_domain.pirq_eoi_map_mfn = 0;
put_page_and_type(mfn_to_page(mfn));
+ put_gfn(current->domain, info.gmfn);
ret = -ENOSPC;
break;
}
+ put_gfn(current->domain, info.gmfn);
ret = 0;
break;
}
diff -r 4699decb8424 -r 7461834954c8 xen/arch/x86/traps.c
--- a/xen/arch/x86/traps.c
+++ b/xen/arch/x86/traps.c
@@ -673,11 +673,12 @@ int wrmsr_hypervisor_regs(uint32_t idx,
return 0;
}
- mfn = gmfn_to_mfn(d, gmfn);
+ mfn = get_gfn_untyped(d, gmfn);
if ( !mfn_valid(mfn) ||
!get_page_and_type(mfn_to_page(mfn), d, PGT_writable_page) )
{
+ put_gfn(d, gmfn);
gdprintk(XENLOG_WARNING,
"Bad GMFN %lx (MFN %lx) to MSR %08x\n",
gmfn, mfn, base + idx);
@@ -689,6 +690,7 @@ int wrmsr_hypervisor_regs(uint32_t idx,
unmap_domain_page(hypercall_page);
put_page_and_type(mfn_to_page(mfn));
+ put_gfn(d, gmfn);
break;
}
@@ -2347,18 +2349,25 @@ static int emulate_privileged_op(struct
arch_set_cr2(v, *reg);
break;
- case 3: /* Write CR3 */
+ case 3: {/* Write CR3 */
+ unsigned long mfn, gfn;
domain_lock(v->domain);
if ( !is_pv_32on64_vcpu(v) )
- rc = new_guest_cr3(gmfn_to_mfn(v->domain,
xen_cr3_to_pfn(*reg)));
+ {
+ gfn = xen_cr3_to_pfn(*reg);
#ifdef CONFIG_COMPAT
- else
- rc = new_guest_cr3(gmfn_to_mfn(v->domain,
compat_cr3_to_pfn(*reg)));
+ } else {
+ gfn = compat_cr3_to_pfn(*reg);
#endif
+ }
+ mfn = get_gfn_untyped(v->domain, gfn);
+ rc = new_guest_cr3(mfn);
+ put_gfn(v->domain, gfn);
domain_unlock(v->domain);
if ( rc == 0 ) /* not okay */
goto fail;
break;
+ }
case 4: /* Write CR4 */
v->arch.pv_vcpu.ctrlreg[4] = pv_guest_cr4_fixup(v, *reg);
diff -r 4699decb8424 -r 7461834954c8 xen/common/grant_table.c
--- a/xen/common/grant_table.c
+++ b/xen/common/grant_table.c
@@ -110,7 +110,7 @@ static unsigned inline int max_nr_maptra
#define gfn_to_mfn_private(_d, _gfn) ({ \
p2m_type_t __p2mt; \
unsigned long __x; \
- __x = mfn_x(gfn_to_mfn_unshare((_d), (_gfn), &__p2mt)); \
+ __x = mfn_x(get_gfn_unshare((_d), (_gfn), &__p2mt)); \
BUG_ON(p2m_is_shared(__p2mt)); /* XXX fixme */ \
if ( !p2m_is_valid(__p2mt) ) \
__x = INVALID_MFN; \
@@ -150,10 +150,10 @@ static int __get_paged_frame(unsigned lo
mfn_t mfn;
if ( readonly )
- mfn = gfn_to_mfn(rd, gfn, &p2mt);
+ mfn = get_gfn(rd, gfn, &p2mt);
else
{
- mfn = gfn_to_mfn_unshare(rd, gfn, &p2mt);
+ mfn = get_gfn_unshare(rd, gfn, &p2mt);
BUG_ON(p2m_is_shared(p2mt));
/* XXX Here, and above in gfn_to_mfn_private, need to handle
* XXX failure to unshare. */
@@ -164,14 +164,16 @@ static int __get_paged_frame(unsigned lo
if ( p2m_is_paging(p2mt) )
{
p2m_mem_paging_populate(rd, gfn);
+ put_gfn(rd, gfn);
rc = GNTST_eagain;
}
} else {
+ put_gfn(rd, gfn);
*frame = INVALID_MFN;
rc = GNTST_bad_page;
}
#else
- *frame = readonly ? gmfn_to_mfn(rd, gfn) : gfn_to_mfn_private(rd, gfn);
+ *frame = readonly ? get_gfn_untyped(rd, gfn) : gfn_to_mfn_private(rd, gfn);
#endif
return rc;
@@ -468,13 +470,14 @@ __gnttab_map_grant_ref(
struct domain *ld, *rd, *owner;
struct vcpu *led;
int handle;
+ unsigned long gfn = INVALID_GFN;
unsigned long frame = 0, nr_gets = 0;
struct page_info *pg;
int rc = GNTST_okay;
u32 old_pin;
u32 act_pin;
unsigned int cache_flags;
- struct active_grant_entry *act;
+ struct active_grant_entry *act = NULL;
struct grant_mapping *mt;
grant_entry_v1_t *sha1;
grant_entry_v2_t *sha2;
@@ -565,7 +568,6 @@ __gnttab_map_grant_ref(
if ( !act->pin )
{
- unsigned long gfn;
unsigned long frame;
gfn = sha1 ? sha1->frame : sha2->full_page.frame;
@@ -698,6 +700,7 @@ __gnttab_map_grant_ref(
op->handle = handle;
op->status = GNTST_okay;
+ put_gfn(rd, gfn);
rcu_unlock_domain(rd);
return;
@@ -735,6 +738,8 @@ __gnttab_map_grant_ref(
gnttab_clear_flag(_GTF_reading, status);
unlock_out:
+ if ( gfn != INVALID_GFN )
+ put_gfn(rd, gfn);
spin_unlock(&rd->grant_table->lock);
op->status = rc;
put_maptrack_handle(ld->grant_table, handle);
@@ -1475,6 +1480,7 @@ gnttab_transfer(
/* Check the passed page frame for basic validity. */
if ( unlikely(!mfn_valid(mfn)) )
{
+ put_gfn(d, gop.mfn);
gdprintk(XENLOG_INFO, "gnttab_transfer: out-of-range %lx\n",
(unsigned long)gop.mfn);
gop.status = GNTST_bad_page;
@@ -1484,6 +1490,7 @@ gnttab_transfer(
page = mfn_to_page(mfn);
if ( unlikely(is_xen_heap_page(page)) )
{
+ put_gfn(d, gop.mfn);
gdprintk(XENLOG_INFO, "gnttab_transfer: xen frame %lx\n",
(unsigned long)gop.mfn);
gop.status = GNTST_bad_page;
@@ -1492,6 +1499,7 @@ gnttab_transfer(
if ( steal_page(d, page, 0) < 0 )
{
+ put_gfn(d, gop.mfn);
gop.status = GNTST_bad_page;
goto copyback;
}
@@ -1504,6 +1512,7 @@ gnttab_transfer(
/* Find the target domain. */
if ( unlikely((e = rcu_lock_domain_by_id(gop.domid)) == NULL) )
{
+ put_gfn(d, gop.mfn);
gdprintk(XENLOG_INFO, "gnttab_transfer: can't find domain %d\n",
gop.domid);
page->count_info &= ~(PGC_count_mask|PGC_allocated);
@@ -1514,6 +1523,7 @@ gnttab_transfer(
if ( xsm_grant_transfer(d, e) )
{
+ put_gfn(d, gop.mfn);
gop.status = GNTST_permission_denied;
unlock_and_copyback:
rcu_unlock_domain(e);
@@ -1566,6 +1576,7 @@ gnttab_transfer(
e->tot_pages, e->max_pages, gop.ref, e->is_dying);
spin_unlock(&e->page_alloc_lock);
rcu_unlock_domain(e);
+ put_gfn(d, gop.mfn);
page->count_info &= ~(PGC_count_mask|PGC_allocated);
free_domheap_page(page);
gop.status = GNTST_general_error;
@@ -1579,6 +1590,7 @@ gnttab_transfer(
page_set_owner(page, e);
spin_unlock(&e->page_alloc_lock);
+ put_gfn(d, gop.mfn);
TRACE_1D(TRC_MEM_PAGE_GRANT_TRANSFER, e->domain_id);
@@ -1850,6 +1862,8 @@ __acquire_grant_for_copy(
{
gfn = sha1->frame;
rc = __get_paged_frame(gfn, &grant_frame, readonly, rd);
+ /* We drop this immediately per the comments at the top */
+ put_gfn(rd, gfn);
if ( rc != GNTST_okay )
goto unlock_out;
act->gfn = gfn;
@@ -1862,6 +1876,7 @@ __acquire_grant_for_copy(
{
gfn = sha2->full_page.frame;
rc = __get_paged_frame(gfn, &grant_frame, readonly, rd);
+ put_gfn(rd, gfn);
if ( rc != GNTST_okay )
goto unlock_out;
act->gfn = gfn;
@@ -1874,6 +1889,7 @@ __acquire_grant_for_copy(
{
gfn = sha2->sub_page.frame;
rc = __get_paged_frame(gfn, &grant_frame, readonly, rd);
+ put_gfn(rd, gfn);
if ( rc != GNTST_okay )
goto unlock_out;
act->gfn = gfn;
@@ -1973,6 +1989,7 @@ __gnttab_copy(
{
#ifdef CONFIG_X86
rc = __get_paged_frame(op->source.u.gmfn, &s_frame, 1, sd);
+ put_gfn(sd, op->source.u.gmfn);
if ( rc != GNTST_okay )
goto error_out;
#else
@@ -2012,6 +2029,7 @@ __gnttab_copy(
{
#ifdef CONFIG_X86
rc = __get_paged_frame(op->dest.u.gmfn, &d_frame, 0, dd);
+ put_gfn(dd, op->dest.u.gmfn);
if ( rc != GNTST_okay )
goto error_out;
#else
diff -r 4699decb8424 -r 7461834954c8 xen/common/memory.c
--- a/xen/common/memory.c
+++ b/xen/common/memory.c
@@ -162,11 +162,12 @@ int guest_remove_page(struct domain *d,
unsigned long mfn;
#ifdef CONFIG_X86
- mfn = mfn_x(gfn_to_mfn(d, gmfn, &p2mt));
+ mfn = mfn_x(get_gfn(d, gmfn, &p2mt));
if ( unlikely(p2m_is_paging(p2mt)) )
{
guest_physmap_remove_page(d, gmfn, mfn, PAGE_ORDER_4K);
p2m_mem_paging_drop_page(d, gmfn);
+ put_gfn(d, gmfn);
return 1;
}
#else
@@ -174,6 +175,7 @@ int guest_remove_page(struct domain *d,
#endif
if ( unlikely(!mfn_valid(mfn)) )
{
+ put_gfn(d, gmfn);
gdprintk(XENLOG_INFO, "Domain %u page number %lx invalid\n",
d->domain_id, gmfn);
return 0;
@@ -187,12 +189,14 @@ int guest_remove_page(struct domain *d,
{
put_page_and_type(page);
guest_physmap_remove_page(d, gmfn, mfn, PAGE_ORDER_4K);
+ put_gfn(d, gmfn);
return 1;
}
#endif /* CONFIG_X86 */
if ( unlikely(!get_page(page, d)) )
{
+ put_gfn(d, gmfn);
gdprintk(XENLOG_INFO, "Bad page free for domain %u\n", d->domain_id);
return 0;
}
@@ -206,6 +210,7 @@ int guest_remove_page(struct domain *d,
guest_physmap_remove_page(d, gmfn, mfn, PAGE_ORDER_4K);
put_page(page);
+ put_gfn(d, gmfn);
return 1;
}
@@ -265,7 +270,7 @@ static long memory_exchange(XEN_GUEST_HA
PAGE_LIST_HEAD(out_chunk_list);
unsigned long in_chunk_order, out_chunk_order;
xen_pfn_t gpfn, gmfn, mfn;
- unsigned long i, j, k;
+ unsigned long i, j, k = 0; /* gcc ... */
unsigned int memflags = 0;
long rc = 0;
struct domain *d;
@@ -363,9 +368,10 @@ static long memory_exchange(XEN_GUEST_HA
p2m_type_t p2mt;
/* Shared pages cannot be exchanged */
- mfn = mfn_x(gfn_to_mfn_unshare(d, gmfn + k, &p2mt));
+ mfn = mfn_x(get_gfn_unshare(d, gmfn + k, &p2mt));
if ( p2m_is_shared(p2mt) )
{
+ put_gfn(d, gmfn + k);
rc = -ENOMEM;
goto fail;
}
@@ -374,6 +380,7 @@ static long memory_exchange(XEN_GUEST_HA
#endif
if ( unlikely(!mfn_valid(mfn)) )
{
+ put_gfn(d, gmfn + k);
rc = -EINVAL;
goto fail;
}
@@ -382,11 +389,13 @@ static long memory_exchange(XEN_GUEST_HA
if ( unlikely(steal_page(d, page, MEMF_no_refcount)) )
{
+ put_gfn(d, gmfn + k);
rc = -EINVAL;
goto fail;
}
page_list_add(page, &in_chunk_list);
+ put_gfn(d, gmfn + k);
}
}
@@ -487,8 +496,12 @@ static long memory_exchange(XEN_GUEST_HA
fail:
/* Reassign any input pages we managed to steal. */
while ( (page = page_list_remove_head(&in_chunk_list)) )
+ {
+ put_gfn(d, gmfn + k--);
if ( assign_pages(d, page, 0, MEMF_no_refcount) )
BUG();
+ }
+
dying:
rcu_unlock_domain(d);
/* Free any output pages we managed to allocate. */
diff -r 4699decb8424 -r 7461834954c8 xen/common/tmem_xen.c
--- a/xen/common/tmem_xen.c
+++ b/xen/common/tmem_xen.c
@@ -109,22 +109,28 @@ static inline void *cli_get_page(tmem_cl
struct page_info *page;
int ret;
- cli_mfn = mfn_x(gfn_to_mfn(current->domain, cmfn, &t));
+ cli_mfn = mfn_x(get_gfn(current->domain, cmfn, &t));
if ( t != p2m_ram_rw || !mfn_valid(cli_mfn) )
+ {
+ put_gfn(current->domain, (unsigned long) cmfn);
return NULL;
+ }
page = mfn_to_page(cli_mfn);
if ( cli_write )
ret = get_page_and_type(page, current->domain, PGT_writable_page);
else
ret = get_page(page, current->domain);
if ( !ret )
+ {
+ put_gfn(current->domain, (unsigned long) cmfn);
return NULL;
+ }
*pcli_mfn = cli_mfn;
*pcli_pfp = (pfp_t *)page;
return map_domain_page(cli_mfn);
}
-static inline void cli_put_page(void *cli_va, pfp_t *cli_pfp,
+static inline void cli_put_page(tmem_cli_mfn_t cmfn, void *cli_va, pfp_t
*cli_pfp,
unsigned long cli_mfn, bool_t mark_dirty)
{
if ( mark_dirty )
@@ -135,6 +141,7 @@ static inline void cli_put_page(void *cl
else
put_page((struct page_info *)cli_pfp);
unmap_domain_page(cli_va);
+ put_gfn(current->domain, (unsigned long) cmfn);
}
#endif
@@ -169,7 +176,7 @@ EXPORT int tmh_copy_from_client(pfp_t *p
(pfn_offset+len <= PAGE_SIZE) )
memcpy((char *)tmem_va+tmem_offset,(char *)cli_va+pfn_offset,len);
if ( !tmemc )
- cli_put_page(cli_va, cli_pfp, cli_mfn, 0);
+ cli_put_page(cmfn, cli_va, cli_pfp, cli_mfn, 0);
unmap_domain_page(tmem_va);
return 1;
}
@@ -197,7 +204,7 @@ EXPORT int tmh_compress_from_client(tmem
ASSERT(ret == LZO_E_OK);
*out_va = dmem;
if ( !tmemc )
- cli_put_page(cli_va, cli_pfp, cli_mfn, 0);
+ cli_put_page(cmfn, cli_va, cli_pfp, cli_mfn, 0);
unmap_domain_page(cli_va);
return 1;
}
@@ -225,7 +232,7 @@ EXPORT int tmh_copy_to_client(tmem_cli_m
memcpy((char *)cli_va+pfn_offset,(char *)tmem_va+tmem_offset,len);
unmap_domain_page(tmem_va);
if ( !tmemc )
- cli_put_page(cli_va, cli_pfp, cli_mfn, 1);
+ cli_put_page(cmfn, cli_va, cli_pfp, cli_mfn, 1);
mb();
return 1;
}
@@ -249,7 +256,7 @@ EXPORT int tmh_decompress_to_client(tmem
ASSERT(ret == LZO_E_OK);
ASSERT(out_len == PAGE_SIZE);
if ( !tmemc )
- cli_put_page(cli_va, cli_pfp, cli_mfn, 1);
+ cli_put_page(cmfn, cli_va, cli_pfp, cli_mfn, 1);
mb();
return 1;
}
@@ -271,7 +278,7 @@ EXPORT int tmh_copy_tze_to_client(tmem_c
memcpy((char *)cli_va,(char *)tmem_va,len);
if ( len < PAGE_SIZE )
memset((char *)cli_va+len,0,PAGE_SIZE-len);
- cli_put_page(cli_va, cli_pfp, cli_mfn, 1);
+ cli_put_page(cmfn, cli_va, cli_pfp, cli_mfn, 1);
mb();
return 1;
}
diff -r 4699decb8424 -r 7461834954c8 xen/include/asm-ia64/mm.h
--- a/xen/include/asm-ia64/mm.h
+++ b/xen/include/asm-ia64/mm.h
@@ -549,6 +549,8 @@ extern u64 translate_domain_pte(u64 ptev
#define gmfn_to_mfn(_d, gpfn) \
gmfn_to_mfn_foreign((_d), (gpfn))
+#define put_gfn(d, g) ((void)0)
+
#define __gpfn_invalid(_d, gpfn) \
(lookup_domain_mpa((_d), ((gpfn)<<PAGE_SHIFT), NULL) == INVALID_MFN)
diff -r 4699decb8424 -r 7461834954c8 xen/include/asm-x86/guest_pt.h
--- a/xen/include/asm-x86/guest_pt.h
+++ b/xen/include/asm-x86/guest_pt.h
@@ -51,9 +51,9 @@ gfn_to_paddr(gfn_t gfn)
return ((paddr_t)gfn_x(gfn)) << PAGE_SHIFT;
}
-/* Override gfn_to_mfn to work with gfn_t */
-#undef gfn_to_mfn
-#define gfn_to_mfn(d, g, t) gfn_to_mfn_type((d), gfn_x(g), (t), p2m_alloc)
+/* Override get_gfn to work with gfn_t */
+#undef get_gfn
+#define get_gfn(d, g, t) get_gfn_type((d), gfn_x(g), (t), p2m_alloc)
/* Types of the guest's page tables and access functions for them */
diff -r 4699decb8424 -r 7461834954c8 xen/include/asm-x86/p2m.h
--- a/xen/include/asm-x86/p2m.h
+++ b/xen/include/asm-x86/p2m.h
@@ -3,6 +3,7 @@
*
* physical-to-machine mappings for automatically-translated domains.
*
+ * Copyright (c) 2011 GridCentric Inc. (Andres Lagar-Cavilla)
* Copyright (c) 2007 Advanced Micro Devices (Wei Huang)
* Parts of this code are Copyright (c) 2006-2007 by XenSource Inc.
* Parts of this code are Copyright (c) 2006 by Michael A Fetterman
@@ -305,47 +306,66 @@ struct p2m_domain *p2m_get_p2m(struct vc
#define p2m_get_pagetable(p2m) ((p2m)->phys_table)
+/**** p2m query accessors. After calling any of the variants below, you
+ * need to call put_gfn(domain, gfn). If you don't, you'll lock the
+ * hypervisor. ****/
/* Read a particular P2M table, mapping pages as we go. Most callers
- * should _not_ call this directly; use the other gfn_to_mfn_* functions
+ * should _not_ call this directly; use the other get_gfn* functions
* below unless you know you want to walk a p2m that isn't a domain's
* main one.
* If the lookup succeeds, the return value is != INVALID_MFN and
* *page_order is filled in with the order of the superpage (if any) that
* the entry was found in. */
-mfn_t gfn_to_mfn_type_p2m(struct p2m_domain *p2m, unsigned long gfn,
+mfn_t get_gfn_type_access(struct p2m_domain *p2m, unsigned long gfn,
p2m_type_t *t, p2m_access_t *a, p2m_query_t q,
unsigned int *page_order);
/* General conversion function from gfn to mfn */
-static inline mfn_t gfn_to_mfn_type(struct domain *d,
+static inline mfn_t get_gfn_type(struct domain *d,
unsigned long gfn, p2m_type_t *t,
p2m_query_t q)
{
p2m_access_t a;
- return gfn_to_mfn_type_p2m(p2m_get_hostp2m(d), gfn, t, &a, q, NULL);
+ return get_gfn_type_access(p2m_get_hostp2m(d), gfn, t, &a, q, NULL);
}
/* Syntactic sugar: most callers will use one of these.
- * N.B. gfn_to_mfn_query() is the _only_ one guaranteed not to take the
+ * N.B. get_gfn_query() is the _only_ one guaranteed not to take the
* p2m lock; none of the others can be called with the p2m or paging
* lock held. */
-#define gfn_to_mfn(d, g, t) gfn_to_mfn_type((d), (g), (t), p2m_alloc)
-#define gfn_to_mfn_query(d, g, t) gfn_to_mfn_type((d), (g), (t), p2m_query)
-#define gfn_to_mfn_guest(d, g, t) gfn_to_mfn_type((d), (g), (t), p2m_guest)
-#define gfn_to_mfn_unshare(d, g, t) gfn_to_mfn_type((d), (g), (t), p2m_unshare)
+#define get_gfn(d, g, t) get_gfn_type((d), (g), (t), p2m_alloc)
+#define get_gfn_query(d, g, t) get_gfn_type((d), (g), (t), p2m_query)
+#define get_gfn_guest(d, g, t) get_gfn_type((d), (g), (t), p2m_guest)
+#define get_gfn_unshare(d, g, t) get_gfn_type((d), (g), (t), p2m_unshare)
/* Compatibility function exporting the old untyped interface */
-static inline unsigned long gmfn_to_mfn(struct domain *d, unsigned long gpfn)
+static inline unsigned long get_gfn_untyped(struct domain *d, unsigned long
gpfn)
{
mfn_t mfn;
p2m_type_t t;
- mfn = gfn_to_mfn(d, gpfn, &t);
+ mfn = get_gfn(d, gpfn, &t);
if ( p2m_is_valid(t) )
return mfn_x(mfn);
return INVALID_MFN;
}
+/* This is a noop for now. */
+static inline void __put_gfn(struct p2m_domain *p2m, unsigned long gfn)
+{
+}
+
+#define put_gfn(d, gfn) __put_gfn(p2m_get_hostp2m((d)), (gfn))
+
+/* These are identical for now. The intent is to have the caller not worry
+ * about put_gfn. To only be used in printk's, crash situations, or to
+ * peek at a type. You're not holding the p2m entry exclsively after calling
+ * this. */
+#define get_gfn_unlocked(d, g, t) get_gfn_type((d), (g), (t),
p2m_alloc)
+#define get_gfn_query_unlocked(d, g, t) get_gfn_type((d), (g), (t),
p2m_query)
+#define get_gfn_guest_unlocked(d, g, t) get_gfn_type((d), (g), (t),
p2m_guest)
+#define get_gfn_unshare_unlocked(d, g, t) get_gfn_type((d), (g), (t),
p2m_unshare)
+
/* General conversion function from mfn to gfn */
static inline unsigned long mfn_to_gfn(struct domain *d, mfn_t mfn)
{
@@ -529,7 +549,8 @@ static inline int p2m_gfn_check_limit(
#define p2m_gfn_check_limit(d, g, o) 0
#endif
-/* Directly set a p2m entry: only for use by p2m code */
+/* Directly set a p2m entry: only for use by p2m code. Does not need
+ * a call to put_gfn afterwards/ */
int set_p2m_entry(struct p2m_domain *p2m, unsigned long gfn, mfn_t mfn,
unsigned int page_order, p2m_type_t p2mt, p2m_access_t p2ma);
_______________________________________________
Xen-devel mailing list
Xen-devel@xxxxxxxxxxxxxxxxxxx
http://lists.xensource.com/xen-devel
|