xref: /openbsd/usr.sbin/ldomctl/config.c (revision ee96180d)
1 /*	$OpenBSD: config.c,v 1.43 2022/10/06 21:35:52 kn Exp $	*/
2 
3 /*
4  * Copyright (c) 2012, 2018 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 "ldom_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 component {
50 	const char *path;
51 	const char *nac;
52 	int assigned;
53 
54 	struct md_node *hv_node;
55 	TAILQ_ENTRY(component) link;
56 };
57 
58 TAILQ_HEAD(, component) components;
59 
60 struct hostbridge {
61 	const char *path;
62 
63 	uint64_t num_msi_eqs;
64 	uint64_t num_msis;
65 	uint64_t max_vpcis;
66 	TAILQ_ENTRY(hostbridge) link;
67 };
68 
69 TAILQ_HEAD(, hostbridge) hostbridges;
70 
71 struct frag {
72 	TAILQ_ENTRY(frag) link;
73 	uint64_t base;
74 };
75 
76 struct guest **guests;
77 struct console **consoles;
78 struct cpu **cpus;
79 struct device **pcie_busses;
80 struct device **network_devices;
81 struct mblock **mblocks;
82 struct ldc_endpoint **ldc_endpoints;
83 extern struct domain *domain;
84 
85 TAILQ_HEAD(, rootcomplex) rootcomplexes;
86 
87 uint64_t max_cpus;
88 bool have_cwqs;
89 bool have_rngs;
90 
91 uint64_t max_guests;
92 uint64_t max_hv_ldcs;
93 uint64_t max_guest_ldcs;
94 uint64_t md_maxsize;
95 uint64_t md_elbow_room;
96 uint64_t max_mblocks;
97 uint64_t directio_capability;
98 
99 uint64_t max_devices = 16;
100 
101 uint64_t rombase;
102 uint64_t romsize;
103 uint64_t uartbase;
104 
105 uint64_t max_page_size;
106 
107 uint64_t content_version;
108 uint64_t stick_frequency;
109 uint64_t tod_frequency;
110 uint64_t tod;
111 uint64_t erpt_pa;
112 uint64_t erpt_size;
113 
114 struct md *pri;
115 struct md *hvmd;
116 struct md *protomd;
117 
118 struct guest *guest_lookup(const char *);
119 void guest_prune_phys_io(struct guest *);
120 void guest_prune_pcie(struct guest *, struct md_node *, const char *);
121 void guest_add_vpcie(struct guest *, uint64_t);
122 void guest_fixup_phys_io(struct guest *);
123 
124 TAILQ_HEAD(, frag) free_frags = TAILQ_HEAD_INITIALIZER(free_frags);
125 TAILQ_HEAD(, cpu) free_cpus = TAILQ_HEAD_INITIALIZER(free_cpus);
126 int total_cpus;
127 TAILQ_HEAD(, mblock) free_memory = TAILQ_HEAD_INITIALIZER(free_memory);
128 uint64_t total_memory;
129 
130 struct cpu *
pri_find_cpu(uint64_t pid)131 pri_find_cpu(uint64_t pid)
132 {
133 	struct cpu *cpu = NULL;
134 
135 	TAILQ_FOREACH(cpu, &free_cpus, link) {
136 		if (cpu->pid == pid)
137 			break;
138 	}
139 
140 	return cpu;
141 }
142 
143 void
pri_link_core(struct md * md,struct md_node * node,struct core * core)144 pri_link_core(struct md *md, struct md_node *node, struct core *core)
145 {
146 	struct md_node *node2;
147 	struct md_prop *prop;
148 	struct cpu *cpu;
149 	uint64_t pid;
150 
151 	TAILQ_FOREACH(prop, &node->prop_list, link) {
152 		if (prop->tag == MD_PROP_ARC &&
153 		    strcmp(prop->name->str, "back") == 0) {
154 			node2 = prop->d.arc.node;
155 			if (strcmp(node2->name->str, "cpu") != 0) {
156 				pri_link_core(md, node2, core);
157 				continue;
158 			}
159 
160 			pid = -1;
161 			if (!md_get_prop_val(md, node2, "pid", &pid))
162 				md_get_prop_val(md, node2, "id", &pid);
163 
164 			cpu = pri_find_cpu(pid);
165 			if (cpu == NULL)
166 				errx(1, "couldn't determine core for VCPU %lld\n", pid);
167 			cpu->core = core;
168 		}
169 	}
170 }
171 
172 void
pri_add_core(struct md * md,struct md_node * node)173 pri_add_core(struct md *md, struct md_node *node)
174 {
175 	struct core *core;
176 
177 	core = xzalloc(sizeof(*core));
178 	TAILQ_INSERT_TAIL(&cores, core, link);
179 
180 	pri_link_core(md, node, core);
181 }
182 
183 void
pri_init_cores(struct md * md)184 pri_init_cores(struct md *md)
185 {
186 	struct md_node *node;
187 	const void *type;
188 	size_t len;
189 
190 	TAILQ_INIT(&cores);
191 
192 	TAILQ_FOREACH(node, &md->node_list, link) {
193 		if (strcmp(node->name->str, "tlb") == 0 &&
194 		    md_get_prop_data(md, node, "type", &type, &len) &&
195 		    strcmp(type, "data") == 0) {
196 			pri_add_core(md, node);
197 		}
198 	}
199 }
200 
201 void
pri_add_hostbridge(struct md * md,struct md_node * node)202 pri_add_hostbridge(struct md *md, struct md_node *node)
203 {
204 	struct hostbridge *hostbridge;
205 
206 	hostbridge = xzalloc(sizeof(*hostbridge));
207 	md_get_prop_str(md, node, "path", &hostbridge->path);
208 	md_get_prop_val(md, node, "#msi-eqs", &hostbridge->num_msi_eqs);
209 	md_get_prop_val(md, node, "#msi", &hostbridge->num_msis);
210 	if (!md_get_prop_val(md, node, "#max-vpcis", &hostbridge->max_vpcis))
211 		hostbridge->max_vpcis = 10;
212 	TAILQ_INSERT_TAIL(&hostbridges, hostbridge, link);
213 }
214 
215 void
pri_init_components(struct md * md)216 pri_init_components(struct md *md)
217 {
218 	struct component *component;
219 	struct md_node *node;
220 	const char *path;
221 	const char *nac;
222 	const char *type;
223 
224 	TAILQ_INIT(&components);
225 	TAILQ_INIT(&hostbridges);
226 
227 	TAILQ_FOREACH(node, &md->node_list, link) {
228 		if (strcmp(node->name->str, "component") != 0)
229 			continue;
230 
231 		if (md_get_prop_str(md, node, "assignable-path", &path)) {
232 			component = xzalloc(sizeof(*component));
233 			component->path = path;
234 			if (md_get_prop_str(md, node, "nac", &nac))
235 				component->nac = nac;
236 			else
237 				component->nac = "-";
238 			TAILQ_INSERT_TAIL(&components, component, link);
239 		}
240 
241 		if (md_get_prop_str(md, node, "type", &type) &&
242 		    strcmp(type, "hostbridge") == 0)
243 			pri_add_hostbridge(md, node);
244 	}
245 }
246 
247 void
pri_init_phys_io(struct md * md)248 pri_init_phys_io(struct md *md)
249 {
250 	struct md_node *node;
251 	const char *device_type;
252 	uint64_t cfg_handle;
253 	struct rootcomplex *rootcomplex;
254 	char *path;
255 	size_t len;
256 
257 	TAILQ_INIT(&rootcomplexes);
258 
259 	TAILQ_FOREACH(node, &md->node_list, link) {
260 		if (strcmp(node->name->str, "iodevice") == 0 &&
261 		    md_get_prop_str(md, node, "device-type", &device_type) &&
262 		    strcmp(device_type, "pciex") == 0) {
263 			if (!md_get_prop_val(md, node, "cfg-handle",
264 					     &cfg_handle))
265 				continue;
266 
267 			rootcomplex = xzalloc(sizeof(*rootcomplex));
268 			md_get_prop_val(md, node, "#msi-eqs",
269 			    &rootcomplex->num_msi_eqs);
270 			md_get_prop_val(md, node, "#msi",
271 			    &rootcomplex->num_msis);
272 			md_get_prop_data(md, node, "msi-ranges",
273 			    &rootcomplex->msi_ranges, &len);
274 			rootcomplex->num_msi_ranges =
275 			    len / (2 * sizeof(uint64_t));
276 			md_get_prop_data(md, node, "virtual-dma",
277 			    &rootcomplex->vdma_ranges, &len);
278 			rootcomplex->num_vdma_ranges =
279 			    len / (2 * sizeof(uint64_t));
280 			rootcomplex->cfghandle = cfg_handle;
281 			xasprintf(&path, "/@%llx", cfg_handle);
282 			rootcomplex->path = path;
283 			TAILQ_INSERT_TAIL(&rootcomplexes, rootcomplex, link);
284 		}
285 	}
286 }
287 
288 void
pri_add_cpu(struct md * md,struct md_node * node)289 pri_add_cpu(struct md *md, struct md_node *node)
290 {
291 	struct cpu *cpu;
292 	uint64_t mmu_page_size_list;
293 	uint64_t page_size;
294 
295 	cpu = xzalloc(sizeof(*cpu));
296 	/*
297 	 * Only UltraSPARC T1 CPUs have a "pid" property.  All other
298 	 * just have a "id" property that can be used as the physical ID.
299 	 */
300 	if (!md_get_prop_val(md, node, "pid", &cpu->pid))
301 		md_get_prop_val(md, node, "id", &cpu->pid);
302 	cpu->vid = -1;
303 	cpu->gid = -1;
304 	cpu->partid = -1;
305 	cpu->resource_id = -1;
306 	TAILQ_INSERT_TAIL(&free_cpus, cpu, link);
307 	total_cpus++;
308 
309 	mmu_page_size_list = 0x9;
310 	md_get_prop_val(md, node, "mmu-page-size-list", &mmu_page_size_list);
311 
312 	page_size = 1024;
313 	while (mmu_page_size_list) {
314 		page_size *= 8;
315 		mmu_page_size_list >>= 1;
316 	}
317 
318 	if (page_size > max_page_size)
319 		max_page_size = page_size;
320 }
321 
322 struct cpu *
pri_alloc_cpu(uint64_t pid)323 pri_alloc_cpu(uint64_t pid)
324 {
325 	struct cpu *cpu;
326 
327 	if (pid == -1 && !TAILQ_EMPTY(&free_cpus)) {
328 		cpu = TAILQ_FIRST(&free_cpus);
329 		TAILQ_REMOVE(&free_cpus, cpu, link);
330 		return cpu;
331 	}
332 
333 	TAILQ_FOREACH(cpu, &free_cpus, link) {
334 		if (cpu->pid == pid) {
335 			TAILQ_REMOVE(&free_cpus, cpu, link);
336 			return cpu;
337 		}
338 	}
339 
340 	return NULL;
341 }
342 
343 void
pri_free_cpu(struct cpu * cpu)344 pri_free_cpu(struct cpu *cpu)
345 {
346 	TAILQ_INSERT_TAIL(&free_cpus, cpu, link);
347 }
348 
349 void
pri_add_mblock(struct md * md,struct md_node * node)350 pri_add_mblock(struct md *md, struct md_node *node)
351 {
352 	struct mblock *mblock;
353 
354 	mblock = xzalloc(sizeof(*mblock));
355 	md_get_prop_val(md, node, "base", &mblock->membase);
356 	md_get_prop_val(md, node, "size", &mblock->memsize);
357 	mblock->resource_id = -1;
358 	TAILQ_INSERT_TAIL(&free_memory, mblock, link);
359 	total_memory += mblock->memsize;
360 }
361 
362 struct mblock *
pri_alloc_memory(uint64_t base,uint64_t size)363 pri_alloc_memory(uint64_t base, uint64_t size)
364 {
365 	struct mblock *mblock, *new_mblock;
366 	uint64_t memend;
367 
368 	if (base == -1 && !TAILQ_EMPTY(&free_memory)) {
369 		mblock = TAILQ_FIRST(&free_memory);
370 		base = mblock->membase;
371 	}
372 
373 	TAILQ_FOREACH(mblock, &free_memory, link) {
374 		if (base >= mblock->membase &&
375 		    base < mblock->membase + mblock->memsize) {
376 			if (base > mblock->membase) {
377 				new_mblock = xzalloc(sizeof(*new_mblock));
378 				new_mblock->membase = mblock->membase;
379 				new_mblock->memsize = base - mblock->membase;
380 				new_mblock->resource_id = -1;
381 				TAILQ_INSERT_BEFORE(mblock, new_mblock, link);
382 			}
383 
384 			memend = mblock->membase + mblock->memsize;
385 			mblock->membase = base + size;
386 			mblock->memsize = memend - mblock->membase;
387 			if (mblock->memsize == 0) {
388 				TAILQ_REMOVE(&free_memory, mblock, link);
389 				free(mblock);
390 			}
391 
392 			total_memory -= size;
393 
394 			new_mblock = xzalloc(sizeof(*new_mblock));
395 			new_mblock->membase = base;
396 			new_mblock->memsize = size;
397 			new_mblock->resource_id = -1;
398 			return new_mblock;
399 		}
400 	}
401 
402 	return NULL;
403 }
404 
405 void
pri_delete_devalias(struct md * md)406 pri_delete_devalias(struct md *md)
407 {
408 	struct md_node *node;
409 
410 	/*
411 	 * There may be multiple "devalias" nodes.  Only remove the one
412 	 * that resides under the "openboot" node.
413 	 */
414 	node = md_find_node(protomd, "openboot");
415 	assert(node);
416 	node = md_find_subnode(protomd, node, "devalias");
417 	if (node)
418 		md_delete_node(protomd, node);
419 }
420 
421 void
pri_init(struct md * md)422 pri_init(struct md *md)
423 {
424 	struct md_node *node, *node2;
425 	struct md_prop *prop;
426 	uint64_t base, size;
427 	uint64_t offset, guest_use;
428 
429 	node = md_find_node(pri, "platform");
430 	if (node == NULL)
431 		errx(1, "platform node not found");
432 
433 	md_get_prop_val(md, node, "max-cpus", &max_cpus);
434 
435 	node = md_find_node(pri, "firmware");
436 	if (node == NULL)
437 		errx(1, "firmware node not found");
438 
439 	md_get_prop_val(md, node, "max_guests", &max_guests);
440 	md_get_prop_val(md, node, "max_hv_ldcs", &max_hv_ldcs);
441 	md_get_prop_val(md, node, "max_guest_ldcs", &max_guest_ldcs);
442 	md_get_prop_val(md, node, "md_elbow_room", &md_elbow_room);
443 	md_get_prop_val(md, node, "max_mblocks", &max_mblocks);
444 	md_get_prop_val(md, node, "directio_capability", &directio_capability);
445 
446 	node = md_find_node(md, "read_only_memory");
447 	if (node == NULL)
448 		errx(1, "read_only_memory node not found");
449 	if (!md_get_prop_val(md, node, "base", &base))
450 		errx(1, "missing base property in read_only_memory node");
451 	if (!md_get_prop_val(md, node, "size", &size))
452 		errx(1, "missing size property in read_only_memory node");
453 	TAILQ_FOREACH(prop, &node->prop_list, link) {
454 		if (prop->tag == MD_PROP_ARC &&
455 		    strcmp(prop->name->str, "fwd") == 0) {
456 			node2 = prop->d.arc.node;
457 			if (!md_get_prop_val(md, node2, "guest_use",
458 			    &guest_use) || guest_use == 0)
459 				continue;
460 			if (!md_get_prop_val(md, node2, "offset", &offset) ||
461 			    !md_get_prop_val(md, node2, "size", &size))
462 				continue;
463 			rombase = base + offset;
464 			romsize = size;
465 		}
466 	}
467 	if (romsize == 0)
468 		errx(1, "no suitable firmware image found");
469 
470 	node = md_find_node(md, "platform");
471 	assert(node);
472 	md_set_prop_val(md, node, "domaining-enabled", 0x1);
473 
474 	md_write(md, "pri");
475 
476 	protomd = md_copy(md);
477 	md_find_delete_node(protomd, "components");
478 	md_find_delete_node(protomd, "domain-services");
479 	md_find_delete_node(protomd, "channel-devices");
480 	md_find_delete_node(protomd, "channel-endpoints");
481 	md_find_delete_node(protomd, "firmware");
482 	md_find_delete_node(protomd, "ldc_endpoints");
483 	md_find_delete_node(protomd, "memory-segments");
484 	pri_delete_devalias(protomd);
485 	md_collect_garbage(protomd);
486 	md_write(protomd, "protomd");
487 
488 	guests = xzalloc(max_guests * sizeof(*guests));
489 	consoles = xzalloc(max_guests * sizeof(*consoles));
490 	cpus = xzalloc(max_cpus * sizeof(*cpus));
491 	pcie_busses = xzalloc(max_devices * sizeof(*pcie_busses));
492 	network_devices = xzalloc(max_devices * sizeof(*network_devices));
493 	mblocks = xzalloc(max_mblocks * sizeof(*mblocks));
494 	ldc_endpoints = xzalloc(max_guest_ldcs * sizeof(*ldc_endpoints));
495 
496 	node = md_find_node(md, "cpus");
497 	TAILQ_FOREACH(prop, &node->prop_list, link) {
498 		if (prop->tag == MD_PROP_ARC &&
499 		    strcmp(prop->name->str, "fwd") == 0)
500 			pri_add_cpu(md, prop->d.arc.node);
501 	}
502 
503 	node = md_find_node(md, "memory");
504 	TAILQ_FOREACH(prop, &node->prop_list, link) {
505 		if (prop->tag == MD_PROP_ARC &&
506 		    strcmp(prop->name->str, "fwd") == 0)
507 			pri_add_mblock(md, prop->d.arc.node);
508 	}
509 
510 	pri_init_cores(md);
511 	pri_init_components(md);
512 	pri_init_phys_io(md);
513 }
514 
515 void
hvmd_fixup_guest(struct md * md,struct md_node * guest,struct md_node * node)516 hvmd_fixup_guest(struct md *md, struct md_node *guest, struct md_node *node)
517 {
518 	struct md_prop *prop;
519 
520 	TAILQ_FOREACH(prop, &guest->prop_list, link) {
521 		if (prop->tag == MD_PROP_ARC &&
522 		    strcmp(prop->name->str, "fwd") == 0) {
523 			if (prop->d.arc.node == node)
524 				return;
525 		}
526 	}
527 
528 	md_add_prop_arc(md, guest, "fwd", node);
529 }
530 
531 uint64_t fragsize;
532 TAILQ_HEAD(, mblock) frag_mblocks;
533 struct mblock *hvmd_mblock;
534 
535 void
hvmd_init_frag(struct md * md,struct md_node * node)536 hvmd_init_frag(struct md *md, struct md_node *node)
537 {
538 	struct frag *frag;
539 	struct mblock *mblock;
540 	uint64_t base, size;
541 
542 	md_get_prop_val(md, node, "base", &base);
543 	md_get_prop_val(md, node, "size", &size);
544 
545 	pri_alloc_memory(base, size);
546 
547 	mblock = xzalloc(sizeof(*mblock));
548 	mblock->membase = base;
549 	mblock->memsize = size;
550 	TAILQ_INSERT_TAIL(&frag_mblocks, mblock, link);
551 
552 	while (size > fragsize) {
553 		frag = xmalloc(sizeof(*frag));
554 		frag->base = base;
555 		TAILQ_INSERT_TAIL(&free_frags, frag, link);
556 		base += fragsize;
557 		size -= fragsize;
558 	}
559 }
560 
561 uint64_t
hvmd_alloc_frag(uint64_t base)562 hvmd_alloc_frag(uint64_t base)
563 {
564 	struct frag *frag = TAILQ_FIRST(&free_frags);
565 
566 	if (base != -1) {
567 		TAILQ_FOREACH(frag, &free_frags, link) {
568 			if (frag->base == base)
569 				break;
570 		}
571 	}
572 
573 	if (frag == NULL)
574 		return -1;
575 
576 	TAILQ_REMOVE(&free_frags, frag, link);
577 	base = frag->base;
578 	free(frag);
579 
580 	return base;
581 }
582 
583 void
hvmd_free_frag(uint64_t base)584 hvmd_free_frag(uint64_t base)
585 {
586 	struct frag *frag;
587 
588 	frag = xmalloc(sizeof(*frag));
589 	frag->base = base;
590 	TAILQ_INSERT_TAIL(&free_frags, frag, link);
591 }
592 
593 void
hvmd_init_mblock(struct md * md,struct md_node * node)594 hvmd_init_mblock(struct md *md, struct md_node *node)
595 {
596 	struct mblock *mblock;
597 	uint64_t resource_id;
598 	struct md_node *node2;
599 	struct md_prop *prop;
600 
601 	if (!md_get_prop_val(md, node, "resource_id", &resource_id))
602 		errx(1, "missing resource_id property in mblock node");
603 
604 	if (resource_id >= max_mblocks)
605 		errx(1, "resource_id larger than max_mblocks");
606 
607 	mblock = xzalloc(sizeof(*mblock));
608 	md_get_prop_val(md, node, "membase", &mblock->membase);
609 	md_get_prop_val(md, node, "memsize", &mblock->memsize);
610 	md_get_prop_val(md, node, "realbase", &mblock->realbase);
611 	mblock->resource_id = resource_id;
612 	mblocks[resource_id] = mblock;
613 	mblock->hv_node = node;
614 
615 	/* Fixup missing links. */
616 	TAILQ_FOREACH(prop, &node->prop_list, link) {
617 		if (prop->tag == MD_PROP_ARC &&
618 		    strcmp(prop->name->str, "back") == 0) {
619 			node2 = prop->d.arc.node;
620 			if (strcmp(node2->name->str, "guest") == 0)
621 				hvmd_fixup_guest(md, node2, node);
622 		}
623 	}
624 }
625 
626 void
hvmd_init_console(struct md * md,struct md_node * node)627 hvmd_init_console(struct md *md, struct md_node *node)
628 {
629 	struct console *console;
630 	uint64_t resource_id;
631 
632 	if (!md_get_prop_val(md, node, "resource_id", &resource_id))
633 		errx(1, "missing resource_id property in console node");
634 
635 	if (resource_id >= max_guests)
636 		errx(1, "resource_id larger than max_guests");
637 
638 	console = xzalloc(sizeof(*console));
639 	md_get_prop_val(md, node, "ino", &console->ino);
640 	md_get_prop_val(md, node, "uartbase", &console->uartbase);
641 	console->resource_id = resource_id;
642 	consoles[resource_id] = console;
643 	console->hv_node = node;
644 }
645 
646 void
hvmd_init_cpu(struct md * md,struct md_node * node)647 hvmd_init_cpu(struct md *md, struct md_node *node)
648 {
649 	struct cpu *cpu;
650 	uint64_t pid;
651 	uint64_t resource_id;
652 	struct md_node *node2;
653 	struct md_prop *prop;
654 
655 	if (!md_get_prop_val(md, node, "resource_id", &resource_id))
656 		errx(1, "missing resource_id property in cpu node");
657 
658 	if (resource_id >= max_cpus)
659 		errx(1, "resource_id larger than max-cpus");
660 
661 	if (!md_get_prop_val(md, node, "pid", &pid))
662 		errx(1, "missing pid property in cpu node");
663 
664 	cpu = pri_alloc_cpu(pid);
665 	md_get_prop_val(md, node, "vid", &cpu->vid);
666 	if (!md_get_prop_val(md, node, "gid", &cpu->gid))
667 		cpu->gid = 0;
668 	md_get_prop_val(md, node, "partid", &cpu->partid);
669 	cpu->resource_id = resource_id;
670 	cpus[resource_id] = cpu;
671 	cpu->hv_node = node;
672 
673 	/* Fixup missing links. */
674 	TAILQ_FOREACH(prop, &node->prop_list, link) {
675 		if (prop->tag == MD_PROP_ARC &&
676 		    strcmp(prop->name->str, "back") == 0) {
677 			node2 = prop->d.arc.node;
678 			if (strcmp(node2->name->str, "guest") == 0)
679 				hvmd_fixup_guest(md, node2, node);
680 		}
681 	}
682 }
683 
684 void
hvmd_init_device(struct md * md,struct md_node * node)685 hvmd_init_device(struct md *md, struct md_node *node)
686 {
687 	struct hostbridge *hostbridge;
688 	struct device *device;
689 	uint64_t resource_id;
690 	struct md_node *node2;
691 	struct md_prop *prop;
692 	char *path;
693 
694 	if (strcmp(node->name->str, "pcie_bus") != 0 &&
695 	    strcmp(node->name->str, "network_device") != 0)
696 		return;
697 
698 	if (!md_get_prop_val(md, node, "resource_id", &resource_id))
699 		errx(1, "missing resource_id property in ldc_endpoint node");
700 
701 	if (resource_id >= max_devices)
702 		errx(1, "resource_id larger than max_devices");
703 
704 	device = xzalloc(sizeof(*device));
705 	md_get_prop_val(md, node, "gid", &device->gid);
706 	md_get_prop_val(md, node, "cfghandle", &device->cfghandle);
707 	md_get_prop_val(md, node, "rcid", &device->rcid);
708 	device->resource_id = resource_id;
709 	if (strcmp(node->name->str, "pcie_bus") == 0)
710 		pcie_busses[resource_id] = device;
711 	else
712 		network_devices[resource_id] = device;
713 	device->hv_node = node;
714 
715 	/* Fixup missing links. */
716 	TAILQ_FOREACH(prop, &node->prop_list, link) {
717 		if (prop->tag == MD_PROP_ARC &&
718 		    strcmp(prop->name->str, "back") == 0) {
719 			node2 = prop->d.arc.node;
720 			if (strcmp(node2->name->str, "guest") == 0)
721 				hvmd_fixup_guest(md, node2, node);
722 		}
723 	}
724 
725 	xasprintf(&path, "/@%llx", device->cfghandle);
726 	TAILQ_FOREACH(hostbridge, &hostbridges, link) {
727 		if (strcmp(hostbridge->path, path) == 0)
728 			break;
729 	}
730 	free(path);
731 	if (hostbridge == NULL)
732 		return;
733 
734 	device->msi_eqs_per_vpci =
735 	    hostbridge->num_msi_eqs / hostbridge->max_vpcis;
736 	device->msis_per_vpci =
737 	    hostbridge->num_msis / hostbridge->max_vpcis;
738 	device->msi_base = hostbridge->num_msis;
739 
740 	device->num_msi_eqs = device->msi_eqs_per_vpci +
741 	    hostbridge->num_msi_eqs % hostbridge->max_vpcis;
742 	device->num_msis = device->msis_per_vpci +
743 	    hostbridge->num_msis % hostbridge->max_vpcis;
744 	device->msi_ranges[0] = 0;
745 	device->msi_ranges[1] = device->num_msis;
746 }
747 
748 void
hvmd_init_endpoint(struct md * md,struct md_node * node)749 hvmd_init_endpoint(struct md *md, struct md_node *node)
750 {
751 	struct ldc_endpoint *endpoint;
752 	uint64_t resource_id;
753 
754 	if (!md_get_prop_val(md, node, "resource_id", &resource_id))
755 		errx(1, "missing resource_id property in ldc_endpoint node");
756 
757 	if (resource_id >= max_guest_ldcs)
758 		errx(1, "resource_id larger than max_guest_ldcs");
759 
760 	if (ldc_endpoints[resource_id]) {
761 		/*
762 		 * Some machine descriptions seem to have duplicate
763 		 * arcs.  Fortunately, these can be easily detected
764 		 * and ignored.
765 		 */
766 		if (ldc_endpoints[resource_id]->hv_node == node)
767 			return;
768 		errx(1, "duplicate resource_id");
769 	}
770 
771 	endpoint = xzalloc(sizeof(*endpoint));
772 	endpoint->target_guest = -1;
773 	endpoint->tx_ino = -1;
774 	endpoint->rx_ino = -1;
775 	endpoint->private_svc = -1;
776 	endpoint->svc_id = -1;
777 	md_get_prop_val(md, node, "target_type", &endpoint->target_type);
778 	md_get_prop_val(md, node, "target_guest", &endpoint->target_guest);
779 	md_get_prop_val(md, node, "channel", &endpoint->channel);
780 	md_get_prop_val(md, node, "target_channel", &endpoint->target_channel);
781 	md_get_prop_val(md, node, "tx-ino", &endpoint->tx_ino);
782 	md_get_prop_val(md, node, "rx-ino", &endpoint->rx_ino);
783 	md_get_prop_val(md, node, "private_svc", &endpoint->private_svc);
784 	md_get_prop_val(md, node, "svc_id", &endpoint->svc_id);
785 	endpoint->resource_id = resource_id;
786 	ldc_endpoints[resource_id] = endpoint;
787 	endpoint->hv_node = node;
788 }
789 
790 void
hvmd_init_guest(struct md * md,struct md_node * node)791 hvmd_init_guest(struct md *md, struct md_node *node)
792 {
793 	struct guest *guest;
794 	struct md_node *node2;
795 	struct md_prop *prop;
796 	uint64_t resource_id;
797 	struct ldc_endpoint *endpoint;
798 	char *path;
799 
800 	if (!md_get_prop_val(md, node, "resource_id", &resource_id))
801 		errx(1, "missing resource_id property in guest node");
802 
803 	if (resource_id >= max_guests)
804 		errx(1, "resource_id larger than max_guests");
805 
806 	guest = xzalloc(sizeof(*guest));
807 	TAILQ_INIT(&guest->cpu_list);
808 	TAILQ_INIT(&guest->device_list);
809 	TAILQ_INIT(&guest->subdevice_list);
810 	TAILQ_INIT(&guest->mblock_list);
811 	TAILQ_INIT(&guest->endpoint_list);
812 	md_get_prop_str(md, node, "name", &guest->name);
813 	md_get_prop_val(md, node, "gid", &guest->gid);
814 	md_get_prop_val(md, node, "pid", &guest->pid);
815 	md_get_prop_val(md, node, "tod-offset", &guest->tod_offset);
816 	md_get_prop_val(md, node, "perfctraccess", &guest->perfctraccess);
817 	md_get_prop_val(md, node, "perfctrhtaccess", &guest->perfctrhtaccess);
818 	md_get_prop_val(md, node, "rngctlaccessible", &guest->rngctlaccessible);
819 	md_get_prop_val(md, node, "mdpa", &guest->mdpa);
820 	guest->resource_id = resource_id;
821 	guests[resource_id] = guest;
822 	guest->hv_node = node;
823 
824 	if (strcmp(guest->name, "primary") == 0 && guest->gid != 0)
825 		errx(1, "gid of primary domain isn't 0");
826 
827 	hvmd_alloc_frag(guest->mdpa);
828 
829 	TAILQ_FOREACH(prop, &node->prop_list, link) {
830 		if (prop->tag == MD_PROP_ARC &&
831 		    strcmp(prop->name->str, "fwd") == 0) {
832 			node2 = prop->d.arc.node;
833 			if (strcmp(node2->name->str, "console") == 0) {
834 				md_get_prop_val(md, node2, "resource_id",
835 				    &resource_id);
836 				guest->console = consoles[resource_id];
837 				consoles[resource_id]->guest = guest;
838 			}
839 			if (strcmp(node2->name->str, "cpu") == 0) {
840 				md_get_prop_val(md, node2, "resource_id",
841 				    &resource_id);
842 				TAILQ_INSERT_TAIL(&guest->cpu_list,
843 				    cpus[resource_id], link);
844 				cpus[resource_id]->guest = guest;
845 			}
846 			if (strcmp(node2->name->str, "pcie_bus") == 0) {
847 				md_get_prop_val(md, node2, "resource_id",
848 				    &resource_id);
849 				TAILQ_INSERT_TAIL(&guest->device_list,
850 				    pcie_busses[resource_id], link);
851 				pcie_busses[resource_id]->guest = guest;
852 			}
853 			if (strcmp(node2->name->str, "network_device") == 0) {
854 				md_get_prop_val(md, node2, "resource_id",
855 				    &resource_id);
856 				TAILQ_INSERT_TAIL(&guest->device_list,
857 				    network_devices[resource_id], link);
858 				network_devices[resource_id]->guest = guest;
859 			}
860 			if (strcmp(node2->name->str, "mblock") == 0) {
861 				md_get_prop_val(md, node2, "resource_id",
862 				    &resource_id);
863 				TAILQ_INSERT_TAIL(&guest->mblock_list,
864 				    mblocks[resource_id], link);
865 				mblocks[resource_id]->guest = guest;
866 			}
867 			if (strcmp(node2->name->str, "ldc_endpoint") == 0) {
868 				md_get_prop_val(md, node2, "resource_id",
869 				    &resource_id);
870 				TAILQ_INSERT_TAIL(&guest->endpoint_list,
871 				    ldc_endpoints[resource_id], link);
872 				ldc_endpoints[resource_id]->guest = guest;
873 			}
874 		}
875 	}
876 
877 	TAILQ_FOREACH(endpoint, &guest->endpoint_list, link) {
878 		if (endpoint->channel >= guest->endpoint_id)
879 			guest->endpoint_id = endpoint->channel + 1;
880 	}
881 
882 	xasprintf(&path, "%s.md", guest->name);
883 	guest->md = md_read(path);
884 
885 	if (guest->md == NULL)
886 		err(1, "unable to get guest MD");
887 
888 	free(path);
889 }
890 
891 void
hvmd_init(struct md * md)892 hvmd_init(struct md *md)
893 {
894 	struct md_node *node;
895 	struct md_prop *prop;
896 
897 	node = md_find_node(md, "root");
898 	md_get_prop_val(md, node, "content-version", &content_version);
899 	md_get_prop_val(md, node, "stick-frequency", &stick_frequency);
900 	md_get_prop_val(md, node, "tod-frequency", &tod_frequency);
901 	md_get_prop_val(md, node, "tod", &tod);
902 	md_get_prop_val(md, node, "erpt-pa", &erpt_pa);
903 	md_get_prop_val(md, node, "erpt-size", &erpt_size);
904 	md_get_prop_val(md, node, "uartbase", &uartbase);
905 
906 	node = md_find_node(md, "platform");
907 	if (node)
908 		md_get_prop_val(md, node, "stick-frequency", &stick_frequency);
909 
910 	node = md_find_node(md, "hvmd_mblock");
911 	if (node) {
912 		hvmd_mblock = xzalloc(sizeof(*hvmd_mblock));
913 		md_get_prop_val(md, node, "base", &hvmd_mblock->membase);
914 		md_get_prop_val(md, node, "size", &hvmd_mblock->memsize);
915 		md_get_prop_val(md, node, "md_maxsize", &md_maxsize);
916 		pri_alloc_memory(hvmd_mblock->membase, hvmd_mblock->memsize);
917 	}
918 
919 	node = md_find_node(md, "frag_space");
920 	md_get_prop_val(md, node, "fragsize", &fragsize);
921 	if (fragsize == 0)
922 		fragsize = md_maxsize;
923 	TAILQ_INIT(&frag_mblocks);
924 	TAILQ_FOREACH(prop, &node->prop_list, link) {
925 		if (prop->tag == MD_PROP_ARC &&
926 		    strcmp(prop->name->str, "fwd") == 0)
927 			hvmd_init_frag(md, prop->d.arc.node);
928 	}
929 	pri_alloc_memory(0, fragsize);
930 
931 	node = md_find_node(md, "consoles");
932 	TAILQ_FOREACH(prop, &node->prop_list, link) {
933 		if (prop->tag == MD_PROP_ARC &&
934 		    strcmp(prop->name->str, "fwd") == 0)
935 			hvmd_init_console(md, prop->d.arc.node);
936 	}
937 
938 	node = md_find_node(md, "cpus");
939 	TAILQ_FOREACH(prop, &node->prop_list, link) {
940 		if (prop->tag == MD_PROP_ARC &&
941 		    strcmp(prop->name->str, "fwd") == 0)
942 			hvmd_init_cpu(md, prop->d.arc.node);
943 	}
944 
945 	have_cwqs = (md_find_node(md, "cwqs") != NULL);
946 	have_rngs = (md_find_node(md, "rngs") != NULL);
947 
948 	node = md_find_node(md, "devices");
949 	TAILQ_FOREACH(prop, &node->prop_list, link) {
950 		if (prop->tag == MD_PROP_ARC &&
951 		    strcmp(prop->name->str, "fwd") == 0)
952 			hvmd_init_device(md, prop->d.arc.node);
953 	}
954 
955 	node = md_find_node(md, "memory");
956 	TAILQ_FOREACH(prop, &node->prop_list, link) {
957 		if (prop->tag == MD_PROP_ARC &&
958 		    strcmp(prop->name->str, "fwd") == 0)
959 			hvmd_init_mblock(md, prop->d.arc.node);
960 	}
961 
962 	node = md_find_node(md, "ldc_endpoints");
963 	TAILQ_FOREACH(prop, &node->prop_list, link) {
964 		if (prop->tag == MD_PROP_ARC &&
965 		    strcmp(prop->name->str, "fwd") == 0)
966 			hvmd_init_endpoint(md, prop->d.arc.node);
967 	}
968 
969 	node = md_find_node(md, "guests");
970 	TAILQ_FOREACH(prop, &node->prop_list, link) {
971 		if (prop->tag == MD_PROP_ARC &&
972 		    strcmp(prop->name->str, "fwd") == 0)
973 			hvmd_init_guest(md, prop->d.arc.node);
974 	}
975 
976 	hvmd_alloc_frag(-1);
977 }
978 
979 void
hvmd_finalize_cpu(struct md * md,struct cpu * cpu)980 hvmd_finalize_cpu(struct md *md, struct cpu *cpu)
981 {
982 	struct md_node *parent;
983 	struct md_node *node;
984 	int i;
985 
986 	for (i = 0; i < MAX_STRANDS_PER_CORE; i++) {
987 		if (cpu->core->guests[i] == cpu->guest) {
988 			cpu->partid = i + 1;
989 			break;
990 		}
991 		if (cpu->core->guests[i] == NULL) {
992 			cpu->core->guests[i] = cpu->guest;
993 			cpu->partid = i + 1;
994 			break;
995 		}
996 	}
997 
998 	parent = md_find_node(md, "cpus");
999 	assert(parent);
1000 
1001 	node = md_add_node(md, "cpu");
1002 	md_link_node(md, parent, node);
1003 	md_add_prop_val(md, node, "pid", cpu->pid);
1004 	md_add_prop_val(md, node, "vid", cpu->vid);
1005 	md_add_prop_val(md, node, "gid", cpu->gid);
1006 	md_add_prop_val(md, node, "partid", cpu->partid);
1007 	md_add_prop_val(md, node, "resource_id", cpu->resource_id);
1008 	cpu->hv_node = node;
1009 }
1010 
1011 void
hvmd_finalize_cpus(struct md * md)1012 hvmd_finalize_cpus(struct md *md)
1013 {
1014 	struct md_node *parent;
1015 	struct md_node *node;
1016 	uint64_t resource_id;
1017 
1018 	parent = md_find_node(md, "root");
1019 	assert(parent);
1020 
1021 	node = md_add_node(md, "cpus");
1022 	md_link_node(md, parent, node);
1023 
1024 	for (resource_id = 0; resource_id < max_cpus; resource_id++) {
1025 		if (cpus[resource_id])
1026 			hvmd_finalize_cpu(md, cpus[resource_id]);
1027 	}
1028 }
1029 
1030 void
hvmd_finalize_maus(struct md * md)1031 hvmd_finalize_maus(struct md *md)
1032 {
1033 	struct md_node *parent;
1034 	struct md_node *node;
1035 	struct md_node *child;
1036 	int i;
1037 
1038 	parent = md_find_node(md, "root");
1039 	assert(parent);
1040 
1041 	node = md_add_node(md, "maus");
1042 	md_link_node(md, parent, node);
1043 
1044 	if (have_cwqs) {
1045 		node = md_add_node(md, "cwqs");
1046 		md_link_node(md, parent, node);
1047 	}
1048 
1049 	if (have_rngs) {
1050 		node = md_add_node(md, "rngs");
1051 		md_link_node(md, parent, node);
1052 		child = md_add_node(md, "rng");
1053 		md_link_node(md, node, child);
1054 		for (i = 0; i < max_cpus; i++) {
1055 			if (cpus[i])
1056 				md_link_node(md, cpus[i]->hv_node, child);
1057 		}
1058 	}
1059 }
1060 
1061 void
hvmd_finalize_device(struct md * md,struct device * device,const char * name)1062 hvmd_finalize_device(struct md *md, struct device *device, const char *name)
1063 {
1064 	struct md_node *parent;
1065 	struct md_node *node;
1066 
1067 	parent = md_find_node(md, "devices");
1068 	assert(parent);
1069 
1070 	node = md_add_node(md, name);
1071 	md_link_node(md, parent, node);
1072 	md_add_prop_val(md, node, "resource_id", device->resource_id);
1073 	md_add_prop_val(md, node, "cfghandle", device->cfghandle);
1074 	md_add_prop_val(md, node, "gid", device->gid);
1075 	md_add_prop_val(md, node, "rcid", device->rcid);
1076 	device->hv_node = node;
1077 }
1078 
1079 void
hvmd_finalize_pcie_device(struct md * md,struct device * device)1080 hvmd_finalize_pcie_device(struct md *md, struct device *device)
1081 {
1082 	struct rootcomplex *rootcomplex;
1083 	struct md_node *node, *child, *parent;
1084 	struct component *component;
1085 	struct subdevice *subdevice;
1086 	uint64_t resource_id = 0;
1087 	char *path;
1088 
1089 	hvmd_finalize_device(md, device,
1090 	    device->virtual ? "virtual_pcie_bus" : "pcie_bus");
1091 	node = device->hv_node;
1092 
1093 	if (!directio_capability)
1094 		return;
1095 
1096 	TAILQ_FOREACH(rootcomplex, &rootcomplexes, link) {
1097 		if (rootcomplex->cfghandle == device->cfghandle)
1098 			break;
1099 	}
1100 	if (rootcomplex == NULL)
1101 		return;
1102 
1103 	md_add_prop_val(md, node, "allow_bypass", 0);
1104 
1105 	md_add_prop_val(md, node, "#msi-eqs", device->num_msi_eqs);
1106 	md_add_prop_val(md, node, "#msi", device->num_msis);
1107 	md_add_prop_data(md, node, "msi-ranges", (void *)device->msi_ranges,
1108 	    sizeof(device->msi_ranges));
1109 	md_add_prop_data(md, node, "virtual-dma", rootcomplex->vdma_ranges,
1110 	    rootcomplex->num_vdma_ranges * 2 * sizeof(uint64_t));
1111 
1112 	xasprintf(&path, "/@%llx", device->cfghandle);
1113 
1114 	if (!device->virtual) {
1115 		parent = md_add_node(md, "pcie_assignable_devices");
1116 		md_link_node(md, node, parent);
1117 
1118 		TAILQ_FOREACH(component, &components, link) {
1119 			const char *path2 = component->path;
1120 
1121 			if (strncmp(path, path2, strlen(path)) != 0)
1122 				continue;
1123 
1124 			path2 = strchr(path2, '/');
1125 			if (path2 == NULL || *path2++ == 0)
1126 				continue;
1127 			path2 = strchr(path2, '/');
1128 			if (path2 == NULL || *path2++ == 0)
1129 				continue;
1130 
1131 			child = md_add_node(md, "pcie_device");
1132 			md_link_node(md, parent, child);
1133 
1134 			md_add_prop_str(md, child, "path", path2);
1135 			md_add_prop_val(md, child, "resource_id", resource_id);
1136 			resource_id++;
1137 
1138 			component->hv_node = child;
1139 		}
1140 	}
1141 
1142 	parent = md_add_node(md, "pcie_assigned_devices");
1143 	md_link_node(md, node, parent);
1144 
1145 	TAILQ_FOREACH(subdevice, &device->guest->subdevice_list, link) {
1146 		if (strncmp(path, subdevice->path, strlen(path)) != 0)
1147 			continue;
1148 		TAILQ_FOREACH(component, &components, link) {
1149 			if (strcmp(subdevice->path, component->path) == 0)
1150 				md_link_node(md, parent, component->hv_node);
1151 		}
1152 	}
1153 
1154 	free(path);
1155 }
1156 
1157 void
hvmd_finalize_devices(struct md * md)1158 hvmd_finalize_devices(struct md *md)
1159 {
1160 	struct md_node *parent;
1161 	struct md_node *node;
1162 	uint64_t resource_id;
1163 
1164 	parent = md_find_node(md, "root");
1165 	assert(parent);
1166 
1167 	node = md_add_node(md, "devices");
1168 	md_link_node(md, parent, node);
1169 
1170 	for (resource_id = 0; resource_id < max_devices; resource_id++) {
1171 		if (pcie_busses[resource_id])
1172 			hvmd_finalize_pcie_device(md, pcie_busses[resource_id]);
1173 	}
1174 	for (resource_id = 0; resource_id < max_devices; resource_id++) {
1175 		if (network_devices[resource_id])
1176 			hvmd_finalize_device(md, network_devices[resource_id],
1177 			    "network_device");
1178 	}
1179 }
1180 
1181 void
hvmd_finalize_mblock(struct md * md,struct mblock * mblock)1182 hvmd_finalize_mblock(struct md *md, struct mblock *mblock)
1183 {
1184 	struct md_node *parent;
1185 	struct md_node *node;
1186 
1187 	parent = md_find_node(md, "memory");
1188 	assert(parent);
1189 
1190 	node = md_add_node(md, "mblock");
1191 	md_link_node(md, parent, node);
1192 	md_add_prop_val(md, node, "membase", mblock->membase);
1193 	md_add_prop_val(md, node, "memsize", mblock->memsize);
1194 	md_add_prop_val(md, node, "realbase", mblock->realbase);
1195 	md_add_prop_val(md, node, "resource_id", mblock->resource_id);
1196 	mblock->hv_node = node;
1197 }
1198 
1199 void
hvmd_finalize_memory(struct md * md)1200 hvmd_finalize_memory(struct md *md)
1201 {
1202 	struct md_node *parent;
1203 	struct md_node *node;
1204 	uint64_t resource_id;
1205 
1206 	parent = md_find_node(md, "root");
1207 	assert(parent);
1208 
1209 	node = md_add_node(md, "memory");
1210 	md_link_node(md, parent, node);
1211 
1212 	for (resource_id = 0; resource_id < max_mblocks; resource_id++) {
1213 		if (mblocks[resource_id])
1214 			hvmd_finalize_mblock(md, mblocks[resource_id]);
1215 	}
1216 }
1217 
1218 void
hvmd_finalize_endpoint(struct md * md,struct ldc_endpoint * endpoint)1219 hvmd_finalize_endpoint(struct md *md, struct ldc_endpoint *endpoint)
1220 {
1221 	struct md_node *parent;
1222 	struct md_node *node;
1223 
1224 	parent = md_find_node(md, "ldc_endpoints");
1225 	assert(parent);
1226 
1227 	node = md_add_node(md, "ldc_endpoint");
1228 	md_link_node(md, parent, node);
1229 	md_add_prop_val(md, node, "resource_id", endpoint->resource_id);
1230 	md_add_prop_val(md, node, "target_type", endpoint->target_type);
1231 	md_add_prop_val(md, node, "channel", endpoint->channel);
1232 	if (endpoint->target_guest != -1)
1233 		md_add_prop_val(md, node, "target_guest",
1234 		    endpoint->target_guest);
1235 	md_add_prop_val(md, node, "target_channel", endpoint->target_channel);
1236 	if (endpoint->tx_ino != -1)
1237 		md_add_prop_val(md, node, "tx-ino", endpoint->tx_ino);
1238 	if (endpoint->rx_ino != -1)
1239 		md_add_prop_val(md, node, "rx-ino", endpoint->rx_ino);
1240 	if (endpoint->private_svc != -1)
1241 		md_add_prop_val(md, node, "private_svc",
1242 		    endpoint->private_svc);
1243 	if (endpoint->svc_id != -1)
1244 		md_add_prop_val(md, node, "svc_id", endpoint->svc_id);
1245 	endpoint->hv_node = node;
1246 }
1247 
1248 void
hvmd_finalize_endpoints(struct md * md)1249 hvmd_finalize_endpoints(struct md *md)
1250 {
1251 	struct md_node *parent;
1252 	struct md_node *node;
1253 	uint64_t resource_id;
1254 
1255 	parent = md_find_node(md, "root");
1256 	assert(parent);
1257 
1258 	node = md_add_node(md, "ldc_endpoints");
1259 	md_link_node(md, parent, node);
1260 
1261 	for (resource_id = 0; resource_id < max_guest_ldcs; resource_id++) {
1262 		if (ldc_endpoints[resource_id])
1263 			hvmd_finalize_endpoint(md, ldc_endpoints[resource_id]);
1264 	}
1265 }
1266 
1267 void
hvmd_finalize_console(struct md * md,struct console * console)1268 hvmd_finalize_console(struct md *md, struct console *console)
1269 {
1270 	struct md_node *parent;
1271 	struct md_node *node;
1272 	struct ldc_endpoint *endpoint;
1273 
1274 	parent = md_find_node(md, "consoles");
1275 	assert(parent);
1276 
1277 	node = md_add_node(md, "console");
1278 	md_link_node(md, parent, node);
1279 	md_add_prop_val(md, node, "resource_id", console->resource_id);
1280 	md_add_prop_val(md, node, "ino", console->ino);
1281 	console->hv_node = node;
1282 
1283 	if (console->uartbase) {
1284 		md_add_prop_val(md, node, "uartbase", console->uartbase);
1285 		return;
1286 	}
1287 
1288 	TAILQ_FOREACH(endpoint, &console->guest->endpoint_list, link) {
1289 		if (endpoint->rx_ino == console->ino) {
1290 			md_link_node(md, node, endpoint->hv_node);
1291 			break;
1292 		}
1293 	}
1294 }
1295 
1296 void
hvmd_finalize_consoles(struct md * md)1297 hvmd_finalize_consoles(struct md *md)
1298 {
1299 	struct md_node *parent;
1300 	struct md_node *node;
1301 	uint64_t resource_id;
1302 
1303 	parent = md_find_node(md, "root");
1304 	assert(parent);
1305 
1306 	node = md_add_node(md, "consoles");
1307 	md_link_node(md, parent, node);
1308 
1309 	for (resource_id = 0; resource_id < max_guests; resource_id++) {
1310 		if (consoles[resource_id])
1311 			hvmd_finalize_console(md, consoles[resource_id]);
1312 	}
1313 }
1314 
1315 void
hvmd_finalize_guest(struct md * md,struct guest * guest)1316 hvmd_finalize_guest(struct md *md, struct guest *guest)
1317 {
1318 	struct md_node *node;
1319 	struct md_node *parent;
1320 	struct cpu *cpu;
1321 	struct device *device;
1322 	struct mblock *mblock;
1323 	struct ldc_endpoint *endpoint;
1324 
1325 	parent = md_find_node(md, "guests");
1326 	assert(parent);
1327 
1328 	node = md_add_node(md, "guest");
1329 	md_link_node(md, parent, node);
1330 	md_add_prop_str(md, node, "name", guest->name);
1331 	md_add_prop_val(md, node, "gid", guest->gid);
1332 	md_add_prop_val(md, node, "pid", guest->pid);
1333 	md_add_prop_val(md, node, "resource_id", guest->resource_id);
1334 	md_add_prop_val(md, node, "tod-offset", guest->tod_offset);
1335 	md_add_prop_val(md, node, "reset-reason", 0);
1336 	md_add_prop_val(md, node, "perfctraccess", guest->perfctraccess);
1337 	md_add_prop_val(md, node, "perfctrhtaccess", guest->perfctrhtaccess);
1338 	md_add_prop_val(md, node, "rngctlaccessible", guest->rngctlaccessible);
1339 	md_add_prop_val(md, node, "diagpriv", 0);
1340 	md_add_prop_val(md, node, "mdpa", guest->mdpa);
1341 	md_add_prop_val(md, node, "rombase", rombase);
1342 	md_add_prop_val(md, node, "romsize", romsize);
1343 	md_add_prop_val(md, node, "uartbase", uartbase);
1344 	guest->hv_node = node;
1345 
1346 	node = md_add_node(md, "virtual_devices");
1347 	md_link_node(md, guest->hv_node, node);
1348 	md_add_prop_val(md, node, "cfghandle", 0x100);
1349 
1350 	node = md_add_node(md, "channel_devices");
1351 	md_link_node(md, guest->hv_node, node);
1352 	md_add_prop_val(md, node, "cfghandle", 0x200);
1353 
1354 	if (guest->console)
1355 		md_link_node(md, guest->hv_node, guest->console->hv_node);
1356 	TAILQ_FOREACH(cpu, &guest->cpu_list, link)
1357 		md_link_node(md, guest->hv_node, cpu->hv_node);
1358 	TAILQ_FOREACH(device, &guest->device_list, link)
1359 		md_link_node(md, guest->hv_node, device->hv_node);
1360 	TAILQ_FOREACH(mblock, &guest->mblock_list, link)
1361 		md_link_node(md, guest->hv_node, mblock->hv_node);
1362 	TAILQ_FOREACH(endpoint, &guest->endpoint_list, link)
1363 		md_link_node(md, guest->hv_node, endpoint->hv_node);
1364 }
1365 
1366 void
hvmd_finalize_guests(struct md * md)1367 hvmd_finalize_guests(struct md *md)
1368 {
1369 	struct md_node *parent;
1370 	struct md_node *node;
1371 	uint64_t resource_id;
1372 
1373 	parent = md_find_node(md, "root");
1374 	assert(parent);
1375 
1376 	node = md_add_node(md, "guests");
1377 	md_link_node(md, parent, node);
1378 
1379 	for (resource_id = 0; resource_id < max_guests; resource_id++) {
1380 		if (guests[resource_id])
1381 			hvmd_finalize_guest(md, guests[resource_id]);
1382 	}
1383 }
1384 
1385 void
hvmd_finalize(void)1386 hvmd_finalize(void)
1387 {
1388 	struct md *md;
1389 	struct md_node *node;
1390 	struct md_node *parent;
1391 	struct mblock *mblock;
1392 
1393 	md = md_alloc();
1394 	node = md_add_node(md, "root");
1395 	md_add_prop_val(md, node, "content-version", content_version);
1396 	if (content_version <= 0x100000000) {
1397 		md_add_prop_val(md, node, "stick-frequency", stick_frequency);
1398 		if (tod_frequency != 0)
1399 			md_add_prop_val(md, node, "tod-frequency",
1400 			    tod_frequency);
1401 		if (tod != 0)
1402 			md_add_prop_val(md, node, "tod", tod);
1403 		if (erpt_pa != 0)
1404 			md_add_prop_val(md, node, "erpt-pa", erpt_pa);
1405 		if (erpt_size != 0)
1406 			md_add_prop_val(md, node, "erpt-size", erpt_size);
1407 
1408 		parent = node;
1409 		node = md_add_node(md, "platform");
1410 		md_link_node(md, parent, node);
1411 		md_add_prop_val(md, node, "stick-frequency", stick_frequency);
1412 	}
1413 
1414 	parent = md_find_node(md, "root");
1415 	assert(parent);
1416 
1417 	node = md_add_node(md, "frag_space");
1418 	md_link_node(md, parent, node);
1419 	md_add_prop_val(md, node, "fragsize", fragsize);
1420 
1421 	parent = md_find_node(md, "frag_space");
1422 	TAILQ_FOREACH(mblock, &frag_mblocks, link) {
1423 		node = md_add_node(md, "frag_mblock");
1424 		md_link_node(md, parent, node);
1425 		md_add_prop_val(md, node, "base", mblock->membase);
1426 		md_add_prop_val(md, node, "size", mblock->memsize);
1427 	}
1428 
1429 	if (hvmd_mblock) {
1430 		parent = md_find_node(md, "root");
1431 		assert(parent);
1432 
1433 		node = md_add_node(md, "hvmd_mblock");
1434 		md_link_node(md, parent, node);
1435 		md_add_prop_val(md, node, "base", hvmd_mblock->membase);
1436 		md_add_prop_val(md, node, "size", hvmd_mblock->memsize);
1437 		md_add_prop_val(md, node, "md_maxsize", md_maxsize);
1438 	}
1439 
1440 	hvmd_finalize_cpus(md);
1441 	hvmd_finalize_maus(md);
1442 	hvmd_finalize_devices(md);
1443 	hvmd_finalize_memory(md);
1444 	hvmd_finalize_endpoints(md);
1445 	hvmd_finalize_consoles(md);
1446 	hvmd_finalize_guests(md);
1447 
1448 	md_write(md, "hv.md");
1449 }
1450 
1451 struct ldc_endpoint *
hvmd_add_endpoint(struct guest * guest)1452 hvmd_add_endpoint(struct guest *guest)
1453 {
1454 	struct ldc_endpoint *endpoint;
1455 	uint64_t resource_id;
1456 
1457 	for (resource_id = 0; resource_id < max_guest_ldcs; resource_id++)
1458 		if (ldc_endpoints[resource_id] == NULL)
1459 			break;
1460 	assert(resource_id < max_guest_ldcs);
1461 
1462 	endpoint = xzalloc(sizeof(*endpoint));
1463 	endpoint->target_guest = -1;
1464 	endpoint->tx_ino = -1;
1465 	endpoint->rx_ino = -1;
1466 	endpoint->private_svc = -1;
1467 	endpoint->svc_id = -1;
1468 	endpoint->resource_id = resource_id;
1469 	ldc_endpoints[resource_id] = endpoint;
1470 
1471 	TAILQ_INSERT_TAIL(&guest->endpoint_list, endpoint, link);
1472 	endpoint->guest = guest;
1473 
1474 	return endpoint;
1475 }
1476 
1477 struct console *
hvmd_add_console(struct guest * guest)1478 hvmd_add_console(struct guest *guest)
1479 {
1480 	struct guest *primary;
1481 	struct console *console;
1482 	uint64_t resource_id;
1483 	uint64_t client_channel, server_channel;
1484 
1485 	primary = guest_lookup("primary");
1486 	client_channel = guest->endpoint_id++;
1487 	server_channel = primary->endpoint_id++;
1488 
1489 	for (resource_id = 0; resource_id < max_guests; resource_id++)
1490 		if (consoles[resource_id] == NULL)
1491 			break;
1492 	assert(resource_id < max_guests);
1493 
1494 	console = xzalloc(sizeof(*console));
1495 	console->ino = 0x11;
1496 	console->resource_id = resource_id;
1497 	consoles[resource_id] = console;
1498 
1499 	console->client_endpoint = hvmd_add_endpoint(guest);
1500 	console->client_endpoint->tx_ino = 0x11;
1501 	console->client_endpoint->rx_ino = 0x11;
1502 	console->client_endpoint->target_type = LDC_GUEST;
1503 	console->client_endpoint->target_guest = primary->gid;
1504 	console->client_endpoint->target_channel = server_channel;
1505 	console->client_endpoint->channel = client_channel;
1506 	console->client_endpoint->private_svc = LDC_CONSOLE_SVC;
1507 
1508 	console->server_endpoint = hvmd_add_endpoint(primary);
1509 	console->server_endpoint->tx_ino = 2 * server_channel;
1510 	console->server_endpoint->rx_ino = 2 * server_channel + 1;
1511 	console->server_endpoint->target_type = LDC_GUEST;
1512 	console->server_endpoint->target_guest = guest->gid;
1513 	console->server_endpoint->channel = server_channel;
1514 	console->server_endpoint->target_channel = client_channel;
1515 
1516 	guest->console = console;
1517 	console->guest = guest;
1518 
1519 	return console;
1520 }
1521 
1522 void
hvmd_add_domain_services(struct guest * guest)1523 hvmd_add_domain_services(struct guest *guest)
1524 {
1525 	struct guest *primary;
1526 	struct ldc_channel *ds = &guest->domain_services;
1527 	uint64_t client_channel, server_channel;
1528 
1529 	primary = guest_lookup("primary");
1530 	client_channel = guest->endpoint_id++;
1531 	server_channel = primary->endpoint_id++;
1532 
1533 	ds->client_endpoint = hvmd_add_endpoint(guest);
1534 	ds->client_endpoint->tx_ino = 2 * client_channel;
1535 	ds->client_endpoint->rx_ino = 2 * client_channel + 1;
1536 	ds->client_endpoint->target_type = LDC_GUEST;
1537 	ds->client_endpoint->target_guest = primary->gid;
1538 	ds->client_endpoint->target_channel = server_channel;
1539 	ds->client_endpoint->channel = client_channel;
1540 
1541 	ds->server_endpoint = hvmd_add_endpoint(primary);
1542 	ds->server_endpoint->tx_ino = 2 * server_channel;
1543 	ds->server_endpoint->rx_ino = 2 * server_channel + 1;
1544 	ds->server_endpoint->target_type = LDC_GUEST;
1545 	ds->server_endpoint->target_guest = guest->gid;
1546 	ds->server_endpoint->channel = server_channel;
1547 	ds->server_endpoint->target_channel = client_channel;
1548 }
1549 
1550 struct ldc_channel *
hvmd_add_vio(struct guest * guest)1551 hvmd_add_vio(struct guest *guest)
1552 {
1553 	struct guest *primary;
1554 	struct ldc_channel *lc = &guest->vio[guest->num_vios++];
1555 	uint64_t client_channel, server_channel;
1556 
1557 	primary = guest_lookup("primary");
1558 	client_channel = guest->endpoint_id++;
1559 	server_channel = primary->endpoint_id++;
1560 
1561 	lc->client_endpoint = hvmd_add_endpoint(guest);
1562 	lc->client_endpoint->tx_ino = 2 * client_channel;
1563 	lc->client_endpoint->rx_ino = 2 * client_channel + 1;
1564 	lc->client_endpoint->target_type = LDC_GUEST;
1565 	lc->client_endpoint->target_guest = primary->gid;
1566 	lc->client_endpoint->target_channel = server_channel;
1567 	lc->client_endpoint->channel = client_channel;
1568 
1569 	lc->server_endpoint = hvmd_add_endpoint(primary);
1570 	lc->server_endpoint->tx_ino = 2 * server_channel;
1571 	lc->server_endpoint->rx_ino = 2 * server_channel + 1;
1572 	lc->server_endpoint->target_type = LDC_GUEST;
1573 	lc->server_endpoint->target_guest = guest->gid;
1574 	lc->server_endpoint->channel = server_channel;
1575 	lc->server_endpoint->target_channel = client_channel;
1576 
1577 	return lc;
1578 }
1579 
1580 struct guest *
hvmd_add_guest(const char * name)1581 hvmd_add_guest(const char *name)
1582 {
1583 	struct guest *guest;
1584 	uint64_t resource_id;
1585 
1586 	for (resource_id = 0; resource_id < max_guests; resource_id++)
1587 		if (guests[resource_id] == NULL)
1588 			break;
1589 	assert(resource_id < max_guests);
1590 
1591 	guest = xzalloc(sizeof(*guest));
1592 	TAILQ_INIT(&guest->cpu_list);
1593 	TAILQ_INIT(&guest->device_list);
1594 	TAILQ_INIT(&guest->subdevice_list);
1595 	TAILQ_INIT(&guest->mblock_list);
1596 	TAILQ_INIT(&guest->endpoint_list);
1597 	guests[resource_id] = guest;
1598 	guest->name = name;
1599 	guest->gid = resource_id;
1600 	guest->pid = resource_id + 1;
1601 	guest->resource_id = resource_id;
1602 	guest->mdpa = hvmd_alloc_frag(-1);
1603 
1604 	hvmd_add_console(guest);
1605 	hvmd_add_domain_services(guest);
1606 
1607 	return guest;
1608 }
1609 
1610 struct md_node *
guest_add_channel_endpoints(struct guest * guest)1611 guest_add_channel_endpoints(struct guest *guest)
1612 {
1613 	struct md *md = guest->md;
1614 	struct md_node *parent;
1615 	struct md_node *node;
1616 
1617 	parent = md_find_node(md, "root");
1618 	assert(parent);
1619 
1620 	node = md_add_node(md, "channel-endpoints");
1621 	md_link_node(md, parent, node);
1622 
1623 	return node;
1624 }
1625 
1626 struct md_node *
guest_add_endpoint(struct guest * guest,uint64_t id)1627 guest_add_endpoint(struct guest *guest, uint64_t id)
1628 {
1629 	struct md *md = guest->md;
1630 	struct md_node *parent;
1631 	struct md_node *node;
1632 
1633 	parent = md_find_node(md, "channel-endpoints");
1634 	if (parent == NULL)
1635 		parent = guest_add_channel_endpoints(guest);
1636 
1637 	node = md_add_node(md, "channel-endpoint");
1638 	md_link_node(md, parent, node);
1639 	md_add_prop_val(md, node, "id", id);
1640 	md_add_prop_val(md, node, "tx-ino", 2 * id);
1641 	md_add_prop_val(md, node, "rx-ino", 2 * id + 1);
1642 
1643 	return node;
1644 }
1645 
1646 struct md_node *
guest_add_vcc(struct guest * guest)1647 guest_add_vcc(struct guest *guest)
1648 {
1649 	const char compatible[] = "SUNW,sun4v-virtual-console-concentrator";
1650 	struct md *md = guest->md;
1651 	struct md_node *parent;
1652 	struct md_node *node;
1653 
1654 	parent = md_find_node(md, "channel-devices");
1655 	assert(parent != NULL);
1656 
1657 	node = md_add_node(md, "virtual-device");
1658 	md_link_node(md, parent, node);
1659 	md_add_prop_str(md, node, "name", "virtual-console-concentrator");
1660 	md_add_prop_data(md, node, "compatible", compatible,
1661 	    sizeof(compatible));
1662 	md_add_prop_str(md, node, "device_type", "vcc");
1663 	md_add_prop_val(md, node, "cfg-handle", 0x0);
1664 	md_add_prop_str(md, node, "svc-name", "primary-vcc0");
1665 
1666 	return node;
1667 }
1668 
1669 struct md_node *
guest_find_vcc(struct guest * guest)1670 guest_find_vcc(struct guest *guest)
1671 {
1672 	struct md *md = guest->md;
1673 	struct md_node *node, *node2;
1674 	struct md_prop *prop;
1675 	const char *name;
1676 
1677 	node = md_find_node(md, "channel-devices");
1678 	assert(node != NULL);
1679 
1680 	TAILQ_FOREACH(prop, &node->prop_list, link) {
1681 		if (prop->tag == MD_PROP_ARC &&
1682 		    strcmp(prop->name->str, "fwd") == 0) {
1683 			node2 = prop->d.arc.node;
1684 			if (!md_get_prop_str(md, node2, "name", &name))
1685 				continue;
1686 			if (strcmp(name, "virtual-console-concentrator") == 0)
1687 				return node2;
1688 		}
1689 	}
1690 
1691 	return NULL;
1692 }
1693 
1694 struct md_node *
guest_add_vcc_port(struct guest * guest,struct md_node * vcc,const char * domain,uint64_t id,uint64_t channel)1695 guest_add_vcc_port(struct guest *guest, struct md_node *vcc,
1696     const char *domain, uint64_t id, uint64_t channel)
1697 {
1698 	struct md *md = guest->md;
1699 	struct md_node *node;
1700 	struct md_node *child;
1701 
1702 	if (vcc == NULL)
1703 		vcc = guest_find_vcc(guest);
1704 	if (vcc == NULL)
1705 		vcc = guest_add_vcc(guest);
1706 
1707 	node = md_add_node(md, "virtual-device-port");
1708 	md_link_node(md, vcc, node);
1709 	md_add_prop_str(md, node, "name", "vcc-port");
1710 	md_add_prop_val(md, node, "id", id);
1711 	md_add_prop_str(md, node, "vcc-domain-name", domain);
1712 	md_add_prop_str(md, node, "vcc-group-name", domain);
1713 	/* OpenBSD doesn't care about this, but Solaris might. */
1714 	md_add_prop_val(md, node, "vcc-tcp-port", 5000 + id);
1715 
1716 	child = guest_add_endpoint(guest, channel);
1717 	md_link_node(md, node, child);
1718 
1719 	return node;
1720 }
1721 
1722 struct md_node *
guest_add_vds(struct guest * guest)1723 guest_add_vds(struct guest *guest)
1724 {
1725 	const char compatible[] = "SUNW,sun4v-disk-server";
1726 	struct md *md = guest->md;
1727 	struct md_node *parent;
1728 	struct md_node *node;
1729 
1730 	parent = md_find_node(md, "channel-devices");
1731 	assert(parent != NULL);
1732 
1733 	node = md_add_node(md, "virtual-device");
1734 	md_link_node(md, parent, node);
1735 	md_add_prop_str(md, node, "name", "virtual-disk-server");
1736 	md_add_prop_data(md, node, "compatible", compatible,
1737 	    sizeof(compatible));
1738 	md_add_prop_str(md, node, "device_type", "vds");
1739 	md_add_prop_val(md, node, "cfg-handle", 0x0);
1740 	md_add_prop_str(md, node, "svc-name", "primary-vds0");
1741 
1742 	return node;
1743 }
1744 
1745 struct md_node *
guest_find_vds(struct guest * guest)1746 guest_find_vds(struct guest *guest)
1747 {
1748 	struct md *md = guest->md;
1749 	struct md_node *node, *node2;
1750 	struct md_prop *prop;
1751 	const char *name;
1752 
1753 	node = md_find_node(md, "channel-devices");
1754 	assert(node != NULL);
1755 
1756 	TAILQ_FOREACH(prop, &node->prop_list, link) {
1757 		if (prop->tag == MD_PROP_ARC &&
1758 		    strcmp(prop->name->str, "fwd") == 0) {
1759 			node2 = prop->d.arc.node;
1760 			if (!md_get_prop_str(md, node2, "name", &name))
1761 				continue;
1762 			if (strcmp(name, "virtual-disk-server") == 0)
1763 				return node2;
1764 		}
1765 	}
1766 
1767 	return NULL;
1768 }
1769 
1770 struct md_node *
guest_add_vds_port(struct guest * guest,struct md_node * vds,const char * path,uint64_t id,uint64_t channel)1771 guest_add_vds_port(struct guest *guest, struct md_node *vds,
1772     const char *path, uint64_t id, uint64_t channel)
1773 {
1774 	struct md *md = guest->md;
1775 	struct md_node *node;
1776 	struct md_node *child;
1777 
1778 	if (vds == NULL)
1779 		vds = guest_find_vds(guest);
1780 	if (vds == NULL)
1781 		vds = guest_add_vds(guest);
1782 
1783 	node = md_add_node(md, "virtual-device-port");
1784 	md_link_node(md, vds, node);
1785 	md_add_prop_str(md, node, "name", "vds-port");
1786 	md_add_prop_val(md, node, "id", id);
1787 	md_add_prop_str(md, node, "vds-block-device", path);
1788 
1789 	child = guest_add_endpoint(guest, channel);
1790 	md_link_node(md, node, child);
1791 
1792 	return node;
1793 }
1794 
1795 struct md_node *
guest_add_vsw(struct guest * guest)1796 guest_add_vsw(struct guest *guest)
1797 {
1798 	const char compatible[] = "SUNW,sun4v-network-switch";
1799 	struct md *md = guest->md;
1800 	struct md_node *parent;
1801 	struct md_node *node;
1802 
1803 	parent = md_find_node(md, "channel-devices");
1804 	assert(parent != NULL);
1805 
1806 	node = md_add_node(md, "virtual-device");
1807 	md_link_node(md, parent, node);
1808 	md_add_prop_str(md, node, "name", "virtual-network-switch");
1809 	md_add_prop_data(md, node, "compatible", compatible,
1810 	    sizeof(compatible));
1811 	md_add_prop_str(md, node, "device_type", "vsw");
1812 	md_add_prop_val(md, node, "cfg-handle", 0x0);
1813 	md_add_prop_str(md, node, "svc-name", "primary-vsw0");
1814 
1815 	return node;
1816 }
1817 
1818 struct md_node *
guest_find_vsw(struct guest * guest)1819 guest_find_vsw(struct guest *guest)
1820 {
1821 	struct md *md = guest->md;
1822 	struct md_node *node, *node2;
1823 	struct md_prop *prop;
1824 	const char *name;
1825 
1826 	node = md_find_node(md, "channel-devices");
1827 	assert(node != NULL);
1828 
1829 	TAILQ_FOREACH(prop, &node->prop_list, link) {
1830 		if (prop->tag == MD_PROP_ARC &&
1831 		    strcmp(prop->name->str, "fwd") == 0) {
1832 			node2 = prop->d.arc.node;
1833 			if (!md_get_prop_str(md, node2, "name", &name))
1834 				continue;
1835 			if (strcmp(name, "virtual-network-switch") == 0)
1836 				return node2;
1837 		}
1838 	}
1839 
1840 	return NULL;
1841 }
1842 
1843 struct md_node *
guest_add_vsw_port(struct guest * guest,struct md_node * vds,uint64_t id,uint64_t channel)1844 guest_add_vsw_port(struct guest *guest, struct md_node *vds,
1845     uint64_t id, uint64_t channel)
1846 {
1847 	struct md *md = guest->md;
1848 	struct md_node *node;
1849 	struct md_node *child;
1850 	uint64_t mac_addr;
1851 
1852 	if (vds == NULL)
1853 		vds = guest_find_vsw(guest);
1854 	if (vds == NULL)
1855 		vds = guest_add_vsw(guest);
1856 	if (!md_get_prop_val(md, vds, "local-mac-address", &mac_addr)) {
1857 		mac_addr = 0x00144ff80000 + (arc4random() & 0x3ffff);
1858 		md_add_prop_val(md, vds, "local-mac-address", mac_addr);
1859 	}
1860 
1861 	node = md_add_node(md, "virtual-device-port");
1862 	md_link_node(md, vds, node);
1863 	md_add_prop_str(md, node, "name", "vsw-port");
1864 	md_add_prop_val(md, node, "id", id);
1865 
1866 	child = guest_add_endpoint(guest, channel);
1867 	md_link_node(md, node, child);
1868 
1869 	return node;
1870 }
1871 
1872 struct md_node *
guest_add_console_device(struct guest * guest)1873 guest_add_console_device(struct guest *guest)
1874 {
1875 	const char compatible[] = "SUNW,sun4v-console";
1876 	struct md *md = guest->md;
1877 	struct md_node *parent;
1878 	struct md_node *node;
1879 
1880 	parent = md_find_node(md, "virtual-devices");
1881 	assert(parent);
1882 
1883 	node = md_add_node(md, "virtual-device");
1884 	md_link_node(md, parent, node);
1885 	md_add_prop_str(md, node, "name", "console");
1886 	md_add_prop_str(md, node, "device-type", "serial");
1887 	md_add_prop_val(md, node, "intr", 0x1);
1888 	md_add_prop_val(md, node, "ino", 0x11);
1889 	md_add_prop_val(md, node, "channel#", 0);
1890 	md_add_prop_val(md, node, "cfg-handle", 0x1);
1891 	md_add_prop_data(md, node, "compatible", compatible,
1892 	    sizeof(compatible));
1893 
1894 	return node;
1895 }
1896 
1897 struct md_node *
guest_add_vdc(struct guest * guest,uint64_t cfghandle)1898 guest_add_vdc(struct guest *guest, uint64_t cfghandle)
1899 {
1900 	const char compatible[] = "SUNW,sun4v-disk";
1901 	struct md *md = guest->md;
1902 	struct md_node *parent;
1903 	struct md_node *node;
1904 
1905 	parent = md_find_node(md, "channel-devices");
1906 	assert(parent);
1907 
1908 	node = md_add_node(md, "virtual-device");
1909 	md_link_node(md, parent, node);
1910 	md_add_prop_str(md, node, "name", "disk");
1911 	md_add_prop_str(md, node, "device-type", "block");
1912 	md_add_prop_val(md, node, "cfg-handle", cfghandle);
1913 	md_add_prop_data(md, node, "compatible", compatible,
1914 	    sizeof(compatible));
1915 
1916 	return node;
1917 }
1918 
1919 struct md_node *
guest_add_vdc_port(struct guest * guest,struct md_node * vdc,uint64_t cfghandle,uint64_t id,uint64_t channel)1920 guest_add_vdc_port(struct guest *guest, struct md_node *vdc,
1921     uint64_t cfghandle, uint64_t id, uint64_t channel)
1922 {
1923 	struct md *md = guest->md;
1924 	struct md_node *node;
1925 	struct md_node *child;
1926 
1927 	if (vdc == NULL)
1928 		vdc = guest_add_vdc(guest, cfghandle);
1929 
1930 	node = md_add_node(md, "virtual-device-port");
1931 	md_link_node(md, vdc, node);
1932 	md_add_prop_str(md, node, "name", "vdc-port");
1933 	md_add_prop_val(md, node, "id", id);
1934 
1935 	child = guest_add_endpoint(guest, channel);
1936 	md_link_node(md, node, child);
1937 
1938 	return node;
1939 }
1940 
1941 struct md_node *
guest_add_vnet(struct guest * guest,uint64_t mac_addr,uint64_t mtu,uint64_t cfghandle)1942 guest_add_vnet(struct guest *guest, uint64_t mac_addr, uint64_t mtu,
1943     uint64_t cfghandle)
1944 {
1945 	const char compatible[] = "SUNW,sun4v-network";
1946 	struct md *md = guest->md;
1947 	struct md_node *parent;
1948 	struct md_node *node;
1949 
1950 	parent = md_find_node(md, "channel-devices");
1951 	assert(parent);
1952 
1953 	node = md_add_node(md, "virtual-device");
1954 	md_link_node(md, parent, node);
1955 	md_add_prop_str(md, node, "name", "network");
1956 	md_add_prop_str(md, node, "device-type", "network");
1957 	md_add_prop_val(md, node, "cfg-handle", cfghandle);
1958 	md_add_prop_data(md, node, "compatible", compatible,
1959 	    sizeof(compatible));
1960 	if (mac_addr == -1)
1961 		mac_addr = 0x00144ff80000 + (arc4random() & 0x3ffff);
1962 	md_add_prop_val(md, node, "local-mac-address", mac_addr);
1963 	md_add_prop_val(md, node, "mtu", mtu);
1964 
1965 	return node;
1966 }
1967 
1968 struct md_node *
guest_add_vnet_port(struct guest * guest,struct md_node * vdc,uint64_t mac_addr,uint64_t remote_mac_addr,uint64_t mtu,uint64_t cfghandle,uint64_t id,uint64_t channel)1969 guest_add_vnet_port(struct guest *guest, struct md_node *vdc,
1970     uint64_t mac_addr, uint64_t remote_mac_addr, uint64_t mtu, uint64_t cfghandle,
1971     uint64_t id, uint64_t channel)
1972 {
1973 	struct md *md = guest->md;
1974 	struct md_node *node;
1975 	struct md_node *child;
1976 
1977 	if (vdc == NULL)
1978 		vdc = guest_add_vnet(guest, mac_addr, mtu, cfghandle);
1979 
1980 	node = md_add_node(md, "virtual-device-port");
1981 	md_link_node(md, vdc, node);
1982 	md_add_prop_str(md, node, "name", "vnet-port");
1983 	md_add_prop_val(md, node, "id", id);
1984 	md_add_prop_val(md, node, "switch-port", 0);
1985 	md_add_prop_data(md, node, "remote-mac-address",
1986 	    (uint8_t *)&remote_mac_addr, sizeof(remote_mac_addr));
1987 
1988 	child = guest_add_endpoint(guest, channel);
1989 	md_link_node(md, node, child);
1990 
1991 	return node;
1992 }
1993 
1994 struct md_node *
guest_add_channel_devices(struct guest * guest)1995 guest_add_channel_devices(struct guest *guest)
1996 {
1997 	const char compatible[] = "SUNW,sun4v-channel-devices";
1998 	struct md *md = guest->md;
1999 	struct md_node *parent;
2000 	struct md_node *node;
2001 
2002 	parent = md_find_node(md, "virtual-devices");
2003 	assert(parent);
2004 
2005 	node = md_add_node(md, "channel-devices");
2006 	md_link_node(md, parent, node);
2007 	md_add_prop_str(md, node, "name", "channel-devices");
2008 	md_add_prop_str(md, node, "device-type", "channel-devices");
2009 	md_add_prop_data(md, node, "compatible", compatible,
2010 	    sizeof(compatible));
2011 	md_add_prop_val(md, node, "cfg-handle", 0x200);
2012 
2013 	return node;
2014 }
2015 
2016 struct md_node *
guest_add_domain_services(struct guest * guest)2017 guest_add_domain_services(struct guest *guest)
2018 {
2019 	struct md *md = guest->md;
2020 	struct md_node *parent;
2021 	struct md_node *node;
2022 
2023 	parent = md_find_node(md, "root");
2024 	assert(parent);
2025 
2026 	node = md_add_node(md, "domain-services");
2027 	md_link_node(md, parent, node);
2028 
2029 	return node;
2030 }
2031 
2032 struct md_node *
guest_add_domain_services_port(struct guest * guest,uint64_t id)2033 guest_add_domain_services_port(struct guest *guest, uint64_t id)
2034 {
2035 	struct md *md = guest->md;
2036 	struct md_node *parent;
2037 	struct md_node *node;
2038 	struct md_node *child;
2039 
2040 	parent = md_find_node(md, "domain-services");
2041 	if (parent == NULL)
2042 		parent = guest_add_domain_services(guest);
2043 
2044 	node = md_add_node(md, "domain-services-port");
2045 	md_link_node(md, parent, node);
2046 	md_add_prop_val(md, node, "id", id);
2047 
2048 	child = guest_add_endpoint(guest,
2049 	    guest->domain_services.client_endpoint->channel);
2050 	md_link_node(md, node, child);
2051 
2052 	return node;
2053 }
2054 
2055 void
guest_add_devalias(struct guest * guest,const char * name,const char * path)2056 guest_add_devalias(struct guest *guest, const char *name, const char *path)
2057 {
2058 	struct md *md = guest->md;
2059 	struct md_node *parent;
2060 	struct md_node *node;
2061 
2062 	parent = md_find_node(md, "openboot");
2063 	assert(parent);
2064 
2065 	node = md_find_subnode(md, parent, "devalias");
2066 	if (node == NULL) {
2067 		node = md_add_node(md, "devalias");
2068 		md_link_node(md, parent, node);
2069 	}
2070 
2071 	md_add_prop_str(md, node, name, path);
2072 }
2073 
2074 void
guest_set_domaining_enabled(struct guest * guest)2075 guest_set_domaining_enabled(struct guest *guest)
2076 {
2077 	struct md *md = guest->md;
2078 	struct md_node *node;
2079 
2080 	node = md_find_node(md, "platform");
2081 	assert(node);
2082 
2083 	md_set_prop_val(md, node, "domaining-enabled", 0x1);
2084 }
2085 
2086 void
guest_set_mac_address(struct guest * guest)2087 guest_set_mac_address(struct guest *guest)
2088 {
2089 	struct md *md = guest->md;
2090 	struct md_node *node;
2091 	uint64_t mac_address;
2092 	uint64_t hostid;
2093 
2094 	node = md_find_node(md, "platform");
2095 	assert(node);
2096 
2097 	mac_address = 0x00144ff80000 + (arc4random() & 0x3ffff);
2098 	md_set_prop_val(md, node, "mac-address", mac_address);
2099 
2100 	hostid = 0x84000000 | (mac_address & 0x00ffffff);
2101 	md_set_prop_val(md, node, "hostid", hostid);
2102 }
2103 
2104 struct md_node *
guest_find_vc(struct guest * guest)2105 guest_find_vc(struct guest *guest)
2106 {
2107 	struct md *md = guest->md;
2108 	struct md_node *node, *node2;
2109 	struct md_node *vc = NULL;
2110 	struct md_prop *prop;
2111 	const char *name;
2112 
2113 	node = md_find_node(md, "channel-devices");
2114 	assert(node != NULL);
2115 
2116 	TAILQ_FOREACH(prop, &node->prop_list, link) {
2117 		if (prop->tag == MD_PROP_ARC &&
2118 		    strcmp(prop->name->str, "fwd") == 0) {
2119 			node2 = prop->d.arc.node;
2120 			if (!md_get_prop_str(md, node2, "name", &name))
2121 				continue;
2122 			if (strcmp(name, "virtual-channel") == 0)
2123 				vc = node2;
2124 		}
2125 	}
2126 
2127 	return vc;
2128 }
2129 
2130 struct md_node *
guest_add_vc_port(struct guest * guest,struct md_node * vc,const char * domain,uint64_t id,uint64_t channel)2131 guest_add_vc_port(struct guest *guest, struct md_node *vc,
2132     const char *domain, uint64_t id, uint64_t channel)
2133 {
2134 	struct md *md = guest->md;
2135 	struct md_node *node;
2136 	struct md_node *child;
2137 	char *str;
2138 
2139 	if (vc == NULL)
2140 		vc = guest_find_vc(guest);
2141 	assert(vc);
2142 
2143 	node = md_add_node(md, "virtual-device-port");
2144 	md_link_node(md, vc, node);
2145 	md_add_prop_str(md, node, "name", "vldc-port");
2146 	md_add_prop_val(md, node, "id", id);
2147 	xasprintf(&str, "ldom-%s", domain);
2148 	md_add_prop_str(md, node, "vldc-svc-name", str);
2149 	free(str);
2150 
2151 	child = guest_add_endpoint(guest, channel);
2152 	md_link_node(md, node, child);
2153 
2154 	return node;
2155 }
2156 
2157 struct guest *
guest_create(const char * name)2158 guest_create(const char *name)
2159 {
2160 	struct guest *guest;
2161 	struct guest *primary;
2162 	struct md_node *node;
2163 
2164 	primary = guest_lookup("primary");
2165 
2166 	guest = hvmd_add_guest(name);
2167 	guest->md = md_copy(protomd);
2168 
2169 	md_find_delete_node(guest->md, "dimm_configuration");
2170 	md_find_delete_node(guest->md, "platform_services");
2171 	md_collect_garbage(guest->md);
2172 
2173 	guest_set_domaining_enabled(guest);
2174 	guest_set_mac_address(guest);
2175 	guest_add_channel_devices(guest);
2176 	guest_add_domain_services_port(guest, 0);
2177 	guest_add_console_device(guest);
2178 	guest_add_devalias(guest, "virtual-console",
2179 	    "/virtual-devices/console@1");
2180 
2181 	guest_add_vcc_port(primary, NULL, guest->name, guest->gid - 1,
2182 	    guest->console->server_endpoint->channel);
2183 
2184 	guest_add_vc_port(primary, NULL, guest->name, guest->gid + 2,
2185 	    guest->domain_services.server_endpoint->channel);
2186 
2187 	node = md_find_node(guest->md, "root");
2188 	md_add_prop_val(guest->md, node, "reset-reason", 0);
2189 
2190 	return guest;
2191 }
2192 
2193 int
guest_match_path(struct guest * guest,const char * path)2194 guest_match_path(struct guest *guest, const char *path)
2195 {
2196 	struct subdevice *subdevice;
2197 	size_t len = strlen(path);
2198 
2199 	TAILQ_FOREACH(subdevice, &guest->subdevice_list, link) {
2200 		const char *path2 = subdevice->path;
2201 		size_t len2 = strlen(path2);
2202 
2203 		if (strncmp(path, path2, len < len2 ? len : len2) == 0)
2204 			return 1;
2205 	}
2206 
2207 	return 0;
2208 }
2209 
2210 void
guest_prune_phys_io(struct guest * guest)2211 guest_prune_phys_io(struct guest *guest)
2212 {
2213 	const char compatible[] = "SUNW,sun4v-vpci";
2214 	struct md *md = guest->md;
2215 	struct md_node *node, *node2;
2216 	struct md_prop *prop, *prop2;
2217 	const char *device_type;
2218 	uint64_t cfg_handle;
2219 	char *path;
2220 
2221 	node = md_find_node(guest->md, "phys_io");
2222 	TAILQ_FOREACH_SAFE(prop, &node->prop_list, link, prop2) {
2223 		if (prop->tag == MD_PROP_ARC &&
2224 		    strcmp(prop->name->str, "fwd") == 0) {
2225 			node2 = prop->d.arc.node;
2226 			if (!md_get_prop_str(md, node2, "device-type",
2227 			    &device_type))
2228 				device_type = "unknown";
2229 			if (strcmp(device_type, "pciex") != 0) {
2230 				md_delete_node(md, node2);
2231 				continue;
2232 			}
2233 
2234 			if (!md_get_prop_val(md, node2, "cfg-handle",
2235 			    &cfg_handle)) {
2236 				md_delete_node(md, node2);
2237 				continue;
2238 			}
2239 
2240 			xasprintf(&path, "/@%llx", cfg_handle);
2241 			if (!guest_match_path(guest, path)) {
2242 				md_delete_node(md, node2);
2243 				continue;
2244 			}
2245 
2246 			md_set_prop_data(md, node2, "compatible",
2247 			    compatible, sizeof(compatible));
2248 			md_add_prop_val(md, node2, "virtual-root-complex", 1);
2249 			guest_prune_pcie(guest, node2, path);
2250 			free(path);
2251 
2252 			guest_add_vpcie(guest, cfg_handle);
2253 		}
2254 	}
2255 }
2256 
2257 void
guest_prune_pcie(struct guest * guest,struct md_node * node,const char * path)2258 guest_prune_pcie(struct guest *guest, struct md_node *node, const char *path)
2259 {
2260 	struct md *md = guest->md;
2261 	struct md_node *node2;
2262 	struct md_prop *prop, *prop2;
2263 	uint64_t device_number;
2264 	char *path2;
2265 
2266 	TAILQ_FOREACH_SAFE(prop, &node->prop_list, link, prop2) {
2267 		if (prop->tag == MD_PROP_ARC &&
2268 		    strcmp(prop->name->str, "fwd") == 0) {
2269 			node2 = prop->d.arc.node;
2270 			if (strcmp(node2->name->str, "wart") == 0) {
2271 				md_delete_node(md, node2);
2272 				continue;
2273 			}
2274 			if (!md_get_prop_val(md, node2, "device-number",
2275 			    &device_number))
2276 				continue;
2277 			xasprintf(&path2, "%s/@%llx", path, device_number);
2278 			if (guest_match_path(guest, path2))
2279 				guest_prune_pcie(guest, node2, path2);
2280 			else
2281 				md_delete_node(md, node2);
2282 			free(path2);
2283 		}
2284 	}
2285 }
2286 
2287 void
guest_add_vpcie(struct guest * guest,uint64_t cfghandle)2288 guest_add_vpcie(struct guest *guest, uint64_t cfghandle)
2289 {
2290 	struct device *device, *phys_device = NULL;
2291 	uint64_t resource_id;
2292 
2293 	for (resource_id = 0; resource_id < max_devices; resource_id++) {
2294 		if (pcie_busses[resource_id] &&
2295 		    pcie_busses[resource_id]->cfghandle == cfghandle) {
2296 			phys_device = pcie_busses[resource_id];
2297 			break;
2298 		}
2299 	}
2300 	if (phys_device == NULL)
2301 		errx(1, "no matching physical device");
2302 
2303 	for (resource_id = 0; resource_id < max_devices; resource_id++) {
2304 		if (pcie_busses[resource_id] == NULL)
2305 			break;
2306 	}
2307 	if (resource_id >= max_devices)
2308 		errx(1, "no available resource_id");
2309 
2310 	device = xzalloc(sizeof(*device));
2311 	device->gid = guest->gid;
2312 	device->cfghandle = cfghandle;
2313 	device->resource_id = resource_id;
2314 	device->rcid = phys_device->rcid;
2315 	device->virtual = 1;
2316 	device->guest = guest;
2317 
2318 	device->num_msi_eqs = phys_device->msi_eqs_per_vpci;
2319 	device->num_msis = phys_device->msis_per_vpci;
2320 	phys_device->msi_base -= phys_device->msis_per_vpci;
2321 	device->msi_ranges[0] = phys_device->msi_base;
2322 	device->msi_ranges[1] = device->num_msis;
2323 
2324 	pcie_busses[resource_id] = device;
2325 	TAILQ_INSERT_TAIL(&guest->device_list, device, link);
2326 }
2327 
2328 void
guest_fixup_phys_io(struct guest * guest)2329 guest_fixup_phys_io(struct guest *guest)
2330 {
2331 	struct md *md = guest->md;
2332 	struct md_node *node, *node2;
2333 	struct md_prop *prop, *prop2;
2334 	struct device *device;
2335 	uint64_t cfg_handle;
2336 	uint64_t mapping[3];
2337 	const void *buf;
2338 	size_t len;
2339 
2340 	if (!directio_capability)
2341 		return;
2342 
2343 	node = md_find_node(guest->md, "phys_io");
2344 	TAILQ_FOREACH_SAFE(prop, &node->prop_list, link, prop2) {
2345 		if (prop->tag == MD_PROP_ARC &&
2346 		    strcmp(prop->name->str, "fwd") == 0) {
2347 			node2 = prop->d.arc.node;
2348 
2349 			if (!md_get_prop_val(md, node2, "cfg-handle",
2350 			    &cfg_handle))
2351 				continue;
2352 
2353 			TAILQ_FOREACH(device, &guest->device_list, link) {
2354 				if (device->cfghandle == cfg_handle)
2355 					break;
2356 			}
2357 			if (device == NULL)
2358 				continue;
2359 
2360 			md_set_prop_val(md, node2, "#msi-eqs",
2361 			    device->num_msi_eqs);
2362 			md_set_prop_val(md, node2, "#msi",
2363 			    device->num_msis);
2364 			md_set_prop_data(md, node2, "msi-ranges",
2365 			    (void *)device->msi_ranges,
2366 			    sizeof(device->msi_ranges));
2367 
2368 			md_get_prop_data(md, node2, "msi-eq-to-devino",
2369 			    &buf, &len);
2370 			memcpy(mapping, buf, sizeof(mapping));
2371 			mapping[1] = device->num_msi_eqs;
2372 			md_set_prop_data(md, node2, "msi-eq-to-devino",
2373 			    (void *)mapping, sizeof(mapping));
2374 		}
2375 	}
2376 }
2377 
2378 struct guest *
guest_lookup(const char * name)2379 guest_lookup(const char *name)
2380 {
2381 	uint64_t resource_id;
2382 
2383 	for (resource_id = 0; resource_id < max_guests; resource_id++) {
2384 		if (guests[resource_id] &&
2385 		    strcmp(guests[resource_id]->name, name) == 0)
2386 			return guests[resource_id];
2387 	}
2388 
2389 	return NULL;
2390 }
2391 
2392 void
guest_delete_virtual_device_port(struct guest * guest,struct md_node * port)2393 guest_delete_virtual_device_port(struct guest *guest, struct md_node *port)
2394 {
2395 	struct md *md = guest->md;
2396 	struct md_node *node;
2397 	struct md_prop *prop;
2398 
2399 	TAILQ_FOREACH(node, &md->node_list, link) {
2400 		if (strcmp(node->name->str, "virtual-device-port") != 0)
2401 			continue;
2402 		TAILQ_FOREACH(prop, &node->prop_list, link) {
2403 			if (prop->tag == MD_PROP_ARC &&
2404 			    prop->d.arc.node == port) {
2405 				md_delete_node(md, node);
2406 				return;
2407 			}
2408 		}
2409 	}
2410 }
2411 
2412 void
guest_delete_endpoint(struct guest * guest,struct ldc_endpoint * endpoint)2413 guest_delete_endpoint(struct guest *guest, struct ldc_endpoint *endpoint)
2414 {
2415 	struct md *md = guest->md;
2416 	struct md_node *node, *node2;
2417 	struct md_prop *prop;
2418 	uint64_t id, resource_id;
2419 
2420 	node = md_find_node(md, "channel-endpoints");
2421 	TAILQ_FOREACH(prop, &node->prop_list, link) {
2422 		if (prop->tag == MD_PROP_ARC &&
2423 		    strcmp(prop->name->str, "fwd") == 0) {
2424 			node2 = prop->d.arc.node;
2425 			if (!md_get_prop_val(hvmd, node2, "id", &id))
2426 				continue;
2427 			if (id == endpoint->channel) {
2428 				guest_delete_virtual_device_port(guest, node2);
2429 				md_delete_node(md, node2);
2430 				break;
2431 			}
2432 		}
2433 	}
2434 
2435 	TAILQ_REMOVE(&guest->endpoint_list, endpoint, link);
2436 	ldc_endpoints[endpoint->resource_id] = NULL;
2437 
2438 	/* Delete peer as well. */
2439 	for (resource_id = 0; resource_id < max_guest_ldcs; resource_id++) {
2440 		struct ldc_endpoint *peer = ldc_endpoints[resource_id];
2441 
2442 		if (peer && peer->target_type == LDC_GUEST &&
2443 		    peer->target_channel == endpoint->channel &&
2444 		    peer->channel == endpoint->target_channel &&
2445 		    peer->target_guest == guest->gid)
2446 			guest_delete_endpoint(peer->guest, peer);
2447 	}
2448 
2449 	free(endpoint);
2450 }
2451 
2452 void
guest_delete(struct guest * guest)2453 guest_delete(struct guest *guest)
2454 {
2455 	struct cpu *cpu, *cpu2;
2456 	struct mblock *mblock, *mblock2;
2457 	struct ldc_endpoint *endpoint, *endpoint2;
2458 
2459 	consoles[guest->console->resource_id] = NULL;
2460 	free(guest->console);
2461 
2462 	TAILQ_FOREACH_SAFE(cpu, &guest->cpu_list, link, cpu2) {
2463 		TAILQ_REMOVE(&guest->cpu_list, cpu, link);
2464 		cpus[cpu->resource_id] = NULL;
2465 		pri_free_cpu(cpu);
2466 	}
2467 
2468 	TAILQ_FOREACH_SAFE(mblock, &guest->mblock_list, link, mblock2) {
2469 		TAILQ_REMOVE(&guest->mblock_list, mblock, link);
2470 		mblocks[mblock->resource_id] = NULL;
2471 		free(mblock);
2472 	}
2473 
2474 	TAILQ_FOREACH_SAFE(endpoint, &guest->endpoint_list, link, endpoint2)
2475 		guest_delete_endpoint(guest, endpoint);
2476 
2477 	hvmd_free_frag(guest->mdpa);
2478 
2479 	guests[guest->resource_id] = NULL;
2480 	free(guest);
2481 }
2482 
2483 void
guest_delete_cpu(struct guest * guest,uint64_t vid)2484 guest_delete_cpu(struct guest *guest, uint64_t vid)
2485 {
2486 	struct cpu *cpu;
2487 
2488 	TAILQ_FOREACH(cpu, &guest->cpu_list, link) {
2489 		if (cpu->vid == vid) {
2490 			TAILQ_REMOVE(&guest->cpu_list, cpu, link);
2491 			cpus[cpu->resource_id] = NULL;
2492 			pri_free_cpu(cpu);
2493 			return;
2494 		}
2495 	}
2496 }
2497 
2498 void
guest_add_cpu(struct guest * guest,uint64_t stride)2499 guest_add_cpu(struct guest *guest, uint64_t stride)
2500 {
2501 	struct cpu *cpu;
2502 
2503 	cpu = pri_alloc_cpu(-1);
2504 
2505 	/*
2506 	 * Allocate (but don't assign) additional virtual CPUs if the
2507 	 * specified stride is bigger than one.
2508 	 */
2509 	while (stride-- > 1)
2510 		pri_alloc_cpu(-1);
2511 
2512 	if (cpu->resource_id == -1) {
2513 		uint64_t resource_id;
2514 
2515 		for (resource_id = 0; resource_id < max_cpus; resource_id++)
2516 			if (cpus[resource_id] == NULL)
2517 				break;
2518 		assert(resource_id < max_cpus);
2519 		cpu->resource_id = resource_id;
2520 	}
2521 	cpus[cpu->resource_id] = cpu;
2522 
2523 	cpu->vid = guest->cpu_vid++;
2524 	cpu->gid = guest->gid;
2525 	cpu->partid = 1;
2526 
2527 	TAILQ_INSERT_TAIL(&guest->cpu_list, cpu, link);
2528 	cpu->guest = guest;
2529 }
2530 
2531 void
guest_delete_memory(struct guest * guest)2532 guest_delete_memory(struct guest *guest)
2533 {
2534 	struct mblock *mblock, *tmp;
2535 
2536 	TAILQ_FOREACH_SAFE(mblock, &guest->mblock_list, link, tmp) {
2537 		if (mblock->resource_id != -1)
2538 			mblocks[mblock->resource_id] = NULL;
2539 		TAILQ_REMOVE(&guest->mblock_list, mblock, link);
2540 		free(mblock);
2541 	}
2542 }
2543 
2544 void
guest_add_memory(struct guest * guest,uint64_t base,uint64_t size)2545 guest_add_memory(struct guest *guest, uint64_t base, uint64_t size)
2546 {
2547 	struct mblock *mblock;
2548 	uint64_t resource_id;
2549 
2550 	mblock = pri_alloc_memory(base, size);
2551 	if (mblock == NULL)
2552 		errx(1, "unable to allocate guest memory");
2553 	for (resource_id = 0; resource_id < max_cpus; resource_id++)
2554 		if (mblocks[resource_id] == NULL)
2555 			break;
2556 	assert(resource_id < max_mblocks);
2557 	mblock->resource_id = resource_id;
2558 	mblocks[resource_id] = mblock;
2559 
2560 	mblock->realbase = mblock->membase & (max_page_size - 1);
2561 	if (mblock->realbase == 0)
2562 		mblock->realbase = max_page_size;
2563 
2564 	TAILQ_INSERT_TAIL(&guest->mblock_list, mblock, link);
2565 	mblock->guest = guest;
2566 }
2567 
2568 void
guest_add_vdisk(struct guest * guest,uint64_t id,const char * path,const char * user_devalias)2569 guest_add_vdisk(struct guest *guest, uint64_t id, const char *path,
2570     const char *user_devalias)
2571 {
2572 	struct guest *primary;
2573 	struct ldc_channel *lc;
2574 	char *devalias;
2575 	char *devpath;
2576 
2577 	primary = guest_lookup("primary");
2578 
2579 	lc = hvmd_add_vio(guest);
2580 	guest_add_vds_port(primary, NULL, path, id,
2581 	    lc->server_endpoint->channel);
2582 	guest_add_vdc_port(guest, NULL, id, 0, lc->client_endpoint->channel);
2583 
2584 	xasprintf(&devalias, "disk%d", id);
2585 	xasprintf(&devpath,
2586 	    "/virtual-devices@100/channel-devices@200/disk@%d", id);
2587 	if (id == 0)
2588 		guest_add_devalias(guest, "disk", devpath);
2589 	guest_add_devalias(guest, devalias, devpath);
2590 	if (user_devalias != NULL)
2591 		guest_add_devalias(guest, user_devalias, devpath);
2592 	free(devalias);
2593 	free(devpath);
2594 }
2595 
2596 void
guest_add_vnetwork(struct guest * guest,uint64_t id,uint64_t mac_addr,uint64_t mtu,const char * user_devalias)2597 guest_add_vnetwork(struct guest *guest, uint64_t id, uint64_t mac_addr,
2598     uint64_t mtu, const char *user_devalias)
2599 {
2600 	struct guest *primary;
2601 	struct ldc_channel *lc;
2602 	char *devalias;
2603 	char *devpath;
2604 	struct md_node *node;
2605 	uint64_t remote_mac_addr = -1;
2606 
2607 	primary = guest_lookup("primary");
2608 
2609 	lc = hvmd_add_vio(guest);
2610 	guest_add_vsw_port(primary, NULL, id, lc->server_endpoint->channel);
2611 	node = guest_find_vsw(primary);
2612 	md_get_prop_val(primary->md, node, "local-mac-address", &remote_mac_addr);
2613 	guest_add_vnet_port(guest, NULL, mac_addr, remote_mac_addr, mtu, id, 0,
2614 	    lc->client_endpoint->channel);
2615 
2616 	xasprintf(&devalias, "net%d", id);
2617 	xasprintf(&devpath,
2618 	    "/virtual-devices@100/channel-devices@200/network@%d", id);
2619 	if (id == 0)
2620 		guest_add_devalias(guest, "net", devpath);
2621 	guest_add_devalias(guest, devalias, devpath);
2622 	if (user_devalias != NULL)
2623 		guest_add_devalias(guest, user_devalias, devpath);
2624 	free(devalias);
2625 	free(devpath);
2626 }
2627 
2628 void
guest_add_variable(struct guest * guest,const char * name,const char * str)2629 guest_add_variable(struct guest *guest, const char *name, const char *str)
2630 {
2631 	struct md *md = guest->md;
2632 	struct md_node *parent;
2633 	struct md_node *node;
2634 
2635 	node = md_find_node(md, "variables");
2636 	if (node == NULL) {
2637 		parent = md_find_node(md, "root");
2638 		assert(parent);
2639 
2640 		node = md_add_node(md, "variables");
2641 		md_link_node(md, parent, node);
2642 	}
2643 
2644 	md_add_prop_str(md, node, name, str);
2645 }
2646 
2647 void
guest_add_iodev(struct guest * guest,const char * dev)2648 guest_add_iodev(struct guest *guest, const char *dev)
2649 {
2650 	struct component *component;
2651 	struct subdevice *subdevice;
2652 
2653 	if (!directio_capability)
2654 		errx(1, "direct I/O not supported by hypervisor");
2655 
2656 	TAILQ_FOREACH(component, &components, link) {
2657 		if (strcmp(component->nac, dev) == 0 ||
2658 		    strcmp(component->path, dev) == 0)
2659 			break;
2660 	}
2661 
2662 	if (component == NULL)
2663 		errx(1, "incorrect device path %s", dev);
2664 	if (component->assigned)
2665 		errx(1, "device path %s already assigned", dev);
2666 
2667 	subdevice = xzalloc(sizeof(*subdevice));
2668 	subdevice->path = component->path;
2669 	TAILQ_INSERT_TAIL(&guest->subdevice_list, subdevice, link);
2670 	component->assigned = 1;
2671 }
2672 
2673 struct cpu *
guest_find_cpu(struct guest * guest,uint64_t pid)2674 guest_find_cpu(struct guest *guest, uint64_t pid)
2675 {
2676 	struct cpu *cpu;
2677 
2678 	TAILQ_FOREACH(cpu, &guest->cpu_list, link)
2679 		if (cpu->pid == pid)
2680 			return cpu;
2681 
2682 	return NULL;
2683 }
2684 
2685 void
guest_finalize(struct guest * guest)2686 guest_finalize(struct guest *guest)
2687 {
2688 	struct md *md = guest->md;
2689 	struct md_node *node, *node2;
2690 	struct md_prop *prop, *prop2;
2691 	struct mblock *mblock;
2692 	struct md_node *parent;
2693 	struct md_node *child;
2694 	struct cpu *cpu;
2695 	uint64_t pid;
2696 	const char *name;
2697 	char *path;
2698 
2699 	node = md_find_node(md, "cpus");
2700 	TAILQ_FOREACH_SAFE(prop, &node->prop_list, link, prop2) {
2701 		if (prop->tag == MD_PROP_ARC &&
2702 		    strcmp(prop->name->str, "fwd") == 0) {
2703 			node2 = prop->d.arc.node;
2704 			if (!md_get_prop_val(md, node2, "pid", &pid))
2705 				if (!md_get_prop_val(md, node2, "id", &pid))
2706 					continue;
2707 			cpu = guest_find_cpu(guest, pid);
2708 			if (cpu == NULL) {
2709 				md_delete_node(md, node2);
2710 				continue;
2711 			}
2712 			md_set_prop_val(md, node2, "id", cpu->vid);
2713 		}
2714 	}
2715 
2716 	/*
2717 	 * We don't support crypto units yet, so delete any "ncp" and
2718 	 * "n2cp" nodes.  If we don't, Solaris whines about not being
2719 	 * able to configure crypto work queues.
2720 	 */
2721 	node = md_find_node(md, "virtual-devices");
2722 	TAILQ_FOREACH_SAFE(prop, &node->prop_list, link, prop2) {
2723 		if (prop->tag == MD_PROP_ARC &&
2724 		    strcmp(prop->name->str, "fwd") == 0) {
2725 			node2 = prop->d.arc.node;
2726 			if (!md_get_prop_str(md, node2, "name", &name))
2727 				continue;
2728 			if (strcmp(name, "ncp") == 0)
2729 				md_delete_node(md, node2);
2730 			if (strcmp(name, "n2cp") == 0)
2731 				md_delete_node(md, node2);
2732 		}
2733 	}
2734 
2735 	node = md_find_node(md, "memory");
2736 	TAILQ_FOREACH_SAFE(prop, &node->prop_list, link, prop2) {
2737 		if (prop->tag == MD_PROP_ARC &&
2738 		    strcmp(prop->name->str, "fwd") == 0) {
2739 			node2 = prop->d.arc.node;
2740 			md_delete_node(md, node2);
2741 		}
2742 	}
2743 
2744 	if (strcmp(guest->name, "primary") != 0)
2745 		guest_prune_phys_io(guest);
2746 	guest_fixup_phys_io(guest);
2747 
2748 	md_collect_garbage(md);
2749 
2750 	parent = md_find_node(md, "memory");
2751 	TAILQ_FOREACH(mblock, &guest->mblock_list, link) {
2752 		child = md_add_node(md, "mblock");
2753 		md_add_prop_val(md, child, "base", mblock->realbase);
2754 		md_add_prop_val(md, child, "size", mblock->memsize);
2755 		md_link_node(md, parent, child);
2756 	}
2757 
2758 	xasprintf(&path, "%s.md", guest->name);
2759 	md_write(guest->md, path);
2760 	free(path);
2761 }
2762 
2763 struct guest *
primary_init(void)2764 primary_init(void)
2765 {
2766 	struct guest *guest;
2767 
2768 	guest = guest_lookup("primary");
2769 	assert(guest);
2770 
2771 	guest_set_domaining_enabled(guest);
2772 
2773 	return guest;
2774 }
2775 
2776 void
build_config(const char * filename,int noaction)2777 build_config(const char *filename, int noaction)
2778 {
2779 	struct guest *primary;
2780 	struct guest *guest;
2781 	struct ldc_endpoint *endpoint;
2782 	struct component *component;
2783 	uint64_t resource_id;
2784 	int i;
2785 
2786 	struct ldom_config conf;
2787 	struct domain *domain;
2788 	struct vdisk *vdisk;
2789 	struct vnet *vnet;
2790 	struct var *var;
2791 	struct iodev *iodev;
2792 	uint64_t num_cpus = 0, primary_num_cpus = 0;
2793 	uint64_t primary_stride = 1;
2794 	uint64_t memory = 0, primary_memory = 0;
2795 
2796 	SIMPLEQ_INIT(&conf.domain_list);
2797 	if (parse_config(filename, &conf) < 0)
2798 		exit(1);
2799 
2800 	pri = md_read("pri");
2801 	if (pri == NULL)
2802 		err(1, "unable to get PRI");
2803 	hvmd = md_read("hv.md");
2804 	if (hvmd == NULL)
2805 		err(1, "unable to get Hypervisor MD");
2806 
2807 	pri_init(pri);
2808 	pri_alloc_memory(hv_membase, hv_memsize);
2809 
2810 	SIMPLEQ_FOREACH(domain, &conf.domain_list, entry) {
2811 		if (strcmp(domain->name, "primary") == 0) {
2812 			primary_num_cpus = domain->vcpu;
2813 			primary_stride = domain->vcpu_stride;
2814 			primary_memory = domain->memory;
2815 		}
2816 		num_cpus += (domain->vcpu * domain->vcpu_stride);
2817 		memory += domain->memory;
2818 	}
2819 	if (primary_num_cpus == 0 && total_cpus > num_cpus)
2820 		primary_num_cpus = total_cpus - num_cpus;
2821 	if (primary_memory == 0 && total_memory > memory)
2822 		primary_memory = total_memory - memory;
2823 	if (num_cpus > total_cpus || primary_num_cpus == 0)
2824 		errx(1, "not enough VCPU resources available");
2825 	if (memory > total_memory || primary_memory == 0)
2826 		errx(1, "not enough memory available");
2827 
2828 	if (noaction)
2829 		exit(0);
2830 
2831 	hvmd_init(hvmd);
2832 	primary = primary_init();
2833 
2834 	for (resource_id = 0; resource_id <max_guests; resource_id++)
2835 		if (guests[resource_id] &&
2836 		    strcmp(guests[resource_id]->name, "primary") != 0)
2837 			guest_delete(guests[resource_id]);
2838 
2839 	primary->endpoint_id = 0;
2840 	TAILQ_FOREACH(endpoint, &primary->endpoint_list, link) {
2841 		if (endpoint->channel >= primary->endpoint_id)
2842 			primary->endpoint_id = endpoint->channel + 1;
2843 	}
2844 
2845 	for (i = 0; i < max_cpus; i++)
2846 		guest_delete_cpu(primary, i);
2847 	for (i = 0; i < primary_num_cpus; i++)
2848 		guest_add_cpu(primary, primary_stride);
2849 	guest_delete_memory(primary);
2850 	guest_add_memory(primary, -1, primary_memory);
2851 
2852 	SIMPLEQ_FOREACH(domain, &conf.domain_list, entry) {
2853 		if (strcmp(domain->name, "primary") != 0)
2854 			continue;
2855 		SIMPLEQ_FOREACH(var, &domain->var_list, entry)
2856 			guest_add_variable(primary, var->name, var->str);
2857 	}
2858 
2859 	SIMPLEQ_FOREACH(domain, &conf.domain_list, entry) {
2860 		if (strcmp(domain->name, "primary") == 0)
2861 			continue;
2862 		guest = guest_create(domain->name);
2863 		for (i = 0; i < domain->vcpu; i++)
2864 			guest_add_cpu(guest, domain->vcpu_stride);
2865 		guest_add_memory(guest, -1, domain->memory);
2866 		i = 0;
2867 		SIMPLEQ_FOREACH(vdisk, &domain->vdisk_list, entry)
2868 			guest_add_vdisk(guest, i++, vdisk->path,
2869 			    vdisk->devalias);
2870 		i = 0;
2871 		SIMPLEQ_FOREACH(vnet, &domain->vnet_list, entry)
2872 			guest_add_vnetwork(guest, i++, vnet->mac_addr,
2873 			    vnet->mtu, vnet->devalias);
2874 		SIMPLEQ_FOREACH(var, &domain->var_list, entry)
2875 			guest_add_variable(guest, var->name, var->str);
2876 		SIMPLEQ_FOREACH(iodev, &domain->iodev_list, entry)
2877 			guest_add_iodev(guest, iodev->dev);
2878 
2879 		guest_finalize(guest);
2880 	}
2881 
2882 	TAILQ_FOREACH(component, &components, link) {
2883 		if (component->assigned)
2884 			continue;
2885 		guest_add_iodev(primary, component->path);
2886 	}
2887 
2888 	guest_finalize(primary);
2889 	hvmd_finalize();
2890 }
2891 
2892 void
list_components(void)2893 list_components(void)
2894 {
2895 	struct component *component;
2896 
2897 	pri = md_read("pri");
2898 	if (pri == NULL)
2899 		err(1, "unable to get PRI");
2900 
2901 	pri_init_components(pri);
2902 
2903 	printf("%-16s %s\n", "PATH", "NAME");
2904 	TAILQ_FOREACH(component, &components, link) {
2905 		printf("%-16s %s\n", component->path, component->nac);
2906 	}
2907 }
2908