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
42struct core {
43	struct guest *guests[MAX_STRANDS_PER_CORE];
44	TAILQ_ENTRY(core) link;
45};
46
47TAILQ_HEAD(, core) cores;
48
49struct 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
58TAILQ_HEAD(, component) components;
59
60struct 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
69TAILQ_HEAD(, hostbridge) hostbridges;
70
71struct frag {
72	TAILQ_ENTRY(frag) link;
73	uint64_t base;
74};
75
76struct guest **guests;
77struct console **consoles;
78struct cpu **cpus;
79struct device **pcie_busses;
80struct device **network_devices;
81struct mblock **mblocks;
82struct ldc_endpoint **ldc_endpoints;
83extern struct domain *domain;
84
85TAILQ_HEAD(, rootcomplex) rootcomplexes;
86
87uint64_t max_cpus;
88bool have_cwqs;
89bool have_rngs;
90
91uint64_t max_guests;
92uint64_t max_hv_ldcs;
93uint64_t max_guest_ldcs;
94uint64_t md_maxsize;
95uint64_t md_elbow_room;
96uint64_t max_mblocks;
97uint64_t directio_capability;
98
99uint64_t max_devices = 16;
100
101uint64_t rombase;
102uint64_t romsize;
103uint64_t uartbase;
104
105uint64_t max_page_size;
106
107uint64_t content_version;
108uint64_t stick_frequency;
109uint64_t tod_frequency;
110uint64_t tod;
111uint64_t erpt_pa;
112uint64_t erpt_size;
113
114struct md *pri;
115struct md *hvmd;
116struct md *protomd;
117
118struct guest *guest_lookup(const char *);
119void guest_prune_phys_io(struct guest *);
120void guest_prune_pcie(struct guest *, struct md_node *, const char *);
121void guest_add_vpcie(struct guest *, uint64_t);
122void guest_fixup_phys_io(struct guest *);
123
124TAILQ_HEAD(, frag) free_frags = TAILQ_HEAD_INITIALIZER(free_frags);
125TAILQ_HEAD(, cpu) free_cpus = TAILQ_HEAD_INITIALIZER(free_cpus);
126int total_cpus;
127TAILQ_HEAD(, mblock) free_memory = TAILQ_HEAD_INITIALIZER(free_memory);
128uint64_t total_memory;
129
130struct cpu *
131pri_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
143void
144pri_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
172void
173pri_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
183void
184pri_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
201void
202pri_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
215void
216pri_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
247void
248pri_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
288void
289pri_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
322struct cpu *
323pri_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
343void
344pri_free_cpu(struct cpu *cpu)
345{
346	TAILQ_INSERT_TAIL(&free_cpus, cpu, link);
347}
348
349void
350pri_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
362struct mblock *
363pri_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
405void
406pri_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
421void
422pri_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
515void
516hvmd_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
531uint64_t fragsize;
532TAILQ_HEAD(, mblock) frag_mblocks;
533struct mblock *hvmd_mblock;
534
535void
536hvmd_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
561uint64_t
562hvmd_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
583void
584hvmd_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
593void
594hvmd_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
626void
627hvmd_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
646void
647hvmd_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
684void
685hvmd_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
748void
749hvmd_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
790void
791hvmd_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
891void
892hvmd_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
979void
980hvmd_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
1011void
1012hvmd_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
1030void
1031hvmd_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
1061void
1062hvmd_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
1079void
1080hvmd_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
1157void
1158hvmd_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
1181void
1182hvmd_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
1199void
1200hvmd_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
1218void
1219hvmd_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
1248void
1249hvmd_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
1267void
1268hvmd_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
1296void
1297hvmd_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
1315void
1316hvmd_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
1366void
1367hvmd_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
1385void
1386hvmd_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
1451struct ldc_endpoint *
1452hvmd_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
1477struct console *
1478hvmd_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
1522void
1523hvmd_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
1550struct ldc_channel *
1551hvmd_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
1580struct guest *
1581hvmd_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
1610struct md_node *
1611guest_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
1626struct md_node *
1627guest_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
1646struct md_node *
1647guest_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
1669struct md_node *
1670guest_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
1694struct md_node *
1695guest_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
1722struct md_node *
1723guest_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
1745struct md_node *
1746guest_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
1770struct md_node *
1771guest_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
1795struct md_node *
1796guest_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
1818struct md_node *
1819guest_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
1843struct md_node *
1844guest_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
1872struct md_node *
1873guest_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
1897struct md_node *
1898guest_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
1919struct md_node *
1920guest_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
1941struct md_node *
1942guest_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
1968struct md_node *
1969guest_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
1994struct md_node *
1995guest_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
2016struct md_node *
2017guest_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
2032struct md_node *
2033guest_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
2055void
2056guest_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
2074void
2075guest_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
2086void
2087guest_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
2104struct md_node *
2105guest_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
2130struct md_node *
2131guest_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
2157struct guest *
2158guest_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
2193int
2194guest_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
2210void
2211guest_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
2257void
2258guest_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
2287void
2288guest_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
2328void
2329guest_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
2378struct guest *
2379guest_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
2392void
2393guest_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
2412void
2413guest_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
2452void
2453guest_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
2483void
2484guest_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
2498void
2499guest_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
2531void
2532guest_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
2544void
2545guest_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
2568void
2569guest_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
2596void
2597guest_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
2628void
2629guest_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
2647void
2648guest_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
2673struct cpu *
2674guest_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
2685void
2686guest_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
2763struct guest *
2764primary_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
2776void
2777build_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
2892void
2893list_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