diff --git a/xen/arch/x86/mm/mem_event.c b/xen/arch/x86/mm/mem_event.c index c6197f8751..d484f1f50d 100644 --- a/xen/arch/x86/mm/mem_event.c +++ b/xen/arch/x86/mm/mem_event.c @@ -45,7 +45,7 @@ static int mem_event_enable(struct domain *d, struct domain *dom_mem_event = current->domain; struct vcpu *v = current; unsigned long ring_addr = mec->ring_addr; - unsigned long shared_addr = mec->shared_addr; + unsigned long shared_addr = mec->u.shared_addr; l1_pgentry_t l1e; unsigned long shared_gfn = 0, ring_gfn = 0; /* gcc ... */ p2m_type_t p2mt; diff --git a/xen/arch/x86/mm/mem_paging.c b/xen/arch/x86/mm/mem_paging.c index 5c02095163..14b3827664 100644 --- a/xen/arch/x86/mm/mem_paging.c +++ b/xen/arch/x86/mm/mem_paging.c @@ -47,7 +47,7 @@ int mem_paging_domctl(struct domain *d, xen_domctl_mem_event_op_t *mec, case XEN_DOMCTL_MEM_EVENT_OP_PAGING_PREP: { unsigned long gfn = mec->gfn; - return p2m_mem_paging_prep(d, gfn); + return p2m_mem_paging_prep(d, gfn, mec->u.buffer); } break; diff --git a/xen/arch/x86/mm/p2m.c b/xen/arch/x86/mm/p2m.c index 5054f92143..ad92307c62 100644 --- a/xen/arch/x86/mm/p2m.c +++ b/xen/arch/x86/mm/p2m.c @@ -974,14 +974,21 @@ void p2m_mem_paging_populate(struct domain *d, unsigned long gfn) * mfn if populate was called for gfn which was nominated but not evicted. In * this case only the p2mt needs to be forwarded. */ -int p2m_mem_paging_prep(struct domain *d, unsigned long gfn) +int p2m_mem_paging_prep(struct domain *d, unsigned long gfn, uint64_t buffer) { struct page_info *page; p2m_type_t p2mt; p2m_access_t a; mfn_t mfn; struct p2m_domain *p2m = p2m_get_hostp2m(d); - int ret; + int ret, page_extant = 1; + const void *user_ptr = (const void *) buffer; + + if ( user_ptr ) + /* Sanity check the buffer and bail out early if trouble */ + if ( (buffer & (PAGE_SIZE - 1)) || + (!access_ok(user_ptr, PAGE_SIZE)) ) + return -EINVAL; p2m_lock(p2m); @@ -1001,6 +1008,27 @@ int p2m_mem_paging_prep(struct domain *d, unsigned long gfn) if ( unlikely(page == NULL) ) goto out; mfn = page_to_mfn(page); + page_extant = 0; + } + + /* If we were given a buffer, now is the time to use it */ + if ( !page_extant && user_ptr ) + { + void *guest_map; + int rc; + + ASSERT( mfn_valid(mfn) ); + guest_map = map_domain_page(mfn_x(mfn)); + rc = copy_from_user(guest_map, user_ptr, PAGE_SIZE); + unmap_domain_page(guest_map); + if ( rc ) + { + gdprintk(XENLOG_ERR, "Failed to load paging-in gfn %lx domain %u " + "bytes left %d\n", gfn, d->domain_id, rc); + ret = -EFAULT; + put_page(page); /* Don't leak pages */ + goto out; + } } /* Fix p2m mapping */ diff --git a/xen/include/asm-x86/p2m.h b/xen/include/asm-x86/p2m.h index efb77e1ab1..bbffa2464c 100644 --- a/xen/include/asm-x86/p2m.h +++ b/xen/include/asm-x86/p2m.h @@ -479,7 +479,7 @@ void p2m_mem_paging_drop_page(struct domain *d, unsigned long gfn); /* Start populating a paged out frame */ void p2m_mem_paging_populate(struct domain *d, unsigned long gfn); /* Prepare the p2m for paging a frame in */ -int p2m_mem_paging_prep(struct domain *d, unsigned long gfn); +int p2m_mem_paging_prep(struct domain *d, unsigned long gfn, uint64_t buffer); /* Resume normal operation (in case a domain was paused) */ void p2m_mem_paging_resume(struct domain *d); #else diff --git a/xen/include/public/domctl.h b/xen/include/public/domctl.h index b265a47aec..509442b22f 100644 --- a/xen/include/public/domctl.h +++ b/xen/include/public/domctl.h @@ -742,8 +742,12 @@ struct xen_domctl_mem_event_op { uint32_t op; /* XEN_DOMCTL_MEM_EVENT_OP_*_* */ uint32_t mode; /* XEN_DOMCTL_MEM_EVENT_OP_* */ - /* OP_ENABLE */ - uint64_aligned_t shared_addr; /* IN: Virtual address of shared page */ + union { + /* OP_ENABLE IN: Virtual address of shared page */ + uint64_aligned_t shared_addr; + /* PAGING_PREP IN: buffer to immediately fill page in */ + uint64_aligned_t buffer; + } u; uint64_aligned_t ring_addr; /* IN: Virtual address of ring page */ /* Other OPs */