mirror of
https://github.com/xen-project/xen.git
synced 2026-10-30 03:00:05 +01:00
Long ago domains to be saved were limited to 1TB size due to the migration stream v1 limitations which used a 32 bit value for the PFN and the frame type (4 bits) leaving only 28 bits for the PFN. Migration stream V2 uses a 64 bit value for this purpose, so there is no need to refuse saving (or migrating) domains larger than 1 TB. For 32 bit toolstacks there is still a size limit, as domains larger than about 1TB will lead to an exhausted virtual address space of the saving process. So keep the test for 32 bit, but don't base it on the page type macros. As a migration could lead to the situation where a 32 bit toolstack would have to handle such a large domain (in case the sending side is 64 bit) the same test should be added for restoring a domain. Signed-off-by: Juergen Gross <jgross@suse.com> Acked-by: Wei Liu <wei.liu2@citrix.com> Release-acked-by: Julien Grall <julien.grall@linaro.org>
262 lines
6.6 KiB
C
262 lines
6.6 KiB
C
#include <assert.h>
|
|
#include <arpa/inet.h>
|
|
|
|
#include "xc_sr_common_x86.h"
|
|
|
|
/*
|
|
* Process an HVM_CONTEXT record from the stream.
|
|
*/
|
|
static int handle_hvm_context(struct xc_sr_context *ctx,
|
|
struct xc_sr_record *rec)
|
|
{
|
|
xc_interface *xch = ctx->xch;
|
|
void *p;
|
|
|
|
p = malloc(rec->length);
|
|
if ( !p )
|
|
{
|
|
ERROR("Unable to allocate %u bytes for hvm context", rec->length);
|
|
return -1;
|
|
}
|
|
|
|
free(ctx->x86_hvm.restore.context);
|
|
|
|
ctx->x86_hvm.restore.context = memcpy(p, rec->data, rec->length);
|
|
ctx->x86_hvm.restore.contextsz = rec->length;
|
|
|
|
return 0;
|
|
}
|
|
|
|
/*
|
|
* Process an HVM_PARAMS record from the stream.
|
|
*/
|
|
static int handle_hvm_params(struct xc_sr_context *ctx,
|
|
struct xc_sr_record *rec)
|
|
{
|
|
xc_interface *xch = ctx->xch;
|
|
struct xc_sr_rec_hvm_params *hdr = rec->data;
|
|
struct xc_sr_rec_hvm_params_entry *entry = hdr->param;
|
|
unsigned int i;
|
|
int rc;
|
|
|
|
if ( rec->length < sizeof(*hdr) )
|
|
{
|
|
ERROR("HVM_PARAMS record truncated: length %u, header size %zu",
|
|
rec->length, sizeof(*hdr));
|
|
return -1;
|
|
}
|
|
|
|
if ( rec->length != (sizeof(*hdr) + hdr->count * sizeof(*entry)) )
|
|
{
|
|
ERROR("HVM_PARAMS record truncated: header %zu, count %u, "
|
|
"expected len %zu, got %u",
|
|
sizeof(*hdr), hdr->count, hdr->count * sizeof(*entry),
|
|
rec->length);
|
|
return -1;
|
|
}
|
|
|
|
/*
|
|
* Tolerate empty records. Older sending sides used to accidentally
|
|
* generate them.
|
|
*/
|
|
if ( hdr->count == 0 )
|
|
{
|
|
DBGPRINTF("Skipping empty HVM_PARAMS record\n");
|
|
return 0;
|
|
}
|
|
|
|
for ( i = 0; i < hdr->count; i++, entry++ )
|
|
{
|
|
switch ( entry->index )
|
|
{
|
|
case HVM_PARAM_CONSOLE_PFN:
|
|
ctx->restore.console_gfn = entry->value;
|
|
xc_clear_domain_page(xch, ctx->domid, entry->value);
|
|
break;
|
|
case HVM_PARAM_STORE_PFN:
|
|
ctx->restore.xenstore_gfn = entry->value;
|
|
xc_clear_domain_page(xch, ctx->domid, entry->value);
|
|
break;
|
|
case HVM_PARAM_IOREQ_PFN:
|
|
case HVM_PARAM_BUFIOREQ_PFN:
|
|
xc_clear_domain_page(xch, ctx->domid, entry->value);
|
|
break;
|
|
}
|
|
|
|
rc = xc_hvm_param_set(xch, ctx->domid, entry->index, entry->value);
|
|
if ( rc < 0 )
|
|
{
|
|
PERROR("set HVM param %"PRId64" = 0x%016"PRIx64,
|
|
entry->index, entry->value);
|
|
return rc;
|
|
}
|
|
}
|
|
return 0;
|
|
}
|
|
|
|
/* restore_ops function. */
|
|
static bool x86_hvm_pfn_is_valid(const struct xc_sr_context *ctx, xen_pfn_t pfn)
|
|
{
|
|
return true;
|
|
}
|
|
|
|
/* restore_ops function. */
|
|
static xen_pfn_t x86_hvm_pfn_to_gfn(const struct xc_sr_context *ctx,
|
|
xen_pfn_t pfn)
|
|
{
|
|
return pfn;
|
|
}
|
|
|
|
/* restore_ops function. */
|
|
static void x86_hvm_set_gfn(struct xc_sr_context *ctx, xen_pfn_t pfn,
|
|
xen_pfn_t gfn)
|
|
{
|
|
/* no op */
|
|
}
|
|
|
|
/* restore_ops function. */
|
|
static void x86_hvm_set_page_type(struct xc_sr_context *ctx,
|
|
xen_pfn_t pfn, xen_pfn_t type)
|
|
{
|
|
/* no-op */
|
|
}
|
|
|
|
/* restore_ops function. */
|
|
static int x86_hvm_localise_page(struct xc_sr_context *ctx,
|
|
uint32_t type, void *page)
|
|
{
|
|
/* no-op */
|
|
return 0;
|
|
}
|
|
|
|
/*
|
|
* restore_ops function. Confirms the stream matches the domain.
|
|
*/
|
|
static int x86_hvm_setup(struct xc_sr_context *ctx)
|
|
{
|
|
xc_interface *xch = ctx->xch;
|
|
|
|
if ( ctx->restore.guest_type != DHDR_TYPE_X86_HVM )
|
|
{
|
|
ERROR("Unable to restore %s domain into an x86_hvm domain",
|
|
dhdr_type_to_str(ctx->restore.guest_type));
|
|
return -1;
|
|
}
|
|
else if ( ctx->restore.guest_page_size != PAGE_SIZE )
|
|
{
|
|
ERROR("Invalid page size %u for x86_hvm domains",
|
|
ctx->restore.guest_page_size);
|
|
return -1;
|
|
}
|
|
#ifdef __i386__
|
|
/* Very large domains (> 1TB) will exhaust virtual address space. */
|
|
if ( ctx->restore.p2m_size > 0x0fffffff )
|
|
{
|
|
errno = E2BIG;
|
|
PERROR("Cannot restore this big a guest");
|
|
return -1;
|
|
}
|
|
#endif
|
|
|
|
return 0;
|
|
}
|
|
|
|
/*
|
|
* restore_ops function.
|
|
*/
|
|
static int x86_hvm_process_record(struct xc_sr_context *ctx,
|
|
struct xc_sr_record *rec)
|
|
{
|
|
switch ( rec->type )
|
|
{
|
|
case REC_TYPE_TSC_INFO:
|
|
return handle_tsc_info(ctx, rec);
|
|
|
|
case REC_TYPE_HVM_CONTEXT:
|
|
return handle_hvm_context(ctx, rec);
|
|
|
|
case REC_TYPE_HVM_PARAMS:
|
|
return handle_hvm_params(ctx, rec);
|
|
|
|
default:
|
|
return RECORD_NOT_PROCESSED;
|
|
}
|
|
}
|
|
|
|
/*
|
|
* restore_ops function. Sets extra hvm parameters and seeds the grant table.
|
|
*/
|
|
static int x86_hvm_stream_complete(struct xc_sr_context *ctx)
|
|
{
|
|
xc_interface *xch = ctx->xch;
|
|
int rc;
|
|
|
|
rc = xc_hvm_param_set(xch, ctx->domid, HVM_PARAM_STORE_EVTCHN,
|
|
ctx->restore.xenstore_evtchn);
|
|
if ( rc )
|
|
{
|
|
PERROR("Failed to set HVM_PARAM_STORE_EVTCHN");
|
|
return rc;
|
|
}
|
|
|
|
rc = xc_hvm_param_set(xch, ctx->domid, HVM_PARAM_CONSOLE_EVTCHN,
|
|
ctx->restore.console_evtchn);
|
|
if ( rc )
|
|
{
|
|
PERROR("Failed to set HVM_PARAM_CONSOLE_EVTCHN");
|
|
return rc;
|
|
}
|
|
|
|
rc = xc_domain_hvm_setcontext(xch, ctx->domid,
|
|
ctx->x86_hvm.restore.context,
|
|
ctx->x86_hvm.restore.contextsz);
|
|
if ( rc < 0 )
|
|
{
|
|
PERROR("Unable to restore HVM context");
|
|
return rc;
|
|
}
|
|
|
|
rc = xc_dom_gnttab_hvm_seed(xch, ctx->domid,
|
|
ctx->restore.console_gfn,
|
|
ctx->restore.xenstore_gfn,
|
|
ctx->restore.console_domid,
|
|
ctx->restore.xenstore_domid);
|
|
if ( rc )
|
|
{
|
|
PERROR("Failed to seed grant table");
|
|
return rc;
|
|
}
|
|
|
|
return rc;
|
|
}
|
|
|
|
static int x86_hvm_cleanup(struct xc_sr_context *ctx)
|
|
{
|
|
free(ctx->x86_hvm.restore.context);
|
|
|
|
return 0;
|
|
}
|
|
|
|
struct xc_sr_restore_ops restore_ops_x86_hvm =
|
|
{
|
|
.pfn_is_valid = x86_hvm_pfn_is_valid,
|
|
.pfn_to_gfn = x86_hvm_pfn_to_gfn,
|
|
.set_gfn = x86_hvm_set_gfn,
|
|
.set_page_type = x86_hvm_set_page_type,
|
|
.localise_page = x86_hvm_localise_page,
|
|
.setup = x86_hvm_setup,
|
|
.process_record = x86_hvm_process_record,
|
|
.stream_complete = x86_hvm_stream_complete,
|
|
.cleanup = x86_hvm_cleanup,
|
|
};
|
|
|
|
/*
|
|
* Local variables:
|
|
* mode: C
|
|
* c-file-style: "BSD"
|
|
* c-basic-offset: 4
|
|
* tab-width: 4
|
|
* indent-tabs-mode: nil
|
|
* End:
|
|
*/
|