From mboxrd@z Thu Jan 1 00:00:00 1970 From: David Vrabel Subject: [PATCH 6/8] libxl: allow a generation ID to be specified at domain creation Date: Wed, 18 Jun 2014 17:12:55 +0100 Message-ID: <1403107977-13795-7-git-send-email-david.vrabel@citrix.com> References: <1403107977-13795-1-git-send-email-david.vrabel@citrix.com> Mime-Version: 1.0 Content-Type: text/plain; charset="us-ascii" Content-Transfer-Encoding: 7bit Return-path: Received: from mail6.bemta4.messagelabs.com ([85.158.143.247]) by lists.xen.org with esmtp (Exim 4.72) (envelope-from ) id 1WxIU1-0001y9-1M for xen-devel@lists.xenproject.org; Wed, 18 Jun 2014 16:13:09 +0000 In-Reply-To: <1403107977-13795-1-git-send-email-david.vrabel@citrix.com> List-Unsubscribe: , List-Post: List-Help: List-Subscribe: , Sender: xen-devel-bounces@lists.xen.org Errors-To: xen-devel-bounces@lists.xen.org To: xen-devel@lists.xenproject.org Cc: David Vrabel , Ian Jackson , Ian Campbell , Stefano Stabellini List-Id: xen-devel@lists.xenproject.org Toolstacks may specify a VM generation ID using the u.hvm.ms_vm_genid field in the libxl_domain_build_info structure, when creating a domain. The toolstack is responsible for providing the correct generation ID according to the Microsoft specification (e.g., generating new random ones with libxl_ms_vm_genid_generate() as appropriate when restoring). Although the specification requires that a ACPI Notify event is raised if the generation ID is changed, the generation ID is never changed when the domain is in a state to receive such an event (it's either newly created or suspended). Signed-off-by: David Vrabel --- tools/libxl/Makefile | 1 + tools/libxl/gentest.py | 2 +- tools/libxl/libxl.h | 13 +++++ tools/libxl/libxl_dom.c | 10 ++++ tools/libxl/libxl_genid.c | 111 ++++++++++++++++++++++++++++++++++++++++++ tools/libxl/libxl_internal.h | 6 +++ tools/libxl/libxl_json.c | 39 +++++++++++++++ tools/libxl/libxl_json.h | 1 + tools/libxl/libxl_types.idl | 3 ++ 9 files changed, 185 insertions(+), 1 deletion(-) create mode 100644 tools/libxl/libxl_genid.c diff --git a/tools/libxl/Makefile b/tools/libxl/Makefile index 4cfa275..6499aa7 100644 --- a/tools/libxl/Makefile +++ b/tools/libxl/Makefile @@ -77,6 +77,7 @@ LIBXL_OBJS = flexarray.o libxl.o libxl_create.o libxl_dm.o libxl_pci.o \ libxl_json.o libxl_aoutils.o libxl_numa.o \ libxl_save_callout.o _libxl_save_msgs_callout.o \ libxl_qmp.o libxl_event.o libxl_fork.o $(LIBXL_OBJS-y) +LIBXL_OBJS += libxl_genid.o LIBXL_OBJS += _libxl_types.o libxl_flask.o _libxl_types_internal.o LIBXL_TESTS += timedereg diff --git a/tools/libxl/gentest.py b/tools/libxl/gentest.py index eb9a21b..0195bf4 100644 --- a/tools/libxl/gentest.py +++ b/tools/libxl/gentest.py @@ -60,7 +60,7 @@ def gen_rand_init(ty, v, indent = " ", parent = None): s += "%s(%s);\n" % (ty.rand_init, ty.pass_arg(v, isref=parent is None, passby=idl.PASS_BY_REFERENCE)) - elif ty.typename in ["libxl_uuid", "libxl_mac", "libxl_hwcap"]: + elif ty.typename in ["libxl_uuid", "libxl_mac", "libxl_hwcap", "libxl_ms_vm_genid"]: s += "rand_bytes((uint8_t *)%s, sizeof(*%s));\n" % (v,v) elif ty.typename in ["libxl_domid", "libxl_devid"] or isinstance(ty, idl.Number): s += "%s = rand() %% (sizeof(%s)*8);\n" % \ diff --git a/tools/libxl/libxl.h b/tools/libxl/libxl.h index 17b8a7b..0fc6170 100644 --- a/tools/libxl/libxl.h +++ b/tools/libxl/libxl.h @@ -104,6 +104,11 @@ #define LIBXL_HAVE_BUILDINFO_EVENT_CHANNELS 1 /* + * libxl_domain_build_info has the u.hvm.ms_vm_genid field. + */ +#define LIBXL_HAVE_BUILDINFO_HVM_MS_VM_GENID 1 + +/* * LIBXL_HAVE_DEVICE_DISK_DIRECT_IO_SAFE indicates that a * 'direct_io_safe' field (of boolean type) is present in * libxl_device_disk. @@ -579,6 +584,11 @@ typedef struct libxl__ctx libxl_ctx; #define LIBXL_TIMER_MODE_DEFAULT -1 #define LIBXL_MEMKB_DEFAULT ~0ULL +#define LIBXL_MS_VM_GENID_LEN 16 +typedef struct { + uint8_t bytes[LIBXL_MS_VM_GENID_LEN]; +} libxl_ms_vm_genid; + #include "_libxl_types.h" const libxl_version_info* libxl_get_version_info(libxl_ctx *ctx); @@ -1189,6 +1199,9 @@ int libxl_flask_getenforce(libxl_ctx *ctx); int libxl_flask_setenforce(libxl_ctx *ctx, int mode); int libxl_flask_loadpolicy(libxl_ctx *ctx, void *policy, uint32_t size); +int libxl_ms_vm_genid_generate(libxl_ctx *ctx, libxl_ms_vm_genid *id); +bool libxl_ms_vm_genid_is_zero(const libxl_ms_vm_genid *id); + /* misc */ /* Each of these sets or clears the flag according to whether the diff --git a/tools/libxl/libxl_dom.c b/tools/libxl/libxl_dom.c index a63c31c..b94364f 100644 --- a/tools/libxl/libxl_dom.c +++ b/tools/libxl/libxl_dom.c @@ -314,6 +314,16 @@ int libxl__build_post(libxl__gc *gc, uint32_t domid, if (info->cpuid != NULL) libxl_cpuid_set(ctx, domid, info->cpuid); + if (info->type == LIBXL_DOMAIN_TYPE_HVM + && !libxl_ms_vm_genid_is_zero(&info->u.hvm.ms_vm_genid)) { + rc = libxl__ms_vm_genid_set(gc, domid, + &info->u.hvm.ms_vm_genid); + if (rc) { + LOG(ERROR, "Failed to set VM Generation ID"); + return rc; + } + } + ents = libxl__calloc(gc, 12 + (info->max_vcpus * 2) + 2, sizeof(char *)); ents[0] = "memory/static-max"; ents[1] = GCSPRINTF("%"PRId64, info->max_memkb); diff --git a/tools/libxl/libxl_genid.c b/tools/libxl/libxl_genid.c new file mode 100644 index 0000000..9853fa6 --- /dev/null +++ b/tools/libxl/libxl_genid.c @@ -0,0 +1,111 @@ +/* + * Copyright (C) 2014 Citrix Systems R&D Ltd. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as published + * by the Free Software Foundation; version 2.1 only. with the special + * exception on linking described in file LICENSE. + * + * This program 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. + */ + +#include "libxl_osdeps.h" /* must come before any other headers */ + +#include "libxl_internal.h" + +#include +#include + +/* + * Generate a random VM generation ID. + * + * Returns ERROR_FAIL if a suitable source of random numbers is not + * available. + * + * See Microsoft's "Virtual Machine Generation ID" specification for + * further details, including when a new generation ID is required. + * + * http://www.microsoft.com/en-us/download/details.aspx?id=30707 + */ +int libxl_ms_vm_genid_generate(libxl_ctx *ctx, libxl_ms_vm_genid *id) +{ + GC_INIT(ctx); + int ret; + + ret = libxl__random_bytes(gc, id->bytes, LIBXL_MS_VM_GENID_LEN); + + GC_FREE; + return ret; +} + +/* + * Is this VM generation ID all zeros? + */ +bool libxl_ms_vm_genid_is_zero(const libxl_ms_vm_genid *id) +{ + static const libxl_ms_vm_genid zero; + + return memcmp(id->bytes, zero.bytes, LIBXL_MS_VM_GENID_LEN) == 0; +} + +int libxl__ms_vm_genid_set(libxl__gc *gc, uint32_t domid, + const libxl_ms_vm_genid *id) +{ + libxl_ctx *ctx = libxl__gc_owner(gc); + const char *dom_path; + uint64_t genid[2]; + uint64_t paddr = 0; + int rc; + + memcpy(genid, id->bytes, LIBXL_MS_VM_GENID_LEN); + + /* + * Set the "platform/generation-id" XenStore key to pass the ID to + * hvmloader. + */ + dom_path = libxl__xs_get_dompath(gc, domid); + if (!dom_path) { + rc = ERROR_FAIL; + goto out; + } + rc = libxl__xs_write(gc, XBT_NULL, + GCSPRINTF("%s/platform/generation-id", dom_path), + "%"PRIu64 ":%" PRIu64, genid[0], genid[1]); + if (rc < 0) + goto out; + + /* + * Update the ID in guest memory (if available). + */ + xc_hvm_param_get(ctx->xch, domid, HVM_PARAM_VM_GENERATION_ID_ADDR, &paddr); + if (paddr) { + void *vaddr; + + vaddr = xc_map_foreign_range(ctx->xch, domid, XC_PAGE_SIZE, + PROT_READ | PROT_WRITE, + paddr >> XC_PAGE_SHIFT); + if (vaddr == NULL) { + rc = ERROR_FAIL; + goto out; + } + memcpy(vaddr + (paddr & ~XC_PAGE_MASK), genid, 2 * sizeof(*genid)); + munmap(vaddr, XC_PAGE_SIZE); + + /* + * The spec requires an ACPI Notify event is injected into the + * guest when the generation ID is changed. + * + * This is only called for domains that are suspended or newly + * created and they won't be in a state to receive such an + * event. + */ + } + + rc = 0; + + out: + return rc; +} diff --git a/tools/libxl/libxl_internal.h b/tools/libxl/libxl_internal.h index d4f32a9..2eea557 100644 --- a/tools/libxl/libxl_internal.h +++ b/tools/libxl/libxl_internal.h @@ -3086,6 +3086,10 @@ void libxl__numa_candidate_put_nodemap(libxl__gc *gc, libxl_bitmap_copy(CTX, &cndt->nodemap, nodemap); } +_hidden int libxl__ms_vm_genid_set(libxl__gc *gc, uint32_t domid, + const libxl_ms_vm_genid *id); + + /* Som handy macros for defbool type. */ #define LIBXL__DEFBOOL_DEFAULT (0) #define LIBXL__DEFBOOL_FALSE (-1) @@ -3163,6 +3167,8 @@ int libxl_key_value_list_parse_json(libxl__gc *gc, libxl_key_value_list *p); int libxl_hwcap_parse_json(libxl__gc *gc, const libxl__json_object *o, libxl_hwcap *p); +int libxl_ms_vm_genid_parse_json(libxl__gc *gc, const libxl__json_object *o, + libxl_ms_vm_genid *p); int libxl__int_parse_json(libxl__gc *gc, const libxl__json_object *o, void *p); int libxl__uint8_parse_json(libxl__gc *gc, const libxl__json_object *o, diff --git a/tools/libxl/libxl_json.c b/tools/libxl/libxl_json.c index fb9baf8..63125dc 100644 --- a/tools/libxl/libxl_json.c +++ b/tools/libxl/libxl_json.c @@ -377,6 +377,45 @@ int libxl_hwcap_parse_json(libxl__gc *gc, const libxl__json_object *o, return 0; } +yajl_gen_status libxl_ms_vm_genid_gen_json(yajl_gen hand, libxl_ms_vm_genid *p) +{ + yajl_gen_status s; + int i; + + s = yajl_gen_array_open(hand); + if (s != yajl_gen_status_ok) + return s; + + for (i = 0; i < LIBXL_MS_VM_GENID_LEN; i++) { + s = yajl_gen_integer(hand, p->bytes[i]); + if (s != yajl_gen_status_ok) + return s; + } + + return yajl_gen_array_close(hand); +} + +int libxl_ms_vm_genid_parse_json(libxl__gc *gc, const libxl__json_object *o, + libxl_ms_vm_genid *p) +{ + unsigned int i; + + if (!libxl__json_object_is_array(o)) + return ERROR_FAIL; + + for (i = 0; i < LIBXL_MS_VM_GENID_LEN; i++) { + const libxl__json_object *t; + + t = libxl__json_array_get(o, i); + if (!t || !libxl__json_object_is_integer(t)) + return ERROR_FAIL; + + p->bytes[i] = libxl__json_object_get_integer(t); + } + + return 0; +} + yajl_gen_status libxl__string_gen_json(yajl_gen hand, const char *p) { diff --git a/tools/libxl/libxl_json.h b/tools/libxl/libxl_json.h index e4c0f6c..af26e78 100644 --- a/tools/libxl/libxl_json.h +++ b/tools/libxl/libxl_json.h @@ -33,6 +33,7 @@ yajl_gen_status libxl_string_list_gen_json(yajl_gen hand, libxl_string_list *p); yajl_gen_status libxl_key_value_list_gen_json(yajl_gen hand, libxl_key_value_list *p); yajl_gen_status libxl_hwcap_gen_json(yajl_gen hand, libxl_hwcap *p); +yajl_gen_status libxl_ms_vm_genid_gen_json(yajl_gen hand, libxl_ms_vm_genid *p); #include <_libxl_types_json.h> diff --git a/tools/libxl/libxl_types.idl b/tools/libxl/libxl_types.idl index f0f6e34..630698d 100644 --- a/tools/libxl/libxl_types.idl +++ b/tools/libxl/libxl_types.idl @@ -17,6 +17,7 @@ libxl_cpuid_policy_list = Builtin("cpuid_policy_list", dispose_fn="libxl_cpuid_d libxl_string_list = Builtin("string_list", dispose_fn="libxl_string_list_dispose", passby=PASS_BY_REFERENCE) libxl_key_value_list = Builtin("key_value_list", dispose_fn="libxl_key_value_list_dispose", passby=PASS_BY_REFERENCE) libxl_hwcap = Builtin("hwcap", passby=PASS_BY_REFERENCE) +libxl_ms_vm_genid = Builtin("ms_vm_genid", passby=PASS_BY_REFERENCE) # # Specific integer types @@ -371,6 +372,8 @@ libxl_domain_build_info = Struct("domain_build_info",[ ("xen_platform_pci", libxl_defbool), ("usbdevice_list", libxl_string_list), ("vendor_device", libxl_vendor_device), + # See libxl_ms_vm_genid_generate() + ("ms_vm_genid", libxl_ms_vm_genid), ])), ("pv", Struct(None, [("kernel", string), ("slack_memkb", MemKB), -- 1.7.10.4