@@ -496,6 +496,7 @@ int xc_domain_hvm_getcontext_partial(xc_
domctl.domain = (domid_t) domid;
domctl.u.hvmcontext_partial.type = typecode;
domctl.u.hvmcontext_partial.instance = instance;
+ domctl.u.hvmcontext_partial.bufsz = size;
set_xen_guest_handle(domctl.u.hvmcontext_partial.buffer, ctxt_buf);
ret = do_domctl(xch, &domctl);
@@ -590,8 +590,12 @@ long arch_do_domctl(
domain_pause(d);
ret = hvm_save_one(d, domctl->u.hvmcontext_partial.type,
domctl->u.hvmcontext_partial.instance,
- domctl->u.hvmcontext_partial.buffer);
+ domctl->u.hvmcontext_partial.buffer,
+ &domctl->u.hvmcontext_partial.bufsz);
domain_unpause(d);
+
+ if ( !ret )
+ copyback = true;
break;
case XEN_DOMCTL_set_address_size:
@@ -76,8 +76,8 @@ size_t hvm_save_size(struct domain *d)
/* Extract a single instance of a save record, by marshalling all
* records of that type and copying out the one we need. */
-int hvm_save_one(struct domain *d, uint16_t typecode, uint16_t instance,
- XEN_GUEST_HANDLE_64(uint8) handle)
+int hvm_save_one(struct domain *d, unsigned int typecode, unsigned int instance,
+ XEN_GUEST_HANDLE_64(uint8) handle, uint64_t *bufsz)
{
int rv = -ENOENT;
size_t sz = 0;
@@ -117,16 +117,20 @@ int hvm_save_one(struct domain *d, uint1
desc = (void *)(ctxt.data + off);
/* Move past header */
off += sizeof(*desc);
+ if ( ctxt.cur < desc->length ||
+ off > ctxt.cur - desc->length )
+ break;
if ( instance == desc->instance )
{
- uint32_t copy_length = desc->length;
-
- if ( ctxt.cur < copy_length ||
- off > ctxt.cur - copy_length )
- copy_length = ctxt.cur - off;
rv = 0;
- if ( copy_to_guest(handle, ctxt.data + off, copy_length) )
+ if ( guest_handle_is_null(handle) )
+ *bufsz = desc->length;
+ else if ( *bufsz < desc->length )
+ rv = -ENOBUFS;
+ else if ( copy_to_guest(handle, ctxt.data + off, desc->length) )
rv = -EFAULT;
+ else
+ *bufsz = desc->length;
break;
}
}
@@ -37,7 +37,7 @@
#include "hvm/save.h"
#include "memory.h"
-#define XEN_DOMCTL_INTERFACE_VERSION 0x0000000d
+#define XEN_DOMCTL_INTERFACE_VERSION 0x0000000e
/*
* NB. xen_domctl.domain is an IN/OUT parameter for this operation.
@@ -747,6 +747,7 @@ DEFINE_XEN_GUEST_HANDLE(xen_domctl_debug
typedef struct xen_domctl_hvmcontext_partial {
uint32_t type; /* IN: Type of record required */
uint32_t instance; /* IN: Instance of that type */
+ uint64_aligned_t bufsz; /* IN: size of buffer */
XEN_GUEST_HANDLE_64(uint8) buffer; /* OUT: buffer to write record into */
} xen_domctl_hvmcontext_partial_t;
DEFINE_XEN_GUEST_HANDLE(xen_domctl_hvmcontext_partial_t);
@@ -132,8 +132,8 @@ __initcall(__hvm_register_##_x##_save_an
/* Entry points for saving and restoring HVM domain state */
size_t hvm_save_size(struct domain *d);
int hvm_save(struct domain *d, hvm_domain_context_t *h);
-int hvm_save_one(struct domain *d, uint16_t typecode, uint16_t instance,
- XEN_GUEST_HANDLE_64(uint8) handle);
+int hvm_save_one(struct domain *d, unsigned int typecode, unsigned int instance,
+ XEN_GUEST_HANDLE_64(uint8) handle, uint64_t *bufsz);
int hvm_load(struct domain *d, hvm_domain_context_t *h);
/* Arch-specific definitions. */