@@ -1116,6 +1116,39 @@ FIFO-based event channel ABI support up to 131,071 event channels.
Other guests are limited to 4095 (64-bit x86 and ARM) or 1023 (32-bit
x86).
+=item B<vnvdimms=[ 'VNVDIMM_SPEC', 'VNVDIMM_SPEC', ... ]>
+
+Specifies the virtual NVDIMM devices which are provided to the guest.
+
+Each B<VNVDIMM_SPEC> is a comma-separated list of C<KEY=VALUE> settings
+from the following list:
+
+=over 4
+
+=item B<type=TYPE>
+
+Specifies the type of host backend of the virtual NVDIMM device. Following
+is a list of supported types:
+
+=over 4
+
+=item B<mfn>
+
+backs the virtual NVDIMM device by a contiguous host PMEM region.
+
+=back
+
+=item B<backend=BACKEND>
+
+Specifies the host backend of the virtual NVDIMM device. If C<type=mfn>,
+then B<BACKEND> specifies the start MFN of the host PMEM region.
+
+=item B<nr_pages=NUMBER>
+
+Specifies the number of pages of the host backend.
+
+=back
+
=back
=head2 Paravirtualised (PV) Guest Specific Options
@@ -139,7 +139,7 @@ LIBXL_OBJS = flexarray.o libxl.o libxl_create.o libxl_dm.o libxl_pci.o \
libxl_dom_suspend.o libxl_dom_save.o libxl_usb.o \
libxl_vtpm.o libxl_nic.o libxl_disk.o libxl_console.o \
libxl_cpupool.o libxl_mem.o libxl_sched.o libxl_tmem.o \
- libxl_9pfs.o libxl_domain.o \
+ libxl_9pfs.o libxl_domain.o libxl_vnvdimm.o \
$(LIBXL_OBJS-y)
LIBXL_OBJS += libxl_genid.o
LIBXL_OBJS += _libxl_types.o libxl_flask.o _libxl_types_internal.o
@@ -1474,6 +1474,11 @@ int libxl_get_memory_target_0x040700(libxl_ctx *ctx, uint32_t domid,
uint32_t *out_target)
LIBXL_EXTERNAL_CALLERS_ONLY;
+int libxl_vnvdimm_copy_config(libxl_ctx *ctx,
+ libxl_domain_config *dst,
+ const libxl_domain_config *src)
+ LIBXL_EXTERNAL_CALLERS_ONLY;
+
/*
* WARNING
* This memory management API is unstable even in Xen 4.2.
@@ -240,6 +240,10 @@ libxl_checkpointed_stream = Enumeration("checkpointed_stream", [
(2, "COLO"),
])
+libxl_vnvdimm_backend_type = Enumeration("vnvdimm_backend_type", [
+ (0, "mfn"),
+ ])
+
#
# Complex libxl types
#
@@ -780,6 +784,16 @@ libxl_device_channel = Struct("device_channel", [
])),
])
+libxl_device_vnvdimm = Struct("device_vnvdimm", [
+ ("backend_domid", libxl_domid),
+ ("backend_domname", string),
+ ("devid", libxl_devid),
+ ("nr_pages", uint64),
+ ("u", KeyedUnion(None, libxl_vnvdimm_backend_type, "backend_type",
+ [("mfn", uint64),
+ ])),
+])
+
libxl_domain_config = Struct("domain_config", [
("c_info", libxl_domain_create_info),
("b_info", libxl_domain_build_info),
@@ -798,6 +812,7 @@ libxl_domain_config = Struct("domain_config", [
("channels", Array(libxl_device_channel, "num_channels")),
("usbctrls", Array(libxl_device_usbctrl, "num_usbctrls")),
("usbdevs", Array(libxl_device_usbdev, "num_usbdevs")),
+ ("vnvdimms", Array(libxl_device_vnvdimm, "num_vnvdimms")),
("on_poweroff", libxl_action_on_shutdown),
("on_reboot", libxl_action_on_shutdown),
new file mode 100644
@@ -0,0 +1,49 @@
+/*
+ * tools/libxl/libxl_vnvdimm.c
+ *
+ * Copyright (C) 2017, Intel Corporation
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License, version 2.1, as published by the Free Software Foundation.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include <xenctrl.h>
+
+#include "libxl_internal.h"
+
+int libxl_vnvdimm_copy_config(libxl_ctx *ctx,
+ libxl_domain_config *dst,
+ const libxl_domain_config *src)
+{
+ GC_INIT(ctx);
+ unsigned int nr = src->num_vnvdimms;
+ libxl_device_vnvdimm *vnvdimms;
+ int rc = 0;
+
+ if (!nr)
+ goto out;
+
+ vnvdimms = libxl__calloc(NOGC, nr, sizeof(*vnvdimms));
+ if (!vnvdimms) {
+ rc = ERROR_NOMEM;
+ goto out;
+ }
+
+ dst->num_vnvdimms = nr;
+ while (nr--)
+ libxl_device_vnvdimm_copy(ctx, &vnvdimms[nr], &src->vnvdimms[nr]);
+ dst->vnvdimms = vnvdimms;
+
+ out:
+ GC_FREE;
+ return rc;
+}
@@ -804,13 +804,111 @@ int parse_usbdev_config(libxl_device_usbdev *usbdev, char *token)
return 0;
}
+static int parse_vnvdimm_config(libxl_device_vnvdimm *vnvdimm, char *token)
+{
+ char *oparg, *endptr;
+ unsigned long val;
+
+ if (MATCH_OPTION("type", token, oparg)) {
+ if (libxl_vnvdimm_backend_type_from_string(oparg,
+ &vnvdimm->backend_type)) {
+ fprintf(stderr,
+ "ERROR: invalid vNVDIMM backend type '%s'\n",
+ oparg);
+ return 1;
+ }
+ } else if (MATCH_OPTION("nr_pages", token, oparg)) {
+ val = strtoul(oparg, &endptr, 0);
+ if (endptr == oparg || val == ULONG_MAX)
+ {
+ fprintf(stderr,
+ "ERROR: invalid number of vNVDIMM backend pages '%s'\n",
+ oparg);
+ return 1;
+ }
+ vnvdimm->nr_pages = val;
+ } else if (MATCH_OPTION("backend", token, oparg)) {
+ /* Skip: handled by parse_vnvdimms() */
+ } else {
+ fprintf(stderr, "ERROR: unknown string '%s' in vnvdimm spec\n", token);
+ return 1;
+ }
+
+ return 0;
+}
+
+/*
+ * vnvdimms = [ 'type=<mfn>, backend=<base_mfn>, nr_pages=<N>', ... ]
+ */
+static void parse_vnvdimms(XLU_Config *config, libxl_domain_config *d_config)
+{
+ XLU_ConfigList *vnvdimms;
+ const char *buf;
+ int rc;
+
+ rc = xlu_cfg_get_list(config, "vnvdimms", &vnvdimms, 0, 0);
+ if ( rc )
+ return;
+
+#if !defined(__linux__)
+ fprintf(stderr, "ERROR: 'vnvdimms' is only supported on Linux\n");
+ exit(-ERROR_FAIL);
+#endif
+
+ d_config->num_vnvdimms = 0;
+ d_config->vnvdimms = NULL;
+
+ while ((buf = xlu_cfg_get_listitem(vnvdimms,
+ d_config->num_vnvdimms)) != NULL) {
+ libxl_device_vnvdimm *vnvdimm =
+ ARRAY_EXTEND_INIT(d_config->vnvdimms, d_config->num_vnvdimms,
+ libxl_device_vnvdimm_init);
+ char *buf2 = strdup(buf), *backend = NULL, *p, *endptr;
+ unsigned long mfn;
+
+ p = strtok(buf2, ",");
+ if (!p)
+ goto skip_nvdimm;
+
+ do {
+ while (*p == ' ')
+ p++;
+
+ rc = 0;
+ if (!MATCH_OPTION("backend", p, backend))
+ rc = parse_vnvdimm_config(vnvdimm, p);
+ if (rc)
+ exit(-ERROR_FAIL);
+ } while ((p = strtok(NULL, ",")) != NULL);
+
+ switch (vnvdimm->backend_type)
+ {
+ case LIBXL_VNVDIMM_BACKEND_TYPE_MFN:
+ mfn = strtoul(backend, &endptr, 0);
+ if (endptr == backend || mfn == ULONG_MAX)
+ {
+ fprintf(stderr,
+ "ERROR: invalid start MFN of host NVDIMM '%s'\n",
+ backend);
+ exit(-ERROR_FAIL);
+ }
+ vnvdimm->u.mfn = mfn;
+
+ break;
+ }
+
+ skip_nvdimm:
+ free(buf2);
+ }
+}
+
void parse_config_data(const char *config_source,
const char *config_data,
int config_len,
libxl_domain_config *d_config)
{
const char *buf;
- long l, vcpus = 0, nr_dm_acpi_pages;
+ long l, vcpus = 0, nr_dm_acpi_pages = 0;
XLU_Config *config;
XLU_ConfigList *cpus, *vbds, *nics, *pcis, *cvfbs, *cpuids, *vtpms,
*usbctrls, *usbdevs, *p9devs;
@@ -1942,6 +2040,16 @@ skip_usbdev:
exit(-ERROR_FAIL);
}
b_info->u.hvm.dm_acpi_pages = nr_dm_acpi_pages;
+
+ /* parse 'vnvdimms' */
+ parse_vnvdimms(config, d_config);
+
+ /*
+ * If 'dm_acpi_pages' is not specified, reserve one DM ACPI
+ * page for vNVDIMM devices.
+ */
+ if (d_config->vnvdimms && !nr_dm_acpi_pages)
+ b_info->u.hvm.dm_acpi_pages = 1;
}
/* If we've already got vfb=[] for PV guest then ignore top level
@@ -381,12 +381,25 @@ static void reload_domain_config(uint32_t domid,
if (rc) {
LOG("failed to retrieve guest configuration (rc=%d). "
"reusing old configuration", rc);
- libxl_domain_config_dispose(&d_config_new);
+ goto error_out;
} else {
+ rc = libxl_vnvdimm_copy_config(ctx, &d_config_new, d_config);
+ if (rc) {
+ LOG("failed to copy vnvdimm configuration (rc=%d). "
+ "reusing old configuration", rc);
+ libxl_domain_config_dispose(&d_config_new);
+ goto error_out;
+ }
+
libxl_domain_config_dispose(d_config);
/* Steal allocations */
memcpy(d_config, &d_config_new, sizeof(libxl_domain_config));
}
+
+ return;
+
+ error_out:
+ libxl_domain_config_dispose(&d_config_new);
}
/* Can update r_domid if domain is destroyed */
A new xl domain configuration vnvdimms = [ 'type=mfn, backend=START_PMEM_MFN, nr_pages=N', ... ] is added to specify the virtual NVDIMM devices backed by the specified host PMEM pages. As the kernel PMEM driver does not work in Dom0 now, we have to specify MFNs. Signed-off-by: Haozhong Zhang <haozhong.zhang@intel.com> --- Cc: Ian Jackson <ian.jackson@eu.citrix.com> Cc: Wei Liu <wei.liu2@citrix.com> --- docs/man/xl.cfg.pod.5.in | 33 +++++++++++++ tools/libxl/Makefile | 2 +- tools/libxl/libxl.h | 5 ++ tools/libxl/libxl_types.idl | 15 ++++++ tools/libxl/libxl_vnvdimm.c | 49 ++++++++++++++++++++ tools/xl/xl_parse.c | 110 +++++++++++++++++++++++++++++++++++++++++++- tools/xl/xl_vmcontrol.c | 15 +++++- 7 files changed, 226 insertions(+), 3 deletions(-) create mode 100644 tools/libxl/libxl_vnvdimm.c