1 #include <stdbool.h>
2 #include <syslog.h>
3 #include <stdio.h>
4 #include <err.h>
5 #include <stdlib.h>
6 #include <sys/mman.h>
7 #include <sys/time.h>
8 #include <inttypes.h>
9 #include <xenstore.h>
10 #include <xenctrl.h>
11 #include <xenguest.h>
12 #include <libxl.h>
13 #include <xenevtchn.h>
14 #include <xenforeignmemory.h>
15 #include <xen/io/xs_wire.h>
16
17 #include "init-dom-json.h"
18
19 #define XENSTORE_PFN_OFFSET 1
20 #define STR_MAX_LENGTH 128
21
alloc_xs_page(struct xc_interface_core * xch,libxl_dominfo * info,uint64_t * xenstore_pfn)22 static int alloc_xs_page(struct xc_interface_core *xch,
23 libxl_dominfo *info,
24 uint64_t *xenstore_pfn)
25 {
26 int rc;
27 const xen_pfn_t base = GUEST_MAGIC_BASE >> XC_PAGE_SHIFT;
28 xen_pfn_t p2m = (GUEST_MAGIC_BASE >> XC_PAGE_SHIFT) + XENSTORE_PFN_OFFSET;
29
30 rc = xc_domain_setmaxmem(xch, info->domid,
31 info->max_memkb + (XC_PAGE_SIZE/1024));
32 if (rc < 0)
33 return rc;
34
35 rc = xc_domain_populate_physmap_exact(xch, info->domid, 1, 0, 0, &p2m);
36 if (rc < 0)
37 return rc;
38
39 *xenstore_pfn = base + XENSTORE_PFN_OFFSET;
40 rc = xc_clear_domain_page(xch, info->domid, *xenstore_pfn);
41 if (rc < 0)
42 return rc;
43
44 return 0;
45 }
46
do_xs_write_dom(struct xs_handle * xsh,xs_transaction_t t,domid_t domid,char * path,char * val)47 static bool do_xs_write_dom(struct xs_handle *xsh, xs_transaction_t t,
48 domid_t domid, char *path, char *val)
49 {
50 char full_path[STR_MAX_LENGTH];
51 struct xs_permissions perms[2];
52 int rc;
53
54 perms[0].id = domid;
55 perms[0].perms = XS_PERM_NONE;
56 perms[1].id = 0;
57 perms[1].perms = XS_PERM_READ;
58
59 rc = snprintf(full_path, STR_MAX_LENGTH,
60 "/local/domain/%u/%s", domid, path);
61 if (rc < 0 || rc >= STR_MAX_LENGTH)
62 return false;
63 if (!xs_write(xsh, t, full_path, val, strlen(val)))
64 return false;
65 return xs_set_permissions(xsh, t, full_path, perms, 2);
66 }
67
do_xs_write_libxl(struct xs_handle * xsh,xs_transaction_t t,domid_t domid,char * path,char * val)68 static bool do_xs_write_libxl(struct xs_handle *xsh, xs_transaction_t t,
69 domid_t domid, char *path, char *val)
70 {
71 char full_path[STR_MAX_LENGTH];
72 int rc;
73
74 rc = snprintf(full_path, STR_MAX_LENGTH,
75 "/libxl/%u/%s", domid, path);
76 if (rc < 0 || rc >= STR_MAX_LENGTH)
77 return false;
78 return xs_write(xsh, t, full_path, val, strlen(val));
79 }
80
do_xs_write_vm(struct xs_handle * xsh,xs_transaction_t t,libxl_uuid uuid,char * path,char * val)81 static bool do_xs_write_vm(struct xs_handle *xsh, xs_transaction_t t,
82 libxl_uuid uuid, char *path, char *val)
83 {
84 char full_path[STR_MAX_LENGTH];
85 int rc;
86
87 rc = snprintf(full_path, STR_MAX_LENGTH,
88 "/vm/" LIBXL_UUID_FMT "/%s", LIBXL_UUID_BYTES(uuid), path);
89 if (rc < 0 || rc >= STR_MAX_LENGTH)
90 return false;
91 return xs_write(xsh, t, full_path, val, strlen(val));
92 }
93
94 /*
95 * The xenstore nodes are the xenstore nodes libxl writes at domain
96 * creation.
97 *
98 * The list was retrieved by running xenstore-ls on a corresponding
99 * domain started by xl/libxl.
100 */
create_xenstore(struct xs_handle * xsh,libxl_dominfo * info,libxl_uuid uuid,evtchn_port_t xenstore_port)101 static int create_xenstore(struct xs_handle *xsh,
102 libxl_dominfo *info, libxl_uuid uuid,
103 evtchn_port_t xenstore_port)
104 {
105 domid_t domid;
106 unsigned int i;
107 char uuid_str[STR_MAX_LENGTH];
108 char dom_name_str[STR_MAX_LENGTH];
109 char vm_val_str[STR_MAX_LENGTH];
110 char id_str[STR_MAX_LENGTH];
111 char max_memkb_str[STR_MAX_LENGTH];
112 char target_memkb_str[STR_MAX_LENGTH];
113 char cpu_str[STR_MAX_LENGTH];
114 char xenstore_port_str[STR_MAX_LENGTH];
115 char ring_ref_str[STR_MAX_LENGTH];
116 xs_transaction_t t;
117 struct timeval start_time;
118 char start_time_str[STR_MAX_LENGTH];
119 int rc;
120
121 if (gettimeofday(&start_time, NULL) < 0)
122 return -errno;
123 rc = snprintf(start_time_str, STR_MAX_LENGTH, "%jd.%02d",
124 (intmax_t)start_time.tv_sec, (int)start_time.tv_usec / 10000);
125 if (rc < 0 || rc >= STR_MAX_LENGTH)
126 return rc;
127
128 domid = info->domid;
129 rc = snprintf(id_str, STR_MAX_LENGTH, "%u", domid);
130 if (rc < 0 || rc >= STR_MAX_LENGTH)
131 return rc;
132 rc = snprintf(dom_name_str, STR_MAX_LENGTH, "dom0less-%u", domid);
133 if (rc < 0 || rc >= STR_MAX_LENGTH)
134 return rc;
135 rc = snprintf(uuid_str, STR_MAX_LENGTH, LIBXL_UUID_FMT, LIBXL_UUID_BYTES(uuid));
136 if (rc < 0 || rc >= STR_MAX_LENGTH)
137 return rc;
138 rc = snprintf(vm_val_str, STR_MAX_LENGTH,
139 "vm/" LIBXL_UUID_FMT, LIBXL_UUID_BYTES(uuid));
140 if (rc < 0 || rc >= STR_MAX_LENGTH)
141 return rc;
142 rc = snprintf(max_memkb_str, STR_MAX_LENGTH, "%"PRIu64, info->max_memkb);
143 if (rc < 0 || rc >= STR_MAX_LENGTH)
144 return rc;
145 rc = snprintf(target_memkb_str, STR_MAX_LENGTH, "%"PRIu64, info->current_memkb);
146 if (rc < 0 || rc >= STR_MAX_LENGTH)
147 return rc;
148 rc = snprintf(ring_ref_str, STR_MAX_LENGTH, "%lld",
149 (GUEST_MAGIC_BASE >> XC_PAGE_SHIFT) + XENSTORE_PFN_OFFSET);
150 if (rc < 0 || rc >= STR_MAX_LENGTH)
151 return rc;
152 rc = snprintf(xenstore_port_str, STR_MAX_LENGTH, "%u", xenstore_port);
153 if (rc < 0 || rc >= STR_MAX_LENGTH)
154 return rc;
155
156 retry_transaction:
157 t = xs_transaction_start(xsh);
158 if (t == XBT_NULL)
159 return -errno;
160
161 rc = -EIO;
162 /* /vm */
163 if (!do_xs_write_vm(xsh, t, uuid, "name", dom_name_str)) goto err;
164 if (!do_xs_write_vm(xsh, t, uuid, "uuid", uuid_str)) goto err;
165 if (!do_xs_write_vm(xsh, t, uuid, "start_time", start_time_str)) goto err;
166
167 /* /domain */
168 if (!do_xs_write_dom(xsh, t, domid, "vm", vm_val_str)) goto err;
169 if (!do_xs_write_dom(xsh, t, domid, "name", dom_name_str)) goto err;
170 if (!do_xs_write_dom(xsh, t, domid, "cpu", "")) goto err;
171 for (i = 0; i < info->vcpu_max_id; i++) {
172 rc = snprintf(cpu_str, STR_MAX_LENGTH, "cpu/%u/availability/", i);
173 if (rc < 0 || rc >= STR_MAX_LENGTH)
174 goto err;
175 rc = -EIO;
176 if (!do_xs_write_dom(xsh, t, domid, cpu_str,
177 (info->cpupool & (1 << i)) ? "online" : "offline"))
178 goto err;
179 }
180
181 if (!do_xs_write_dom(xsh, t, domid, "memory", "")) goto err;
182 if (!do_xs_write_dom(xsh, t, domid, "memory/static-max", max_memkb_str)) goto err;
183 if (!do_xs_write_dom(xsh, t, domid, "memory/target", target_memkb_str)) goto err;
184 if (!do_xs_write_dom(xsh, t, domid, "memory/videoram", "-1")) goto err;
185
186 if (!do_xs_write_dom(xsh, t, domid, "device", "")) goto err;
187 if (!do_xs_write_dom(xsh, t, domid, "device/suspend", "")) goto err;
188 if (!do_xs_write_dom(xsh, t, domid, "device/suspend/event-channel", "")) goto err;
189
190 if (!do_xs_write_dom(xsh, t, domid, "control", "")) goto err;
191 if (!do_xs_write_dom(xsh, t, domid, "control/shutdown", "")) goto err;
192 if (!do_xs_write_dom(xsh, t, domid, "control/feature-poweroff", "1")) goto err;
193 if (!do_xs_write_dom(xsh, t, domid, "control/feature-reboot", "1")) goto err;
194 if (!do_xs_write_dom(xsh, t, domid, "control/feature-suspend", "")) goto err;
195 if (!do_xs_write_dom(xsh, t, domid, "control/sysrq", "")) goto err;
196 if (!do_xs_write_dom(xsh, t, domid, "control/platform-feature-multiprocessor-suspend", "1")) goto err;
197 if (!do_xs_write_dom(xsh, t, domid, "control/platform-feature-xs_reset_watches", "1")) goto err;
198
199 if (!do_xs_write_dom(xsh, t, domid, "domid", id_str)) goto err;
200 if (!do_xs_write_dom(xsh, t, domid, "data", "")) goto err;
201 if (!do_xs_write_dom(xsh, t, domid, "drivers", "")) goto err;
202 if (!do_xs_write_dom(xsh, t, domid, "feature", "")) goto err;
203 if (!do_xs_write_dom(xsh, t, domid, "attr", "")) goto err;
204
205 if (!do_xs_write_dom(xsh, t, domid, "store/port", xenstore_port_str)) goto err;
206 if (!do_xs_write_dom(xsh, t, domid, "store/ring-ref", ring_ref_str)) goto err;
207
208 if (!do_xs_write_libxl(xsh, t, domid, "type", "pvh")) goto err;
209 if (!do_xs_write_libxl(xsh, t, domid, "dm-version", "qemu_xen")) goto err;
210
211 if (!xs_transaction_end(xsh, t, false)) {
212 if (errno == EAGAIN)
213 goto retry_transaction;
214 else
215 return -errno;
216 }
217
218 return 0;
219
220 err:
221 xs_transaction_end(xsh, t, true);
222 return rc;
223 }
224
init_domain(struct xs_handle * xsh,struct xc_interface_core * xch,xenforeignmemory_handle * xfh,libxl_dominfo * info)225 static int init_domain(struct xs_handle *xsh,
226 struct xc_interface_core *xch,
227 xenforeignmemory_handle *xfh,
228 libxl_dominfo *info)
229 {
230 libxl_uuid uuid;
231 uint64_t xenstore_evtchn, xenstore_pfn;
232 int rc;
233 struct xenstore_domain_interface *intf;
234
235 printf("Init dom0less domain: %u\n", info->domid);
236
237 rc = xc_hvm_param_get(xch, info->domid, HVM_PARAM_STORE_EVTCHN,
238 &xenstore_evtchn);
239 if (rc != 0) {
240 printf("Failed to get HVM_PARAM_STORE_EVTCHN\n");
241 return 1;
242 }
243
244 /* no xen,enhanced; nothing to do */
245 if (!xenstore_evtchn)
246 return 0;
247
248 /* Alloc xenstore page */
249 if (alloc_xs_page(xch, info, &xenstore_pfn) != 0) {
250 printf("Error on alloc magic pages\n");
251 return 1;
252 }
253
254 intf = xenforeignmemory_map(xfh, info->domid, PROT_READ | PROT_WRITE, 1,
255 &xenstore_pfn, NULL);
256 if (!intf) {
257 printf("Error mapping xenstore page\n");
258 return 1;
259 }
260 intf->connection = XENSTORE_RECONNECT;
261 xenforeignmemory_unmap(xfh, intf, 1);
262
263 rc = xc_dom_gnttab_seed(xch, info->domid, true,
264 (xen_pfn_t)-1, xenstore_pfn, 0, 0);
265 if (rc)
266 err(1, "xc_dom_gnttab_seed");
267
268 libxl_uuid_generate(&uuid);
269 xc_domain_sethandle(xch, info->domid, libxl_uuid_bytearray(&uuid));
270
271 rc = gen_stub_json_config(info->domid, &uuid);
272 if (rc)
273 err(1, "gen_stub_json_config");
274
275 /* Now everything is ready: set HVM_PARAM_STORE_PFN */
276 rc = xc_hvm_param_set(xch, info->domid, HVM_PARAM_STORE_PFN,
277 xenstore_pfn);
278 if (rc < 0)
279 return rc;
280
281 rc = create_xenstore(xsh, info, uuid, xenstore_evtchn);
282 if (rc)
283 err(1, "writing to xenstore");
284
285 rc = xs_introduce_domain(xsh, info->domid,
286 (GUEST_MAGIC_BASE >> XC_PAGE_SHIFT) + XENSTORE_PFN_OFFSET,
287 xenstore_evtchn);
288 if (!rc)
289 err(1, "xs_introduce_domain");
290 return 0;
291 }
292
293 /* Check if domain has been configured in XS */
domain_exists(struct xs_handle * xsh,int domid)294 static bool domain_exists(struct xs_handle *xsh, int domid)
295 {
296 return xs_is_domain_introduced(xsh, domid);
297 }
298
main(int argc,char ** argv)299 int main(int argc, char **argv)
300 {
301 libxl_dominfo *info = NULL;
302 libxl_ctx *ctx;
303 int nb_vm = 0, rc = 0, i;
304 struct xs_handle *xsh = NULL;
305 struct xc_interface_core *xch = NULL;
306 xenforeignmemory_handle *xfh = NULL;
307
308 /* TODO reuse libxl xsh connection */
309 xsh = xs_open(0);
310 xch = xc_interface_open(0, 0, 0);
311 xfh = xenforeignmemory_open(0, 0);
312 if (xsh == NULL || xch == NULL || xfh == NULL) {
313 fprintf(stderr, "Cannot open xc/xs/xenforeignmemory interfaces");
314 rc = -errno;
315 goto out;
316 }
317
318 rc = libxl_ctx_alloc(&ctx, LIBXL_VERSION, 0, NULL);
319 if (rc) {
320 fprintf(stderr, "cannot init xl context\n");
321 goto out;
322 }
323
324 info = libxl_list_domain(ctx, &nb_vm);
325 if (!info) {
326 fprintf(stderr, "libxl_list_vm failed.\n");
327 rc = -1;
328 goto out;
329 }
330
331 for (i = 0; i < nb_vm; i++) {
332 domid_t domid = info[i].domid;
333
334 /* Don't need to check for Dom0 */
335 if (!domid)
336 continue;
337
338 printf("Checking domid: %u\n", domid);
339 if (!domain_exists(xsh, domid)) {
340 rc = init_domain(xsh, xch, xfh, &info[i]);
341 if (rc < 0) {
342 fprintf(stderr, "init_domain failed.\n");
343 goto out;
344 }
345 } else {
346 printf("Domain %u has already been initialized\n", domid);
347 }
348 }
349 out:
350 libxl_dominfo_list_free(info, nb_vm);
351 return rc;
352 }
353