1 /*
2  * Copyright (C) 2014 Citrix Systems R&D Ltd.
3  *
4  * This program is free software; you can redistribute it and/or modify
5  * it under the terms of the GNU Lesser General Public License as published
6  * by the Free Software Foundation; version 2.1 only. with the special
7  * exception on linking described in file LICENSE.
8  *
9  * This program is distributed in the hope that it will be useful,
10  * but WITHOUT ANY WARRANTY; without even the implied warranty of
11  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
12  * GNU Lesser General Public License for more details.
13  */
14 
15 #include "libxl_osdeps.h" /* must come before any other headers */
16 
17 #include "libxl_internal.h"
18 
19 #include <xenctrl.h>
20 #include <xen/hvm/params.h>
21 
22 /*
23  * Generate a random VM generation ID.
24  *
25  * Returns ERROR_FAIL if a suitable source of random numbers is not
26  * available.
27  *
28  * See Microsoft's "Virtual Machine Generation ID" specification for
29  * further details, including when a new generation ID is required.
30  *
31  *   http://www.microsoft.com/en-us/download/details.aspx?id=30707
32  */
libxl_ms_vm_genid_generate(libxl_ctx * ctx,libxl_ms_vm_genid * id)33 int libxl_ms_vm_genid_generate(libxl_ctx *ctx, libxl_ms_vm_genid *id)
34 {
35     GC_INIT(ctx);
36     int ret;
37 
38     ret = libxl__random_bytes(gc, id->bytes, LIBXL_MS_VM_GENID_LEN);
39 
40     GC_FREE;
41     return ret;
42 }
43 
44 /*
45  * Is this VM generation ID all zeros?
46  */
libxl_ms_vm_genid_is_zero(const libxl_ms_vm_genid * id)47 bool libxl_ms_vm_genid_is_zero(const libxl_ms_vm_genid *id)
48 {
49     static const libxl_ms_vm_genid zero;
50 
51     return memcmp(id->bytes, zero.bytes, LIBXL_MS_VM_GENID_LEN) == 0;
52 }
53 
libxl_ms_vm_genid_copy(libxl_ctx * ctx,libxl_ms_vm_genid * dst,const libxl_ms_vm_genid * src)54 void libxl_ms_vm_genid_copy(libxl_ctx *ctx, libxl_ms_vm_genid *dst,
55                             const libxl_ms_vm_genid *src)
56 {
57     memcpy(dst, src, LIBXL_MS_VM_GENID_LEN);
58 }
59 
libxl__ms_vm_genid_set(libxl__gc * gc,uint32_t domid,const libxl_ms_vm_genid * id)60 int libxl__ms_vm_genid_set(libxl__gc *gc, uint32_t domid,
61                            const libxl_ms_vm_genid *id)
62 {
63     libxl_ctx *ctx = libxl__gc_owner(gc);
64     const char *dom_path;
65     uint64_t genid[2];
66     uint64_t paddr = 0;
67     int rc;
68 
69     memcpy(genid, id->bytes, LIBXL_MS_VM_GENID_LEN);
70 
71     /*
72      * Set the "platform/generation-id" XenStore key to pass the ID to
73      * hvmloader.
74      */
75     dom_path = libxl__xs_get_dompath(gc, domid);
76     if (!dom_path) {
77         rc = ERROR_FAIL;
78         goto out;
79     }
80     rc = libxl__xs_printf(gc, XBT_NULL,
81 			  GCSPRINTF("%s/platform/generation-id", dom_path),
82 			  "%"PRIu64 ":%" PRIu64, genid[0], genid[1]);
83     if (rc < 0)
84         goto out;
85 
86     /*
87      * Update the ID in guest memory (if available).
88      */
89     xc_hvm_param_get(ctx->xch, domid, HVM_PARAM_VM_GENERATION_ID_ADDR, &paddr);
90     if (paddr) {
91         void *vaddr;
92 
93         vaddr = xc_map_foreign_range(ctx->xch, domid, XC_PAGE_SIZE,
94                                      PROT_READ | PROT_WRITE,
95                                      paddr >> XC_PAGE_SHIFT);
96         if (vaddr == NULL) {
97             rc = ERROR_FAIL;
98             goto out;
99         }
100         memcpy(vaddr + (paddr & ~XC_PAGE_MASK), genid, 2 * sizeof(*genid));
101         munmap(vaddr, XC_PAGE_SIZE);
102 
103         /*
104          * The spec requires an ACPI Notify event is injected into the
105          * guest when the generation ID is changed.
106          *
107          * This is only called for domains that are suspended or newly
108          * created and they won't be in a state to receive such an
109          * event.
110          */
111     }
112 
113     rc = 0;
114 
115   out:
116     return rc;
117 }
118