mirror of
https://github.com/xen-project/xen.git
synced 2026-10-29 10:40:03 +01:00
A previous patch added support for priv-mapping guest resources directly
(rather than having to foreign-map, which requires P2M modification for
HVM guests).
This patch makes use of the new API to seed the guest grant table unless
the underlying infrastructure (i.e. privcmd) doesn't support it, in which
case the old scheme is used.
NOTE: The call to xc_dom_gnttab_hvm_seed() in hvm_build_set_params() was
actually unnecessary, as the grant table has already been seeded
by a prior call to xc_dom_gnttab_init() made by libxl__build_dom().
Signed-off-by: Paul Durrant <paul.durrant@citrix.com>
Acked-by: Marek Marczykowski-Górecki <marmarek@invisiblethingslab.com>
Reviewed-by: Roger Pau Monné <roger.pau@citrix.com>
Acked-by: Wei Liu <wei.liu2@citrix.com>
Reviewed-by: Andrew Cooper <andrew.cooper3@citrix.com>
262 lines
6.5 KiB
C
262 lines
6.5 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_seed(xch, ctx->domid, true,
|
|
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:
|
|
*/
|