@@ -128,6 +128,33 @@ can no longer be safely inferred.
A record of this type terminates the image. No further data from the buffer
should be consumed.
+### SHARED_INFO
+
+```
+ 0 1 2 3 4 5 6 7 octet
++-------+-------+-------+-------+-------+-------+-------+-------+
+| type == 2 | instance == 0 |
++-------------------------------+-------------------------------+
+| length |
++-------------------------------+-------------------------------+
+| flags | buffer
++-------------------------------+
+...
+```
+
+\pagebreak
+The record body contains the following fields:
+
+| Field | Description |
+|-------------|-------------------------------------------------|
+| `flags` | A bit-wise OR of the following: |
+| | |
+| | 0x00000001: The domain has 32-bit (compat) |
+| | shared info |
+| | |
+| `buffer` | The shared info (`length` being architecture |
+| | dependent[4]) |
+
* * *
[1] See https://xenbits.xen.org/gitweb/?p=xen.git;a=blob;f=docs/designs/non-cooperative-migration.md
@@ -135,3 +162,5 @@ should be consumed.
[2] See https://xenbits.xen.org/gitweb/?p=xen.git;a=blob;f=xen/include/public/hvm/save.h
[3] See https://xenbits.xen.org/gitweb/?p=xen.git;a=blob;f=docs/specs/libxc-migration-stream.pandoc
+
+[4] See https://xenbits.xen.org/gitweb/?p=xen.git;a=blob;f=tools/include/xen-foreign/reference.size
@@ -57,6 +57,85 @@ static void dump_start(void)
printf(" START: Xen %u.%u\n", s->xen_major, s->xen_minor);
}
+static void print_binary(const char *prefix, const void *val, size_t size,
+ const char *suffix)
+{
+ printf("%s", prefix);
+
+ while ( size-- )
+ {
+ uint8_t octet = *(const uint8_t *)val++;
+ unsigned int i;
+
+ for ( i = 0; i < 8; i++ )
+ {
+ printf("%u", octet & 1);
+ octet >>= 1;
+ }
+ }
+
+ printf("%s", suffix);
+}
+
+static void dump_shared_info(void)
+{
+ struct domain_context_shared_info *s;
+ bool has_32bit_shinfo;
+ shared_info_any_t *info;
+ unsigned int i, n;
+
+ GET_PTR(s);
+ has_32bit_shinfo = s->flags & DOMAIN_CONTEXT_32BIT_SHARED_INFO;
+
+ printf(" SHARED_INFO: has_32bit_shinfo: %s\n",
+ has_32bit_shinfo ? "true" : "false");
+
+ info = (shared_info_any_t *)s->buffer;
+
+#define GET_FIELD_PTR(_f) \
+ (has_32bit_shinfo ? \
+ (const void *)&(info->x32._f) : \
+ (const void *)&(info->x64._f))
+#define GET_FIELD_SIZE(_f) \
+ (has_32bit_shinfo ? sizeof(info->x32._f) : sizeof(info->x64._f))
+#define GET_FIELD(_f) \
+ (has_32bit_shinfo ? info->x32._f : info->x64._f)
+
+ n = has_32bit_shinfo ?
+ ARRAY_SIZE(info->x32.evtchn_pending) :
+ ARRAY_SIZE(info->x64.evtchn_pending);
+
+ for ( i = 0; i < n; i++ )
+ {
+ const char *prefix = !i ?
+ " evtchn_pending: " :
+ " ";
+
+ print_binary(prefix, GET_FIELD_PTR(evtchn_pending[0]),
+ GET_FIELD_SIZE(evtchn_pending[0]), "\n");
+ }
+
+ for ( i = 0; i < n; i++ )
+ {
+ const char *prefix = !i ?
+ " evtchn_mask: " :
+ " ";
+
+ print_binary(prefix, GET_FIELD_PTR(evtchn_mask[0]),
+ GET_FIELD_SIZE(evtchn_mask[0]), "\n");
+ }
+
+ printf(" wc: version: %u sec: %u nsec: %u",
+ GET_FIELD(wc_version), GET_FIELD(wc_sec), GET_FIELD(wc_nsec));
+ if ( !has_32bit_shinfo )
+ printf(" sec_hi: %u", info->x64.xen_wc_sec_hi);
+ printf("\n");
+
+#undef GET_FIELD
+#undef GET_FIELD_SIZE
+#undef GET_FIELD_PTR
+}
+
static void dump_end(void)
{
struct domain_context_end *e;
@@ -145,6 +224,7 @@ int main(int argc, char **argv)
switch (rec->type)
{
case DOMAIN_CONTEXT_START: dump_start(); break;
+ case DOMAIN_CONTEXT_SHARED_INFO: dump_shared_info(); break;
case DOMAIN_CONTEXT_END: dump_end(); break;
default:
printf("Unknown type %u: skipping\n", rec->type);
@@ -33,6 +33,7 @@
#include <xen/xenoprof.h>
#include <xen/irq.h>
#include <xen/argo.h>
+#include <xen/save.h>
#include <asm/debugger.h>
#include <asm/p2m.h>
#include <asm/processor.h>
@@ -1671,6 +1672,118 @@ int continue_hypercall_on_cpu(
return 0;
}
+static int save_shared_info(struct domain *d, struct domain_ctxt_state *c,
+ bool dry_run)
+{
+#ifdef CONFIG_COMPAT
+ struct domain_context_shared_info s = {
+ .flags = has_32bit_shinfo(d) ? DOMAIN_CONTEXT_32BIT_SHARED_INFO : 0,
+ };
+ size_t size = has_32bit_shinfo(d) ?
+ sizeof(struct compat_shared_info) :
+ sizeof(struct shared_info);
+#else
+ struct domain_context_shared_info s = {};
+ size_t size = sizeof(struct shared_info);
+#endif
+ int rc;
+
+ rc = domain_save_ctxt_rec_begin(c, DOMAIN_CONTEXT_SHARED_INFO, 0);
+ if ( rc )
+ return rc;
+
+ rc = domain_save_ctxt_rec_data(c, &s, offsetof(typeof(s), buffer));
+ if ( rc )
+ return rc;
+
+ rc = domain_save_ctxt_rec_data(c, d->shared_info, size);
+ if ( rc )
+ return rc;
+
+ return domain_save_ctxt_rec_end(c);
+}
+
+static int load_shared_info(struct domain *d, struct domain_ctxt_state *c)
+{
+ struct domain_context_shared_info s = {};
+ size_t size;
+ unsigned int i;
+ int rc;
+
+ rc = domain_load_ctxt_rec_begin(c, DOMAIN_CONTEXT_SHARED_INFO, &i);
+ if ( rc )
+ return rc;
+
+ if ( i ) /* expect only a single instance */
+ return -ENXIO;
+
+ rc = domain_load_ctxt_rec_data(c, &s, offsetof(typeof(s), buffer));
+ if ( rc )
+ return rc;
+
+ if ( s.flags & ~DOMAIN_CONTEXT_32BIT_SHARED_INFO )
+ return -EINVAL;
+
+ if ( s.flags & DOMAIN_CONTEXT_32BIT_SHARED_INFO )
+ {
+#ifdef CONFIG_COMPAT
+ d->arch.has_32bit_shinfo = true;
+ size = sizeof(struct compat_shared_info);
+#else
+ return -EINVAL;
+#endif
+ }
+ else
+ size = sizeof(struct shared_info);
+
+ if ( is_pv_domain(d) )
+ {
+ shared_info_t *shinfo = xzalloc(shared_info_t);
+
+ if ( !shinfo )
+ return -ENOMEM;
+
+ rc = domain_load_ctxt_rec_data(c, shinfo, size);
+ if ( rc )
+ goto out;
+
+ memcpy(&shared_info(d, vcpu_info), &__shared_info(d, shinfo, vcpu_info),
+ sizeof(shared_info(d, vcpu_info)));
+ memcpy(&shared_info(d, arch), &__shared_info(d, shinfo, arch),
+ sizeof(shared_info(d, arch)));
+
+ memset(&shared_info(d, evtchn_pending), 0,
+ sizeof(shared_info(d, evtchn_pending)));
+ memset(&shared_info(d, evtchn_mask), 0xff,
+ sizeof(shared_info(d, evtchn_mask)));
+
+#ifdef CONFIG_X86
+ shared_info(d, arch.pfn_to_mfn_frame_list_list) = 0;
+#endif
+ for ( i = 0; i < XEN_LEGACY_MAX_VCPUS; i++ )
+ shared_info(d, vcpu_info[i].evtchn_pending_sel) = 0;
+
+ rc = domain_load_ctxt_rec_end(c, false);
+
+ out:
+ xfree(shinfo);
+ }
+ else
+ {
+ /*
+ * No modifications to shared_info are required for restoring non-PV
+ * domains.
+ */
+ rc = domain_load_ctxt_rec_data(c, NULL, size);
+ if ( !rc )
+ rc = domain_load_ctxt_rec_end(c, true);
+ }
+
+ return rc;
+}
+
+DOMAIN_REGISTER_CTXT_TYPE(SHARED_INFO, save_shared_info, load_shared_info);
+
/*
* Local variables:
* mode: C
@@ -49,6 +49,7 @@ struct domain_context_record {
enum {
DOMAIN_CONTEXT_END,
DOMAIN_CONTEXT_START,
+ DOMAIN_CONTEXT_SHARED_INFO,
/* New types go here */
DOMAIN_CONTEXT_NR_TYPES
};
@@ -58,6 +59,16 @@ struct domain_context_start {
uint32_t xen_major, xen_minor;
};
+struct domain_context_shared_info {
+ uint32_t flags;
+
+#define _DOMAIN_CONTEXT_32BIT_SHARED_INFO 0
+#define DOMAIN_CONTEXT_32BIT_SHARED_INFO \
+ (1U << _DOMAIN_CONTEXT_32BIT_SHARED_INFO)
+
+ uint8_t buffer[XEN_FLEX_ARRAY_DIM];
+};
+
/* Terminating entry */
struct domain_context_end {};