xref: /openbsd-src/usr.sbin/ldomctl/config.c (revision f2da64fbbbf1b03f09f390ab01267c93dfd77c4c)
1 /*	$OpenBSD: config.c,v 1.21 2014/09/28 18:42:50 kettenis Exp $	*/
2 
3 /*
4  * Copyright (c) 2012 Mark Kettenis
5  *
6  * Permission to use, copy, modify, and distribute this software for any
7  * purpose with or without fee is hereby granted, provided that the above
8  * copyright notice and this permission notice appear in all copies.
9  *
10  * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
11  * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
12  * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
13  * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
14  * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
15  * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
16  * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
17  */
18 
19 #include <sys/types.h>
20 #include <sys/queue.h>
21 #include <assert.h>
22 #include <err.h>
23 #include <stdarg.h>
24 #include <stdbool.h>
25 #include <stdio.h>
26 #include <stdlib.h>
27 #include <string.h>
28 
29 #include "mdesc.h"
30 #include "ldomctl.h"
31 #include "util.h"
32 
33 #define LDC_GUEST	0
34 #define LDC_HV		1
35 #define LDC_SP		2
36 
37 #define LDC_HVCTL_SVC	1
38 #define LDC_CONSOLE_SVC	2
39 
40 #define MAX_STRANDS_PER_CORE	16
41 
42 struct core {
43 	struct guest *guests[MAX_STRANDS_PER_CORE];
44 	TAILQ_ENTRY(core) link;
45 };
46 
47 TAILQ_HEAD(, core) cores;
48 
49 struct frag {
50 	TAILQ_ENTRY(frag) link;
51 	uint64_t base;
52 };
53 
54 struct guest **guests;
55 struct console **consoles;
56 struct cpu **cpus;
57 struct device **pcie_busses;
58 struct device **network_devices;
59 struct mblock **mblocks;
60 struct ldc_endpoint **ldc_endpoints;
61 
62 uint64_t max_cpus;
63 bool have_cwqs;
64 bool have_rngs;
65 
66 uint64_t max_guests;
67 uint64_t max_hv_ldcs;
68 uint64_t max_guest_ldcs;
69 uint64_t md_maxsize;
70 uint64_t md_elbow_room;
71 uint64_t max_mblocks;
72 
73 uint64_t max_devices = 16;
74 
75 uint64_t rombase;
76 uint64_t romsize;
77 
78 uint64_t max_page_size;
79 
80 uint64_t content_version;
81 uint64_t stick_frequency;
82 uint64_t tod_frequency;
83 uint64_t tod;
84 uint64_t erpt_pa;
85 uint64_t erpt_size;
86 
87 struct md *pri;
88 struct md *hvmd;
89 struct md *protomd;
90 
91 struct guest *guest_lookup(const char *);
92 
93 TAILQ_HEAD(, frag) free_frags = TAILQ_HEAD_INITIALIZER(free_frags);
94 TAILQ_HEAD(, cpu) free_cpus = TAILQ_HEAD_INITIALIZER(free_cpus);
95 int total_cpus;
96 TAILQ_HEAD(, mblock) free_memory = TAILQ_HEAD_INITIALIZER(free_memory);
97 uint64_t total_memory;
98 
99 struct cpu *
100 pri_find_cpu(uint64_t pid)
101 {
102 	struct cpu *cpu = NULL;
103 
104 	TAILQ_FOREACH(cpu, &free_cpus, link) {
105 		if (cpu->pid == pid)
106 			break;
107 	}
108 
109 	return cpu;
110 }
111 
112 void
113 pri_link_core(struct md *md, struct md_node *node, struct core *core)
114 {
115 	struct md_node *node2;
116 	struct md_prop *prop;
117 	struct cpu *cpu;
118 	uint64_t pid;
119 
120 	TAILQ_FOREACH(prop, &node->prop_list, link) {
121 		if (prop->tag == MD_PROP_ARC &&
122 		    strcmp(prop->name->str, "back") == 0) {
123 			node2 = prop->d.arc.node;
124 			if (strcmp(node2->name->str, "cpu") != 0) {
125 				pri_link_core(md, node2, core);
126 				continue;
127 			}
128 
129 			pid = -1;
130 			if (!md_get_prop_val(md, node2, "pid", &pid))
131 				md_get_prop_val(md, node2, "id", &pid);
132 
133 			cpu = pri_find_cpu(pid);
134 			if (cpu == NULL)
135 				errx(1, "couldn't determine core for VCPU %lld\n", pid);
136 			cpu->core = core;
137 		}
138 	}
139 }
140 
141 void
142 pri_add_core(struct md *md, struct md_node *node)
143 {
144 	struct core *core;
145 
146 	core = xzalloc(sizeof(*core));
147 	TAILQ_INSERT_TAIL(&cores, core, link);
148 
149 	pri_link_core(md, node, core);
150 }
151 
152 void
153 pri_init_cores(struct md *md)
154 {
155 	struct md_node *node;
156 	const void *type;
157 	size_t len;
158 
159 	TAILQ_INIT(&cores);
160 
161 	TAILQ_FOREACH(node, &md->node_list, link) {
162 		if (strcmp(node->name->str, "tlb") == 0 &&
163 		    md_get_prop_data(md, node, "type", &type, &len) &&
164 		    strcmp(type, "data") == 0) {
165 			pri_add_core(md, node);
166 		}
167 	}
168 }
169 
170 void
171 pri_add_cpu(struct md *md, struct md_node *node)
172 {
173 	struct cpu *cpu;
174 	uint64_t mmu_page_size_list;
175 	uint64_t page_size;
176 
177 	cpu = xzalloc(sizeof(*cpu));
178 	/*
179 	 * Only UltraSPARC T1 CPUs have a "pid" property.  All other
180 	 * just have a "id" property that can be used as the physical ID.
181 	 */
182 	if (!md_get_prop_val(md, node, "pid", &cpu->pid))
183 		md_get_prop_val(md, node, "id", &cpu->pid);
184 	cpu->vid = -1;
185 	cpu->gid = -1;
186 	cpu->partid = -1;
187 	cpu->resource_id = -1;
188 	TAILQ_INSERT_TAIL(&free_cpus, cpu, link);
189 	total_cpus++;
190 
191 	mmu_page_size_list = 0x9;
192 	md_get_prop_val(md, node, "mmu-page-size-list", &mmu_page_size_list);
193 
194 	page_size = 1024;
195 	while (mmu_page_size_list) {
196 		page_size *= 8;
197 		mmu_page_size_list >>= 1;
198 	}
199 
200 	if (page_size > max_page_size)
201 		max_page_size = page_size;
202 }
203 
204 struct cpu *
205 pri_alloc_cpu(uint64_t pid)
206 {
207 	struct cpu *cpu;
208 
209 	if (pid == -1 && !TAILQ_EMPTY(&free_cpus)) {
210 		cpu = TAILQ_FIRST(&free_cpus);
211 		TAILQ_REMOVE(&free_cpus, cpu, link);
212 		return cpu;
213 	}
214 
215 	TAILQ_FOREACH(cpu, &free_cpus, link) {
216 		if (cpu->pid == pid) {
217 			TAILQ_REMOVE(&free_cpus, cpu, link);
218 			return cpu;
219 		}
220 	}
221 
222 	return NULL;
223 }
224 
225 void
226 pri_free_cpu(struct cpu *cpu)
227 {
228 	TAILQ_INSERT_TAIL(&free_cpus, cpu, link);
229 }
230 
231 void
232 pri_add_mblock(struct md *md, struct md_node *node)
233 {
234 	struct mblock *mblock;
235 
236 	mblock = xzalloc(sizeof(*mblock));
237 	md_get_prop_val(md, node, "base", &mblock->membase);
238 	md_get_prop_val(md, node, "size", &mblock->memsize);
239 	mblock->resource_id = -1;
240 	TAILQ_INSERT_TAIL(&free_memory, mblock, link);
241 	total_memory += mblock->memsize;
242 }
243 
244 struct mblock *
245 pri_alloc_memory(uint64_t base, uint64_t size)
246 {
247 	struct mblock *mblock, *new_mblock;
248 	uint64_t memend;
249 
250 	if (base == -1 && !TAILQ_EMPTY(&free_memory)) {
251 		mblock = TAILQ_FIRST(&free_memory);
252 		base = mblock->membase;
253 	}
254 
255 	TAILQ_FOREACH(mblock, &free_memory, link) {
256 		if (base >= mblock->membase &&
257 		    base < mblock->membase + mblock->memsize) {
258 			if (base > mblock->membase) {
259 				new_mblock = xzalloc(sizeof(*new_mblock));
260 				new_mblock->membase = mblock->membase;
261 				new_mblock->memsize = base - mblock->membase;
262 				new_mblock->resource_id = -1;
263 				TAILQ_INSERT_BEFORE(mblock, new_mblock, link);
264 			}
265 
266 			memend = mblock->membase + mblock->memsize;
267 			mblock->membase = base + size;
268 			mblock->memsize = memend - mblock->membase;
269 			if (mblock->memsize == 0) {
270 				TAILQ_REMOVE(&free_memory, mblock, link);
271 				free(mblock);
272 			}
273 
274 			total_memory -= size;
275 
276 			new_mblock = xzalloc(sizeof(*new_mblock));
277 			new_mblock->membase = base;
278 			new_mblock->memsize = size;
279 			new_mblock->resource_id = -1;
280 			return new_mblock;;
281 		}
282 	}
283 
284 	return NULL;
285 }
286 
287 void
288 pri_init(struct md *md)
289 {
290 	struct md_node *node, *node2;
291 	struct md_prop *prop;
292 	uint64_t base, size;
293 	uint64_t offset, guest_use;
294 
295 	node = md_find_node(pri, "platform");
296 	if (node == NULL)
297 		errx(1, "platform node not found");
298 
299 	md_get_prop_val(md, node, "max-cpus", &max_cpus);
300 
301 	node = md_find_node(pri, "firmware");
302 	if (node == NULL)
303 		errx(1, "firmware node not found");
304 
305 	md_get_prop_val(md, node, "max_guests", &max_guests);
306 	md_get_prop_val(md, node, "max_hv_ldcs", &max_hv_ldcs);
307 	md_get_prop_val(md, node, "max_guest_ldcs", &max_guest_ldcs);
308 	md_get_prop_val(md, node, "md_elbow_room", &md_elbow_room);
309 	md_get_prop_val(md, node, "max_mblocks", &max_mblocks);
310 
311 	node = md_find_node(md, "read_only_memory");
312 	if (node == NULL)
313 		errx(1, "read_only_memory node not found");
314 	if (!md_get_prop_val(md, node, "base", &base))
315 		errx(1, "missing base property in read_only_memory node");
316 	if (!md_get_prop_val(md, node, "size", &size))
317 		errx(1, "missing size property in read_only_memory node");
318 	TAILQ_FOREACH(prop, &node->prop_list, link) {
319 		if (prop->tag == MD_PROP_ARC &&
320 		    strcmp(prop->name->str, "fwd") == 0) {
321 			node2 = prop->d.arc.node;
322 			if (!md_get_prop_val(md, node2, "guest_use",
323 			    &guest_use) || guest_use == 0)
324 				continue;
325 			if (!md_get_prop_val(md, node2, "offset", &offset) ||
326 			    !md_get_prop_val(md, node2, "size", &size))
327 					continue;
328 			rombase = base + offset;
329 			romsize = size;
330 		}
331 	}
332 	if (romsize == 0)
333 		errx(1, "no suitable firmware image found");
334 
335 	node = md_find_node(md, "platform");
336 	assert(node);
337 	md_set_prop_val(md, node, "domaining-enabled", 0x1);
338 
339 	md_write(md, "pri");
340 
341 	protomd = md_copy(md);
342 	md_find_delete_node(protomd, "components");
343 	md_find_delete_node(protomd, "devalias");
344 	md_find_delete_node(protomd, "domain-services");
345 	md_find_delete_node(protomd, "channel-devices");
346 	md_find_delete_node(protomd, "channel-endpoints");
347 	md_find_delete_node(protomd, "firmware");
348 	md_find_delete_node(protomd, "ldc_endpoints");
349 	md_find_delete_node(protomd, "memory-segments");
350 	md_collect_garbage(protomd);
351 	md_write(protomd, "protomd");
352 
353 	guests = xzalloc(max_guests * sizeof(*guests));
354 	consoles = xzalloc(max_guests * sizeof(*consoles));
355 	cpus = xzalloc(max_cpus * sizeof(*cpus));
356 	pcie_busses = xzalloc(max_devices * sizeof(*pcie_busses));
357 	network_devices = xzalloc(max_devices * sizeof(*network_devices));
358 	mblocks = xzalloc(max_mblocks * sizeof(*mblocks));
359 	ldc_endpoints = xzalloc(max_guest_ldcs * sizeof(*ldc_endpoints));
360 
361 	node = md_find_node(md, "cpus");
362 	TAILQ_FOREACH(prop, &node->prop_list, link) {
363 		if (prop->tag == MD_PROP_ARC &&
364 		    strcmp(prop->name->str, "fwd") == 0)
365 			pri_add_cpu(md, prop->d.arc.node);
366 	}
367 
368 	node = md_find_node(md, "memory");
369 	TAILQ_FOREACH(prop, &node->prop_list, link) {
370 		if (prop->tag == MD_PROP_ARC &&
371 		    strcmp(prop->name->str, "fwd") == 0)
372 			pri_add_mblock(md, prop->d.arc.node);
373 	}
374 
375 	pri_init_cores(md);
376 }
377 
378 void
379 hvmd_fixup_guest(struct md *md, struct md_node *guest, struct md_node *node)
380 {
381 	struct md_prop *prop;
382 
383 	TAILQ_FOREACH(prop, &guest->prop_list, link) {
384 		if (prop->tag == MD_PROP_ARC &&
385 		    strcmp(prop->name->str, "fwd") == 0) {
386 			if (prop->d.arc.node == node)
387 				return;
388 		}
389 	}
390 
391 	md_add_prop_arc(md, guest, "fwd", node);
392 }
393 
394 uint64_t fragsize;
395 TAILQ_HEAD(, mblock) frag_mblocks;
396 struct mblock *hvmd_mblock;
397 
398 void
399 hvmd_init_frag(struct md *md, struct md_node *node)
400 {
401 	struct frag *frag;
402 	struct mblock *mblock;
403 	uint64_t base, size;
404 
405 	md_get_prop_val(md, node, "base", &base);
406 	md_get_prop_val(md, node, "size", &size);
407 
408 	pri_alloc_memory(base, size);
409 
410 	mblock = xzalloc(sizeof(*mblock));
411 	mblock->membase = base;
412 	mblock->memsize = size;
413 	TAILQ_INSERT_TAIL(&frag_mblocks, mblock, link);
414 
415 	while (size > fragsize) {
416 		frag = xmalloc(sizeof(*frag));
417 		frag->base = base;
418 		TAILQ_INSERT_TAIL(&free_frags, frag, link);
419 		base += fragsize;
420 		size -= fragsize;
421 	}
422 }
423 
424 uint64_t
425 hvmd_alloc_frag(uint64_t base)
426 {
427 	struct frag *frag = TAILQ_FIRST(&free_frags);
428 
429 	if (base != -1) {
430 		TAILQ_FOREACH(frag, &free_frags, link) {
431 			if (frag->base == base)
432 				break;
433 		}
434 	}
435 
436 	if (frag == NULL)
437 		return -1;
438 
439 	TAILQ_REMOVE(&free_frags, frag, link);
440 	base = frag->base;
441 	free(frag);
442 
443 	return base;
444 }
445 
446 void
447 hvmd_free_frag(uint64_t base)
448 {
449 	struct frag *frag;
450 
451 	frag = xmalloc(sizeof(*frag));
452 	frag->base = base;
453 	TAILQ_INSERT_TAIL(&free_frags, frag, link);
454 }
455 
456 void
457 hvmd_init_mblock(struct md *md, struct md_node *node)
458 {
459 	struct mblock *mblock;
460 	uint64_t resource_id;
461 	struct md_node *node2;
462 	struct md_prop *prop;
463 
464 	if (!md_get_prop_val(md, node, "resource_id", &resource_id))
465 		errx(1, "missing resource_id property in mblock node");
466 
467 	if (resource_id >= max_mblocks)
468 		errx(1, "resource_id larger than max_mblocks");
469 
470 	mblock = xzalloc(sizeof(*mblock));
471 	md_get_prop_val(md, node, "membase", &mblock->membase);
472 	md_get_prop_val(md, node, "memsize", &mblock->memsize);
473 	md_get_prop_val(md, node, "realbase", &mblock->realbase);
474 	mblock->resource_id = resource_id;
475 	mblocks[resource_id] = mblock;
476 	mblock->hv_node = node;
477 
478 	/* Fixup missing links. */
479 	TAILQ_FOREACH(prop, &node->prop_list, link) {
480 		if (prop->tag == MD_PROP_ARC &&
481 		    strcmp(prop->name->str, "back") == 0) {
482 			node2 = prop->d.arc.node;
483 			if (strcmp(node2->name->str, "guest") == 0)
484 				hvmd_fixup_guest(md, node2, node);
485 		}
486 	}
487 }
488 
489 void
490 hvmd_init_console(struct md *md, struct md_node *node)
491 {
492 	struct console *console;
493 	uint64_t resource_id;
494 
495 	if (!md_get_prop_val(md, node, "resource_id", &resource_id))
496 		errx(1, "missing resource_id property in console node");
497 
498 	if (resource_id >= max_guests)
499 		errx(1, "resource_id larger than max_guests");
500 
501 	console = xmalloc(sizeof(*console));
502 	md_get_prop_val(md, node, "ino", &console->ino);
503 	console->resource_id = resource_id;
504 	consoles[resource_id] = console;
505 	console->hv_node = node;
506 }
507 
508 void
509 hvmd_init_cpu(struct md *md, struct md_node *node)
510 {
511 	struct cpu *cpu;
512 	uint64_t pid;
513 	uint64_t resource_id;
514 	struct md_node *node2;
515 	struct md_prop *prop;
516 
517 	if (!md_get_prop_val(md, node, "resource_id", &resource_id))
518 		errx(1, "missing resource_id property in cpu node");
519 
520 	if (resource_id >= max_cpus)
521 		errx(1, "resource_id larger than max-cpus");
522 
523 	if (!md_get_prop_val(md, node, "pid", &pid))
524 		errx(1, "missing pid property in cpu node");
525 
526 	cpu = pri_alloc_cpu(pid);
527 	md_get_prop_val(md, node, "vid", &cpu->vid);
528 	if (!md_get_prop_val(md, node, "gid", &cpu->gid))
529 		cpu->gid = 0;
530 	md_get_prop_val(md, node, "partid", &cpu->partid);
531 	cpu->resource_id = resource_id;
532 	cpus[resource_id] = cpu;
533 	cpu->hv_node = node;
534 
535 	/* Fixup missing links. */
536 	TAILQ_FOREACH(prop, &node->prop_list, link) {
537 		if (prop->tag == MD_PROP_ARC &&
538 		    strcmp(prop->name->str, "back") == 0) {
539 			node2 = prop->d.arc.node;
540 			if (strcmp(node2->name->str, "guest") == 0)
541 				hvmd_fixup_guest(md, node2, node);
542 		}
543 	}
544 }
545 
546 void
547 hvmd_init_device(struct md *md, struct md_node *node)
548 {
549 	struct device *device;
550 	uint64_t resource_id;
551 	struct md_node *node2;
552 	struct md_prop *prop;
553 
554 	if (strcmp(node->name->str, "pcie_bus") != 0 &&
555 	    strcmp(node->name->str, "network_device") != 0)
556 		return;
557 
558 	if (!md_get_prop_val(md, node, "resource_id", &resource_id))
559 		errx(1, "missing resource_id property in ldc_endpoint node");
560 
561 	if (resource_id >= max_devices)
562 		errx(1, "resource_id larger than max_devices");
563 
564 	device = xzalloc(sizeof(*device));
565 	md_get_prop_val(md, node, "gid", &device->gid);
566 	md_get_prop_val(md, node, "cfghandle", &device->cfghandle);
567 	device->resource_id = resource_id;
568 	if (strcmp(node->name->str, "pcie_bus") == 0)
569 		pcie_busses[resource_id] = device;
570 	else
571 		network_devices[resource_id] = device;
572 	device->hv_node = node;
573 
574 	/* Fixup missing links. */
575 	TAILQ_FOREACH(prop, &node->prop_list, link) {
576 		if (prop->tag == MD_PROP_ARC &&
577 		    strcmp(prop->name->str, "back") == 0) {
578 			node2 = prop->d.arc.node;
579 			if (strcmp(node2->name->str, "guest") == 0)
580 				hvmd_fixup_guest(md, node2, node);
581 		}
582 	}
583 }
584 
585 void
586 hvmd_init_endpoint(struct md *md, struct md_node *node)
587 {
588 	struct ldc_endpoint *endpoint;
589 	uint64_t resource_id;
590 
591 	if (!md_get_prop_val(md, node, "resource_id", &resource_id))
592 		errx(1, "missing resource_id property in ldc_endpoint node");
593 
594 	if (resource_id >= max_guest_ldcs)
595 		errx(1, "resource_id larger than max_guest_ldcs");
596 
597 	if (ldc_endpoints[resource_id]) {
598 		/*
599 		 * Some machine descriptions seem to have duplicate
600 		 * arcs.  Fortunately, these can be easily detected
601 		 * and ignored.
602 		 */
603 		if (ldc_endpoints[resource_id]->hv_node == node)
604 			return;
605 		errx(1, "duplicate resource_id");
606 	}
607 
608 	endpoint = xzalloc(sizeof(*endpoint));
609 	endpoint->target_guest = -1;
610 	endpoint->tx_ino = -1;
611 	endpoint->rx_ino = -1;
612 	endpoint->private_svc = -1;
613 	endpoint->svc_id = -1;
614 	md_get_prop_val(md, node, "target_type", &endpoint->target_type);
615 	md_get_prop_val(md, node, "target_guest", &endpoint->target_guest);
616 	md_get_prop_val(md, node, "channel", &endpoint->channel);
617 	md_get_prop_val(md, node, "target_channel", &endpoint->target_channel);
618 	md_get_prop_val(md, node, "tx-ino", &endpoint->tx_ino);
619 	md_get_prop_val(md, node, "rx-ino", &endpoint->rx_ino);
620 	md_get_prop_val(md, node, "private_svc", &endpoint->private_svc);
621 	md_get_prop_val(md, node, "svc_id", &endpoint->svc_id);
622 	endpoint->resource_id = resource_id;
623 	ldc_endpoints[resource_id] = endpoint;
624 	endpoint->hv_node = node;
625 }
626 
627 void
628 hvmd_init_guest(struct md *md, struct md_node *node)
629 {
630 	struct guest *guest;
631 	struct md_node *node2;
632 	struct md_prop *prop;
633 	uint64_t resource_id;
634 	struct ldc_endpoint *endpoint;
635 	char *path;
636 
637 	if (!md_get_prop_val(md, node, "resource_id", &resource_id))
638 		errx(1, "missing resource_id property in guest node");
639 
640 	if (resource_id >= max_guests)
641 		errx(1, "resource_id larger than max_guests");
642 
643 	guest = xzalloc(sizeof(*guest));
644 	TAILQ_INIT(&guest->cpu_list);
645 	TAILQ_INIT(&guest->device_list);
646 	TAILQ_INIT(&guest->mblock_list);
647 	TAILQ_INIT(&guest->endpoint_list);
648 	md_get_prop_str(md, node, "name", &guest->name);
649 	md_get_prop_val(md, node, "gid", &guest->gid);
650 	md_get_prop_val(md, node, "pid", &guest->pid);
651 	md_get_prop_val(md, node, "tod-offset", &guest->tod_offset);
652 	md_get_prop_val(md, node, "perfctraccess", &guest->perfctraccess);
653 	md_get_prop_val(md, node, "perfctrhtaccess", &guest->perfctrhtaccess);
654 	md_get_prop_val(md, node, "rngctlaccessible", &guest->rngctlaccessible);
655 	md_get_prop_val(md, node, "mdpa", &guest->mdpa);
656 	guest->resource_id = resource_id;
657 	guests[resource_id] = guest;
658 	guest->hv_node = node;
659 
660 	if (strcmp(guest->name, "primary") == 0 && guest->gid != 0)
661 		errx(1, "gid of primary domain isn't 0");
662 
663 	hvmd_alloc_frag(guest->mdpa);
664 
665 	TAILQ_FOREACH(prop, &node->prop_list, link) {
666 		if (prop->tag == MD_PROP_ARC &&
667 		    strcmp(prop->name->str, "fwd") == 0) {
668 			node2 = prop->d.arc.node;
669 			if (strcmp(node2->name->str, "console") == 0) {
670 				md_get_prop_val(md, node2, "resource_id",
671 				    &resource_id);
672 				guest->console = consoles[resource_id];
673 				consoles[resource_id]->guest = guest;
674 			}
675 			if (strcmp(node2->name->str, "cpu") == 0) {
676 				md_get_prop_val(md, node2, "resource_id",
677 				    &resource_id);
678 				TAILQ_INSERT_TAIL(&guest->cpu_list,
679 				    cpus[resource_id], link);
680 				cpus[resource_id]->guest = guest;
681 			}
682 			if (strcmp(node2->name->str, "pcie_bus") == 0) {
683 				md_get_prop_val(md, node2, "resource_id",
684 				    &resource_id);
685 				TAILQ_INSERT_TAIL(&guest->device_list,
686 				    pcie_busses[resource_id], link);
687 				pcie_busses[resource_id]->guest = guest;
688 			}
689 			if (strcmp(node2->name->str, "network_device") == 0) {
690 				md_get_prop_val(md, node2, "resource_id",
691 				    &resource_id);
692 				TAILQ_INSERT_TAIL(&guest->device_list,
693 				    network_devices[resource_id], link);
694 				network_devices[resource_id]->guest = guest;
695 			}
696 			if (strcmp(node2->name->str, "mblock") == 0) {
697 				md_get_prop_val(md, node2, "resource_id",
698 				    &resource_id);
699 				TAILQ_INSERT_TAIL(&guest->mblock_list,
700 				    mblocks[resource_id], link);
701 				mblocks[resource_id]->guest = guest;
702 			}
703 			if (strcmp(node2->name->str, "ldc_endpoint") == 0) {
704 				md_get_prop_val(md, node2, "resource_id",
705 				    &resource_id);
706 				TAILQ_INSERT_TAIL(&guest->endpoint_list,
707 				    ldc_endpoints[resource_id], link);
708 				ldc_endpoints[resource_id]->guest = guest;
709 			}
710 		}
711 	}
712 
713 	TAILQ_FOREACH(endpoint, &guest->endpoint_list, link) {
714 		if (endpoint->channel >= guest->endpoint_id)
715 			guest->endpoint_id = endpoint->channel + 1;
716 	}
717 
718 	xasprintf(&path, "%s.md", guest->name);
719 	guest->md = md_read(path);
720 
721 	if (guest->md == NULL)
722 		err(1, "unable to get guest MD");
723 
724 	free(path);
725 }
726 
727 void
728 hvmd_init(struct md *md)
729 {
730 	struct md_node *node;
731 	struct md_prop *prop;
732 
733 	node = md_find_node(md, "root");
734 	md_get_prop_val(md, node, "content-version", &content_version);
735 	md_get_prop_val(md, node, "stick-frequency", &stick_frequency);
736 	md_get_prop_val(md, node, "tod-frequency", &tod_frequency);
737 	md_get_prop_val(md, node, "tod", &tod);
738 	md_get_prop_val(md, node, "erpt-pa", &erpt_pa);
739 	md_get_prop_val(md, node, "erpt-size", &erpt_size);
740 
741 	node = md_find_node(md, "frag_space");
742 	md_get_prop_val(md, node, "fragsize", &fragsize);
743 	TAILQ_INIT(&frag_mblocks);
744 	TAILQ_FOREACH(prop, &node->prop_list, link) {
745 		if (prop->tag == MD_PROP_ARC &&
746 		    strcmp(prop->name->str, "fwd") == 0)
747 			hvmd_init_frag(md, prop->d.arc.node);
748 	}
749 	pri_alloc_memory(0, fragsize);
750 
751 	node = md_find_node(md, "hvmd_mblock");
752 	if (node) {
753 		hvmd_mblock = xzalloc(sizeof(*hvmd_mblock));
754 		md_get_prop_val(md, node, "base", &hvmd_mblock->membase);
755 		md_get_prop_val(md, node, "size", &hvmd_mblock->memsize);
756 		md_get_prop_val(md, node, "md_maxsize", &md_maxsize);
757 		pri_alloc_memory(hvmd_mblock->membase, hvmd_mblock->memsize);
758 	}
759 
760 	node = md_find_node(md, "consoles");
761 	TAILQ_FOREACH(prop, &node->prop_list, link) {
762 		if (prop->tag == MD_PROP_ARC &&
763 		    strcmp(prop->name->str, "fwd") == 0)
764 			hvmd_init_console(md, prop->d.arc.node);
765 	}
766 
767 	node = md_find_node(md, "cpus");
768 	TAILQ_FOREACH(prop, &node->prop_list, link) {
769 		if (prop->tag == MD_PROP_ARC &&
770 		    strcmp(prop->name->str, "fwd") == 0)
771 			hvmd_init_cpu(md, prop->d.arc.node);
772 	}
773 
774 	have_cwqs = (md_find_node(md, "cwqs") != NULL);
775 	have_rngs = (md_find_node(md, "rngs") != NULL);
776 
777 	node = md_find_node(md, "devices");
778 	TAILQ_FOREACH(prop, &node->prop_list, link) {
779 		if (prop->tag == MD_PROP_ARC &&
780 		    strcmp(prop->name->str, "fwd") == 0)
781 			hvmd_init_device(md, prop->d.arc.node);
782 	}
783 
784 	node = md_find_node(md, "memory");
785 	TAILQ_FOREACH(prop, &node->prop_list, link) {
786 		if (prop->tag == MD_PROP_ARC &&
787 		    strcmp(prop->name->str, "fwd") == 0)
788 			hvmd_init_mblock(md, prop->d.arc.node);
789 	}
790 
791 	node = md_find_node(md, "ldc_endpoints");
792 	TAILQ_FOREACH(prop, &node->prop_list, link) {
793 		if (prop->tag == MD_PROP_ARC &&
794 		    strcmp(prop->name->str, "fwd") == 0)
795 			hvmd_init_endpoint(md, prop->d.arc.node);
796 	}
797 
798 	node = md_find_node(md, "guests");
799 	TAILQ_FOREACH(prop, &node->prop_list, link) {
800 		if (prop->tag == MD_PROP_ARC &&
801 		    strcmp(prop->name->str, "fwd") == 0)
802 			hvmd_init_guest(md, prop->d.arc.node);
803 	}
804 
805 	hvmd_alloc_frag(-1);
806 }
807 
808 void
809 hvmd_finalize_cpu(struct md *md, struct cpu *cpu)
810 {
811 	struct md_node *parent;
812 	struct md_node *node;
813 	int i;
814 
815 	for (i = 0; i < MAX_STRANDS_PER_CORE; i++) {
816 		if (cpu->core->guests[i] == cpu->guest) {
817 			cpu->partid = i + 1;
818 			break;
819 		}
820 		if (cpu->core->guests[i] == NULL) {
821 			cpu->core->guests[i] = cpu->guest;
822 			cpu->partid = i + 1;
823 			break;
824 		}
825 	}
826 
827 	parent = md_find_node(md, "cpus");
828 	assert(parent);
829 
830 	node = md_add_node(md, "cpu");
831 	md_link_node(md, parent, node);
832 	md_add_prop_val(md, node, "pid", cpu->pid);
833 	md_add_prop_val(md, node, "vid", cpu->vid);
834 	md_add_prop_val(md, node, "gid", cpu->gid);
835 	md_add_prop_val(md, node, "partid", cpu->partid);
836 	md_add_prop_val(md, node, "resource_id", cpu->resource_id);
837 	cpu->hv_node = node;
838 }
839 
840 void
841 hvmd_finalize_cpus(struct md *md)
842 {
843 	struct md_node *parent;
844 	struct md_node *node;
845 	uint64_t resource_id;
846 
847 	parent = md_find_node(md, "root");
848 	assert(parent);
849 
850 	node = md_add_node(md, "cpus");
851 	md_link_node(md, parent, node);
852 
853 	for (resource_id = 0; resource_id < max_cpus; resource_id++) {
854 		if (cpus[resource_id])
855 			hvmd_finalize_cpu(md, cpus[resource_id]);
856 	}
857 }
858 
859 void
860 hvmd_finalize_maus(struct md *md)
861 {
862 	struct md_node *parent;
863 	struct md_node *node;
864 	struct md_node *child;
865 	int i;
866 
867 	parent = md_find_node(md, "root");
868 	assert(parent);
869 
870 	node = md_add_node(md, "maus");
871 	md_link_node(md, parent, node);
872 
873 	if (have_cwqs) {
874 		node = md_add_node(md, "cwqs");
875 		md_link_node(md, parent, node);
876 	}
877 
878 	if (have_rngs) {
879 		node = md_add_node(md, "rngs");
880 		md_link_node(md, parent, node);
881 		child = md_add_node(md, "rng");
882 		md_link_node(md, node, child);
883 		for (i = 0; i < max_cpus; i++) {
884 			if (cpus[i])
885 				md_link_node(md, cpus[i]->hv_node, child);
886 		}
887 	}
888 }
889 
890 void
891 hvmd_finalize_device(struct md *md, struct device *device, const char *name)
892 {
893 	struct md_node *parent;
894 	struct md_node *node;
895 
896 	parent = md_find_node(md, "devices");
897 	assert(parent);
898 
899 	node = md_add_node(md, name);
900 	md_link_node(md, parent, node);
901 	md_add_prop_val(md, node, "resource_id", device->resource_id);
902 	md_add_prop_val(md, node, "cfghandle", device->cfghandle);
903 	md_add_prop_val(md, node, "gid", device->gid);
904 	device->hv_node = node;
905 }
906 
907 void
908 hvmd_finalize_devices(struct md *md)
909 {
910 	struct md_node *parent;
911 	struct md_node *node;
912 	uint64_t resource_id;
913 
914 	parent = md_find_node(md, "root");
915 	assert(parent);
916 
917 	node = md_add_node(md, "devices");
918 	md_link_node(md, parent, node);
919 
920 	for (resource_id = 0; resource_id < max_devices; resource_id++) {
921 		if (pcie_busses[resource_id])
922 			hvmd_finalize_device(md, pcie_busses[resource_id],
923 			    "pcie_bus");
924 	}
925 	for (resource_id = 0; resource_id < max_devices; resource_id++) {
926 		if (network_devices[resource_id])
927 			hvmd_finalize_device(md, network_devices[resource_id],
928 			    "network_device");
929 	}
930 }
931 
932 void
933 hvmd_finalize_mblock(struct md *md, struct mblock *mblock)
934 {
935 	struct md_node *parent;
936 	struct md_node *node;
937 
938 	parent = md_find_node(md, "memory");
939 	assert(parent);
940 
941 	node = md_add_node(md, "mblock");
942 	md_link_node(md, parent, node);
943 	md_add_prop_val(md, node, "membase", mblock->membase);
944 	md_add_prop_val(md, node, "memsize", mblock->memsize);
945 	md_add_prop_val(md, node, "realbase", mblock->realbase);
946 	md_add_prop_val(md, node, "resource_id", mblock->resource_id);
947 	mblock->hv_node = node;
948 }
949 
950 void
951 hvmd_finalize_memory(struct md *md)
952 {
953 	struct md_node *parent;
954 	struct md_node *node;
955 	uint64_t resource_id;
956 
957 	parent = md_find_node(md, "root");
958 	assert(parent);
959 
960 	node = md_add_node(md, "memory");
961 	md_link_node(md, parent, node);
962 
963 	for (resource_id = 0; resource_id < max_mblocks; resource_id++) {
964 		if (mblocks[resource_id])
965 			hvmd_finalize_mblock(md, mblocks[resource_id]);
966 	}
967 }
968 
969 void
970 hvmd_finalize_endpoint(struct md *md, struct ldc_endpoint *endpoint)
971 {
972 	struct md_node *parent;
973 	struct md_node *node;
974 
975 	parent = md_find_node(md, "ldc_endpoints");
976 	assert(parent);
977 
978 	node = md_add_node(md, "ldc_endpoint");
979 	md_link_node(md, parent, node);
980 	md_add_prop_val(md, node, "resource_id", endpoint->resource_id);
981 	md_add_prop_val(md, node, "target_type", endpoint->target_type);
982 	md_add_prop_val(md, node, "channel", endpoint->channel);
983 	if (endpoint->target_guest != -1)
984 		md_add_prop_val(md, node, "target_guest",
985 		    endpoint->target_guest);
986 	md_add_prop_val(md, node, "target_channel", endpoint->target_channel);
987 	if (endpoint->tx_ino != -1)
988 		md_add_prop_val(md, node, "tx-ino", endpoint->tx_ino);
989 	if (endpoint->rx_ino != -1)
990 		md_add_prop_val(md, node, "rx-ino", endpoint->rx_ino);
991 	if (endpoint->private_svc != -1)
992 		md_add_prop_val(md, node, "private_svc",
993 		    endpoint->private_svc);
994 	if (endpoint->svc_id != -1)
995 		md_add_prop_val(md, node, "svc_id", endpoint->svc_id);
996 	endpoint->hv_node = node;
997 }
998 
999 void
1000 hvmd_finalize_endpoints(struct md *md)
1001 {
1002 	struct md_node *parent;
1003 	struct md_node *node;
1004 	uint64_t resource_id;
1005 
1006 	parent = md_find_node(md, "root");
1007 	assert(parent);
1008 
1009 	node = md_add_node(md, "ldc_endpoints");
1010 	md_link_node(md, parent, node);
1011 
1012 	for (resource_id = 0; resource_id < max_guest_ldcs; resource_id++) {
1013 		if (ldc_endpoints[resource_id])
1014 			hvmd_finalize_endpoint(md, ldc_endpoints[resource_id]);
1015 	}
1016 }
1017 
1018 void
1019 hvmd_finalize_console(struct md *md, struct console *console)
1020 {
1021 	struct md_node *parent;
1022 	struct md_node *node;
1023 	struct ldc_endpoint *endpoint;
1024 
1025 	parent = md_find_node(md, "consoles");
1026 	assert(parent);
1027 
1028 	node = md_add_node(md, "console");
1029 	md_link_node(md, parent, node);
1030 	md_add_prop_val(md, node, "resource_id", console->resource_id);
1031 	md_add_prop_val(md, node, "ino", console->ino);
1032 	console->hv_node = node;
1033 
1034 	TAILQ_FOREACH(endpoint, &console->guest->endpoint_list, link) {
1035 		if (endpoint->rx_ino == console->ino) {
1036 			md_link_node(md, node, endpoint->hv_node);
1037 			break;
1038 		}
1039 	}
1040 }
1041 
1042 void
1043 hvmd_finalize_consoles(struct md *md)
1044 {
1045 	struct md_node *parent;
1046 	struct md_node *node;
1047 	uint64_t resource_id;
1048 
1049 	parent = md_find_node(md, "root");
1050 	assert(parent);
1051 
1052 	node = md_add_node(md, "consoles");
1053 	md_link_node(md, parent, node);
1054 
1055 	for (resource_id = 0; resource_id < max_guests; resource_id++) {
1056 		if (consoles[resource_id])
1057 			hvmd_finalize_console(md, consoles[resource_id]);
1058 	}
1059 }
1060 
1061 void
1062 hvmd_finalize_guest(struct md *md, struct guest *guest)
1063 {
1064 	struct md_node *node;
1065 	struct md_node *parent;
1066 	struct cpu *cpu;
1067 	struct device *device;
1068 	struct mblock *mblock;
1069 	struct ldc_endpoint *endpoint;
1070 
1071 	parent = md_find_node(md, "guests");
1072 	assert(parent);
1073 
1074 	node = md_add_node(md, "guest");
1075 	md_link_node(md, parent, node);
1076 	md_add_prop_str(md, node, "name", guest->name);
1077 	md_add_prop_val(md, node, "gid", guest->gid);
1078 	md_add_prop_val(md, node, "pid", guest->pid);
1079 	md_add_prop_val(md, node, "resource_id", guest->resource_id);
1080 	md_add_prop_val(md, node, "tod-offset", guest->tod_offset);
1081 	md_add_prop_val(md, node, "reset-reason", 0);
1082 	md_add_prop_val(md, node, "perfctraccess", guest->perfctraccess);
1083 	md_add_prop_val(md, node, "perfctrhtaccess", guest->perfctrhtaccess);
1084 	md_add_prop_val(md, node, "rngctlaccessible", guest->rngctlaccessible);
1085 	md_add_prop_val(md, node, "diagpriv", 0);
1086 	md_add_prop_val(md, node, "mdpa", guest->mdpa);
1087 	md_add_prop_val(md, node, "rombase", rombase);
1088 	md_add_prop_val(md, node, "romsize", romsize);
1089 	guest->hv_node = node;
1090 
1091 	node = md_add_node(md, "virtual_devices");
1092 	md_link_node(md, guest->hv_node, node);
1093 	md_add_prop_val(md, node, "cfghandle", 0x100);
1094 
1095 	node = md_add_node(md, "channel_devices");
1096 	md_link_node(md, guest->hv_node, node);
1097 	md_add_prop_val(md, node, "cfghandle", 0x200);
1098 
1099 	if (guest->console)
1100 		md_link_node(md, guest->hv_node, guest->console->hv_node);
1101 	TAILQ_FOREACH(cpu, &guest->cpu_list, link)
1102 		md_link_node(md, guest->hv_node, cpu->hv_node);
1103 	TAILQ_FOREACH(device, &guest->device_list, link)
1104 		md_link_node(md, guest->hv_node, device->hv_node);
1105 	TAILQ_FOREACH(mblock, &guest->mblock_list, link)
1106 		md_link_node(md, guest->hv_node, mblock->hv_node);
1107 	TAILQ_FOREACH(endpoint, &guest->endpoint_list, link)
1108 		md_link_node(md, guest->hv_node, endpoint->hv_node);
1109 }
1110 
1111 void
1112 hvmd_finalize_guests(struct md *md)
1113 {
1114 	struct md_node *parent;
1115 	struct md_node *node;
1116 	uint64_t resource_id;
1117 
1118 	parent = md_find_node(md, "root");
1119 	assert(parent);
1120 
1121 	node = md_add_node(md, "guests");
1122 	md_link_node(md, parent, node);
1123 
1124 	for (resource_id = 0; resource_id < max_guests; resource_id++) {
1125 		if (guests[resource_id])
1126 			hvmd_finalize_guest(md, guests[resource_id]);
1127 	}
1128 }
1129 
1130 void
1131 hvmd_finalize(void)
1132 {
1133 	struct md *md;
1134 	struct md_node *node;
1135 	struct md_node *parent;
1136 	struct mblock *mblock;
1137 
1138 	md = md_alloc();
1139 	node = md_add_node(md, "root");
1140 	md_add_prop_val(md, node, "content-version", content_version);
1141 	if (content_version <= 0x100000000) {
1142 		md_add_prop_val(md, node, "stick-frequency", stick_frequency);
1143 		if (tod_frequency != 0)
1144 			md_add_prop_val(md, node, "tod-frequency",
1145 			    tod_frequency);
1146 		if (tod != 0)
1147 			md_add_prop_val(md, node, "tod", tod);
1148 		if (erpt_pa != 0)
1149 			md_add_prop_val(md, node, "erpt-pa", erpt_pa);
1150 		if (erpt_size != 0)
1151 			md_add_prop_val(md, node, "erpt-size", erpt_size);
1152 
1153 		parent = node;
1154 		node = md_add_node(md, "platform");
1155 		md_link_node(md, parent, node);
1156 		md_add_prop_val(md, node, "stick-frequency", stick_frequency);
1157 	}
1158 
1159 	parent = md_find_node(md, "root");
1160 	assert(parent);
1161 
1162 	node = md_add_node(md, "frag_space");
1163 	md_link_node(md, parent, node);
1164 	md_add_prop_val(md, node, "fragsize", fragsize);
1165 
1166 	parent = md_find_node(md, "frag_space");
1167 	TAILQ_FOREACH(mblock, &frag_mblocks, link) {
1168 		node = md_add_node(md, "frag_mblock");
1169 		md_link_node(md, parent, node);
1170 		md_add_prop_val(md, node, "base", mblock->membase);
1171 		md_add_prop_val(md, node, "size", mblock->memsize);
1172 	}
1173 
1174 	if (hvmd_mblock) {
1175 		parent = md_find_node(md, "root");
1176 		assert(parent);
1177 
1178 		node = md_add_node(md, "hvmd_mblock");
1179 		md_link_node(md, parent, node);
1180 		md_add_prop_val(md, node, "base", hvmd_mblock->membase);
1181 		md_add_prop_val(md, node, "size", hvmd_mblock->memsize);
1182 		md_add_prop_val(md, node, "md_maxsize", md_maxsize);
1183 	}
1184 
1185 	hvmd_finalize_cpus(md);
1186 	hvmd_finalize_maus(md);
1187 	hvmd_finalize_devices(md);
1188 	hvmd_finalize_memory(md);
1189 	hvmd_finalize_endpoints(md);
1190 	hvmd_finalize_consoles(md);
1191 	hvmd_finalize_guests(md);
1192 
1193 	md_write(md, "hv.md");
1194 }
1195 
1196 struct ldc_endpoint *
1197 hvmd_add_endpoint(struct guest *guest)
1198 {
1199 	struct ldc_endpoint *endpoint;
1200 	uint64_t resource_id;
1201 
1202 	for (resource_id = 0; resource_id < max_guest_ldcs; resource_id++)
1203 		if (ldc_endpoints[resource_id] == NULL)
1204 			break;
1205 	assert(resource_id < max_guest_ldcs);
1206 
1207 	endpoint = xzalloc(sizeof(*endpoint));
1208 	endpoint->target_guest = -1;
1209 	endpoint->tx_ino = -1;
1210 	endpoint->rx_ino = -1;
1211 	endpoint->private_svc = -1;
1212 	endpoint->svc_id = -1;
1213 	endpoint->resource_id = resource_id;
1214 	ldc_endpoints[resource_id] = endpoint;
1215 
1216 	TAILQ_INSERT_TAIL(&guest->endpoint_list, endpoint, link);
1217 	endpoint->guest = guest;
1218 
1219 	return endpoint;
1220 }
1221 
1222 struct console *
1223 hvmd_add_console(struct guest *guest)
1224 {
1225 	struct guest *primary;
1226 	struct console *console;
1227 	uint64_t resource_id;
1228 	uint64_t client_channel, server_channel;
1229 
1230 	primary = guest_lookup("primary");
1231 	client_channel = guest->endpoint_id++;
1232 	server_channel = primary->endpoint_id++;
1233 
1234 	for (resource_id = 0; resource_id < max_guests; resource_id++)
1235 		if (consoles[resource_id] == NULL)
1236 			break;
1237 	assert(resource_id < max_guests);
1238 
1239 	console = xzalloc(sizeof(*console));
1240 	console->ino = 0x11;
1241 	console->resource_id = resource_id;
1242 	consoles[resource_id] = console;
1243 
1244 	console->client_endpoint = hvmd_add_endpoint(guest);
1245 	console->client_endpoint->tx_ino = 0x11;
1246 	console->client_endpoint->rx_ino = 0x11;
1247 	console->client_endpoint->target_type = LDC_GUEST;
1248 	console->client_endpoint->target_guest = primary->gid;
1249 	console->client_endpoint->target_channel = server_channel;
1250 	console->client_endpoint->channel = client_channel;
1251 	console->client_endpoint->private_svc = LDC_CONSOLE_SVC;
1252 
1253 	console->server_endpoint = hvmd_add_endpoint(primary);
1254 	console->server_endpoint->tx_ino = 2 * server_channel;
1255 	console->server_endpoint->rx_ino = 2 * server_channel + 1;
1256 	console->server_endpoint->target_type = LDC_GUEST;
1257 	console->server_endpoint->target_guest = guest->gid;
1258 	console->server_endpoint->channel = server_channel;
1259 	console->server_endpoint->target_channel = client_channel;
1260 
1261 	guest->console = console;
1262 	console->guest = guest;
1263 
1264 	return console;
1265 }
1266 
1267 void
1268 hvmd_add_domain_services(struct guest *guest)
1269 {
1270 	struct guest *primary;
1271 	struct ldc_channel *ds = &guest->domain_services;
1272 	uint64_t client_channel, server_channel;
1273 
1274 	primary = guest_lookup("primary");
1275 	client_channel = guest->endpoint_id++;
1276 	server_channel = primary->endpoint_id++;
1277 
1278 	ds->client_endpoint = hvmd_add_endpoint(guest);
1279 	ds->client_endpoint->tx_ino = 2 * client_channel;
1280 	ds->client_endpoint->rx_ino = 2 * client_channel + 1;
1281 	ds->client_endpoint->target_type = LDC_GUEST;
1282 	ds->client_endpoint->target_guest = primary->gid;
1283 	ds->client_endpoint->target_channel = server_channel;
1284 	ds->client_endpoint->channel = client_channel;
1285 
1286 	ds->server_endpoint = hvmd_add_endpoint(primary);
1287 	ds->server_endpoint->tx_ino = 2 * server_channel;
1288 	ds->server_endpoint->rx_ino = 2 * server_channel + 1;
1289 	ds->server_endpoint->target_type = LDC_GUEST;
1290 	ds->server_endpoint->target_guest = guest->gid;
1291 	ds->server_endpoint->channel = server_channel;
1292 	ds->server_endpoint->target_channel = client_channel;
1293 }
1294 
1295 struct ldc_channel *
1296 hvmd_add_vio(struct guest *guest)
1297 {
1298 	struct guest *primary;
1299 	struct ldc_channel *lc = &guest->vio[guest->num_vios++];
1300 	uint64_t client_channel, server_channel;
1301 
1302 	primary = guest_lookup("primary");
1303 	client_channel = guest->endpoint_id++;
1304 	server_channel = primary->endpoint_id++;
1305 
1306 	lc->client_endpoint = hvmd_add_endpoint(guest);
1307 	lc->client_endpoint->tx_ino = 2 * client_channel;
1308 	lc->client_endpoint->rx_ino = 2 * client_channel + 1;
1309 	lc->client_endpoint->target_type = LDC_GUEST;
1310 	lc->client_endpoint->target_guest = primary->gid;
1311 	lc->client_endpoint->target_channel = server_channel;
1312 	lc->client_endpoint->channel = client_channel;
1313 
1314 	lc->server_endpoint = hvmd_add_endpoint(primary);
1315 	lc->server_endpoint->tx_ino = 2 * server_channel;
1316 	lc->server_endpoint->rx_ino = 2 * server_channel + 1;
1317 	lc->server_endpoint->target_type = LDC_GUEST;
1318 	lc->server_endpoint->target_guest = guest->gid;
1319 	lc->server_endpoint->channel = server_channel;
1320 	lc->server_endpoint->target_channel = client_channel;
1321 
1322 	return lc;
1323 }
1324 
1325 struct guest *
1326 hvmd_add_guest(const char *name)
1327 {
1328 	struct guest *guest;
1329 	uint64_t resource_id;
1330 
1331 	for (resource_id = 0; resource_id < max_guests; resource_id++)
1332 		if (guests[resource_id] == NULL)
1333 			break;
1334 	assert(resource_id < max_guests);
1335 
1336 	guest = xzalloc(sizeof(*guest));
1337 	TAILQ_INIT(&guest->cpu_list);
1338 	TAILQ_INIT(&guest->device_list);
1339 	TAILQ_INIT(&guest->mblock_list);
1340 	TAILQ_INIT(&guest->endpoint_list);
1341 	guests[resource_id] = guest;
1342 	guest->name = name;
1343 	guest->gid = resource_id;
1344 	guest->pid = resource_id + 1;
1345 	guest->resource_id = resource_id;
1346 	guest->mdpa = hvmd_alloc_frag(-1);
1347 
1348 	hvmd_add_console(guest);
1349 	hvmd_add_domain_services(guest);
1350 
1351 	return guest;
1352 }
1353 
1354 struct md_node *
1355 guest_add_channel_endpoints(struct guest *guest)
1356 {
1357 	struct md *md = guest->md;
1358 	struct md_node *parent;
1359 	struct md_node *node;
1360 
1361 	parent = md_find_node(md, "root");
1362 	assert(parent);
1363 
1364 	node = md_add_node(md, "channel-endpoints");
1365 	md_link_node(md, parent, node);
1366 
1367 	return node;
1368 }
1369 
1370 struct md_node *
1371 guest_add_endpoint(struct guest *guest, uint64_t id)
1372 {
1373 	struct md *md = guest->md;
1374 	struct md_node *parent;
1375 	struct md_node *node;
1376 
1377 	parent = md_find_node(md, "channel-endpoints");
1378 	if (parent == NULL)
1379 		parent = guest_add_channel_endpoints(guest);
1380 
1381 	node = md_add_node(md, "channel-endpoint");
1382 	md_link_node(md, parent, node);
1383 	md_add_prop_val(md, node, "id", id);
1384 	md_add_prop_val(md, node, "tx-ino", 2 * id);
1385 	md_add_prop_val(md, node, "rx-ino", 2 * id + 1);
1386 
1387 	return node;
1388 }
1389 
1390 struct md_node *
1391 guest_add_vcc(struct guest *guest)
1392 {
1393 	const char compatible[] = "SUNW,sun4v-virtual-console-concentrator";
1394 	struct md *md = guest->md;
1395 	struct md_node *parent;
1396 	struct md_node *node;
1397 
1398 	parent = md_find_node(md, "channel-devices");
1399 	assert(parent != NULL);
1400 
1401 	node = md_add_node(md, "virtual-device");
1402 	md_link_node(md, parent, node);
1403 	md_add_prop_str(md, node, "name", "virtual-console-concentrator");
1404 	md_add_prop_data(md, node, "compatible", compatible,
1405 	    sizeof(compatible));
1406 	md_add_prop_str(md, node, "device_type", "vcc");
1407 	md_add_prop_val(md, node, "cfg-handle", 0x0);
1408 	md_add_prop_str(md, node, "svc-name", "primary-vcc0");
1409 
1410 	return node;
1411 }
1412 
1413 struct md_node *
1414 guest_find_vcc(struct guest *guest)
1415 {
1416 	struct md *md = guest->md;
1417 	struct md_node *node, *node2;
1418 	struct md_prop *prop;
1419 	const char *name;
1420 
1421 	node = md_find_node(md, "channel-devices");
1422 	assert(node != NULL);
1423 
1424 	TAILQ_FOREACH(prop, &node->prop_list, link) {
1425 		if (prop->tag == MD_PROP_ARC &&
1426 		    strcmp(prop->name->str, "fwd") == 0) {
1427 			node2 = prop->d.arc.node;
1428 			if (!md_get_prop_str(md, node2, "name", &name))
1429 				continue;
1430 			if (strcmp(name, "virtual-console-concentrator") == 0)
1431 				return node2;
1432 		}
1433 	}
1434 
1435 	return NULL;
1436 }
1437 
1438 struct md_node *
1439 guest_add_vcc_port(struct guest *guest, struct md_node *vcc,
1440     const char *domain, uint64_t id, uint64_t channel)
1441 {
1442 	struct md *md = guest->md;
1443 	struct md_node *node;
1444 	struct md_node *child;
1445 
1446 	if (vcc == NULL)
1447 		vcc = guest_find_vcc(guest);
1448 	if (vcc == NULL)
1449 		vcc = guest_add_vcc(guest);
1450 
1451 	node = md_add_node(md, "virtual-device-port");
1452 	md_link_node(md, vcc, node);
1453 	md_add_prop_str(md, node, "name", "vcc-port");
1454 	md_add_prop_val(md, node, "id", id);
1455 	md_add_prop_str(md, node, "vcc-domain-name", domain);
1456 	md_add_prop_str(md, node, "vcc-group-name", domain);
1457 	/* OpenBSD doesn't care about this, but Solaris might. */
1458 	md_add_prop_val(md, node, "vcc-tcp-port", 5000 + id);
1459 
1460 	child = guest_add_endpoint(guest, channel);
1461 	md_link_node(md, node, child);
1462 
1463 	return node;
1464 }
1465 
1466 struct md_node *
1467 guest_add_vds(struct guest *guest)
1468 {
1469 	const char compatible[] = "SUNW,sun4v-disk-server";
1470 	struct md *md = guest->md;
1471 	struct md_node *parent;
1472 	struct md_node *node;
1473 
1474 	parent = md_find_node(md, "channel-devices");
1475 	assert(parent != NULL);
1476 
1477 	node = md_add_node(md, "virtual-device");
1478 	md_link_node(md, parent, node);
1479 	md_add_prop_str(md, node, "name", "virtual-disk-server");
1480 	md_add_prop_data(md, node, "compatible", compatible,
1481 	    sizeof(compatible));
1482 	md_add_prop_str(md, node, "device_type", "vds");
1483 	md_add_prop_val(md, node, "cfg-handle", 0x0);
1484 	md_add_prop_str(md, node, "svc-name", "primary-vds0");
1485 
1486 	return node;
1487 }
1488 
1489 struct md_node *
1490 guest_find_vds(struct guest *guest)
1491 {
1492 	struct md *md = guest->md;
1493 	struct md_node *node, *node2;
1494 	struct md_prop *prop;
1495 	const char *name;
1496 
1497 	node = md_find_node(md, "channel-devices");
1498 	assert(node != NULL);
1499 
1500 	TAILQ_FOREACH(prop, &node->prop_list, link) {
1501 		if (prop->tag == MD_PROP_ARC &&
1502 		    strcmp(prop->name->str, "fwd") == 0) {
1503 			node2 = prop->d.arc.node;
1504 			if (!md_get_prop_str(md, node2, "name", &name))
1505 				continue;
1506 			if (strcmp(name, "virtual-disk-server") == 0)
1507 				return node2;
1508 		}
1509 	}
1510 
1511 	return NULL;
1512 }
1513 
1514 struct md_node *
1515 guest_add_vds_port(struct guest *guest, struct md_node *vds,
1516     const char *path, uint64_t id, uint64_t channel)
1517 {
1518 	struct md *md = guest->md;
1519 	struct md_node *node;
1520 	struct md_node *child;
1521 
1522 	if (vds == NULL)
1523 		vds = guest_find_vds(guest);
1524 	if (vds == NULL)
1525 		vds = guest_add_vds(guest);
1526 
1527 	node = md_add_node(md, "virtual-device-port");
1528 	md_link_node(md, vds, node);
1529 	md_add_prop_str(md, node, "name", "vds-port");
1530 	md_add_prop_val(md, node, "id", id);
1531 	md_add_prop_str(md, node, "vds-block-device", path);
1532 
1533 	child = guest_add_endpoint(guest, channel);
1534 	md_link_node(md, node, child);
1535 
1536 	return node;
1537 }
1538 
1539 struct md_node *
1540 guest_add_vsw(struct guest *guest)
1541 {
1542 	const char compatible[] = "SUNW,sun4v-network-switch";
1543 	struct md *md = guest->md;
1544 	struct md_node *parent;
1545 	struct md_node *node;
1546 
1547 	parent = md_find_node(md, "channel-devices");
1548 	assert(parent != NULL);
1549 
1550 	node = md_add_node(md, "virtual-device");
1551 	md_link_node(md, parent, node);
1552 	md_add_prop_str(md, node, "name", "virtual-network-switch");
1553 	md_add_prop_data(md, node, "compatible", compatible,
1554 	    sizeof(compatible));
1555 	md_add_prop_str(md, node, "device_type", "vsw");
1556 	md_add_prop_val(md, node, "cfg-handle", 0x0);
1557 	md_add_prop_str(md, node, "svc-name", "primary-vsw0");
1558 
1559 	return node;
1560 }
1561 
1562 struct md_node *
1563 guest_find_vsw(struct guest *guest)
1564 {
1565 	struct md *md = guest->md;
1566 	struct md_node *node, *node2;
1567 	struct md_prop *prop;
1568 	const char *name;
1569 
1570 	node = md_find_node(md, "channel-devices");
1571 	assert(node != NULL);
1572 
1573 	TAILQ_FOREACH(prop, &node->prop_list, link) {
1574 		if (prop->tag == MD_PROP_ARC &&
1575 		    strcmp(prop->name->str, "fwd") == 0) {
1576 			node2 = prop->d.arc.node;
1577 			if (!md_get_prop_str(md, node2, "name", &name))
1578 				continue;
1579 			if (strcmp(name, "virtual-network-switch") == 0)
1580 				return node2;
1581 		}
1582 	}
1583 
1584 	return NULL;
1585 }
1586 
1587 struct md_node *
1588 guest_add_vsw_port(struct guest *guest, struct md_node *vds,
1589     uint64_t id, uint64_t channel)
1590 {
1591 	struct md *md = guest->md;
1592 	struct md_node *node;
1593 	struct md_node *child;
1594 	uint64_t mac_addr;
1595 
1596 	if (vds == NULL)
1597 		vds = guest_find_vsw(guest);
1598 	if (vds == NULL)
1599 		vds = guest_add_vsw(guest);
1600 	if (!md_get_prop_val(md, vds, "local-mac-address", &mac_addr)) {
1601 		mac_addr = 0x00144ff80000 + (arc4random() & 0x3ffff);
1602 		md_add_prop_val(md, vds, "local-mac-address", mac_addr);
1603 	}
1604 
1605 	node = md_add_node(md, "virtual-device-port");
1606 	md_link_node(md, vds, node);
1607 	md_add_prop_str(md, node, "name", "vsw-port");
1608 	md_add_prop_val(md, node, "id", id);
1609 
1610 	child = guest_add_endpoint(guest, channel);
1611 	md_link_node(md, node, child);
1612 
1613 	return node;
1614 }
1615 
1616 struct md_node *
1617 guest_add_console_device(struct guest *guest)
1618 {
1619 	const char compatible[] = "SUNW,sun4v-console";
1620 	struct md *md = guest->md;
1621 	struct md_node *parent;
1622 	struct md_node *node;
1623 
1624 	parent = md_find_node(md, "virtual-devices");
1625 	assert(parent);
1626 
1627 	node = md_add_node(md, "virtual-device");
1628 	md_link_node(md, parent, node);
1629 	md_add_prop_str(md, node, "name", "console");
1630 	md_add_prop_str(md, node, "device-type", "serial");
1631 	md_add_prop_val(md, node, "intr", 0x1);
1632 	md_add_prop_val(md, node, "ino", 0x11);
1633 	md_add_prop_val(md, node, "channel#", 0);
1634 	md_add_prop_val(md, node, "cfg-handle", 0x1);
1635 	md_add_prop_data(md, node, "compatible", compatible,
1636 	    sizeof(compatible));
1637 
1638 	return node;
1639 }
1640 
1641 struct md_node *
1642 guest_add_vdc(struct guest *guest, uint64_t cfghandle)
1643 {
1644 	const char compatible[] = "SUNW,sun4v-disk";
1645 	struct md *md = guest->md;
1646 	struct md_node *parent;
1647 	struct md_node *node;
1648 
1649 	parent = md_find_node(md, "channel-devices");
1650 	assert(parent);
1651 
1652 	node = md_add_node(md, "virtual-device");
1653 	md_link_node(md, parent, node);
1654 	md_add_prop_str(md, node, "name", "disk");
1655 	md_add_prop_str(md, node, "device-type", "block");
1656 	md_add_prop_val(md, node, "cfg-handle", cfghandle);
1657 	md_add_prop_data(md, node, "compatible", compatible,
1658 	    sizeof(compatible));
1659 
1660 	return node;
1661 }
1662 
1663 struct md_node *
1664 guest_add_vdc_port(struct guest *guest, struct md_node *vdc,
1665     uint64_t cfghandle, uint64_t id, uint64_t channel)
1666 {
1667 	struct md *md = guest->md;
1668 	struct md_node *node;
1669 	struct md_node *child;
1670 
1671 	if (vdc == NULL)
1672 		vdc = guest_add_vdc(guest, cfghandle);
1673 
1674 	node = md_add_node(md, "virtual-device-port");
1675 	md_link_node(md, vdc, node);
1676 	md_add_prop_str(md, node, "name", "vdc-port");
1677 	md_add_prop_val(md, node, "id", id);
1678 
1679 	child = guest_add_endpoint(guest, channel);
1680 	md_link_node(md, node, child);
1681 
1682 	return node;
1683 }
1684 
1685 struct md_node *
1686 guest_add_vnet(struct guest *guest, uint64_t mac_addr, uint64_t mtu,
1687     uint64_t cfghandle)
1688 {
1689 	const char compatible[] = "SUNW,sun4v-network";
1690 	struct md *md = guest->md;
1691 	struct md_node *parent;
1692 	struct md_node *node;
1693 
1694 	parent = md_find_node(md, "channel-devices");
1695 	assert(parent);
1696 
1697 	node = md_add_node(md, "virtual-device");
1698 	md_link_node(md, parent, node);
1699 	md_add_prop_str(md, node, "name", "network");
1700 	md_add_prop_str(md, node, "device-type", "network");
1701 	md_add_prop_val(md, node, "cfg-handle", cfghandle);
1702 	md_add_prop_data(md, node, "compatible", compatible,
1703 	    sizeof(compatible));
1704 	if (mac_addr == -1)
1705 		mac_addr = 0x00144ff80000 + (arc4random() & 0x3ffff);
1706 	md_add_prop_val(md, node, "local-mac-address", mac_addr);
1707 	md_add_prop_val(md, node, "mtu", mtu);
1708 
1709 	return node;
1710 }
1711 
1712 struct md_node *
1713 guest_add_vnet_port(struct guest *guest, struct md_node *vdc,
1714     uint64_t mac_addr, uint64_t remote_mac_addr, uint64_t mtu, uint64_t cfghandle,
1715     uint64_t id, uint64_t channel)
1716 {
1717 	struct md *md = guest->md;
1718 	struct md_node *node;
1719 	struct md_node *child;
1720 
1721 	if (vdc == NULL)
1722 		vdc = guest_add_vnet(guest, mac_addr, mtu, cfghandle);
1723 
1724 	node = md_add_node(md, "virtual-device-port");
1725 	md_link_node(md, vdc, node);
1726 	md_add_prop_str(md, node, "name", "vnet-port");
1727 	md_add_prop_val(md, node, "id", id);
1728 	md_add_prop_val(md, node, "switch-port", 0);
1729 	md_add_prop_data(md, node, "remote-mac-address",
1730 	    (uint8_t *)&remote_mac_addr, sizeof(remote_mac_addr));
1731 
1732 	child = guest_add_endpoint(guest, channel);
1733 	md_link_node(md, node, child);
1734 
1735 	return node;
1736 }
1737 
1738 struct md_node *
1739 guest_add_channel_devices(struct guest *guest)
1740 {
1741 	const char compatible[] = "SUNW,sun4v-channel-devices";
1742 	struct md *md = guest->md;
1743 	struct md_node *parent;
1744 	struct md_node *node;
1745 
1746 	parent = md_find_node(md, "virtual-devices");
1747 	assert(parent);
1748 
1749 	node = md_add_node(md, "channel-devices");
1750 	md_link_node(md, parent, node);
1751 	md_add_prop_str(md, node, "name", "channel-devices");
1752 	md_add_prop_str(md, node, "device-type", "channel-devices");
1753 	md_add_prop_data(md, node, "compatible", compatible,
1754 	    sizeof(compatible));
1755 	md_add_prop_val(md, node, "cfg-handle", 0x200);
1756 
1757 	return node;
1758 }
1759 
1760 struct md_node *
1761 guest_add_domain_services(struct guest *guest)
1762 {
1763 	struct md *md = guest->md;
1764 	struct md_node *parent;
1765 	struct md_node *node;
1766 
1767 	parent = md_find_node(md, "root");
1768 	assert(parent);
1769 
1770 	node = md_add_node(md, "domain-services");
1771 	md_link_node(md, parent, node);
1772 
1773 	return node;
1774 }
1775 
1776 struct md_node *
1777 guest_add_domain_services_port(struct guest *guest, uint64_t id)
1778 {
1779 	struct md *md = guest->md;
1780 	struct md_node *parent;
1781 	struct md_node *node;
1782 	struct md_node *child;
1783 
1784 	parent = md_find_node(md, "domain-services");
1785 	if (parent == NULL)
1786 		parent = guest_add_domain_services(guest);
1787 
1788 	node = md_add_node(md, "domain-services-port");
1789 	md_link_node(md, parent, node);
1790 	md_add_prop_val(md, node, "id", id);
1791 
1792 	child = guest_add_endpoint(guest,
1793 	    guest->domain_services.client_endpoint->channel);
1794 	md_link_node(md, node, child);
1795 
1796 	return node;
1797 }
1798 
1799 void
1800 guest_add_devalias(struct guest *guest, const char *name, const char *path)
1801 {
1802 	struct md *md = guest->md;
1803 	struct md_node *parent;
1804 	struct md_node *node;
1805 
1806 	node = md_find_node(md, "devalias");
1807 	if (node == NULL) {
1808 		parent = md_find_node(md, "openboot");
1809 		assert(parent);
1810 
1811 		node = md_add_node(md, "devalias");
1812 		md_link_node(md, parent, node);
1813 	}
1814 
1815 	md_add_prop_str(md, node, name, path);
1816 }
1817 
1818 void
1819 guest_set_domaining_enabled(struct guest *guest)
1820 {
1821 	struct md *md = guest->md;
1822 	struct md_node *node;
1823 
1824 	node = md_find_node(md, "platform");
1825 	assert(node);
1826 
1827 	md_set_prop_val(md, node, "domaining-enabled", 0x1);
1828 }
1829 
1830 void
1831 guest_set_mac_address(struct guest *guest)
1832 {
1833 	struct md *md = guest->md;
1834 	struct md_node *node;
1835 	uint64_t mac_address;
1836 	uint64_t hostid;
1837 
1838 	node = md_find_node(md, "platform");
1839 	assert(node);
1840 
1841 	mac_address = 0x00144ff80000 + (arc4random() & 0x3ffff);
1842 	md_set_prop_val(md, node, "mac-address", mac_address);
1843 
1844 	hostid = 0x84000000 | (mac_address & 0x00ffffff);
1845 	md_set_prop_val(md, node, "hostid", hostid);
1846 }
1847 
1848 struct md_node *
1849 guest_find_vc(struct guest *guest)
1850 {
1851 	struct md *md = guest->md;
1852 	struct md_node *node, *node2;
1853 	struct md_node *vc = NULL;
1854 	struct md_prop *prop;
1855 	const char *name;
1856 
1857 	node = md_find_node(md, "channel-devices");
1858 	assert(node != NULL);
1859 
1860 	TAILQ_FOREACH(prop, &node->prop_list, link) {
1861 		if (prop->tag == MD_PROP_ARC &&
1862 		    strcmp(prop->name->str, "fwd") == 0) {
1863 			node2 = prop->d.arc.node;
1864 			if (!md_get_prop_str(md, node2, "name", &name))
1865 				continue;
1866 			if (strcmp(name, "virtual-channel") == 0)
1867 				vc = node2;
1868 		}
1869 	}
1870 
1871 	return vc;
1872 }
1873 
1874 struct md_node *
1875 guest_add_vc_port(struct guest *guest, struct md_node *vc,
1876     const char *domain, uint64_t id, uint64_t channel)
1877 {
1878 	struct md *md = guest->md;
1879 	struct md_node *node;
1880 	struct md_node *child;
1881 	char *str;
1882 
1883 	if (vc == NULL)
1884 		vc = guest_find_vc(guest);
1885 	assert(vc);
1886 
1887 	node = md_add_node(md, "virtual-device-port");
1888 	md_link_node(md, vc, node);
1889 	md_add_prop_str(md, node, "name", "vldc-port");
1890 	md_add_prop_val(md, node, "id", id);
1891 	xasprintf(&str, "ldom-%s", domain);
1892 	md_add_prop_str(md, node, "vldc-svc-name", str);
1893 	free(str);
1894 
1895 	child = guest_add_endpoint(guest, channel);
1896 	md_link_node(md, node, child);
1897 
1898 	return node;
1899 }
1900 
1901 struct guest *
1902 guest_create(const char *name)
1903 {
1904 	struct guest *guest;
1905 	struct guest *primary;
1906 	struct md_node *node;
1907 
1908 	primary = guest_lookup("primary");
1909 
1910 	guest = hvmd_add_guest(name);
1911 	guest->md = md_copy(protomd);
1912 
1913 	md_find_delete_node(guest->md, "dimm_configuration");
1914 	md_find_delete_node(guest->md, "platform_services");
1915 	md_find_delete_node(guest->md, "phys_io");
1916 	md_collect_garbage(guest->md);
1917 
1918 	guest_set_domaining_enabled(guest);
1919 	guest_set_mac_address(guest);
1920 	guest_add_channel_devices(guest);
1921 	guest_add_domain_services_port(guest, 0);
1922 	guest_add_console_device(guest);
1923 	guest_add_devalias(guest, "virtual-console",
1924 	    "/virtual-devices/console@1");
1925 
1926 	guest_add_vcc_port(primary, NULL, guest->name, guest->gid - 1,
1927 	    guest->console->server_endpoint->channel);
1928 
1929 	guest_add_vc_port(primary, NULL, guest->name, guest->gid + 2,
1930 	    guest->domain_services.server_endpoint->channel);
1931 
1932 	node = md_find_node(guest->md, "root");
1933 	md_add_prop_val(guest->md, node, "reset-reason", 0);
1934 
1935 	return guest;
1936 }
1937 
1938 struct guest *
1939 guest_lookup(const char *name)
1940 {
1941 	uint64_t resource_id;
1942 
1943 	for (resource_id = 0; resource_id < max_guests; resource_id++) {
1944 		if (guests[resource_id] &&
1945 		    strcmp(guests[resource_id]->name, name) == 0)
1946 			return guests[resource_id];
1947 	}
1948 
1949 	return NULL;
1950 }
1951 
1952 void
1953 guest_delete_virtual_device_port(struct guest *guest, struct md_node *port)
1954 {
1955 	struct md *md = guest->md;
1956 	struct md_node *node;
1957 	struct md_prop *prop;
1958 
1959 	TAILQ_FOREACH(node, &md->node_list, link) {
1960 		if (strcmp(node->name->str, "virtual-device-port") != 0)
1961 			continue;
1962 		TAILQ_FOREACH(prop, &node->prop_list, link) {
1963 			if (prop->tag == MD_PROP_ARC &&
1964 			    prop->d.arc.node == port) {
1965 				md_delete_node(md, node);
1966 				return;
1967 			}
1968 		}
1969 	}
1970 }
1971 
1972 void
1973 guest_delete_endpoint(struct guest *guest, struct ldc_endpoint *endpoint)
1974 {
1975 	struct md *md = guest->md;
1976 	struct md_node *node, *node2;
1977 	struct md_prop *prop;
1978 	uint64_t id, resource_id;
1979 
1980 	node = md_find_node(md, "channel-endpoints");
1981 	TAILQ_FOREACH(prop, &node->prop_list, link) {
1982 		if (prop->tag == MD_PROP_ARC &&
1983 		    strcmp(prop->name->str, "fwd") == 0) {
1984 			node2 = prop->d.arc.node;
1985 			if (!md_get_prop_val(hvmd, node2, "id", &id))
1986 				continue;
1987 			if (id == endpoint->channel) {
1988 				guest_delete_virtual_device_port(guest, node2);
1989 				md_delete_node(md, node2);
1990 				break;
1991 			}
1992 		}
1993 	}
1994 
1995 	TAILQ_REMOVE(&guest->endpoint_list, endpoint, link);
1996 	ldc_endpoints[endpoint->resource_id] = NULL;
1997 
1998 	/* Delete peer as well. */
1999 	for (resource_id = 0; resource_id < max_guest_ldcs; resource_id++) {
2000 		struct ldc_endpoint *peer = ldc_endpoints[resource_id];
2001 
2002 		if (peer && peer->target_type == LDC_GUEST &&
2003 		    peer->target_channel == endpoint->channel &&
2004 		    peer->channel == endpoint->target_channel &&
2005 		    peer->target_guest == guest->gid)
2006 			guest_delete_endpoint(peer->guest, peer);
2007 	}
2008 
2009 	free(endpoint);
2010 }
2011 
2012 void
2013 guest_delete(struct guest *guest)
2014 {
2015 	struct cpu *cpu, *cpu2;
2016 	struct mblock *mblock, *mblock2;
2017 	struct ldc_endpoint *endpoint, *endpoint2;
2018 
2019 	consoles[guest->console->resource_id] = NULL;
2020 	free(guest->console);
2021 
2022 	TAILQ_FOREACH_SAFE(cpu, &guest->cpu_list, link, cpu2) {
2023 		TAILQ_REMOVE(&guest->cpu_list, cpu, link);
2024 		cpus[cpu->resource_id] = NULL;
2025 		pri_free_cpu(cpu);
2026 	}
2027 
2028 	TAILQ_FOREACH_SAFE(mblock, &guest->mblock_list, link, mblock2) {
2029 		TAILQ_REMOVE(&guest->mblock_list, mblock, link);
2030 		mblocks[mblock->resource_id] = NULL;
2031 		free(mblock);
2032 	}
2033 
2034 	TAILQ_FOREACH_SAFE(endpoint, &guest->endpoint_list, link, endpoint2)
2035 		guest_delete_endpoint(guest, endpoint);
2036 
2037 	hvmd_free_frag(guest->mdpa);
2038 
2039 	guests[guest->resource_id] = NULL;
2040 	free(guest);
2041 }
2042 
2043 void
2044 guest_delete_cpu(struct guest *guest, uint64_t vid)
2045 {
2046 	struct cpu *cpu;
2047 
2048 	TAILQ_FOREACH(cpu, &guest->cpu_list, link) {
2049 		if (cpu->vid == vid) {
2050 			TAILQ_REMOVE(&guest->cpu_list, cpu, link);
2051 			cpus[cpu->resource_id] = NULL;
2052 			pri_free_cpu(cpu);
2053 			return;
2054 		}
2055 	}
2056 }
2057 
2058 void
2059 guest_add_cpu(struct guest *guest)
2060 {
2061 	struct cpu *cpu;
2062 
2063 	cpu = pri_alloc_cpu(-1);
2064 
2065 	if (cpu->resource_id == -1) {
2066 		uint64_t resource_id;
2067 
2068 		for (resource_id = 0; resource_id < max_cpus; resource_id++)
2069 			if (cpus[resource_id] == NULL)
2070 				break;
2071 		assert(resource_id < max_cpus);
2072 		cpu->resource_id = resource_id;
2073 	}
2074 	cpus[cpu->resource_id] = cpu;
2075 
2076 	cpu->vid = guest->cpu_vid++;
2077 	cpu->gid = guest->gid;
2078 	cpu->partid = 1;
2079 
2080 	TAILQ_INSERT_TAIL(&guest->cpu_list, cpu, link);
2081 	cpu->guest = guest;
2082 }
2083 
2084 void
2085 guest_delete_memory(struct guest *guest)
2086 {
2087 	struct mblock *mblock, *tmp;
2088 
2089 	TAILQ_FOREACH_SAFE(mblock, &guest->mblock_list, link, tmp) {
2090 		if (mblock->resource_id != -1)
2091 			mblocks[mblock->resource_id] = NULL;
2092 		TAILQ_REMOVE(&guest->mblock_list, mblock, link);
2093 		free(mblock);
2094 	}
2095 }
2096 
2097 void
2098 guest_add_memory(struct guest *guest, uint64_t base, uint64_t size)
2099 {
2100 	struct mblock *mblock;
2101 	uint64_t resource_id;
2102 
2103 	mblock = pri_alloc_memory(base, size);
2104 	if (mblock == NULL)
2105 		errx(1, "unable to allocate guest memory");
2106 	for (resource_id = 0; resource_id < max_cpus; resource_id++)
2107 		if (mblocks[resource_id] == NULL)
2108 			break;
2109 	assert(resource_id < max_mblocks);
2110 	mblock->resource_id = resource_id;
2111 	mblocks[resource_id] = mblock;
2112 
2113 	mblock->realbase = mblock->membase & (max_page_size - 1);
2114 	if (mblock->realbase == 0)
2115 		mblock->realbase = max_page_size;
2116 
2117 	TAILQ_INSERT_TAIL(&guest->mblock_list, mblock, link);
2118 	mblock->guest = guest;
2119 }
2120 
2121 void
2122 guest_add_vdisk(struct guest *guest, uint64_t id, const char *path)
2123 {
2124 	struct guest *primary;
2125 	struct ldc_channel *lc;
2126 	char *devalias;
2127 	char *devpath;
2128 
2129 	primary = guest_lookup("primary");
2130 
2131 	lc = hvmd_add_vio(guest);
2132 	guest_add_vds_port(primary, NULL, path, id,
2133 	    lc->server_endpoint->channel);
2134 	guest_add_vdc_port(guest, NULL, id, 0, lc->client_endpoint->channel);
2135 
2136 	xasprintf(&devalias, "disk%d", id);
2137 	xasprintf(&devpath,
2138 	    "/virtual-devices@100/channel-devices@200/disk@%d", id);
2139 	if (id == 0)
2140 		guest_add_devalias(guest, "disk", devpath);
2141 	guest_add_devalias(guest, devalias, devpath);
2142 	free(devalias);
2143 	free(devpath);
2144 }
2145 
2146 void
2147 guest_add_vnetwork(struct guest *guest, uint64_t id, uint64_t mac_addr,
2148     uint64_t mtu)
2149 {
2150 	struct guest *primary;
2151 	struct ldc_channel *lc;
2152 	char *devalias;
2153 	char *devpath;
2154 	struct md_node *node;
2155 	uint64_t remote_mac_addr = -1;
2156 
2157 	primary = guest_lookup("primary");
2158 
2159 	lc = hvmd_add_vio(guest);
2160 	guest_add_vsw_port(primary, NULL, id, lc->server_endpoint->channel);
2161 	node = guest_find_vsw(primary);
2162 	md_get_prop_val(primary->md, node, "local-mac-address", &remote_mac_addr);
2163 	guest_add_vnet_port(guest, NULL, mac_addr, remote_mac_addr, mtu, id, 0,
2164 	    lc->client_endpoint->channel);
2165 
2166 	xasprintf(&devalias, "net%d", id);
2167 	xasprintf(&devpath,
2168 	    "/virtual-devices@100/channel-devices@200/network@%d", id);
2169 	if (id == 0)
2170 		guest_add_devalias(guest, "net", devpath);
2171 	guest_add_devalias(guest, devalias, devpath);
2172 	free(devalias);
2173 	free(devpath);
2174 }
2175 
2176 struct cpu *
2177 guest_find_cpu(struct guest *guest, uint64_t pid)
2178 {
2179 	struct cpu *cpu;
2180 
2181 	TAILQ_FOREACH(cpu, &guest->cpu_list, link)
2182 		if (cpu->pid == pid)
2183 			return cpu;
2184 
2185 	return NULL;
2186 }
2187 
2188 void
2189 guest_finalize(struct guest *guest)
2190 {
2191 	struct md *md = guest->md;
2192 	struct md_node *node, *node2;
2193 	struct md_prop *prop, *prop2;
2194 	struct mblock *mblock;
2195 	struct md_node *parent;
2196 	struct md_node *child;
2197 	struct cpu *cpu;
2198 	uint64_t pid;
2199 	uint64_t id;
2200 	const char *name;
2201 	char *path;
2202 
2203 	node = md_find_node(md, "cpus");
2204 	TAILQ_FOREACH_SAFE(prop, &node->prop_list, link, prop2) {
2205 		if (prop->tag == MD_PROP_ARC &&
2206 		    strcmp(prop->name->str, "fwd") == 0) {
2207 			node2 = prop->d.arc.node;
2208 			if (!md_get_prop_val(md, node2, "pid", &pid))
2209 				if (!md_get_prop_val(md, node2, "id", &pid))
2210 					continue;
2211 			cpu = guest_find_cpu(guest, pid);
2212 			if (cpu == NULL) {
2213 				md_delete_node(md, node2);
2214 				continue;
2215 			}
2216 			md_set_prop_val(md, node2, "id", cpu->vid);
2217 		}
2218 	}
2219 
2220 	/*
2221 	 * We don't support crypto units yet, so delete any "ncp" and
2222 	 * "n2cp" nodes.  If we don't, Solaris whines about not being
2223 	 * able to configure crypto work queues.
2224 	 */
2225 	node = md_find_node(md, "virtual-devices");
2226 	TAILQ_FOREACH_SAFE(prop, &node->prop_list, link, prop2) {
2227 		if (prop->tag == MD_PROP_ARC &&
2228 		    strcmp(prop->name->str, "fwd") == 0) {
2229 			node2 = prop->d.arc.node;
2230 			if (!md_get_prop_str(md, node2, "name", &name))
2231 				continue;
2232 			if (strcmp(name, "ncp") == 0)
2233 				md_delete_node(md, node2);
2234 			if (strcmp(name, "n2cp") == 0)
2235 				md_delete_node(md, node2);
2236 		}
2237 	}
2238 
2239 	md_collect_garbage(md);
2240 
2241 	node = md_find_node(md, "memory");
2242 	md_get_prop_val(md, node, "memory-generation-id#", &id);
2243 	md_delete_node(md, node);
2244 	md_collect_garbage(md);
2245 
2246 	parent = md_find_node(md, "root");
2247 	assert(parent);
2248 
2249 	node = md_add_node(md, "memory");
2250 	md_add_prop_val(md, node, "memory-generation-id#", id);
2251 	md_link_node(md, parent, node);
2252 
2253 	TAILQ_FOREACH(mblock, &guest->mblock_list, link) {
2254 		child = md_add_node(md, "mblock");
2255 		md_add_prop_val(md, child, "base", mblock->realbase);
2256 		md_add_prop_val(md, child, "size", mblock->memsize);
2257 		md_link_node(md, node, child);
2258 	}
2259 
2260 	xasprintf(&path, "%s.md", guest->name);
2261 	md_write(guest->md, path);
2262 	free(path);
2263 }
2264 
2265 struct guest *
2266 primary_init(void)
2267 {
2268 	struct guest *guest;
2269 
2270 	guest = guest_lookup("primary");
2271 	assert(guest);
2272 
2273 	guest_set_domaining_enabled(guest);
2274 
2275 	return guest;
2276 }
2277 
2278 void
2279 build_config(const char *filename)
2280 {
2281 	struct guest *primary;
2282 	struct guest *guest;
2283 	struct ldc_endpoint *endpoint;
2284 	uint64_t resource_id;
2285 	int i;
2286 
2287 	struct ldom_config conf;
2288 	struct domain *domain;
2289 	struct vdisk *vdisk;
2290 	struct vnet *vnet;
2291 	uint64_t num_cpus, primary_num_cpus;
2292 	uint64_t memory, primary_memory;
2293 
2294 	SIMPLEQ_INIT(&conf.domain_list);
2295 	if (parse_config(filename, &conf) < 0)
2296 		exit(1);
2297 
2298 	pri = md_read("pri");
2299 	if (pri == NULL)
2300 		err(1, "unable to get PRI");
2301 	hvmd = md_read("hv.md");
2302 	if (hvmd == NULL)
2303 		err(1, "unable to get Hypervisor MD");
2304 
2305 	pri_init(pri);
2306 	pri_alloc_memory(hv_membase, hv_memsize);
2307 
2308 	num_cpus = primary_num_cpus = 0;
2309 	memory = primary_memory = 0;
2310 	SIMPLEQ_FOREACH(domain, &conf.domain_list, entry) {
2311 		if (strcmp(domain->name, "primary") == 0) {
2312 			primary_num_cpus = domain->vcpu;
2313 			primary_memory = domain->memory;
2314 		}
2315 		num_cpus += domain->vcpu;
2316 		memory += domain->memory;
2317 	}
2318 	if (primary_num_cpus == 0 && total_cpus > num_cpus)
2319 		primary_num_cpus = total_cpus - num_cpus;
2320 	if (primary_memory == 0 && total_memory > memory)
2321 		primary_memory = total_memory - memory;
2322 	if (num_cpus > total_cpus || primary_num_cpus == 0)
2323 		errx(1, "not enough VCPU resources available");
2324 	if (memory > total_memory || primary_memory == 0)
2325 		errx(1, "not enough memory available");
2326 
2327 	hvmd_init(hvmd);
2328 	primary = primary_init();
2329 
2330 	for (resource_id = 0; resource_id <max_guests; resource_id++)
2331 		if (guests[resource_id] &&
2332 		    strcmp(guests[resource_id]->name, "primary") != 0)
2333 			guest_delete(guests[resource_id]);
2334 
2335 	primary->endpoint_id = 0;
2336 	TAILQ_FOREACH(endpoint, &primary->endpoint_list, link) {
2337 		if (endpoint->channel >= primary->endpoint_id)
2338 			primary->endpoint_id = endpoint->channel + 1;
2339 	}
2340 
2341 	for (i = primary_num_cpus; i < max_cpus; i++)
2342 		guest_delete_cpu(primary, i);
2343 	guest_delete_memory(primary);
2344 	guest_add_memory(primary, -1, primary_memory);
2345 
2346 	SIMPLEQ_FOREACH(domain, &conf.domain_list, entry) {
2347 		if (strcmp(domain->name, "primary") == 0)
2348 			continue;
2349 		guest = guest_create(domain->name);
2350 		for (i = 0; i < domain->vcpu; i++)
2351 			guest_add_cpu(guest);
2352 		guest_add_memory(guest, -1, domain->memory);
2353 		i = 0;
2354 		SIMPLEQ_FOREACH(vdisk, &domain->vdisk_list, entry)
2355 			guest_add_vdisk(guest, i++, vdisk->path);
2356 		i = 0;
2357 		SIMPLEQ_FOREACH(vnet, &domain->vnet_list, entry)
2358 			guest_add_vnetwork(guest, i++, vnet->mac_addr,
2359 			    vnet->mtu);
2360 
2361 		guest_finalize(guest);
2362 	}
2363 
2364 	guest_finalize(primary);
2365 	hvmd_finalize();
2366 }
2367