diff options
-rw-r--r-- | tools/libxc/xc_domain.c | 16 | ||||
-rw-r--r-- | tools/libxc/xc_domain_restore.c | 21 | ||||
-rw-r--r-- | tools/libxc/xc_domain_save.c | 13 | ||||
-rw-r--r-- | tools/libxc/xenctrl.h | 11 | ||||
-rw-r--r-- | xen/arch/x86/domctl.c | 36 | ||||
-rw-r--r-- | xen/include/public/domctl.h | 9 |
6 files changed, 101 insertions, 5 deletions
diff --git a/tools/libxc/xc_domain.c b/tools/libxc/xc_domain.c index d98e68bd6d..4b82884905 100644 --- a/tools/libxc/xc_domain.c +++ b/tools/libxc/xc_domain.c @@ -283,6 +283,22 @@ int xc_domain_getinfolist(xc_interface *xch, return ret; } +/* set broken page p2m */ +int xc_set_broken_page_p2m(xc_interface *xch, + uint32_t domid, + unsigned long pfn) +{ + int ret; + DECLARE_DOMCTL; + + domctl.cmd = XEN_DOMCTL_set_broken_page_p2m; + domctl.domain = (domid_t)domid; + domctl.u.set_broken_page_p2m.pfn = pfn; + ret = do_domctl(xch, &domctl); + + return ret ? -1 : 0; +} + /* get info from hvm guest for save */ int xc_domain_hvm_getcontext(xc_interface *xch, uint32_t domid, diff --git a/tools/libxc/xc_domain_restore.c b/tools/libxc/xc_domain_restore.c index 02bfa1c163..454d2cbd49 100644 --- a/tools/libxc/xc_domain_restore.c +++ b/tools/libxc/xc_domain_restore.c @@ -1023,9 +1023,15 @@ static int pagebuf_get_one(xc_interface *xch, struct restore_ctx *ctx, countpages = count; for (i = oldcount; i < buf->nr_pages; ++i) - if ((buf->pfn_types[i] & XEN_DOMCTL_PFINFO_LTAB_MASK) == XEN_DOMCTL_PFINFO_XTAB - ||(buf->pfn_types[i] & XEN_DOMCTL_PFINFO_LTAB_MASK) == XEN_DOMCTL_PFINFO_XALLOC) + { + unsigned long pagetype; + + pagetype = buf->pfn_types[i] & XEN_DOMCTL_PFINFO_LTAB_MASK; + if ( pagetype == XEN_DOMCTL_PFINFO_XTAB || + pagetype == XEN_DOMCTL_PFINFO_BROKEN || + pagetype == XEN_DOMCTL_PFINFO_XALLOC ) --countpages; + } if (!countpages) return count; @@ -1267,6 +1273,17 @@ static int apply_batch(xc_interface *xch, uint32_t dom, struct restore_ctx *ctx, /* a bogus/unmapped/allocate-only page: skip it */ continue; + if ( pagetype == XEN_DOMCTL_PFINFO_BROKEN ) + { + if ( xc_set_broken_page_p2m(xch, dom, pfn) ) + { + ERROR("Set p2m for broken page failed, " + "dom=%d, pfn=%lx\n", dom, pfn); + goto err_mapped; + } + continue; + } + if (pfn_err[i]) { ERROR("unexpected PFN mapping failure pfn %lx map_mfn %lx p2m_mfn %lx", diff --git a/tools/libxc/xc_domain_save.c b/tools/libxc/xc_domain_save.c index d48e9c0fb0..dad681a1d0 100644 --- a/tools/libxc/xc_domain_save.c +++ b/tools/libxc/xc_domain_save.c @@ -1277,6 +1277,13 @@ int xc_domain_save(xc_interface *xch, int io_fd, uint32_t dom, uint32_t max_iter if ( !hvm ) gmfn = pfn_to_mfn(gmfn); + if ( pfn_type[j] == XEN_DOMCTL_PFINFO_BROKEN ) + { + pfn_type[j] |= pfn_batch[j]; + ++run; + continue; + } + if ( pfn_err[j] ) { if ( pfn_type[j] == XEN_DOMCTL_PFINFO_XTAB ) @@ -1371,8 +1378,12 @@ int xc_domain_save(xc_interface *xch, int io_fd, uint32_t dom, uint32_t max_iter } } - /* skip pages that aren't present or are alloc-only */ + /* + * skip pages that aren't present, + * or are broken, or are alloc-only + */ if ( pagetype == XEN_DOMCTL_PFINFO_XTAB + || pagetype == XEN_DOMCTL_PFINFO_BROKEN || pagetype == XEN_DOMCTL_PFINFO_XALLOC ) continue; diff --git a/tools/libxc/xenctrl.h b/tools/libxc/xenctrl.h index 7eb57430c3..1cd13c1b34 100644 --- a/tools/libxc/xenctrl.h +++ b/tools/libxc/xenctrl.h @@ -575,6 +575,17 @@ int xc_domain_getinfolist(xc_interface *xch, xc_domaininfo_t *info); /** + * This function set p2m for broken page + * &parm xch a handle to an open hypervisor interface + * @parm domid the domain id which broken page belong to + * @parm pfn the pfn number of the broken page + * @return 0 on success, -1 on failure + */ +int xc_set_broken_page_p2m(xc_interface *xch, + uint32_t domid, + unsigned long pfn); + +/** * This function returns information about the context of a hvm domain * @parm xch a handle to an open hypervisor interface * @parm domid the domain to get information from diff --git a/xen/arch/x86/domctl.c b/xen/arch/x86/domctl.c index 508c77c899..83daebb26a 100644 --- a/xen/arch/x86/domctl.c +++ b/xen/arch/x86/domctl.c @@ -209,12 +209,18 @@ long arch_do_domctl( for ( j = 0; j < k; j++ ) { unsigned long type = 0; + p2m_type_t t; - page = get_page_from_gfn(d, arr[j], NULL, P2M_ALLOC); + page = get_page_from_gfn(d, arr[j], &t, P2M_ALLOC); if ( unlikely(!page) || unlikely(is_xen_heap_page(page)) ) - type = XEN_DOMCTL_PFINFO_XTAB; + { + if ( p2m_is_broken(t) ) + type = XEN_DOMCTL_PFINFO_BROKEN; + else + type = XEN_DOMCTL_PFINFO_XTAB; + } else { switch( page->u.inuse.type_info & PGT_type_mask ) @@ -235,6 +241,9 @@ long arch_do_domctl( if ( page->u.inuse.type_info & PGT_pinned ) type |= XEN_DOMCTL_PFINFO_LPINTAB; + + if ( page->count_info & PGC_broken ) + type = XEN_DOMCTL_PFINFO_BROKEN; } if ( page ) @@ -1568,6 +1577,29 @@ long arch_do_domctl( } break; + case XEN_DOMCTL_set_broken_page_p2m: + { + struct domain *d; + + d = rcu_lock_domain_by_id(domctl->domain); + if ( d != NULL ) + { + p2m_type_t pt; + unsigned long pfn = domctl->u.set_broken_page_p2m.pfn; + mfn_t mfn = get_gfn_query(d, pfn, &pt); + + if ( unlikely(!mfn_valid(mfn_x(mfn)) || !p2m_is_ram(pt) || + (p2m_change_type(d, pfn, pt, p2m_ram_broken) != pt)) ) + ret = -EINVAL; + + put_gfn(d, pfn); + rcu_unlock_domain(d); + } + else + ret = -ESRCH; + } + break; + default: ret = iommu_do_domctl(domctl, u_domctl); break; diff --git a/xen/include/public/domctl.h b/xen/include/public/domctl.h index 7c0f23df2e..74160b07db 100644 --- a/xen/include/public/domctl.h +++ b/xen/include/public/domctl.h @@ -136,6 +136,7 @@ DEFINE_XEN_GUEST_HANDLE(xen_domctl_getmemlist_t); #define XEN_DOMCTL_PFINFO_LPINTAB (0x1U<<31) #define XEN_DOMCTL_PFINFO_XTAB (0xfU<<28) /* invalid page */ #define XEN_DOMCTL_PFINFO_XALLOC (0xeU<<28) /* allocate-only page */ +#define XEN_DOMCTL_PFINFO_BROKEN (0xdU<<28) /* broken page */ #define XEN_DOMCTL_PFINFO_LTAB_MASK (0xfU<<28) struct xen_domctl_getpageframeinfo { @@ -834,6 +835,12 @@ struct xen_domctl_set_access_required { typedef struct xen_domctl_set_access_required xen_domctl_set_access_required_t; DEFINE_XEN_GUEST_HANDLE(xen_domctl_set_access_required_t); +struct xen_domctl_set_broken_page_p2m { + uint64_aligned_t pfn; +}; +typedef struct xen_domctl_set_broken_page_p2m xen_domctl_set_broken_page_p2m_t; +DEFINE_XEN_GUEST_HANDLE(xen_domctl_set_broken_page_p2m_t); + struct xen_domctl { uint32_t cmd; #define XEN_DOMCTL_createdomain 1 @@ -899,6 +906,7 @@ struct xen_domctl { #define XEN_DOMCTL_set_access_required 64 #define XEN_DOMCTL_audit_p2m 65 #define XEN_DOMCTL_set_virq_handler 66 +#define XEN_DOMCTL_set_broken_page_p2m 67 #define XEN_DOMCTL_gdbsx_guestmemio 1000 #define XEN_DOMCTL_gdbsx_pausevcpu 1001 #define XEN_DOMCTL_gdbsx_unpausevcpu 1002 @@ -954,6 +962,7 @@ struct xen_domctl { struct xen_domctl_audit_p2m audit_p2m; struct xen_domctl_set_virq_handler set_virq_handler; struct xen_domctl_gdbsx_memio gdbsx_guest_memio; + struct xen_domctl_set_broken_page_p2m set_broken_page_p2m; struct xen_domctl_gdbsx_pauseunp_vcpu gdbsx_pauseunp_vcpu; struct xen_domctl_gdbsx_domstatus gdbsx_domstatus; uint8_t pad[128]; |