xref: /openbsd-src/usr.sbin/ldomctl/config.c (revision ee96180de911a25bf20a6f878c381b9ba950e865)
1*ee96180dSkn /*	$OpenBSD: config.c,v 1.43 2022/10/06 21:35:52 kn Exp $	*/
297d8cafcSkettenis 
397d8cafcSkettenis /*
48e765095Skettenis  * Copyright (c) 2012, 2018 Mark Kettenis
597d8cafcSkettenis  *
697d8cafcSkettenis  * Permission to use, copy, modify, and distribute this software for any
797d8cafcSkettenis  * purpose with or without fee is hereby granted, provided that the above
897d8cafcSkettenis  * copyright notice and this permission notice appear in all copies.
997d8cafcSkettenis  *
1097d8cafcSkettenis  * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
1197d8cafcSkettenis  * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
1297d8cafcSkettenis  * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
1397d8cafcSkettenis  * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
1497d8cafcSkettenis  * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
1597d8cafcSkettenis  * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
1697d8cafcSkettenis  * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
1797d8cafcSkettenis  */
1897d8cafcSkettenis 
1997d8cafcSkettenis #include <sys/types.h>
2097d8cafcSkettenis #include <sys/queue.h>
2197d8cafcSkettenis #include <assert.h>
2297d8cafcSkettenis #include <err.h>
2397d8cafcSkettenis #include <stdarg.h>
2497d8cafcSkettenis #include <stdbool.h>
2597d8cafcSkettenis #include <stdio.h>
2697d8cafcSkettenis #include <stdlib.h>
2797d8cafcSkettenis #include <string.h>
2897d8cafcSkettenis 
2997d8cafcSkettenis #include "mdesc.h"
3097d8cafcSkettenis #include "ldomctl.h"
31d73a4c4fSkn #include "ldom_util.h"
3297d8cafcSkettenis 
3397d8cafcSkettenis #define LDC_GUEST	0
3497d8cafcSkettenis #define LDC_HV		1
3597d8cafcSkettenis #define LDC_SP		2
3697d8cafcSkettenis 
3797d8cafcSkettenis #define LDC_HVCTL_SVC	1
3897d8cafcSkettenis #define LDC_CONSOLE_SVC	2
3997d8cafcSkettenis 
4002ce1e77Skettenis #define MAX_STRANDS_PER_CORE	16
4102ce1e77Skettenis 
4202ce1e77Skettenis struct core {
4302ce1e77Skettenis 	struct guest *guests[MAX_STRANDS_PER_CORE];
4402ce1e77Skettenis 	TAILQ_ENTRY(core) link;
4597d8cafcSkettenis };
4697d8cafcSkettenis 
4702ce1e77Skettenis TAILQ_HEAD(, core) cores;
4897d8cafcSkettenis 
498cfaec25Skettenis struct component {
508cfaec25Skettenis 	const char *path;
51fea9819cSkn 	const char *nac;
528cfaec25Skettenis 	int assigned;
538cfaec25Skettenis 
548cfaec25Skettenis 	struct md_node *hv_node;
558cfaec25Skettenis 	TAILQ_ENTRY(component) link;
568cfaec25Skettenis };
578cfaec25Skettenis 
588cfaec25Skettenis TAILQ_HEAD(, component) components;
598cfaec25Skettenis 
608cfaec25Skettenis struct hostbridge {
618cfaec25Skettenis 	const char *path;
628cfaec25Skettenis 
638cfaec25Skettenis 	uint64_t num_msi_eqs;
648cfaec25Skettenis 	uint64_t num_msis;
658cfaec25Skettenis 	uint64_t max_vpcis;
668cfaec25Skettenis 	TAILQ_ENTRY(hostbridge) link;
678cfaec25Skettenis };
688cfaec25Skettenis 
698cfaec25Skettenis TAILQ_HEAD(, hostbridge) hostbridges;
708cfaec25Skettenis 
7197d8cafcSkettenis struct frag {
7297d8cafcSkettenis 	TAILQ_ENTRY(frag) link;
7397d8cafcSkettenis 	uint64_t base;
7497d8cafcSkettenis };
7597d8cafcSkettenis 
7697d8cafcSkettenis struct guest **guests;
7797d8cafcSkettenis struct console **consoles;
7897d8cafcSkettenis struct cpu **cpus;
79e099dd74Skettenis struct device **pcie_busses;
80e099dd74Skettenis struct device **network_devices;
8197d8cafcSkettenis struct mblock **mblocks;
8297d8cafcSkettenis struct ldc_endpoint **ldc_endpoints;
8382783e0eSderaadt extern struct domain *domain;
8497d8cafcSkettenis 
858cfaec25Skettenis TAILQ_HEAD(, rootcomplex) rootcomplexes;
868cfaec25Skettenis 
8797d8cafcSkettenis uint64_t max_cpus;
887aadc77eSkettenis bool have_cwqs;
897aadc77eSkettenis bool have_rngs;
9097d8cafcSkettenis 
9197d8cafcSkettenis uint64_t max_guests;
9297d8cafcSkettenis uint64_t max_hv_ldcs;
9397d8cafcSkettenis uint64_t max_guest_ldcs;
94e099dd74Skettenis uint64_t md_maxsize;
9597d8cafcSkettenis uint64_t md_elbow_room;
9697d8cafcSkettenis uint64_t max_mblocks;
978cfaec25Skettenis uint64_t directio_capability;
9897d8cafcSkettenis 
99e099dd74Skettenis uint64_t max_devices = 16;
100e099dd74Skettenis 
10197d8cafcSkettenis uint64_t rombase;
10297d8cafcSkettenis uint64_t romsize;
103d27a0d69Skettenis uint64_t uartbase;
10497d8cafcSkettenis 
105ecf7be60Skettenis uint64_t max_page_size;
106ecf7be60Skettenis 
107e099dd74Skettenis uint64_t content_version;
108e099dd74Skettenis uint64_t stick_frequency;
1092151b4ddSkettenis uint64_t tod_frequency;
1102151b4ddSkettenis uint64_t tod;
1112151b4ddSkettenis uint64_t erpt_pa;
1122151b4ddSkettenis uint64_t erpt_size;
113e099dd74Skettenis 
11497d8cafcSkettenis struct md *pri;
11597d8cafcSkettenis struct md *hvmd;
11697d8cafcSkettenis struct md *protomd;
11797d8cafcSkettenis 
11897d8cafcSkettenis struct guest *guest_lookup(const char *);
1198cfaec25Skettenis void guest_prune_phys_io(struct guest *);
1208cfaec25Skettenis void guest_prune_pcie(struct guest *, struct md_node *, const char *);
1218cfaec25Skettenis void guest_add_vpcie(struct guest *, uint64_t);
1228cfaec25Skettenis void guest_fixup_phys_io(struct guest *);
12397d8cafcSkettenis 
12497d8cafcSkettenis TAILQ_HEAD(, frag) free_frags = TAILQ_HEAD_INITIALIZER(free_frags);
12597d8cafcSkettenis TAILQ_HEAD(, cpu) free_cpus = TAILQ_HEAD_INITIALIZER(free_cpus);
126ecf7be60Skettenis int total_cpus;
127ecf7be60Skettenis TAILQ_HEAD(, mblock) free_memory = TAILQ_HEAD_INITIALIZER(free_memory);
128ecf7be60Skettenis uint64_t total_memory;
12997d8cafcSkettenis 
13002ce1e77Skettenis struct cpu *
pri_find_cpu(uint64_t pid)13102ce1e77Skettenis pri_find_cpu(uint64_t pid)
13202ce1e77Skettenis {
13302ce1e77Skettenis 	struct cpu *cpu = NULL;
13402ce1e77Skettenis 
13502ce1e77Skettenis 	TAILQ_FOREACH(cpu, &free_cpus, link) {
13602ce1e77Skettenis 		if (cpu->pid == pid)
13702ce1e77Skettenis 			break;
13802ce1e77Skettenis 	}
13902ce1e77Skettenis 
14002ce1e77Skettenis 	return cpu;
14102ce1e77Skettenis }
14297d8cafcSkettenis 
14397d8cafcSkettenis void
pri_link_core(struct md * md,struct md_node * node,struct core * core)14402ce1e77Skettenis pri_link_core(struct md *md, struct md_node *node, struct core *core)
14597d8cafcSkettenis {
14697d8cafcSkettenis 	struct md_node *node2;
14797d8cafcSkettenis 	struct md_prop *prop;
14802ce1e77Skettenis 	struct cpu *cpu;
14902ce1e77Skettenis 	uint64_t pid;
15097d8cafcSkettenis 
15197d8cafcSkettenis 	TAILQ_FOREACH(prop, &node->prop_list, link) {
15297d8cafcSkettenis 		if (prop->tag == MD_PROP_ARC &&
15397d8cafcSkettenis 		    strcmp(prop->name->str, "back") == 0) {
15497d8cafcSkettenis 			node2 = prop->d.arc.node;
15502ce1e77Skettenis 			if (strcmp(node2->name->str, "cpu") != 0) {
15602ce1e77Skettenis 				pri_link_core(md, node2, core);
15702ce1e77Skettenis 				continue;
15897d8cafcSkettenis 			}
15902ce1e77Skettenis 
16002ce1e77Skettenis 			pid = -1;
16102ce1e77Skettenis 			if (!md_get_prop_val(md, node2, "pid", &pid))
16202ce1e77Skettenis 				md_get_prop_val(md, node2, "id", &pid);
16302ce1e77Skettenis 
16402ce1e77Skettenis 			cpu = pri_find_cpu(pid);
16502ce1e77Skettenis 			if (cpu == NULL)
16602ce1e77Skettenis 				errx(1, "couldn't determine core for VCPU %lld\n", pid);
16702ce1e77Skettenis 			cpu->core = core;
16897d8cafcSkettenis 		}
16997d8cafcSkettenis 	}
17097d8cafcSkettenis }
17197d8cafcSkettenis 
17297d8cafcSkettenis void
pri_add_core(struct md * md,struct md_node * node)17302ce1e77Skettenis pri_add_core(struct md *md, struct md_node *node)
17402ce1e77Skettenis {
17502ce1e77Skettenis 	struct core *core;
17602ce1e77Skettenis 
17702ce1e77Skettenis 	core = xzalloc(sizeof(*core));
17802ce1e77Skettenis 	TAILQ_INSERT_TAIL(&cores, core, link);
17902ce1e77Skettenis 
18002ce1e77Skettenis 	pri_link_core(md, node, core);
18102ce1e77Skettenis }
18202ce1e77Skettenis 
18302ce1e77Skettenis void
pri_init_cores(struct md * md)18497d8cafcSkettenis pri_init_cores(struct md *md)
18597d8cafcSkettenis {
18697d8cafcSkettenis 	struct md_node *node;
18797d8cafcSkettenis 	const void *type;
18897d8cafcSkettenis 	size_t len;
18997d8cafcSkettenis 
19002ce1e77Skettenis 	TAILQ_INIT(&cores);
19197d8cafcSkettenis 
19297d8cafcSkettenis 	TAILQ_FOREACH(node, &md->node_list, link) {
19397d8cafcSkettenis 		if (strcmp(node->name->str, "tlb") == 0 &&
19497d8cafcSkettenis 		    md_get_prop_data(md, node, "type", &type, &len) &&
19597d8cafcSkettenis 		    strcmp(type, "data") == 0) {
19602ce1e77Skettenis 			pri_add_core(md, node);
19797d8cafcSkettenis 		}
19897d8cafcSkettenis 	}
19997d8cafcSkettenis }
20097d8cafcSkettenis 
20197d8cafcSkettenis void
pri_add_hostbridge(struct md * md,struct md_node * node)2028cfaec25Skettenis pri_add_hostbridge(struct md *md, struct md_node *node)
2038cfaec25Skettenis {
2048cfaec25Skettenis 	struct hostbridge *hostbridge;
2058cfaec25Skettenis 
2068cfaec25Skettenis 	hostbridge = xzalloc(sizeof(*hostbridge));
2078cfaec25Skettenis 	md_get_prop_str(md, node, "path", &hostbridge->path);
2088cfaec25Skettenis 	md_get_prop_val(md, node, "#msi-eqs", &hostbridge->num_msi_eqs);
2098cfaec25Skettenis 	md_get_prop_val(md, node, "#msi", &hostbridge->num_msis);
2108cfaec25Skettenis 	if (!md_get_prop_val(md, node, "#max-vpcis", &hostbridge->max_vpcis))
2118cfaec25Skettenis 		hostbridge->max_vpcis = 10;
2128cfaec25Skettenis 	TAILQ_INSERT_TAIL(&hostbridges, hostbridge, link);
2138cfaec25Skettenis }
2148cfaec25Skettenis 
2158cfaec25Skettenis void
pri_init_components(struct md * md)2168cfaec25Skettenis pri_init_components(struct md *md)
2178cfaec25Skettenis {
2188cfaec25Skettenis 	struct component *component;
2198cfaec25Skettenis 	struct md_node *node;
2208cfaec25Skettenis 	const char *path;
221fea9819cSkn 	const char *nac;
2228cfaec25Skettenis 	const char *type;
2238cfaec25Skettenis 
2248cfaec25Skettenis 	TAILQ_INIT(&components);
2258cfaec25Skettenis 	TAILQ_INIT(&hostbridges);
2268cfaec25Skettenis 
2278cfaec25Skettenis 	TAILQ_FOREACH(node, &md->node_list, link) {
2288cfaec25Skettenis 		if (strcmp(node->name->str, "component") != 0)
2298cfaec25Skettenis 			continue;
2308cfaec25Skettenis 
2318cfaec25Skettenis 		if (md_get_prop_str(md, node, "assignable-path", &path)) {
2328cfaec25Skettenis 			component = xzalloc(sizeof(*component));
2338cfaec25Skettenis 			component->path = path;
234fea9819cSkn 			if (md_get_prop_str(md, node, "nac", &nac))
235fea9819cSkn 				component->nac = nac;
236fea9819cSkn 			else
237fea9819cSkn 				component->nac = "-";
2388cfaec25Skettenis 			TAILQ_INSERT_TAIL(&components, component, link);
2398cfaec25Skettenis 		}
2408cfaec25Skettenis 
2418cfaec25Skettenis 		if (md_get_prop_str(md, node, "type", &type) &&
2428cfaec25Skettenis 		    strcmp(type, "hostbridge") == 0)
2438cfaec25Skettenis 			pri_add_hostbridge(md, node);
2448cfaec25Skettenis 	}
2458cfaec25Skettenis }
2468cfaec25Skettenis 
2478cfaec25Skettenis void
pri_init_phys_io(struct md * md)2488cfaec25Skettenis pri_init_phys_io(struct md *md)
2498cfaec25Skettenis {
2508cfaec25Skettenis 	struct md_node *node;
2518cfaec25Skettenis 	const char *device_type;
2528cfaec25Skettenis 	uint64_t cfg_handle;
2538cfaec25Skettenis 	struct rootcomplex *rootcomplex;
2548cfaec25Skettenis 	char *path;
2558cfaec25Skettenis 	size_t len;
2568cfaec25Skettenis 
2578cfaec25Skettenis 	TAILQ_INIT(&rootcomplexes);
2588cfaec25Skettenis 
2598cfaec25Skettenis 	TAILQ_FOREACH(node, &md->node_list, link) {
2608cfaec25Skettenis 		if (strcmp(node->name->str, "iodevice") == 0 &&
2618cfaec25Skettenis 		    md_get_prop_str(md, node, "device-type", &device_type) &&
2628cfaec25Skettenis 		    strcmp(device_type, "pciex") == 0) {
2638cfaec25Skettenis 			if (!md_get_prop_val(md, node, "cfg-handle",
2648cfaec25Skettenis 					     &cfg_handle))
2658cfaec25Skettenis 				continue;
2668cfaec25Skettenis 
2678cfaec25Skettenis 			rootcomplex = xzalloc(sizeof(*rootcomplex));
2688cfaec25Skettenis 			md_get_prop_val(md, node, "#msi-eqs",
2698cfaec25Skettenis 			    &rootcomplex->num_msi_eqs);
2708cfaec25Skettenis 			md_get_prop_val(md, node, "#msi",
2718cfaec25Skettenis 			    &rootcomplex->num_msis);
2728cfaec25Skettenis 			md_get_prop_data(md, node, "msi-ranges",
2738cfaec25Skettenis 			    &rootcomplex->msi_ranges, &len);
2748cfaec25Skettenis 			rootcomplex->num_msi_ranges =
2758cfaec25Skettenis 			    len / (2 * sizeof(uint64_t));
2768cfaec25Skettenis 			md_get_prop_data(md, node, "virtual-dma",
2778cfaec25Skettenis 			    &rootcomplex->vdma_ranges, &len);
2788cfaec25Skettenis 			rootcomplex->num_vdma_ranges =
2798cfaec25Skettenis 			    len / (2 * sizeof(uint64_t));
2808cfaec25Skettenis 			rootcomplex->cfghandle = cfg_handle;
2818cfaec25Skettenis 			xasprintf(&path, "/@%llx", cfg_handle);
2828cfaec25Skettenis 			rootcomplex->path = path;
2838cfaec25Skettenis 			TAILQ_INSERT_TAIL(&rootcomplexes, rootcomplex, link);
2848cfaec25Skettenis 		}
2858cfaec25Skettenis 	}
2868cfaec25Skettenis }
2878cfaec25Skettenis 
2888cfaec25Skettenis void
pri_add_cpu(struct md * md,struct md_node * node)28997d8cafcSkettenis pri_add_cpu(struct md *md, struct md_node *node)
29097d8cafcSkettenis {
29197d8cafcSkettenis 	struct cpu *cpu;
292ecf7be60Skettenis 	uint64_t mmu_page_size_list;
293ecf7be60Skettenis 	uint64_t page_size;
29497d8cafcSkettenis 
295ecf7be60Skettenis 	cpu = xzalloc(sizeof(*cpu));
296dc357e04Skettenis 	/*
297dc357e04Skettenis 	 * Only UltraSPARC T1 CPUs have a "pid" property.  All other
298dc357e04Skettenis 	 * just have a "id" property that can be used as the physical ID.
299dc357e04Skettenis 	 */
300dc357e04Skettenis 	if (!md_get_prop_val(md, node, "pid", &cpu->pid))
301dc357e04Skettenis 		md_get_prop_val(md, node, "id", &cpu->pid);
30297d8cafcSkettenis 	cpu->vid = -1;
30397d8cafcSkettenis 	cpu->gid = -1;
30497d8cafcSkettenis 	cpu->partid = -1;
30597d8cafcSkettenis 	cpu->resource_id = -1;
30697d8cafcSkettenis 	TAILQ_INSERT_TAIL(&free_cpus, cpu, link);
307ecf7be60Skettenis 	total_cpus++;
308ecf7be60Skettenis 
309ecf7be60Skettenis 	mmu_page_size_list = 0x9;
310e099dd74Skettenis 	md_get_prop_val(md, node, "mmu-page-size-list", &mmu_page_size_list);
311ecf7be60Skettenis 
312ecf7be60Skettenis 	page_size = 1024;
313ecf7be60Skettenis 	while (mmu_page_size_list) {
314ecf7be60Skettenis 		page_size *= 8;
315ecf7be60Skettenis 		mmu_page_size_list >>= 1;
316ecf7be60Skettenis 	}
317ecf7be60Skettenis 
318ecf7be60Skettenis 	if (page_size > max_page_size)
319ecf7be60Skettenis 		max_page_size = page_size;
32097d8cafcSkettenis }
32197d8cafcSkettenis 
32297d8cafcSkettenis struct cpu *
pri_alloc_cpu(uint64_t pid)32397d8cafcSkettenis pri_alloc_cpu(uint64_t pid)
32497d8cafcSkettenis {
32597d8cafcSkettenis 	struct cpu *cpu;
32697d8cafcSkettenis 
32797d8cafcSkettenis 	if (pid == -1 && !TAILQ_EMPTY(&free_cpus)) {
32897d8cafcSkettenis 		cpu = TAILQ_FIRST(&free_cpus);
32997d8cafcSkettenis 		TAILQ_REMOVE(&free_cpus, cpu, link);
33097d8cafcSkettenis 		return cpu;
33197d8cafcSkettenis 	}
33297d8cafcSkettenis 
33397d8cafcSkettenis 	TAILQ_FOREACH(cpu, &free_cpus, link) {
33497d8cafcSkettenis 		if (cpu->pid == pid) {
33597d8cafcSkettenis 			TAILQ_REMOVE(&free_cpus, cpu, link);
33697d8cafcSkettenis 			return cpu;
33797d8cafcSkettenis 		}
33897d8cafcSkettenis 	}
33997d8cafcSkettenis 
34097d8cafcSkettenis 	return NULL;
34197d8cafcSkettenis }
34297d8cafcSkettenis 
34397d8cafcSkettenis void
pri_free_cpu(struct cpu * cpu)34497d8cafcSkettenis pri_free_cpu(struct cpu *cpu)
34597d8cafcSkettenis {
34697d8cafcSkettenis 	TAILQ_INSERT_TAIL(&free_cpus, cpu, link);
34797d8cafcSkettenis }
34897d8cafcSkettenis 
34997d8cafcSkettenis void
pri_add_mblock(struct md * md,struct md_node * node)350ecf7be60Skettenis pri_add_mblock(struct md *md, struct md_node *node)
351ecf7be60Skettenis {
352ecf7be60Skettenis 	struct mblock *mblock;
353ecf7be60Skettenis 
354ecf7be60Skettenis 	mblock = xzalloc(sizeof(*mblock));
355ecf7be60Skettenis 	md_get_prop_val(md, node, "base", &mblock->membase);
356ecf7be60Skettenis 	md_get_prop_val(md, node, "size", &mblock->memsize);
357ecf7be60Skettenis 	mblock->resource_id = -1;
358ecf7be60Skettenis 	TAILQ_INSERT_TAIL(&free_memory, mblock, link);
359ecf7be60Skettenis 	total_memory += mblock->memsize;
360ecf7be60Skettenis }
361ecf7be60Skettenis 
362ecf7be60Skettenis struct mblock *
pri_alloc_memory(uint64_t base,uint64_t size)363ecf7be60Skettenis pri_alloc_memory(uint64_t base, uint64_t size)
364ecf7be60Skettenis {
365ecf7be60Skettenis 	struct mblock *mblock, *new_mblock;
366ecf7be60Skettenis 	uint64_t memend;
367ecf7be60Skettenis 
368ecf7be60Skettenis 	if (base == -1 && !TAILQ_EMPTY(&free_memory)) {
369ecf7be60Skettenis 		mblock = TAILQ_FIRST(&free_memory);
370ecf7be60Skettenis 		base = mblock->membase;
371ecf7be60Skettenis 	}
372ecf7be60Skettenis 
373ecf7be60Skettenis 	TAILQ_FOREACH(mblock, &free_memory, link) {
374ecf7be60Skettenis 		if (base >= mblock->membase &&
375ecf7be60Skettenis 		    base < mblock->membase + mblock->memsize) {
376ecf7be60Skettenis 			if (base > mblock->membase) {
377ecf7be60Skettenis 				new_mblock = xzalloc(sizeof(*new_mblock));
378ecf7be60Skettenis 				new_mblock->membase = mblock->membase;
379ecf7be60Skettenis 				new_mblock->memsize = base - mblock->membase;
380ecf7be60Skettenis 				new_mblock->resource_id = -1;
381ecf7be60Skettenis 				TAILQ_INSERT_BEFORE(mblock, new_mblock, link);
382ecf7be60Skettenis 			}
383ecf7be60Skettenis 
384ecf7be60Skettenis 			memend = mblock->membase + mblock->memsize;
385ecf7be60Skettenis 			mblock->membase = base + size;
386ecf7be60Skettenis 			mblock->memsize = memend - mblock->membase;
387ecf7be60Skettenis 			if (mblock->memsize == 0) {
388ecf7be60Skettenis 				TAILQ_REMOVE(&free_memory, mblock, link);
389ecf7be60Skettenis 				free(mblock);
390ecf7be60Skettenis 			}
391ecf7be60Skettenis 
392ecf7be60Skettenis 			total_memory -= size;
393ecf7be60Skettenis 
394ecf7be60Skettenis 			new_mblock = xzalloc(sizeof(*new_mblock));
395ecf7be60Skettenis 			new_mblock->membase = base;
396ecf7be60Skettenis 			new_mblock->memsize = size;
397ecf7be60Skettenis 			new_mblock->resource_id = -1;
398ab8e3451Sderaadt 			return new_mblock;
399ecf7be60Skettenis 		}
400ecf7be60Skettenis 	}
401ecf7be60Skettenis 
402ecf7be60Skettenis 	return NULL;
403ecf7be60Skettenis }
404ecf7be60Skettenis 
405ecf7be60Skettenis void
pri_delete_devalias(struct md * md)406d27a0d69Skettenis pri_delete_devalias(struct md *md)
407d27a0d69Skettenis {
408d27a0d69Skettenis 	struct md_node *node;
409d27a0d69Skettenis 
410d27a0d69Skettenis 	/*
411d27a0d69Skettenis 	 * There may be multiple "devalias" nodes.  Only remove the one
412d27a0d69Skettenis 	 * that resides under the "openboot" node.
413d27a0d69Skettenis 	 */
414d27a0d69Skettenis 	node = md_find_node(protomd, "openboot");
415d27a0d69Skettenis 	assert(node);
416d27a0d69Skettenis 	node = md_find_subnode(protomd, node, "devalias");
417d27a0d69Skettenis 	if (node)
418d27a0d69Skettenis 		md_delete_node(protomd, node);
419d27a0d69Skettenis }
420d27a0d69Skettenis 
421d27a0d69Skettenis void
pri_init(struct md * md)42297d8cafcSkettenis pri_init(struct md *md)
42397d8cafcSkettenis {
42497d8cafcSkettenis 	struct md_node *node, *node2;
42597d8cafcSkettenis 	struct md_prop *prop;
42697d8cafcSkettenis 	uint64_t base, size;
42797d8cafcSkettenis 	uint64_t offset, guest_use;
42897d8cafcSkettenis 
42997d8cafcSkettenis 	node = md_find_node(pri, "platform");
43097d8cafcSkettenis 	if (node == NULL)
43197d8cafcSkettenis 		errx(1, "platform node not found");
43297d8cafcSkettenis 
43397d8cafcSkettenis 	md_get_prop_val(md, node, "max-cpus", &max_cpus);
43497d8cafcSkettenis 
43597d8cafcSkettenis 	node = md_find_node(pri, "firmware");
43697d8cafcSkettenis 	if (node == NULL)
43797d8cafcSkettenis 		errx(1, "firmware node not found");
43897d8cafcSkettenis 
43997d8cafcSkettenis 	md_get_prop_val(md, node, "max_guests", &max_guests);
44097d8cafcSkettenis 	md_get_prop_val(md, node, "max_hv_ldcs", &max_hv_ldcs);
44197d8cafcSkettenis 	md_get_prop_val(md, node, "max_guest_ldcs", &max_guest_ldcs);
44297d8cafcSkettenis 	md_get_prop_val(md, node, "md_elbow_room", &md_elbow_room);
44397d8cafcSkettenis 	md_get_prop_val(md, node, "max_mblocks", &max_mblocks);
4448cfaec25Skettenis 	md_get_prop_val(md, node, "directio_capability", &directio_capability);
44597d8cafcSkettenis 
44697d8cafcSkettenis 	node = md_find_node(md, "read_only_memory");
44797d8cafcSkettenis 	if (node == NULL)
44897d8cafcSkettenis 		errx(1, "read_only_memory node not found");
44997d8cafcSkettenis 	if (!md_get_prop_val(md, node, "base", &base))
45097d8cafcSkettenis 		errx(1, "missing base property in read_only_memory node");
45197d8cafcSkettenis 	if (!md_get_prop_val(md, node, "size", &size))
45297d8cafcSkettenis 		errx(1, "missing size property in read_only_memory node");
45397d8cafcSkettenis 	TAILQ_FOREACH(prop, &node->prop_list, link) {
45497d8cafcSkettenis 		if (prop->tag == MD_PROP_ARC &&
45597d8cafcSkettenis 		    strcmp(prop->name->str, "fwd") == 0) {
45697d8cafcSkettenis 			node2 = prop->d.arc.node;
45797d8cafcSkettenis 			if (!md_get_prop_val(md, node2, "guest_use",
45897d8cafcSkettenis 			    &guest_use) || guest_use == 0)
45997d8cafcSkettenis 				continue;
46097d8cafcSkettenis 			if (!md_get_prop_val(md, node2, "offset", &offset) ||
46197d8cafcSkettenis 			    !md_get_prop_val(md, node2, "size", &size))
46297d8cafcSkettenis 				continue;
46397d8cafcSkettenis 			rombase = base + offset;
46497d8cafcSkettenis 			romsize = size;
46597d8cafcSkettenis 		}
46697d8cafcSkettenis 	}
46797d8cafcSkettenis 	if (romsize == 0)
46897d8cafcSkettenis 		errx(1, "no suitable firmware image found");
46997d8cafcSkettenis 
47097d8cafcSkettenis 	node = md_find_node(md, "platform");
47197d8cafcSkettenis 	assert(node);
47297d8cafcSkettenis 	md_set_prop_val(md, node, "domaining-enabled", 0x1);
47397d8cafcSkettenis 
47497d8cafcSkettenis 	md_write(md, "pri");
47597d8cafcSkettenis 
47697d8cafcSkettenis 	protomd = md_copy(md);
47797d8cafcSkettenis 	md_find_delete_node(protomd, "components");
47897d8cafcSkettenis 	md_find_delete_node(protomd, "domain-services");
47997d8cafcSkettenis 	md_find_delete_node(protomd, "channel-devices");
48097d8cafcSkettenis 	md_find_delete_node(protomd, "channel-endpoints");
48197d8cafcSkettenis 	md_find_delete_node(protomd, "firmware");
48297d8cafcSkettenis 	md_find_delete_node(protomd, "ldc_endpoints");
48397d8cafcSkettenis 	md_find_delete_node(protomd, "memory-segments");
484d27a0d69Skettenis 	pri_delete_devalias(protomd);
48597d8cafcSkettenis 	md_collect_garbage(protomd);
48697d8cafcSkettenis 	md_write(protomd, "protomd");
48797d8cafcSkettenis 
48897d8cafcSkettenis 	guests = xzalloc(max_guests * sizeof(*guests));
48997d8cafcSkettenis 	consoles = xzalloc(max_guests * sizeof(*consoles));
49097d8cafcSkettenis 	cpus = xzalloc(max_cpus * sizeof(*cpus));
491e099dd74Skettenis 	pcie_busses = xzalloc(max_devices * sizeof(*pcie_busses));
492e099dd74Skettenis 	network_devices = xzalloc(max_devices * sizeof(*network_devices));
49397d8cafcSkettenis 	mblocks = xzalloc(max_mblocks * sizeof(*mblocks));
49497d8cafcSkettenis 	ldc_endpoints = xzalloc(max_guest_ldcs * sizeof(*ldc_endpoints));
49597d8cafcSkettenis 
49697d8cafcSkettenis 	node = md_find_node(md, "cpus");
49797d8cafcSkettenis 	TAILQ_FOREACH(prop, &node->prop_list, link) {
49897d8cafcSkettenis 		if (prop->tag == MD_PROP_ARC &&
49997d8cafcSkettenis 		    strcmp(prop->name->str, "fwd") == 0)
50097d8cafcSkettenis 			pri_add_cpu(md, prop->d.arc.node);
50197d8cafcSkettenis 	}
50297d8cafcSkettenis 
503ecf7be60Skettenis 	node = md_find_node(md, "memory");
504ecf7be60Skettenis 	TAILQ_FOREACH(prop, &node->prop_list, link) {
505ecf7be60Skettenis 		if (prop->tag == MD_PROP_ARC &&
506ecf7be60Skettenis 		    strcmp(prop->name->str, "fwd") == 0)
507ecf7be60Skettenis 			pri_add_mblock(md, prop->d.arc.node);
508ecf7be60Skettenis 	}
509ecf7be60Skettenis 
51097d8cafcSkettenis 	pri_init_cores(md);
5118cfaec25Skettenis 	pri_init_components(md);
5128cfaec25Skettenis 	pri_init_phys_io(md);
51397d8cafcSkettenis }
51497d8cafcSkettenis 
515ecf7be60Skettenis void
hvmd_fixup_guest(struct md * md,struct md_node * guest,struct md_node * node)516ecf7be60Skettenis hvmd_fixup_guest(struct md *md, struct md_node *guest, struct md_node *node)
517ecf7be60Skettenis {
518ecf7be60Skettenis 	struct md_prop *prop;
519ecf7be60Skettenis 
520ecf7be60Skettenis 	TAILQ_FOREACH(prop, &guest->prop_list, link) {
521ecf7be60Skettenis 		if (prop->tag == MD_PROP_ARC &&
522ecf7be60Skettenis 		    strcmp(prop->name->str, "fwd") == 0) {
523ecf7be60Skettenis 			if (prop->d.arc.node == node)
524ecf7be60Skettenis 				return;
525ecf7be60Skettenis 		}
526ecf7be60Skettenis 	}
527ecf7be60Skettenis 
528ecf7be60Skettenis 	md_add_prop_arc(md, guest, "fwd", node);
529ecf7be60Skettenis }
530ecf7be60Skettenis 
53197d8cafcSkettenis uint64_t fragsize;
532e099dd74Skettenis TAILQ_HEAD(, mblock) frag_mblocks;
5339e5c6997Skettenis struct mblock *hvmd_mblock;
53497d8cafcSkettenis 
53597d8cafcSkettenis void
hvmd_init_frag(struct md * md,struct md_node * node)53697d8cafcSkettenis hvmd_init_frag(struct md *md, struct md_node *node)
53797d8cafcSkettenis {
53897d8cafcSkettenis 	struct frag *frag;
539e099dd74Skettenis 	struct mblock *mblock;
54097d8cafcSkettenis 	uint64_t base, size;
54197d8cafcSkettenis 
54297d8cafcSkettenis 	md_get_prop_val(md, node, "base", &base);
54397d8cafcSkettenis 	md_get_prop_val(md, node, "size", &size);
544e099dd74Skettenis 
545ecf7be60Skettenis 	pri_alloc_memory(base, size);
546e099dd74Skettenis 
547e099dd74Skettenis 	mblock = xzalloc(sizeof(*mblock));
548e099dd74Skettenis 	mblock->membase = base;
549e099dd74Skettenis 	mblock->memsize = size;
550e099dd74Skettenis 	TAILQ_INSERT_TAIL(&frag_mblocks, mblock, link);
551e099dd74Skettenis 
55297d8cafcSkettenis 	while (size > fragsize) {
55397d8cafcSkettenis 		frag = xmalloc(sizeof(*frag));
55497d8cafcSkettenis 		frag->base = base;
55597d8cafcSkettenis 		TAILQ_INSERT_TAIL(&free_frags, frag, link);
55697d8cafcSkettenis 		base += fragsize;
55797d8cafcSkettenis 		size -= fragsize;
55897d8cafcSkettenis 	}
55997d8cafcSkettenis }
56097d8cafcSkettenis 
56197d8cafcSkettenis uint64_t
hvmd_alloc_frag(uint64_t base)56297d8cafcSkettenis hvmd_alloc_frag(uint64_t base)
56397d8cafcSkettenis {
56497d8cafcSkettenis 	struct frag *frag = TAILQ_FIRST(&free_frags);
56597d8cafcSkettenis 
56697d8cafcSkettenis 	if (base != -1) {
56797d8cafcSkettenis 		TAILQ_FOREACH(frag, &free_frags, link) {
56897d8cafcSkettenis 			if (frag->base == base)
56997d8cafcSkettenis 				break;
57097d8cafcSkettenis 		}
57197d8cafcSkettenis 	}
57297d8cafcSkettenis 
573abcbcc4dSdoug 	if (frag == NULL)
57497d8cafcSkettenis 		return -1;
57597d8cafcSkettenis 
57697d8cafcSkettenis 	TAILQ_REMOVE(&free_frags, frag, link);
57797d8cafcSkettenis 	base = frag->base;
57897d8cafcSkettenis 	free(frag);
57997d8cafcSkettenis 
58097d8cafcSkettenis 	return base;
58197d8cafcSkettenis }
58297d8cafcSkettenis 
58397d8cafcSkettenis void
hvmd_free_frag(uint64_t base)584644bca12Skettenis hvmd_free_frag(uint64_t base)
585644bca12Skettenis {
586644bca12Skettenis 	struct frag *frag;
587644bca12Skettenis 
588644bca12Skettenis 	frag = xmalloc(sizeof(*frag));
589644bca12Skettenis 	frag->base = base;
590644bca12Skettenis 	TAILQ_INSERT_TAIL(&free_frags, frag, link);
591644bca12Skettenis }
592644bca12Skettenis 
593644bca12Skettenis void
hvmd_init_mblock(struct md * md,struct md_node * node)59497d8cafcSkettenis hvmd_init_mblock(struct md *md, struct md_node *node)
59597d8cafcSkettenis {
59697d8cafcSkettenis 	struct mblock *mblock;
59797d8cafcSkettenis 	uint64_t resource_id;
598ecf7be60Skettenis 	struct md_node *node2;
599ecf7be60Skettenis 	struct md_prop *prop;
60097d8cafcSkettenis 
60197d8cafcSkettenis 	if (!md_get_prop_val(md, node, "resource_id", &resource_id))
60297d8cafcSkettenis 		errx(1, "missing resource_id property in mblock node");
60397d8cafcSkettenis 
60497d8cafcSkettenis 	if (resource_id >= max_mblocks)
60597d8cafcSkettenis 		errx(1, "resource_id larger than max_mblocks");
60697d8cafcSkettenis 
607e099dd74Skettenis 	mblock = xzalloc(sizeof(*mblock));
60897d8cafcSkettenis 	md_get_prop_val(md, node, "membase", &mblock->membase);
60997d8cafcSkettenis 	md_get_prop_val(md, node, "memsize", &mblock->memsize);
61097d8cafcSkettenis 	md_get_prop_val(md, node, "realbase", &mblock->realbase);
61197d8cafcSkettenis 	mblock->resource_id = resource_id;
61297d8cafcSkettenis 	mblocks[resource_id] = mblock;
61397d8cafcSkettenis 	mblock->hv_node = node;
614ecf7be60Skettenis 
615ecf7be60Skettenis 	/* Fixup missing links. */
616ecf7be60Skettenis 	TAILQ_FOREACH(prop, &node->prop_list, link) {
617ecf7be60Skettenis 		if (prop->tag == MD_PROP_ARC &&
618ecf7be60Skettenis 		    strcmp(prop->name->str, "back") == 0) {
619ecf7be60Skettenis 			node2 = prop->d.arc.node;
620ecf7be60Skettenis 			if (strcmp(node2->name->str, "guest") == 0)
621ecf7be60Skettenis 				hvmd_fixup_guest(md, node2, node);
622ecf7be60Skettenis 		}
623ecf7be60Skettenis 	}
62497d8cafcSkettenis }
62597d8cafcSkettenis 
62697d8cafcSkettenis void
hvmd_init_console(struct md * md,struct md_node * node)62797d8cafcSkettenis hvmd_init_console(struct md *md, struct md_node *node)
62897d8cafcSkettenis {
62997d8cafcSkettenis 	struct console *console;
63097d8cafcSkettenis 	uint64_t resource_id;
63197d8cafcSkettenis 
63297d8cafcSkettenis 	if (!md_get_prop_val(md, node, "resource_id", &resource_id))
63397d8cafcSkettenis 		errx(1, "missing resource_id property in console node");
63497d8cafcSkettenis 
63597d8cafcSkettenis 	if (resource_id >= max_guests)
63697d8cafcSkettenis 		errx(1, "resource_id larger than max_guests");
63797d8cafcSkettenis 
638d27a0d69Skettenis 	console = xzalloc(sizeof(*console));
63997d8cafcSkettenis 	md_get_prop_val(md, node, "ino", &console->ino);
640d27a0d69Skettenis 	md_get_prop_val(md, node, "uartbase", &console->uartbase);
64197d8cafcSkettenis 	console->resource_id = resource_id;
64297d8cafcSkettenis 	consoles[resource_id] = console;
64397d8cafcSkettenis 	console->hv_node = node;
64497d8cafcSkettenis }
64597d8cafcSkettenis 
64697d8cafcSkettenis void
hvmd_init_cpu(struct md * md,struct md_node * node)64797d8cafcSkettenis hvmd_init_cpu(struct md *md, struct md_node *node)
64897d8cafcSkettenis {
64997d8cafcSkettenis 	struct cpu *cpu;
65097d8cafcSkettenis 	uint64_t pid;
65197d8cafcSkettenis 	uint64_t resource_id;
65297d8cafcSkettenis 	struct md_node *node2;
65397d8cafcSkettenis 	struct md_prop *prop;
65497d8cafcSkettenis 
65597d8cafcSkettenis 	if (!md_get_prop_val(md, node, "resource_id", &resource_id))
65697d8cafcSkettenis 		errx(1, "missing resource_id property in cpu node");
65797d8cafcSkettenis 
65897d8cafcSkettenis 	if (resource_id >= max_cpus)
65997d8cafcSkettenis 		errx(1, "resource_id larger than max-cpus");
66097d8cafcSkettenis 
66197d8cafcSkettenis 	if (!md_get_prop_val(md, node, "pid", &pid))
66297d8cafcSkettenis 		errx(1, "missing pid property in cpu node");
66397d8cafcSkettenis 
66497d8cafcSkettenis 	cpu = pri_alloc_cpu(pid);
66597d8cafcSkettenis 	md_get_prop_val(md, node, "vid", &cpu->vid);
66697d8cafcSkettenis 	if (!md_get_prop_val(md, node, "gid", &cpu->gid))
66797d8cafcSkettenis 		cpu->gid = 0;
66897d8cafcSkettenis 	md_get_prop_val(md, node, "partid", &cpu->partid);
66997d8cafcSkettenis 	cpu->resource_id = resource_id;
67097d8cafcSkettenis 	cpus[resource_id] = cpu;
67197d8cafcSkettenis 	cpu->hv_node = node;
67297d8cafcSkettenis 
67397d8cafcSkettenis 	/* Fixup missing links. */
67497d8cafcSkettenis 	TAILQ_FOREACH(prop, &node->prop_list, link) {
67597d8cafcSkettenis 		if (prop->tag == MD_PROP_ARC &&
67697d8cafcSkettenis 		    strcmp(prop->name->str, "back") == 0) {
67797d8cafcSkettenis 			node2 = prop->d.arc.node;
67897d8cafcSkettenis 			if (strcmp(node2->name->str, "guest") == 0)
67997d8cafcSkettenis 				hvmd_fixup_guest(md, node2, node);
68097d8cafcSkettenis 		}
68197d8cafcSkettenis 	}
68297d8cafcSkettenis }
68397d8cafcSkettenis 
68497d8cafcSkettenis void
hvmd_init_device(struct md * md,struct md_node * node)685e099dd74Skettenis hvmd_init_device(struct md *md, struct md_node *node)
686e099dd74Skettenis {
6878cfaec25Skettenis 	struct hostbridge *hostbridge;
688e099dd74Skettenis 	struct device *device;
689e099dd74Skettenis 	uint64_t resource_id;
690e099dd74Skettenis 	struct md_node *node2;
691e099dd74Skettenis 	struct md_prop *prop;
6928cfaec25Skettenis 	char *path;
693e099dd74Skettenis 
6942151b4ddSkettenis 	if (strcmp(node->name->str, "pcie_bus") != 0 &&
6952151b4ddSkettenis 	    strcmp(node->name->str, "network_device") != 0)
6962151b4ddSkettenis 		return;
6972151b4ddSkettenis 
698e099dd74Skettenis 	if (!md_get_prop_val(md, node, "resource_id", &resource_id))
699e099dd74Skettenis 		errx(1, "missing resource_id property in ldc_endpoint node");
700e099dd74Skettenis 
701e099dd74Skettenis 	if (resource_id >= max_devices)
702e099dd74Skettenis 		errx(1, "resource_id larger than max_devices");
703e099dd74Skettenis 
704e099dd74Skettenis 	device = xzalloc(sizeof(*device));
705e099dd74Skettenis 	md_get_prop_val(md, node, "gid", &device->gid);
706e099dd74Skettenis 	md_get_prop_val(md, node, "cfghandle", &device->cfghandle);
707d27a0d69Skettenis 	md_get_prop_val(md, node, "rcid", &device->rcid);
708e099dd74Skettenis 	device->resource_id = resource_id;
709e099dd74Skettenis 	if (strcmp(node->name->str, "pcie_bus") == 0)
710e099dd74Skettenis 		pcie_busses[resource_id] = device;
711e099dd74Skettenis 	else
712e099dd74Skettenis 		network_devices[resource_id] = device;
713e099dd74Skettenis 	device->hv_node = node;
714e099dd74Skettenis 
715e099dd74Skettenis 	/* Fixup missing links. */
716e099dd74Skettenis 	TAILQ_FOREACH(prop, &node->prop_list, link) {
717e099dd74Skettenis 		if (prop->tag == MD_PROP_ARC &&
718e099dd74Skettenis 		    strcmp(prop->name->str, "back") == 0) {
719e099dd74Skettenis 			node2 = prop->d.arc.node;
720e099dd74Skettenis 			if (strcmp(node2->name->str, "guest") == 0)
721e099dd74Skettenis 				hvmd_fixup_guest(md, node2, node);
722e099dd74Skettenis 		}
723e099dd74Skettenis 	}
7248cfaec25Skettenis 
7258cfaec25Skettenis 	xasprintf(&path, "/@%llx", device->cfghandle);
7268cfaec25Skettenis 	TAILQ_FOREACH(hostbridge, &hostbridges, link) {
7278cfaec25Skettenis 		if (strcmp(hostbridge->path, path) == 0)
7288cfaec25Skettenis 			break;
7298cfaec25Skettenis 	}
7308cfaec25Skettenis 	free(path);
7318cfaec25Skettenis 	if (hostbridge == NULL)
7328cfaec25Skettenis 		return;
7338cfaec25Skettenis 
7348cfaec25Skettenis 	device->msi_eqs_per_vpci =
7358cfaec25Skettenis 	    hostbridge->num_msi_eqs / hostbridge->max_vpcis;
7368cfaec25Skettenis 	device->msis_per_vpci =
7378cfaec25Skettenis 	    hostbridge->num_msis / hostbridge->max_vpcis;
7388cfaec25Skettenis 	device->msi_base = hostbridge->num_msis;
7398cfaec25Skettenis 
7408cfaec25Skettenis 	device->num_msi_eqs = device->msi_eqs_per_vpci +
7418cfaec25Skettenis 	    hostbridge->num_msi_eqs % hostbridge->max_vpcis;
7428cfaec25Skettenis 	device->num_msis = device->msis_per_vpci +
7438cfaec25Skettenis 	    hostbridge->num_msis % hostbridge->max_vpcis;
7448cfaec25Skettenis 	device->msi_ranges[0] = 0;
7458cfaec25Skettenis 	device->msi_ranges[1] = device->num_msis;
746e099dd74Skettenis }
747e099dd74Skettenis 
748e099dd74Skettenis void
hvmd_init_endpoint(struct md * md,struct md_node * node)74997d8cafcSkettenis hvmd_init_endpoint(struct md *md, struct md_node *node)
75097d8cafcSkettenis {
75197d8cafcSkettenis 	struct ldc_endpoint *endpoint;
75297d8cafcSkettenis 	uint64_t resource_id;
75397d8cafcSkettenis 
75497d8cafcSkettenis 	if (!md_get_prop_val(md, node, "resource_id", &resource_id))
75597d8cafcSkettenis 		errx(1, "missing resource_id property in ldc_endpoint node");
75697d8cafcSkettenis 
75797d8cafcSkettenis 	if (resource_id >= max_guest_ldcs)
75897d8cafcSkettenis 		errx(1, "resource_id larger than max_guest_ldcs");
75997d8cafcSkettenis 
76061b75418Skettenis 	if (ldc_endpoints[resource_id]) {
76161b75418Skettenis 		/*
76261b75418Skettenis 		 * Some machine descriptions seem to have duplicate
76361b75418Skettenis 		 * arcs.  Fortunately, these can be easily detected
76461b75418Skettenis 		 * and ignored.
76561b75418Skettenis 		 */
76661b75418Skettenis 		if (ldc_endpoints[resource_id]->hv_node == node)
76761b75418Skettenis 			return;
76897d8cafcSkettenis 		errx(1, "duplicate resource_id");
76961b75418Skettenis 	}
77097d8cafcSkettenis 
77197d8cafcSkettenis 	endpoint = xzalloc(sizeof(*endpoint));
772e099dd74Skettenis 	endpoint->target_guest = -1;
773e099dd74Skettenis 	endpoint->tx_ino = -1;
774e099dd74Skettenis 	endpoint->rx_ino = -1;
775e099dd74Skettenis 	endpoint->private_svc = -1;
776e099dd74Skettenis 	endpoint->svc_id = -1;
77797d8cafcSkettenis 	md_get_prop_val(md, node, "target_type", &endpoint->target_type);
77897d8cafcSkettenis 	md_get_prop_val(md, node, "target_guest", &endpoint->target_guest);
77997d8cafcSkettenis 	md_get_prop_val(md, node, "channel", &endpoint->channel);
78097d8cafcSkettenis 	md_get_prop_val(md, node, "target_channel", &endpoint->target_channel);
78197d8cafcSkettenis 	md_get_prop_val(md, node, "tx-ino", &endpoint->tx_ino);
78297d8cafcSkettenis 	md_get_prop_val(md, node, "rx-ino", &endpoint->rx_ino);
78397d8cafcSkettenis 	md_get_prop_val(md, node, "private_svc", &endpoint->private_svc);
78497d8cafcSkettenis 	md_get_prop_val(md, node, "svc_id", &endpoint->svc_id);
78597d8cafcSkettenis 	endpoint->resource_id = resource_id;
78697d8cafcSkettenis 	ldc_endpoints[resource_id] = endpoint;
78797d8cafcSkettenis 	endpoint->hv_node = node;
78897d8cafcSkettenis }
78997d8cafcSkettenis 
79097d8cafcSkettenis void
hvmd_init_guest(struct md * md,struct md_node * node)79197d8cafcSkettenis hvmd_init_guest(struct md *md, struct md_node *node)
79297d8cafcSkettenis {
79397d8cafcSkettenis 	struct guest *guest;
79497d8cafcSkettenis 	struct md_node *node2;
79597d8cafcSkettenis 	struct md_prop *prop;
79697d8cafcSkettenis 	uint64_t resource_id;
79797d8cafcSkettenis 	struct ldc_endpoint *endpoint;
79897d8cafcSkettenis 	char *path;
79997d8cafcSkettenis 
80097d8cafcSkettenis 	if (!md_get_prop_val(md, node, "resource_id", &resource_id))
80197d8cafcSkettenis 		errx(1, "missing resource_id property in guest node");
80297d8cafcSkettenis 
80397d8cafcSkettenis 	if (resource_id >= max_guests)
80497d8cafcSkettenis 		errx(1, "resource_id larger than max_guests");
80597d8cafcSkettenis 
80697d8cafcSkettenis 	guest = xzalloc(sizeof(*guest));
80797d8cafcSkettenis 	TAILQ_INIT(&guest->cpu_list);
808e099dd74Skettenis 	TAILQ_INIT(&guest->device_list);
8098cfaec25Skettenis 	TAILQ_INIT(&guest->subdevice_list);
81097d8cafcSkettenis 	TAILQ_INIT(&guest->mblock_list);
81197d8cafcSkettenis 	TAILQ_INIT(&guest->endpoint_list);
81297d8cafcSkettenis 	md_get_prop_str(md, node, "name", &guest->name);
81397d8cafcSkettenis 	md_get_prop_val(md, node, "gid", &guest->gid);
81497d8cafcSkettenis 	md_get_prop_val(md, node, "pid", &guest->pid);
815e099dd74Skettenis 	md_get_prop_val(md, node, "tod-offset", &guest->tod_offset);
816e099dd74Skettenis 	md_get_prop_val(md, node, "perfctraccess", &guest->perfctraccess);
817e099dd74Skettenis 	md_get_prop_val(md, node, "perfctrhtaccess", &guest->perfctrhtaccess);
818e099dd74Skettenis 	md_get_prop_val(md, node, "rngctlaccessible", &guest->rngctlaccessible);
81997d8cafcSkettenis 	md_get_prop_val(md, node, "mdpa", &guest->mdpa);
82097d8cafcSkettenis 	guest->resource_id = resource_id;
82197d8cafcSkettenis 	guests[resource_id] = guest;
82297d8cafcSkettenis 	guest->hv_node = node;
82397d8cafcSkettenis 
82497d8cafcSkettenis 	if (strcmp(guest->name, "primary") == 0 && guest->gid != 0)
82597d8cafcSkettenis 		errx(1, "gid of primary domain isn't 0");
82697d8cafcSkettenis 
82797d8cafcSkettenis 	hvmd_alloc_frag(guest->mdpa);
82897d8cafcSkettenis 
82997d8cafcSkettenis 	TAILQ_FOREACH(prop, &node->prop_list, link) {
83097d8cafcSkettenis 		if (prop->tag == MD_PROP_ARC &&
83197d8cafcSkettenis 		    strcmp(prop->name->str, "fwd") == 0) {
83297d8cafcSkettenis 			node2 = prop->d.arc.node;
83397d8cafcSkettenis 			if (strcmp(node2->name->str, "console") == 0) {
83497d8cafcSkettenis 				md_get_prop_val(md, node2, "resource_id",
83597d8cafcSkettenis 				    &resource_id);
83697d8cafcSkettenis 				guest->console = consoles[resource_id];
83797d8cafcSkettenis 				consoles[resource_id]->guest = guest;
83897d8cafcSkettenis 			}
83997d8cafcSkettenis 			if (strcmp(node2->name->str, "cpu") == 0) {
84097d8cafcSkettenis 				md_get_prop_val(md, node2, "resource_id",
84197d8cafcSkettenis 				    &resource_id);
84297d8cafcSkettenis 				TAILQ_INSERT_TAIL(&guest->cpu_list,
84397d8cafcSkettenis 				    cpus[resource_id], link);
84497d8cafcSkettenis 				cpus[resource_id]->guest = guest;
84597d8cafcSkettenis 			}
846e099dd74Skettenis 			if (strcmp(node2->name->str, "pcie_bus") == 0) {
847e099dd74Skettenis 				md_get_prop_val(md, node2, "resource_id",
848e099dd74Skettenis 				    &resource_id);
849e099dd74Skettenis 				TAILQ_INSERT_TAIL(&guest->device_list,
850e099dd74Skettenis 				    pcie_busses[resource_id], link);
851e099dd74Skettenis 				pcie_busses[resource_id]->guest = guest;
852e099dd74Skettenis 			}
853e099dd74Skettenis 			if (strcmp(node2->name->str, "network_device") == 0) {
854e099dd74Skettenis 				md_get_prop_val(md, node2, "resource_id",
855e099dd74Skettenis 				    &resource_id);
856e099dd74Skettenis 				TAILQ_INSERT_TAIL(&guest->device_list,
857e099dd74Skettenis 				    network_devices[resource_id], link);
858e099dd74Skettenis 				network_devices[resource_id]->guest = guest;
859e099dd74Skettenis 			}
86097d8cafcSkettenis 			if (strcmp(node2->name->str, "mblock") == 0) {
86197d8cafcSkettenis 				md_get_prop_val(md, node2, "resource_id",
86297d8cafcSkettenis 				    &resource_id);
86397d8cafcSkettenis 				TAILQ_INSERT_TAIL(&guest->mblock_list,
86497d8cafcSkettenis 				    mblocks[resource_id], link);
86597d8cafcSkettenis 				mblocks[resource_id]->guest = guest;
86697d8cafcSkettenis 			}
86797d8cafcSkettenis 			if (strcmp(node2->name->str, "ldc_endpoint") == 0) {
86897d8cafcSkettenis 				md_get_prop_val(md, node2, "resource_id",
86997d8cafcSkettenis 				    &resource_id);
87097d8cafcSkettenis 				TAILQ_INSERT_TAIL(&guest->endpoint_list,
87197d8cafcSkettenis 				    ldc_endpoints[resource_id], link);
87297d8cafcSkettenis 				ldc_endpoints[resource_id]->guest = guest;
87397d8cafcSkettenis 			}
87497d8cafcSkettenis 		}
87597d8cafcSkettenis 	}
87697d8cafcSkettenis 
87797d8cafcSkettenis 	TAILQ_FOREACH(endpoint, &guest->endpoint_list, link) {
87897d8cafcSkettenis 		if (endpoint->channel >= guest->endpoint_id)
87997d8cafcSkettenis 			guest->endpoint_id = endpoint->channel + 1;
88097d8cafcSkettenis 	}
88197d8cafcSkettenis 
88297d8cafcSkettenis 	xasprintf(&path, "%s.md", guest->name);
88397d8cafcSkettenis 	guest->md = md_read(path);
884a22abcf3Sgsoares 
885a22abcf3Sgsoares 	if (guest->md == NULL)
886a22abcf3Sgsoares 		err(1, "unable to get guest MD");
887a22abcf3Sgsoares 
88897d8cafcSkettenis 	free(path);
88997d8cafcSkettenis }
89097d8cafcSkettenis 
89197d8cafcSkettenis void
hvmd_init(struct md * md)89297d8cafcSkettenis hvmd_init(struct md *md)
89397d8cafcSkettenis {
89497d8cafcSkettenis 	struct md_node *node;
89597d8cafcSkettenis 	struct md_prop *prop;
89697d8cafcSkettenis 
897e099dd74Skettenis 	node = md_find_node(md, "root");
898e099dd74Skettenis 	md_get_prop_val(md, node, "content-version", &content_version);
899e099dd74Skettenis 	md_get_prop_val(md, node, "stick-frequency", &stick_frequency);
9002151b4ddSkettenis 	md_get_prop_val(md, node, "tod-frequency", &tod_frequency);
9012151b4ddSkettenis 	md_get_prop_val(md, node, "tod", &tod);
9022151b4ddSkettenis 	md_get_prop_val(md, node, "erpt-pa", &erpt_pa);
9032151b4ddSkettenis 	md_get_prop_val(md, node, "erpt-size", &erpt_size);
904d27a0d69Skettenis 	md_get_prop_val(md, node, "uartbase", &uartbase);
905e099dd74Skettenis 
906d27a0d69Skettenis 	node = md_find_node(md, "platform");
907d27a0d69Skettenis 	if (node)
908d27a0d69Skettenis 		md_get_prop_val(md, node, "stick-frequency", &stick_frequency);
90997d8cafcSkettenis 
9109e5c6997Skettenis 	node = md_find_node(md, "hvmd_mblock");
9119e5c6997Skettenis 	if (node) {
9129e5c6997Skettenis 		hvmd_mblock = xzalloc(sizeof(*hvmd_mblock));
9139e5c6997Skettenis 		md_get_prop_val(md, node, "base", &hvmd_mblock->membase);
9149e5c6997Skettenis 		md_get_prop_val(md, node, "size", &hvmd_mblock->memsize);
915e099dd74Skettenis 		md_get_prop_val(md, node, "md_maxsize", &md_maxsize);
9169e5c6997Skettenis 		pri_alloc_memory(hvmd_mblock->membase, hvmd_mblock->memsize);
9179e5c6997Skettenis 	}
9189e5c6997Skettenis 
919d27a0d69Skettenis 	node = md_find_node(md, "frag_space");
920d27a0d69Skettenis 	md_get_prop_val(md, node, "fragsize", &fragsize);
921d27a0d69Skettenis 	if (fragsize == 0)
922d27a0d69Skettenis 		fragsize = md_maxsize;
923d27a0d69Skettenis 	TAILQ_INIT(&frag_mblocks);
924d27a0d69Skettenis 	TAILQ_FOREACH(prop, &node->prop_list, link) {
925d27a0d69Skettenis 		if (prop->tag == MD_PROP_ARC &&
926d27a0d69Skettenis 		    strcmp(prop->name->str, "fwd") == 0)
927d27a0d69Skettenis 			hvmd_init_frag(md, prop->d.arc.node);
928d27a0d69Skettenis 	}
929d27a0d69Skettenis 	pri_alloc_memory(0, fragsize);
930d27a0d69Skettenis 
93197d8cafcSkettenis 	node = md_find_node(md, "consoles");
93297d8cafcSkettenis 	TAILQ_FOREACH(prop, &node->prop_list, link) {
93397d8cafcSkettenis 		if (prop->tag == MD_PROP_ARC &&
93497d8cafcSkettenis 		    strcmp(prop->name->str, "fwd") == 0)
93597d8cafcSkettenis 			hvmd_init_console(md, prop->d.arc.node);
93697d8cafcSkettenis 	}
93797d8cafcSkettenis 
93897d8cafcSkettenis 	node = md_find_node(md, "cpus");
93997d8cafcSkettenis 	TAILQ_FOREACH(prop, &node->prop_list, link) {
94097d8cafcSkettenis 		if (prop->tag == MD_PROP_ARC &&
94197d8cafcSkettenis 		    strcmp(prop->name->str, "fwd") == 0)
94297d8cafcSkettenis 			hvmd_init_cpu(md, prop->d.arc.node);
94397d8cafcSkettenis 	}
94497d8cafcSkettenis 
9457aadc77eSkettenis 	have_cwqs = (md_find_node(md, "cwqs") != NULL);
9467aadc77eSkettenis 	have_rngs = (md_find_node(md, "rngs") != NULL);
9477aadc77eSkettenis 
948e099dd74Skettenis 	node = md_find_node(md, "devices");
949e099dd74Skettenis 	TAILQ_FOREACH(prop, &node->prop_list, link) {
950e099dd74Skettenis 		if (prop->tag == MD_PROP_ARC &&
951e099dd74Skettenis 		    strcmp(prop->name->str, "fwd") == 0)
952e099dd74Skettenis 			hvmd_init_device(md, prop->d.arc.node);
953e099dd74Skettenis 	}
954e099dd74Skettenis 
95597d8cafcSkettenis 	node = md_find_node(md, "memory");
95697d8cafcSkettenis 	TAILQ_FOREACH(prop, &node->prop_list, link) {
95797d8cafcSkettenis 		if (prop->tag == MD_PROP_ARC &&
95897d8cafcSkettenis 		    strcmp(prop->name->str, "fwd") == 0)
95997d8cafcSkettenis 			hvmd_init_mblock(md, prop->d.arc.node);
96097d8cafcSkettenis 	}
96197d8cafcSkettenis 
96297d8cafcSkettenis 	node = md_find_node(md, "ldc_endpoints");
96397d8cafcSkettenis 	TAILQ_FOREACH(prop, &node->prop_list, link) {
96497d8cafcSkettenis 		if (prop->tag == MD_PROP_ARC &&
96597d8cafcSkettenis 		    strcmp(prop->name->str, "fwd") == 0)
96697d8cafcSkettenis 			hvmd_init_endpoint(md, prop->d.arc.node);
96797d8cafcSkettenis 	}
96897d8cafcSkettenis 
96997d8cafcSkettenis 	node = md_find_node(md, "guests");
97097d8cafcSkettenis 	TAILQ_FOREACH(prop, &node->prop_list, link) {
97197d8cafcSkettenis 		if (prop->tag == MD_PROP_ARC &&
97297d8cafcSkettenis 		    strcmp(prop->name->str, "fwd") == 0)
97397d8cafcSkettenis 			hvmd_init_guest(md, prop->d.arc.node);
97497d8cafcSkettenis 	}
97597d8cafcSkettenis 
97697d8cafcSkettenis 	hvmd_alloc_frag(-1);
97797d8cafcSkettenis }
97897d8cafcSkettenis 
97997d8cafcSkettenis void
hvmd_finalize_cpu(struct md * md,struct cpu * cpu)98097d8cafcSkettenis hvmd_finalize_cpu(struct md *md, struct cpu *cpu)
98197d8cafcSkettenis {
98297d8cafcSkettenis 	struct md_node *parent;
98397d8cafcSkettenis 	struct md_node *node;
98402ce1e77Skettenis 	int i;
98502ce1e77Skettenis 
98602ce1e77Skettenis 	for (i = 0; i < MAX_STRANDS_PER_CORE; i++) {
98702ce1e77Skettenis 		if (cpu->core->guests[i] == cpu->guest) {
98802ce1e77Skettenis 			cpu->partid = i + 1;
98902ce1e77Skettenis 			break;
99002ce1e77Skettenis 		}
99102ce1e77Skettenis 		if (cpu->core->guests[i] == NULL) {
99202ce1e77Skettenis 			cpu->core->guests[i] = cpu->guest;
99302ce1e77Skettenis 			cpu->partid = i + 1;
99402ce1e77Skettenis 			break;
99502ce1e77Skettenis 		}
99602ce1e77Skettenis 	}
99797d8cafcSkettenis 
99897d8cafcSkettenis 	parent = md_find_node(md, "cpus");
99997d8cafcSkettenis 	assert(parent);
100097d8cafcSkettenis 
100197d8cafcSkettenis 	node = md_add_node(md, "cpu");
100297d8cafcSkettenis 	md_link_node(md, parent, node);
100397d8cafcSkettenis 	md_add_prop_val(md, node, "pid", cpu->pid);
100497d8cafcSkettenis 	md_add_prop_val(md, node, "vid", cpu->vid);
100597d8cafcSkettenis 	md_add_prop_val(md, node, "gid", cpu->gid);
100697d8cafcSkettenis 	md_add_prop_val(md, node, "partid", cpu->partid);
100797d8cafcSkettenis 	md_add_prop_val(md, node, "resource_id", cpu->resource_id);
100897d8cafcSkettenis 	cpu->hv_node = node;
100997d8cafcSkettenis }
101097d8cafcSkettenis 
101197d8cafcSkettenis void
hvmd_finalize_cpus(struct md * md)101297d8cafcSkettenis hvmd_finalize_cpus(struct md *md)
101397d8cafcSkettenis {
101497d8cafcSkettenis 	struct md_node *parent;
101597d8cafcSkettenis 	struct md_node *node;
101697d8cafcSkettenis 	uint64_t resource_id;
101797d8cafcSkettenis 
101897d8cafcSkettenis 	parent = md_find_node(md, "root");
101997d8cafcSkettenis 	assert(parent);
102097d8cafcSkettenis 
102197d8cafcSkettenis 	node = md_add_node(md, "cpus");
102297d8cafcSkettenis 	md_link_node(md, parent, node);
102397d8cafcSkettenis 
102497d8cafcSkettenis 	for (resource_id = 0; resource_id < max_cpus; resource_id++) {
102597d8cafcSkettenis 		if (cpus[resource_id])
102697d8cafcSkettenis 			hvmd_finalize_cpu(md, cpus[resource_id]);
102797d8cafcSkettenis 	}
102897d8cafcSkettenis }
102997d8cafcSkettenis 
103097d8cafcSkettenis void
hvmd_finalize_maus(struct md * md)1031764a0ebaSkettenis hvmd_finalize_maus(struct md *md)
1032764a0ebaSkettenis {
1033764a0ebaSkettenis 	struct md_node *parent;
1034764a0ebaSkettenis 	struct md_node *node;
10357aadc77eSkettenis 	struct md_node *child;
10367aadc77eSkettenis 	int i;
1037764a0ebaSkettenis 
1038764a0ebaSkettenis 	parent = md_find_node(md, "root");
1039764a0ebaSkettenis 	assert(parent);
1040764a0ebaSkettenis 
1041764a0ebaSkettenis 	node = md_add_node(md, "maus");
1042764a0ebaSkettenis 	md_link_node(md, parent, node);
10437aadc77eSkettenis 
10447aadc77eSkettenis 	if (have_cwqs) {
10459e5c6997Skettenis 		node = md_add_node(md, "cwqs");
10469e5c6997Skettenis 		md_link_node(md, parent, node);
1047764a0ebaSkettenis 	}
1048764a0ebaSkettenis 
10497aadc77eSkettenis 	if (have_rngs) {
10507aadc77eSkettenis 		node = md_add_node(md, "rngs");
10517aadc77eSkettenis 		md_link_node(md, parent, node);
10527aadc77eSkettenis 		child = md_add_node(md, "rng");
10537aadc77eSkettenis 		md_link_node(md, node, child);
10547aadc77eSkettenis 		for (i = 0; i < max_cpus; i++) {
10557aadc77eSkettenis 			if (cpus[i])
10567aadc77eSkettenis 				md_link_node(md, cpus[i]->hv_node, child);
10577aadc77eSkettenis 		}
10587aadc77eSkettenis 	}
10597aadc77eSkettenis }
10607aadc77eSkettenis 
1061764a0ebaSkettenis void
hvmd_finalize_device(struct md * md,struct device * device,const char * name)1062e099dd74Skettenis hvmd_finalize_device(struct md *md, struct device *device, const char *name)
1063e099dd74Skettenis {
1064e099dd74Skettenis 	struct md_node *parent;
1065e099dd74Skettenis 	struct md_node *node;
1066e099dd74Skettenis 
1067e099dd74Skettenis 	parent = md_find_node(md, "devices");
1068e099dd74Skettenis 	assert(parent);
1069e099dd74Skettenis 
1070e099dd74Skettenis 	node = md_add_node(md, name);
1071e099dd74Skettenis 	md_link_node(md, parent, node);
1072e099dd74Skettenis 	md_add_prop_val(md, node, "resource_id", device->resource_id);
1073e099dd74Skettenis 	md_add_prop_val(md, node, "cfghandle", device->cfghandle);
1074e099dd74Skettenis 	md_add_prop_val(md, node, "gid", device->gid);
1075d27a0d69Skettenis 	md_add_prop_val(md, node, "rcid", device->rcid);
1076e099dd74Skettenis 	device->hv_node = node;
1077e099dd74Skettenis }
1078e099dd74Skettenis 
1079e099dd74Skettenis void
hvmd_finalize_pcie_device(struct md * md,struct device * device)10808cfaec25Skettenis hvmd_finalize_pcie_device(struct md *md, struct device *device)
10818cfaec25Skettenis {
10828cfaec25Skettenis 	struct rootcomplex *rootcomplex;
1083ab8e3451Sderaadt 	struct md_node *node, *child, *parent;
10848cfaec25Skettenis 	struct component *component;
10858cfaec25Skettenis 	struct subdevice *subdevice;
10868cfaec25Skettenis 	uint64_t resource_id = 0;
10878cfaec25Skettenis 	char *path;
10888cfaec25Skettenis 
10898cfaec25Skettenis 	hvmd_finalize_device(md, device,
10908cfaec25Skettenis 	    device->virtual ? "virtual_pcie_bus" : "pcie_bus");
10918cfaec25Skettenis 	node = device->hv_node;
10928cfaec25Skettenis 
10938cfaec25Skettenis 	if (!directio_capability)
10948cfaec25Skettenis 		return;
10958cfaec25Skettenis 
10968cfaec25Skettenis 	TAILQ_FOREACH(rootcomplex, &rootcomplexes, link) {
10978cfaec25Skettenis 		if (rootcomplex->cfghandle == device->cfghandle)
10988cfaec25Skettenis 			break;
10998cfaec25Skettenis 	}
11008cfaec25Skettenis 	if (rootcomplex == NULL)
11018cfaec25Skettenis 		return;
11028cfaec25Skettenis 
11038cfaec25Skettenis 	md_add_prop_val(md, node, "allow_bypass", 0);
11048cfaec25Skettenis 
11058cfaec25Skettenis 	md_add_prop_val(md, node, "#msi-eqs", device->num_msi_eqs);
11068cfaec25Skettenis 	md_add_prop_val(md, node, "#msi", device->num_msis);
11078cfaec25Skettenis 	md_add_prop_data(md, node, "msi-ranges", (void *)device->msi_ranges,
11088cfaec25Skettenis 	    sizeof(device->msi_ranges));
11098cfaec25Skettenis 	md_add_prop_data(md, node, "virtual-dma", rootcomplex->vdma_ranges,
11108cfaec25Skettenis 	    rootcomplex->num_vdma_ranges * 2 * sizeof(uint64_t));
11118cfaec25Skettenis 
11128cfaec25Skettenis 	xasprintf(&path, "/@%llx", device->cfghandle);
11138cfaec25Skettenis 
11148cfaec25Skettenis 	if (!device->virtual) {
11158cfaec25Skettenis 		parent = md_add_node(md, "pcie_assignable_devices");
11168cfaec25Skettenis 		md_link_node(md, node, parent);
11178cfaec25Skettenis 
11188cfaec25Skettenis 		TAILQ_FOREACH(component, &components, link) {
11198cfaec25Skettenis 			const char *path2 = component->path;
11208cfaec25Skettenis 
11218cfaec25Skettenis 			if (strncmp(path, path2, strlen(path)) != 0)
11228cfaec25Skettenis 				continue;
11238cfaec25Skettenis 
11248cfaec25Skettenis 			path2 = strchr(path2, '/');
11258cfaec25Skettenis 			if (path2 == NULL || *path2++ == 0)
11268cfaec25Skettenis 				continue;
11278cfaec25Skettenis 			path2 = strchr(path2, '/');
11288cfaec25Skettenis 			if (path2 == NULL || *path2++ == 0)
11298cfaec25Skettenis 				continue;
11308cfaec25Skettenis 
11318cfaec25Skettenis 			child = md_add_node(md, "pcie_device");
11328cfaec25Skettenis 			md_link_node(md, parent, child);
11338cfaec25Skettenis 
11348cfaec25Skettenis 			md_add_prop_str(md, child, "path", path2);
11358cfaec25Skettenis 			md_add_prop_val(md, child, "resource_id", resource_id);
11368cfaec25Skettenis 			resource_id++;
11378cfaec25Skettenis 
11388cfaec25Skettenis 			component->hv_node = child;
11398cfaec25Skettenis 		}
11408cfaec25Skettenis 	}
11418cfaec25Skettenis 
11428cfaec25Skettenis 	parent = md_add_node(md, "pcie_assigned_devices");
11438cfaec25Skettenis 	md_link_node(md, node, parent);
11448cfaec25Skettenis 
11458cfaec25Skettenis 	TAILQ_FOREACH(subdevice, &device->guest->subdevice_list, link) {
11461f4256daSkn 		if (strncmp(path, subdevice->path, strlen(path)) != 0)
11471f4256daSkn 			continue;
11488cfaec25Skettenis 		TAILQ_FOREACH(component, &components, link) {
11498cfaec25Skettenis 			if (strcmp(subdevice->path, component->path) == 0)
11508cfaec25Skettenis 				md_link_node(md, parent, component->hv_node);
11518cfaec25Skettenis 		}
11528cfaec25Skettenis 	}
11538cfaec25Skettenis 
11548cfaec25Skettenis 	free(path);
11558cfaec25Skettenis }
11568cfaec25Skettenis 
11578cfaec25Skettenis void
hvmd_finalize_devices(struct md * md)1158e099dd74Skettenis hvmd_finalize_devices(struct md *md)
1159e099dd74Skettenis {
1160e099dd74Skettenis 	struct md_node *parent;
1161e099dd74Skettenis 	struct md_node *node;
1162e099dd74Skettenis 	uint64_t resource_id;
1163e099dd74Skettenis 
1164e099dd74Skettenis 	parent = md_find_node(md, "root");
1165e099dd74Skettenis 	assert(parent);
1166e099dd74Skettenis 
1167e099dd74Skettenis 	node = md_add_node(md, "devices");
1168e099dd74Skettenis 	md_link_node(md, parent, node);
1169e099dd74Skettenis 
1170e099dd74Skettenis 	for (resource_id = 0; resource_id < max_devices; resource_id++) {
1171e099dd74Skettenis 		if (pcie_busses[resource_id])
11728cfaec25Skettenis 			hvmd_finalize_pcie_device(md, pcie_busses[resource_id]);
1173e099dd74Skettenis 	}
1174e099dd74Skettenis 	for (resource_id = 0; resource_id < max_devices; resource_id++) {
1175e099dd74Skettenis 		if (network_devices[resource_id])
1176e099dd74Skettenis 			hvmd_finalize_device(md, network_devices[resource_id],
1177e099dd74Skettenis 			    "network_device");
1178e099dd74Skettenis 	}
1179e099dd74Skettenis }
1180e099dd74Skettenis 
1181e099dd74Skettenis void
hvmd_finalize_mblock(struct md * md,struct mblock * mblock)118297d8cafcSkettenis hvmd_finalize_mblock(struct md *md, struct mblock *mblock)
118397d8cafcSkettenis {
118497d8cafcSkettenis 	struct md_node *parent;
118597d8cafcSkettenis 	struct md_node *node;
118697d8cafcSkettenis 
118797d8cafcSkettenis 	parent = md_find_node(md, "memory");
118897d8cafcSkettenis 	assert(parent);
118997d8cafcSkettenis 
119097d8cafcSkettenis 	node = md_add_node(md, "mblock");
119197d8cafcSkettenis 	md_link_node(md, parent, node);
119297d8cafcSkettenis 	md_add_prop_val(md, node, "membase", mblock->membase);
119397d8cafcSkettenis 	md_add_prop_val(md, node, "memsize", mblock->memsize);
119497d8cafcSkettenis 	md_add_prop_val(md, node, "realbase", mblock->realbase);
119597d8cafcSkettenis 	md_add_prop_val(md, node, "resource_id", mblock->resource_id);
119697d8cafcSkettenis 	mblock->hv_node = node;
119797d8cafcSkettenis }
119897d8cafcSkettenis 
119997d8cafcSkettenis void
hvmd_finalize_memory(struct md * md)120097d8cafcSkettenis hvmd_finalize_memory(struct md *md)
120197d8cafcSkettenis {
120297d8cafcSkettenis 	struct md_node *parent;
120397d8cafcSkettenis 	struct md_node *node;
120497d8cafcSkettenis 	uint64_t resource_id;
120597d8cafcSkettenis 
120697d8cafcSkettenis 	parent = md_find_node(md, "root");
120797d8cafcSkettenis 	assert(parent);
120897d8cafcSkettenis 
120997d8cafcSkettenis 	node = md_add_node(md, "memory");
121097d8cafcSkettenis 	md_link_node(md, parent, node);
121197d8cafcSkettenis 
1212e099dd74Skettenis 	for (resource_id = 0; resource_id < max_mblocks; resource_id++) {
121397d8cafcSkettenis 		if (mblocks[resource_id])
121497d8cafcSkettenis 			hvmd_finalize_mblock(md, mblocks[resource_id]);
121597d8cafcSkettenis 	}
121697d8cafcSkettenis }
121797d8cafcSkettenis 
121897d8cafcSkettenis void
hvmd_finalize_endpoint(struct md * md,struct ldc_endpoint * endpoint)121997d8cafcSkettenis hvmd_finalize_endpoint(struct md *md, struct ldc_endpoint *endpoint)
122097d8cafcSkettenis {
122197d8cafcSkettenis 	struct md_node *parent;
122297d8cafcSkettenis 	struct md_node *node;
122397d8cafcSkettenis 
122497d8cafcSkettenis 	parent = md_find_node(md, "ldc_endpoints");
122597d8cafcSkettenis 	assert(parent);
122697d8cafcSkettenis 
122797d8cafcSkettenis 	node = md_add_node(md, "ldc_endpoint");
122897d8cafcSkettenis 	md_link_node(md, parent, node);
122997d8cafcSkettenis 	md_add_prop_val(md, node, "resource_id", endpoint->resource_id);
123097d8cafcSkettenis 	md_add_prop_val(md, node, "target_type", endpoint->target_type);
123197d8cafcSkettenis 	md_add_prop_val(md, node, "channel", endpoint->channel);
123297d8cafcSkettenis 	if (endpoint->target_guest != -1)
123397d8cafcSkettenis 		md_add_prop_val(md, node, "target_guest",
123497d8cafcSkettenis 		    endpoint->target_guest);
123597d8cafcSkettenis 	md_add_prop_val(md, node, "target_channel", endpoint->target_channel);
123697d8cafcSkettenis 	if (endpoint->tx_ino != -1)
123797d8cafcSkettenis 		md_add_prop_val(md, node, "tx-ino", endpoint->tx_ino);
123897d8cafcSkettenis 	if (endpoint->rx_ino != -1)
123997d8cafcSkettenis 		md_add_prop_val(md, node, "rx-ino", endpoint->rx_ino);
124097d8cafcSkettenis 	if (endpoint->private_svc != -1)
124197d8cafcSkettenis 		md_add_prop_val(md, node, "private_svc",
124297d8cafcSkettenis 		    endpoint->private_svc);
124397d8cafcSkettenis 	if (endpoint->svc_id != -1)
124497d8cafcSkettenis 		md_add_prop_val(md, node, "svc_id", endpoint->svc_id);
124597d8cafcSkettenis 	endpoint->hv_node = node;
124697d8cafcSkettenis }
124797d8cafcSkettenis 
124897d8cafcSkettenis void
hvmd_finalize_endpoints(struct md * md)124997d8cafcSkettenis hvmd_finalize_endpoints(struct md *md)
125097d8cafcSkettenis {
125197d8cafcSkettenis 	struct md_node *parent;
125297d8cafcSkettenis 	struct md_node *node;
125397d8cafcSkettenis 	uint64_t resource_id;
125497d8cafcSkettenis 
125597d8cafcSkettenis 	parent = md_find_node(md, "root");
125697d8cafcSkettenis 	assert(parent);
125797d8cafcSkettenis 
125897d8cafcSkettenis 	node = md_add_node(md, "ldc_endpoints");
125997d8cafcSkettenis 	md_link_node(md, parent, node);
126097d8cafcSkettenis 
126197d8cafcSkettenis 	for (resource_id = 0; resource_id < max_guest_ldcs; resource_id++) {
126297d8cafcSkettenis 		if (ldc_endpoints[resource_id])
126397d8cafcSkettenis 			hvmd_finalize_endpoint(md, ldc_endpoints[resource_id]);
126497d8cafcSkettenis 	}
126597d8cafcSkettenis }
126697d8cafcSkettenis 
126797d8cafcSkettenis void
hvmd_finalize_console(struct md * md,struct console * console)126897d8cafcSkettenis hvmd_finalize_console(struct md *md, struct console *console)
126997d8cafcSkettenis {
127097d8cafcSkettenis 	struct md_node *parent;
127197d8cafcSkettenis 	struct md_node *node;
127297d8cafcSkettenis 	struct ldc_endpoint *endpoint;
127397d8cafcSkettenis 
127497d8cafcSkettenis 	parent = md_find_node(md, "consoles");
127597d8cafcSkettenis 	assert(parent);
127697d8cafcSkettenis 
127797d8cafcSkettenis 	node = md_add_node(md, "console");
127897d8cafcSkettenis 	md_link_node(md, parent, node);
127997d8cafcSkettenis 	md_add_prop_val(md, node, "resource_id", console->resource_id);
128097d8cafcSkettenis 	md_add_prop_val(md, node, "ino", console->ino);
128197d8cafcSkettenis 	console->hv_node = node;
128297d8cafcSkettenis 
1283d27a0d69Skettenis 	if (console->uartbase) {
1284d27a0d69Skettenis 		md_add_prop_val(md, node, "uartbase", console->uartbase);
1285d27a0d69Skettenis 		return;
1286d27a0d69Skettenis 	}
1287d27a0d69Skettenis 
128897d8cafcSkettenis 	TAILQ_FOREACH(endpoint, &console->guest->endpoint_list, link) {
128997d8cafcSkettenis 		if (endpoint->rx_ino == console->ino) {
129097d8cafcSkettenis 			md_link_node(md, node, endpoint->hv_node);
129197d8cafcSkettenis 			break;
129297d8cafcSkettenis 		}
129397d8cafcSkettenis 	}
129497d8cafcSkettenis }
129597d8cafcSkettenis 
129697d8cafcSkettenis void
hvmd_finalize_consoles(struct md * md)129797d8cafcSkettenis hvmd_finalize_consoles(struct md *md)
129897d8cafcSkettenis {
129997d8cafcSkettenis 	struct md_node *parent;
130097d8cafcSkettenis 	struct md_node *node;
130197d8cafcSkettenis 	uint64_t resource_id;
130297d8cafcSkettenis 
130397d8cafcSkettenis 	parent = md_find_node(md, "root");
130497d8cafcSkettenis 	assert(parent);
130597d8cafcSkettenis 
130697d8cafcSkettenis 	node = md_add_node(md, "consoles");
130797d8cafcSkettenis 	md_link_node(md, parent, node);
130897d8cafcSkettenis 
130997d8cafcSkettenis 	for (resource_id = 0; resource_id < max_guests; resource_id++) {
131097d8cafcSkettenis 		if (consoles[resource_id])
131197d8cafcSkettenis 			hvmd_finalize_console(md, consoles[resource_id]);
131297d8cafcSkettenis 	}
131397d8cafcSkettenis }
131497d8cafcSkettenis 
131597d8cafcSkettenis void
hvmd_finalize_guest(struct md * md,struct guest * guest)131697d8cafcSkettenis hvmd_finalize_guest(struct md *md, struct guest *guest)
131797d8cafcSkettenis {
1318e099dd74Skettenis 	struct md_node *node;
1319e099dd74Skettenis 	struct md_node *parent;
132097d8cafcSkettenis 	struct cpu *cpu;
1321e099dd74Skettenis 	struct device *device;
132297d8cafcSkettenis 	struct mblock *mblock;
132397d8cafcSkettenis 	struct ldc_endpoint *endpoint;
132497d8cafcSkettenis 
1325e099dd74Skettenis 	parent = md_find_node(md, "guests");
1326e099dd74Skettenis 	assert(parent);
1327e099dd74Skettenis 
1328e099dd74Skettenis 	node = md_add_node(md, "guest");
1329e099dd74Skettenis 	md_link_node(md, parent, node);
1330e099dd74Skettenis 	md_add_prop_str(md, node, "name", guest->name);
1331e099dd74Skettenis 	md_add_prop_val(md, node, "gid", guest->gid);
1332e099dd74Skettenis 	md_add_prop_val(md, node, "pid", guest->pid);
1333e099dd74Skettenis 	md_add_prop_val(md, node, "resource_id", guest->resource_id);
1334e099dd74Skettenis 	md_add_prop_val(md, node, "tod-offset", guest->tod_offset);
1335e099dd74Skettenis 	md_add_prop_val(md, node, "reset-reason", 0);
1336e099dd74Skettenis 	md_add_prop_val(md, node, "perfctraccess", guest->perfctraccess);
1337e099dd74Skettenis 	md_add_prop_val(md, node, "perfctrhtaccess", guest->perfctrhtaccess);
1338e099dd74Skettenis 	md_add_prop_val(md, node, "rngctlaccessible", guest->rngctlaccessible);
1339e099dd74Skettenis 	md_add_prop_val(md, node, "diagpriv", 0);
1340e099dd74Skettenis 	md_add_prop_val(md, node, "mdpa", guest->mdpa);
1341e099dd74Skettenis 	md_add_prop_val(md, node, "rombase", rombase);
1342e099dd74Skettenis 	md_add_prop_val(md, node, "romsize", romsize);
1343d27a0d69Skettenis 	md_add_prop_val(md, node, "uartbase", uartbase);
1344e099dd74Skettenis 	guest->hv_node = node;
1345e099dd74Skettenis 
1346e099dd74Skettenis 	node = md_add_node(md, "virtual_devices");
1347e099dd74Skettenis 	md_link_node(md, guest->hv_node, node);
1348e099dd74Skettenis 	md_add_prop_val(md, node, "cfghandle", 0x100);
1349e099dd74Skettenis 
1350e099dd74Skettenis 	node = md_add_node(md, "channel_devices");
1351e099dd74Skettenis 	md_link_node(md, guest->hv_node, node);
1352e099dd74Skettenis 	md_add_prop_val(md, node, "cfghandle", 0x200);
135397d8cafcSkettenis 
135497d8cafcSkettenis 	if (guest->console)
135597d8cafcSkettenis 		md_link_node(md, guest->hv_node, guest->console->hv_node);
135697d8cafcSkettenis 	TAILQ_FOREACH(cpu, &guest->cpu_list, link)
135797d8cafcSkettenis 		md_link_node(md, guest->hv_node, cpu->hv_node);
1358e099dd74Skettenis 	TAILQ_FOREACH(device, &guest->device_list, link)
1359e099dd74Skettenis 		md_link_node(md, guest->hv_node, device->hv_node);
136097d8cafcSkettenis 	TAILQ_FOREACH(mblock, &guest->mblock_list, link)
136197d8cafcSkettenis 		md_link_node(md, guest->hv_node, mblock->hv_node);
136297d8cafcSkettenis 	TAILQ_FOREACH(endpoint, &guest->endpoint_list, link)
136397d8cafcSkettenis 		md_link_node(md, guest->hv_node, endpoint->hv_node);
136497d8cafcSkettenis }
136597d8cafcSkettenis 
136697d8cafcSkettenis void
hvmd_finalize_guests(struct md * md)136797d8cafcSkettenis hvmd_finalize_guests(struct md *md)
136897d8cafcSkettenis {
1369e099dd74Skettenis 	struct md_node *parent;
1370e099dd74Skettenis 	struct md_node *node;
137197d8cafcSkettenis 	uint64_t resource_id;
137297d8cafcSkettenis 
1373e099dd74Skettenis 	parent = md_find_node(md, "root");
1374e099dd74Skettenis 	assert(parent);
1375e099dd74Skettenis 
1376e099dd74Skettenis 	node = md_add_node(md, "guests");
1377e099dd74Skettenis 	md_link_node(md, parent, node);
1378e099dd74Skettenis 
137997d8cafcSkettenis 	for (resource_id = 0; resource_id < max_guests; resource_id++) {
138097d8cafcSkettenis 		if (guests[resource_id])
138197d8cafcSkettenis 			hvmd_finalize_guest(md, guests[resource_id]);
138297d8cafcSkettenis 	}
138397d8cafcSkettenis }
138497d8cafcSkettenis 
138597d8cafcSkettenis void
hvmd_finalize(void)1386e099dd74Skettenis hvmd_finalize(void)
138797d8cafcSkettenis {
1388e099dd74Skettenis 	struct md *md;
1389e099dd74Skettenis 	struct md_node *node;
1390e099dd74Skettenis 	struct md_node *parent;
1391e099dd74Skettenis 	struct mblock *mblock;
1392e099dd74Skettenis 
1393e099dd74Skettenis 	md = md_alloc();
1394e099dd74Skettenis 	node = md_add_node(md, "root");
1395e099dd74Skettenis 	md_add_prop_val(md, node, "content-version", content_version);
13962151b4ddSkettenis 	if (content_version <= 0x100000000) {
1397e099dd74Skettenis 		md_add_prop_val(md, node, "stick-frequency", stick_frequency);
13982151b4ddSkettenis 		if (tod_frequency != 0)
13992151b4ddSkettenis 			md_add_prop_val(md, node, "tod-frequency",
14002151b4ddSkettenis 			    tod_frequency);
14012151b4ddSkettenis 		if (tod != 0)
14022151b4ddSkettenis 			md_add_prop_val(md, node, "tod", tod);
14032151b4ddSkettenis 		if (erpt_pa != 0)
14042151b4ddSkettenis 			md_add_prop_val(md, node, "erpt-pa", erpt_pa);
14052151b4ddSkettenis 		if (erpt_size != 0)
14062151b4ddSkettenis 			md_add_prop_val(md, node, "erpt-size", erpt_size);
14072151b4ddSkettenis 
14082151b4ddSkettenis 		parent = node;
14092151b4ddSkettenis 		node = md_add_node(md, "platform");
14102151b4ddSkettenis 		md_link_node(md, parent, node);
14112151b4ddSkettenis 		md_add_prop_val(md, node, "stick-frequency", stick_frequency);
14122151b4ddSkettenis 	}
1413e099dd74Skettenis 
1414e099dd74Skettenis 	parent = md_find_node(md, "root");
1415e099dd74Skettenis 	assert(parent);
1416e099dd74Skettenis 
1417e099dd74Skettenis 	node = md_add_node(md, "frag_space");
1418e099dd74Skettenis 	md_link_node(md, parent, node);
1419e099dd74Skettenis 	md_add_prop_val(md, node, "fragsize", fragsize);
1420e099dd74Skettenis 
1421e099dd74Skettenis 	parent = md_find_node(md, "frag_space");
1422e099dd74Skettenis 	TAILQ_FOREACH(mblock, &frag_mblocks, link) {
1423e099dd74Skettenis 		node = md_add_node(md, "frag_mblock");
1424e099dd74Skettenis 		md_link_node(md, parent, node);
1425e099dd74Skettenis 		md_add_prop_val(md, node, "base", mblock->membase);
1426e099dd74Skettenis 		md_add_prop_val(md, node, "size", mblock->memsize);
1427e099dd74Skettenis 	}
1428e099dd74Skettenis 
1429e099dd74Skettenis 	if (hvmd_mblock) {
1430e099dd74Skettenis 		parent = md_find_node(md, "root");
1431e099dd74Skettenis 		assert(parent);
1432e099dd74Skettenis 
1433e099dd74Skettenis 		node = md_add_node(md, "hvmd_mblock");
1434e099dd74Skettenis 		md_link_node(md, parent, node);
14356d6d50ffSkettenis 		md_add_prop_val(md, node, "base", hvmd_mblock->membase);
14366d6d50ffSkettenis 		md_add_prop_val(md, node, "size", hvmd_mblock->memsize);
1437e099dd74Skettenis 		md_add_prop_val(md, node, "md_maxsize", md_maxsize);
1438e099dd74Skettenis 	}
1439e099dd74Skettenis 
144097d8cafcSkettenis 	hvmd_finalize_cpus(md);
1441764a0ebaSkettenis 	hvmd_finalize_maus(md);
1442e099dd74Skettenis 	hvmd_finalize_devices(md);
144397d8cafcSkettenis 	hvmd_finalize_memory(md);
144497d8cafcSkettenis 	hvmd_finalize_endpoints(md);
144597d8cafcSkettenis 	hvmd_finalize_consoles(md);
144697d8cafcSkettenis 	hvmd_finalize_guests(md);
1447ecf7be60Skettenis 
1448e099dd74Skettenis 	md_write(md, "hv.md");
144997d8cafcSkettenis }
145097d8cafcSkettenis 
145197d8cafcSkettenis struct ldc_endpoint *
hvmd_add_endpoint(struct guest * guest)1452e099dd74Skettenis hvmd_add_endpoint(struct guest *guest)
145397d8cafcSkettenis {
145497d8cafcSkettenis 	struct ldc_endpoint *endpoint;
145597d8cafcSkettenis 	uint64_t resource_id;
145697d8cafcSkettenis 
145797d8cafcSkettenis 	for (resource_id = 0; resource_id < max_guest_ldcs; resource_id++)
145897d8cafcSkettenis 		if (ldc_endpoints[resource_id] == NULL)
145997d8cafcSkettenis 			break;
146097d8cafcSkettenis 	assert(resource_id < max_guest_ldcs);
146197d8cafcSkettenis 
146297d8cafcSkettenis 	endpoint = xzalloc(sizeof(*endpoint));
146397d8cafcSkettenis 	endpoint->target_guest = -1;
146497d8cafcSkettenis 	endpoint->tx_ino = -1;
146597d8cafcSkettenis 	endpoint->rx_ino = -1;
146697d8cafcSkettenis 	endpoint->private_svc = -1;
146797d8cafcSkettenis 	endpoint->svc_id = -1;
146897d8cafcSkettenis 	endpoint->resource_id = resource_id;
146997d8cafcSkettenis 	ldc_endpoints[resource_id] = endpoint;
147097d8cafcSkettenis 
147197d8cafcSkettenis 	TAILQ_INSERT_TAIL(&guest->endpoint_list, endpoint, link);
147297d8cafcSkettenis 	endpoint->guest = guest;
147397d8cafcSkettenis 
147497d8cafcSkettenis 	return endpoint;
147597d8cafcSkettenis }
147697d8cafcSkettenis 
147797d8cafcSkettenis struct console *
hvmd_add_console(struct guest * guest)1478e099dd74Skettenis hvmd_add_console(struct guest *guest)
147997d8cafcSkettenis {
148097d8cafcSkettenis 	struct guest *primary;
148197d8cafcSkettenis 	struct console *console;
148297d8cafcSkettenis 	uint64_t resource_id;
148397d8cafcSkettenis 	uint64_t client_channel, server_channel;
148497d8cafcSkettenis 
148597d8cafcSkettenis 	primary = guest_lookup("primary");
148697d8cafcSkettenis 	client_channel = guest->endpoint_id++;
148797d8cafcSkettenis 	server_channel = primary->endpoint_id++;
148897d8cafcSkettenis 
148997d8cafcSkettenis 	for (resource_id = 0; resource_id < max_guests; resource_id++)
149097d8cafcSkettenis 		if (consoles[resource_id] == NULL)
149197d8cafcSkettenis 			break;
149297d8cafcSkettenis 	assert(resource_id < max_guests);
149397d8cafcSkettenis 
149497d8cafcSkettenis 	console = xzalloc(sizeof(*console));
149597d8cafcSkettenis 	console->ino = 0x11;
149697d8cafcSkettenis 	console->resource_id = resource_id;
149797d8cafcSkettenis 	consoles[resource_id] = console;
149897d8cafcSkettenis 
1499e099dd74Skettenis 	console->client_endpoint = hvmd_add_endpoint(guest);
150097d8cafcSkettenis 	console->client_endpoint->tx_ino = 0x11;
150197d8cafcSkettenis 	console->client_endpoint->rx_ino = 0x11;
150297d8cafcSkettenis 	console->client_endpoint->target_type = LDC_GUEST;
150397d8cafcSkettenis 	console->client_endpoint->target_guest = primary->gid;
150497d8cafcSkettenis 	console->client_endpoint->target_channel = server_channel;
150597d8cafcSkettenis 	console->client_endpoint->channel = client_channel;
150697d8cafcSkettenis 	console->client_endpoint->private_svc = LDC_CONSOLE_SVC;
150797d8cafcSkettenis 
1508e099dd74Skettenis 	console->server_endpoint = hvmd_add_endpoint(primary);
150997d8cafcSkettenis 	console->server_endpoint->tx_ino = 2 * server_channel;
151097d8cafcSkettenis 	console->server_endpoint->rx_ino = 2 * server_channel + 1;
151197d8cafcSkettenis 	console->server_endpoint->target_type = LDC_GUEST;
151297d8cafcSkettenis 	console->server_endpoint->target_guest = guest->gid;
151397d8cafcSkettenis 	console->server_endpoint->channel = server_channel;
151497d8cafcSkettenis 	console->server_endpoint->target_channel = client_channel;
151597d8cafcSkettenis 
151697d8cafcSkettenis 	guest->console = console;
151797d8cafcSkettenis 	console->guest = guest;
151897d8cafcSkettenis 
151997d8cafcSkettenis 	return console;
152097d8cafcSkettenis }
152197d8cafcSkettenis 
152297d8cafcSkettenis void
hvmd_add_domain_services(struct guest * guest)1523e099dd74Skettenis hvmd_add_domain_services(struct guest *guest)
152497d8cafcSkettenis {
152597d8cafcSkettenis 	struct guest *primary;
152697d8cafcSkettenis 	struct ldc_channel *ds = &guest->domain_services;
152797d8cafcSkettenis 	uint64_t client_channel, server_channel;
152897d8cafcSkettenis 
152997d8cafcSkettenis 	primary = guest_lookup("primary");
153097d8cafcSkettenis 	client_channel = guest->endpoint_id++;
153197d8cafcSkettenis 	server_channel = primary->endpoint_id++;
153297d8cafcSkettenis 
1533e099dd74Skettenis 	ds->client_endpoint = hvmd_add_endpoint(guest);
153497d8cafcSkettenis 	ds->client_endpoint->tx_ino = 2 * client_channel;
153597d8cafcSkettenis 	ds->client_endpoint->rx_ino = 2 * client_channel + 1;
153697d8cafcSkettenis 	ds->client_endpoint->target_type = LDC_GUEST;
153797d8cafcSkettenis 	ds->client_endpoint->target_guest = primary->gid;
153897d8cafcSkettenis 	ds->client_endpoint->target_channel = server_channel;
153997d8cafcSkettenis 	ds->client_endpoint->channel = client_channel;
154097d8cafcSkettenis 
1541e099dd74Skettenis 	ds->server_endpoint = hvmd_add_endpoint(primary);
154297d8cafcSkettenis 	ds->server_endpoint->tx_ino = 2 * server_channel;
154397d8cafcSkettenis 	ds->server_endpoint->rx_ino = 2 * server_channel + 1;
154497d8cafcSkettenis 	ds->server_endpoint->target_type = LDC_GUEST;
154597d8cafcSkettenis 	ds->server_endpoint->target_guest = guest->gid;
154697d8cafcSkettenis 	ds->server_endpoint->channel = server_channel;
154797d8cafcSkettenis 	ds->server_endpoint->target_channel = client_channel;
154897d8cafcSkettenis }
154997d8cafcSkettenis 
155097d8cafcSkettenis struct ldc_channel *
hvmd_add_vio(struct guest * guest)1551e099dd74Skettenis hvmd_add_vio(struct guest *guest)
155297d8cafcSkettenis {
155397d8cafcSkettenis 	struct guest *primary;
155497d8cafcSkettenis 	struct ldc_channel *lc = &guest->vio[guest->num_vios++];
155597d8cafcSkettenis 	uint64_t client_channel, server_channel;
155697d8cafcSkettenis 
155797d8cafcSkettenis 	primary = guest_lookup("primary");
155897d8cafcSkettenis 	client_channel = guest->endpoint_id++;
155997d8cafcSkettenis 	server_channel = primary->endpoint_id++;
156097d8cafcSkettenis 
1561e099dd74Skettenis 	lc->client_endpoint = hvmd_add_endpoint(guest);
156297d8cafcSkettenis 	lc->client_endpoint->tx_ino = 2 * client_channel;
156397d8cafcSkettenis 	lc->client_endpoint->rx_ino = 2 * client_channel + 1;
156497d8cafcSkettenis 	lc->client_endpoint->target_type = LDC_GUEST;
156597d8cafcSkettenis 	lc->client_endpoint->target_guest = primary->gid;
156697d8cafcSkettenis 	lc->client_endpoint->target_channel = server_channel;
156797d8cafcSkettenis 	lc->client_endpoint->channel = client_channel;
156897d8cafcSkettenis 
1569e099dd74Skettenis 	lc->server_endpoint = hvmd_add_endpoint(primary);
157097d8cafcSkettenis 	lc->server_endpoint->tx_ino = 2 * server_channel;
157197d8cafcSkettenis 	lc->server_endpoint->rx_ino = 2 * server_channel + 1;
157297d8cafcSkettenis 	lc->server_endpoint->target_type = LDC_GUEST;
157397d8cafcSkettenis 	lc->server_endpoint->target_guest = guest->gid;
157497d8cafcSkettenis 	lc->server_endpoint->channel = server_channel;
157597d8cafcSkettenis 	lc->server_endpoint->target_channel = client_channel;
157697d8cafcSkettenis 
157797d8cafcSkettenis 	return lc;
157897d8cafcSkettenis }
157997d8cafcSkettenis 
158097d8cafcSkettenis struct guest *
hvmd_add_guest(const char * name)1581e099dd74Skettenis hvmd_add_guest(const char *name)
158297d8cafcSkettenis {
158397d8cafcSkettenis 	struct guest *guest;
158497d8cafcSkettenis 	uint64_t resource_id;
158597d8cafcSkettenis 
158697d8cafcSkettenis 	for (resource_id = 0; resource_id < max_guests; resource_id++)
158797d8cafcSkettenis 		if (guests[resource_id] == NULL)
158897d8cafcSkettenis 			break;
158997d8cafcSkettenis 	assert(resource_id < max_guests);
159097d8cafcSkettenis 
159197d8cafcSkettenis 	guest = xzalloc(sizeof(*guest));
159297d8cafcSkettenis 	TAILQ_INIT(&guest->cpu_list);
1593e099dd74Skettenis 	TAILQ_INIT(&guest->device_list);
15948cfaec25Skettenis 	TAILQ_INIT(&guest->subdevice_list);
159597d8cafcSkettenis 	TAILQ_INIT(&guest->mblock_list);
159697d8cafcSkettenis 	TAILQ_INIT(&guest->endpoint_list);
159797d8cafcSkettenis 	guests[resource_id] = guest;
159897d8cafcSkettenis 	guest->name = name;
159997d8cafcSkettenis 	guest->gid = resource_id;
160097d8cafcSkettenis 	guest->pid = resource_id + 1;
160197d8cafcSkettenis 	guest->resource_id = resource_id;
160297d8cafcSkettenis 	guest->mdpa = hvmd_alloc_frag(-1);
160397d8cafcSkettenis 
1604e099dd74Skettenis 	hvmd_add_console(guest);
1605e099dd74Skettenis 	hvmd_add_domain_services(guest);
160697d8cafcSkettenis 
160797d8cafcSkettenis 	return guest;
160897d8cafcSkettenis }
160997d8cafcSkettenis 
161097d8cafcSkettenis struct md_node *
guest_add_channel_endpoints(struct guest * guest)161197d8cafcSkettenis guest_add_channel_endpoints(struct guest *guest)
161297d8cafcSkettenis {
161397d8cafcSkettenis 	struct md *md = guest->md;
161497d8cafcSkettenis 	struct md_node *parent;
161597d8cafcSkettenis 	struct md_node *node;
161697d8cafcSkettenis 
161797d8cafcSkettenis 	parent = md_find_node(md, "root");
161897d8cafcSkettenis 	assert(parent);
161997d8cafcSkettenis 
162097d8cafcSkettenis 	node = md_add_node(md, "channel-endpoints");
162197d8cafcSkettenis 	md_link_node(md, parent, node);
162297d8cafcSkettenis 
162397d8cafcSkettenis 	return node;
162497d8cafcSkettenis }
162597d8cafcSkettenis 
162697d8cafcSkettenis struct md_node *
guest_add_endpoint(struct guest * guest,uint64_t id)162797d8cafcSkettenis guest_add_endpoint(struct guest *guest, uint64_t id)
162897d8cafcSkettenis {
162997d8cafcSkettenis 	struct md *md = guest->md;
163097d8cafcSkettenis 	struct md_node *parent;
163197d8cafcSkettenis 	struct md_node *node;
163297d8cafcSkettenis 
163397d8cafcSkettenis 	parent = md_find_node(md, "channel-endpoints");
163497d8cafcSkettenis 	if (parent == NULL)
163597d8cafcSkettenis 		parent = guest_add_channel_endpoints(guest);
163697d8cafcSkettenis 
163797d8cafcSkettenis 	node = md_add_node(md, "channel-endpoint");
163897d8cafcSkettenis 	md_link_node(md, parent, node);
163997d8cafcSkettenis 	md_add_prop_val(md, node, "id", id);
164097d8cafcSkettenis 	md_add_prop_val(md, node, "tx-ino", 2 * id);
164197d8cafcSkettenis 	md_add_prop_val(md, node, "rx-ino", 2 * id + 1);
164297d8cafcSkettenis 
164397d8cafcSkettenis 	return node;
164497d8cafcSkettenis }
164597d8cafcSkettenis 
164697d8cafcSkettenis struct md_node *
guest_add_vcc(struct guest * guest)164797d8cafcSkettenis guest_add_vcc(struct guest *guest)
164897d8cafcSkettenis {
164997d8cafcSkettenis 	const char compatible[] = "SUNW,sun4v-virtual-console-concentrator";
165097d8cafcSkettenis 	struct md *md = guest->md;
165197d8cafcSkettenis 	struct md_node *parent;
165297d8cafcSkettenis 	struct md_node *node;
165397d8cafcSkettenis 
165497d8cafcSkettenis 	parent = md_find_node(md, "channel-devices");
165597d8cafcSkettenis 	assert(parent != NULL);
165697d8cafcSkettenis 
165797d8cafcSkettenis 	node = md_add_node(md, "virtual-device");
165897d8cafcSkettenis 	md_link_node(md, parent, node);
165997d8cafcSkettenis 	md_add_prop_str(md, node, "name", "virtual-console-concentrator");
166097d8cafcSkettenis 	md_add_prop_data(md, node, "compatible", compatible,
166197d8cafcSkettenis 	    sizeof(compatible));
166297d8cafcSkettenis 	md_add_prop_str(md, node, "device_type", "vcc");
166397d8cafcSkettenis 	md_add_prop_val(md, node, "cfg-handle", 0x0);
166497d8cafcSkettenis 	md_add_prop_str(md, node, "svc-name", "primary-vcc0");
166597d8cafcSkettenis 
166697d8cafcSkettenis 	return node;
166797d8cafcSkettenis }
166897d8cafcSkettenis 
166997d8cafcSkettenis struct md_node *
guest_find_vcc(struct guest * guest)167097d8cafcSkettenis guest_find_vcc(struct guest *guest)
167197d8cafcSkettenis {
167297d8cafcSkettenis 	struct md *md = guest->md;
167397d8cafcSkettenis 	struct md_node *node, *node2;
167497d8cafcSkettenis 	struct md_prop *prop;
167597d8cafcSkettenis 	const char *name;
167697d8cafcSkettenis 
167797d8cafcSkettenis 	node = md_find_node(md, "channel-devices");
167897d8cafcSkettenis 	assert(node != NULL);
167997d8cafcSkettenis 
168097d8cafcSkettenis 	TAILQ_FOREACH(prop, &node->prop_list, link) {
168197d8cafcSkettenis 		if (prop->tag == MD_PROP_ARC &&
168297d8cafcSkettenis 		    strcmp(prop->name->str, "fwd") == 0) {
168397d8cafcSkettenis 			node2 = prop->d.arc.node;
168497d8cafcSkettenis 			if (!md_get_prop_str(md, node2, "name", &name))
168597d8cafcSkettenis 				continue;
168697d8cafcSkettenis 			if (strcmp(name, "virtual-console-concentrator") == 0)
168797d8cafcSkettenis 				return node2;
168897d8cafcSkettenis 		}
168997d8cafcSkettenis 	}
169097d8cafcSkettenis 
169197d8cafcSkettenis 	return NULL;
169297d8cafcSkettenis }
169397d8cafcSkettenis 
169497d8cafcSkettenis struct md_node *
guest_add_vcc_port(struct guest * guest,struct md_node * vcc,const char * domain,uint64_t id,uint64_t channel)169597d8cafcSkettenis guest_add_vcc_port(struct guest *guest, struct md_node *vcc,
169697d8cafcSkettenis     const char *domain, uint64_t id, uint64_t channel)
169797d8cafcSkettenis {
169897d8cafcSkettenis 	struct md *md = guest->md;
169997d8cafcSkettenis 	struct md_node *node;
170097d8cafcSkettenis 	struct md_node *child;
170197d8cafcSkettenis 
170297d8cafcSkettenis 	if (vcc == NULL)
170397d8cafcSkettenis 		vcc = guest_find_vcc(guest);
170497d8cafcSkettenis 	if (vcc == NULL)
170597d8cafcSkettenis 		vcc = guest_add_vcc(guest);
170697d8cafcSkettenis 
170797d8cafcSkettenis 	node = md_add_node(md, "virtual-device-port");
170897d8cafcSkettenis 	md_link_node(md, vcc, node);
170997d8cafcSkettenis 	md_add_prop_str(md, node, "name", "vcc-port");
171097d8cafcSkettenis 	md_add_prop_val(md, node, "id", id);
171197d8cafcSkettenis 	md_add_prop_str(md, node, "vcc-domain-name", domain);
171297d8cafcSkettenis 	md_add_prop_str(md, node, "vcc-group-name", domain);
171397d8cafcSkettenis 	/* OpenBSD doesn't care about this, but Solaris might. */
171497d8cafcSkettenis 	md_add_prop_val(md, node, "vcc-tcp-port", 5000 + id);
171597d8cafcSkettenis 
171697d8cafcSkettenis 	child = guest_add_endpoint(guest, channel);
171797d8cafcSkettenis 	md_link_node(md, node, child);
171897d8cafcSkettenis 
171997d8cafcSkettenis 	return node;
172097d8cafcSkettenis }
172197d8cafcSkettenis 
172297d8cafcSkettenis struct md_node *
guest_add_vds(struct guest * guest)172397d8cafcSkettenis guest_add_vds(struct guest *guest)
172497d8cafcSkettenis {
172597d8cafcSkettenis 	const char compatible[] = "SUNW,sun4v-disk-server";
172697d8cafcSkettenis 	struct md *md = guest->md;
172797d8cafcSkettenis 	struct md_node *parent;
172897d8cafcSkettenis 	struct md_node *node;
172997d8cafcSkettenis 
173097d8cafcSkettenis 	parent = md_find_node(md, "channel-devices");
173197d8cafcSkettenis 	assert(parent != NULL);
173297d8cafcSkettenis 
173397d8cafcSkettenis 	node = md_add_node(md, "virtual-device");
173497d8cafcSkettenis 	md_link_node(md, parent, node);
173597d8cafcSkettenis 	md_add_prop_str(md, node, "name", "virtual-disk-server");
173697d8cafcSkettenis 	md_add_prop_data(md, node, "compatible", compatible,
173797d8cafcSkettenis 	    sizeof(compatible));
173897d8cafcSkettenis 	md_add_prop_str(md, node, "device_type", "vds");
173997d8cafcSkettenis 	md_add_prop_val(md, node, "cfg-handle", 0x0);
174097d8cafcSkettenis 	md_add_prop_str(md, node, "svc-name", "primary-vds0");
174197d8cafcSkettenis 
174297d8cafcSkettenis 	return node;
174397d8cafcSkettenis }
174497d8cafcSkettenis 
174597d8cafcSkettenis struct md_node *
guest_find_vds(struct guest * guest)174697d8cafcSkettenis guest_find_vds(struct guest *guest)
174797d8cafcSkettenis {
174897d8cafcSkettenis 	struct md *md = guest->md;
174997d8cafcSkettenis 	struct md_node *node, *node2;
175097d8cafcSkettenis 	struct md_prop *prop;
175197d8cafcSkettenis 	const char *name;
175297d8cafcSkettenis 
175397d8cafcSkettenis 	node = md_find_node(md, "channel-devices");
175497d8cafcSkettenis 	assert(node != NULL);
175597d8cafcSkettenis 
175697d8cafcSkettenis 	TAILQ_FOREACH(prop, &node->prop_list, link) {
175797d8cafcSkettenis 		if (prop->tag == MD_PROP_ARC &&
175897d8cafcSkettenis 		    strcmp(prop->name->str, "fwd") == 0) {
175997d8cafcSkettenis 			node2 = prop->d.arc.node;
176097d8cafcSkettenis 			if (!md_get_prop_str(md, node2, "name", &name))
176197d8cafcSkettenis 				continue;
176297d8cafcSkettenis 			if (strcmp(name, "virtual-disk-server") == 0)
176397d8cafcSkettenis 				return node2;
176497d8cafcSkettenis 		}
176597d8cafcSkettenis 	}
176697d8cafcSkettenis 
176797d8cafcSkettenis 	return NULL;
176897d8cafcSkettenis }
176997d8cafcSkettenis 
177097d8cafcSkettenis struct md_node *
guest_add_vds_port(struct guest * guest,struct md_node * vds,const char * path,uint64_t id,uint64_t channel)177197d8cafcSkettenis guest_add_vds_port(struct guest *guest, struct md_node *vds,
177297d8cafcSkettenis     const char *path, uint64_t id, uint64_t channel)
177397d8cafcSkettenis {
177497d8cafcSkettenis 	struct md *md = guest->md;
177597d8cafcSkettenis 	struct md_node *node;
177697d8cafcSkettenis 	struct md_node *child;
177797d8cafcSkettenis 
177897d8cafcSkettenis 	if (vds == NULL)
177997d8cafcSkettenis 		vds = guest_find_vds(guest);
178097d8cafcSkettenis 	if (vds == NULL)
178197d8cafcSkettenis 		vds = guest_add_vds(guest);
178297d8cafcSkettenis 
178397d8cafcSkettenis 	node = md_add_node(md, "virtual-device-port");
178497d8cafcSkettenis 	md_link_node(md, vds, node);
178597d8cafcSkettenis 	md_add_prop_str(md, node, "name", "vds-port");
178697d8cafcSkettenis 	md_add_prop_val(md, node, "id", id);
178797d8cafcSkettenis 	md_add_prop_str(md, node, "vds-block-device", path);
178897d8cafcSkettenis 
178997d8cafcSkettenis 	child = guest_add_endpoint(guest, channel);
179097d8cafcSkettenis 	md_link_node(md, node, child);
179197d8cafcSkettenis 
179297d8cafcSkettenis 	return node;
179397d8cafcSkettenis }
179497d8cafcSkettenis 
179597d8cafcSkettenis struct md_node *
guest_add_vsw(struct guest * guest)179697d8cafcSkettenis guest_add_vsw(struct guest *guest)
179797d8cafcSkettenis {
179897d8cafcSkettenis 	const char compatible[] = "SUNW,sun4v-network-switch";
179997d8cafcSkettenis 	struct md *md = guest->md;
180097d8cafcSkettenis 	struct md_node *parent;
180197d8cafcSkettenis 	struct md_node *node;
180297d8cafcSkettenis 
180397d8cafcSkettenis 	parent = md_find_node(md, "channel-devices");
180497d8cafcSkettenis 	assert(parent != NULL);
180597d8cafcSkettenis 
180697d8cafcSkettenis 	node = md_add_node(md, "virtual-device");
180797d8cafcSkettenis 	md_link_node(md, parent, node);
180897d8cafcSkettenis 	md_add_prop_str(md, node, "name", "virtual-network-switch");
180997d8cafcSkettenis 	md_add_prop_data(md, node, "compatible", compatible,
181097d8cafcSkettenis 	    sizeof(compatible));
181197d8cafcSkettenis 	md_add_prop_str(md, node, "device_type", "vsw");
181297d8cafcSkettenis 	md_add_prop_val(md, node, "cfg-handle", 0x0);
181397d8cafcSkettenis 	md_add_prop_str(md, node, "svc-name", "primary-vsw0");
181497d8cafcSkettenis 
181597d8cafcSkettenis 	return node;
181697d8cafcSkettenis }
181797d8cafcSkettenis 
181897d8cafcSkettenis struct md_node *
guest_find_vsw(struct guest * guest)181997d8cafcSkettenis guest_find_vsw(struct guest *guest)
182097d8cafcSkettenis {
182197d8cafcSkettenis 	struct md *md = guest->md;
182297d8cafcSkettenis 	struct md_node *node, *node2;
182397d8cafcSkettenis 	struct md_prop *prop;
182497d8cafcSkettenis 	const char *name;
182597d8cafcSkettenis 
182697d8cafcSkettenis 	node = md_find_node(md, "channel-devices");
182797d8cafcSkettenis 	assert(node != NULL);
182897d8cafcSkettenis 
182997d8cafcSkettenis 	TAILQ_FOREACH(prop, &node->prop_list, link) {
183097d8cafcSkettenis 		if (prop->tag == MD_PROP_ARC &&
183197d8cafcSkettenis 		    strcmp(prop->name->str, "fwd") == 0) {
183297d8cafcSkettenis 			node2 = prop->d.arc.node;
183397d8cafcSkettenis 			if (!md_get_prop_str(md, node2, "name", &name))
183497d8cafcSkettenis 				continue;
183597d8cafcSkettenis 			if (strcmp(name, "virtual-network-switch") == 0)
183697d8cafcSkettenis 				return node2;
183797d8cafcSkettenis 		}
183897d8cafcSkettenis 	}
183997d8cafcSkettenis 
184097d8cafcSkettenis 	return NULL;
184197d8cafcSkettenis }
184297d8cafcSkettenis 
184397d8cafcSkettenis struct md_node *
guest_add_vsw_port(struct guest * guest,struct md_node * vds,uint64_t id,uint64_t channel)184497d8cafcSkettenis guest_add_vsw_port(struct guest *guest, struct md_node *vds,
184597d8cafcSkettenis     uint64_t id, uint64_t channel)
184697d8cafcSkettenis {
184797d8cafcSkettenis 	struct md *md = guest->md;
184897d8cafcSkettenis 	struct md_node *node;
184997d8cafcSkettenis 	struct md_node *child;
185092aafd32Skettenis 	uint64_t mac_addr;
185197d8cafcSkettenis 
185297d8cafcSkettenis 	if (vds == NULL)
185397d8cafcSkettenis 		vds = guest_find_vsw(guest);
185497d8cafcSkettenis 	if (vds == NULL)
185597d8cafcSkettenis 		vds = guest_add_vsw(guest);
185692aafd32Skettenis 	if (!md_get_prop_val(md, vds, "local-mac-address", &mac_addr)) {
185792aafd32Skettenis 		mac_addr = 0x00144ff80000 + (arc4random() & 0x3ffff);
185892aafd32Skettenis 		md_add_prop_val(md, vds, "local-mac-address", mac_addr);
185992aafd32Skettenis 	}
186097d8cafcSkettenis 
186197d8cafcSkettenis 	node = md_add_node(md, "virtual-device-port");
186297d8cafcSkettenis 	md_link_node(md, vds, node);
186397d8cafcSkettenis 	md_add_prop_str(md, node, "name", "vsw-port");
186497d8cafcSkettenis 	md_add_prop_val(md, node, "id", id);
186597d8cafcSkettenis 
186697d8cafcSkettenis 	child = guest_add_endpoint(guest, channel);
186797d8cafcSkettenis 	md_link_node(md, node, child);
186897d8cafcSkettenis 
186997d8cafcSkettenis 	return node;
187097d8cafcSkettenis }
187197d8cafcSkettenis 
187297d8cafcSkettenis struct md_node *
guest_add_console_device(struct guest * guest)187397d8cafcSkettenis guest_add_console_device(struct guest *guest)
187497d8cafcSkettenis {
187597d8cafcSkettenis 	const char compatible[] = "SUNW,sun4v-console";
187697d8cafcSkettenis 	struct md *md = guest->md;
187797d8cafcSkettenis 	struct md_node *parent;
187897d8cafcSkettenis 	struct md_node *node;
187997d8cafcSkettenis 
188097d8cafcSkettenis 	parent = md_find_node(md, "virtual-devices");
188197d8cafcSkettenis 	assert(parent);
188297d8cafcSkettenis 
188397d8cafcSkettenis 	node = md_add_node(md, "virtual-device");
188497d8cafcSkettenis 	md_link_node(md, parent, node);
188597d8cafcSkettenis 	md_add_prop_str(md, node, "name", "console");
188697d8cafcSkettenis 	md_add_prop_str(md, node, "device-type", "serial");
188797d8cafcSkettenis 	md_add_prop_val(md, node, "intr", 0x1);
188897d8cafcSkettenis 	md_add_prop_val(md, node, "ino", 0x11);
188997d8cafcSkettenis 	md_add_prop_val(md, node, "channel#", 0);
189097d8cafcSkettenis 	md_add_prop_val(md, node, "cfg-handle", 0x1);
189197d8cafcSkettenis 	md_add_prop_data(md, node, "compatible", compatible,
189297d8cafcSkettenis 	    sizeof(compatible));
189397d8cafcSkettenis 
189497d8cafcSkettenis 	return node;
189597d8cafcSkettenis }
189697d8cafcSkettenis 
189797d8cafcSkettenis struct md_node *
guest_add_vdc(struct guest * guest,uint64_t cfghandle)189897d8cafcSkettenis guest_add_vdc(struct guest *guest, uint64_t cfghandle)
189997d8cafcSkettenis {
190097d8cafcSkettenis 	const char compatible[] = "SUNW,sun4v-disk";
190197d8cafcSkettenis 	struct md *md = guest->md;
190297d8cafcSkettenis 	struct md_node *parent;
190397d8cafcSkettenis 	struct md_node *node;
190497d8cafcSkettenis 
190597d8cafcSkettenis 	parent = md_find_node(md, "channel-devices");
190697d8cafcSkettenis 	assert(parent);
190797d8cafcSkettenis 
190897d8cafcSkettenis 	node = md_add_node(md, "virtual-device");
190997d8cafcSkettenis 	md_link_node(md, parent, node);
191097d8cafcSkettenis 	md_add_prop_str(md, node, "name", "disk");
191197d8cafcSkettenis 	md_add_prop_str(md, node, "device-type", "block");
191297d8cafcSkettenis 	md_add_prop_val(md, node, "cfg-handle", cfghandle);
191397d8cafcSkettenis 	md_add_prop_data(md, node, "compatible", compatible,
191497d8cafcSkettenis 	    sizeof(compatible));
191597d8cafcSkettenis 
191697d8cafcSkettenis 	return node;
191797d8cafcSkettenis }
191897d8cafcSkettenis 
191997d8cafcSkettenis struct md_node *
guest_add_vdc_port(struct guest * guest,struct md_node * vdc,uint64_t cfghandle,uint64_t id,uint64_t channel)192097d8cafcSkettenis guest_add_vdc_port(struct guest *guest, struct md_node *vdc,
192197d8cafcSkettenis     uint64_t cfghandle, uint64_t id, uint64_t channel)
192297d8cafcSkettenis {
192397d8cafcSkettenis 	struct md *md = guest->md;
192497d8cafcSkettenis 	struct md_node *node;
192597d8cafcSkettenis 	struct md_node *child;
192697d8cafcSkettenis 
192797d8cafcSkettenis 	if (vdc == NULL)
192897d8cafcSkettenis 		vdc = guest_add_vdc(guest, cfghandle);
192997d8cafcSkettenis 
193097d8cafcSkettenis 	node = md_add_node(md, "virtual-device-port");
193197d8cafcSkettenis 	md_link_node(md, vdc, node);
193297d8cafcSkettenis 	md_add_prop_str(md, node, "name", "vdc-port");
193397d8cafcSkettenis 	md_add_prop_val(md, node, "id", id);
193497d8cafcSkettenis 
193597d8cafcSkettenis 	child = guest_add_endpoint(guest, channel);
193697d8cafcSkettenis 	md_link_node(md, node, child);
193797d8cafcSkettenis 
193897d8cafcSkettenis 	return node;
193997d8cafcSkettenis }
194097d8cafcSkettenis 
194197d8cafcSkettenis struct md_node *
guest_add_vnet(struct guest * guest,uint64_t mac_addr,uint64_t mtu,uint64_t cfghandle)194297d8cafcSkettenis guest_add_vnet(struct guest *guest, uint64_t mac_addr, uint64_t mtu,
194397d8cafcSkettenis     uint64_t cfghandle)
194497d8cafcSkettenis {
194597d8cafcSkettenis 	const char compatible[] = "SUNW,sun4v-network";
194697d8cafcSkettenis 	struct md *md = guest->md;
194797d8cafcSkettenis 	struct md_node *parent;
194897d8cafcSkettenis 	struct md_node *node;
194997d8cafcSkettenis 
195097d8cafcSkettenis 	parent = md_find_node(md, "channel-devices");
195197d8cafcSkettenis 	assert(parent);
195297d8cafcSkettenis 
195397d8cafcSkettenis 	node = md_add_node(md, "virtual-device");
195497d8cafcSkettenis 	md_link_node(md, parent, node);
195597d8cafcSkettenis 	md_add_prop_str(md, node, "name", "network");
195697d8cafcSkettenis 	md_add_prop_str(md, node, "device-type", "network");
195797d8cafcSkettenis 	md_add_prop_val(md, node, "cfg-handle", cfghandle);
195897d8cafcSkettenis 	md_add_prop_data(md, node, "compatible", compatible,
195997d8cafcSkettenis 	    sizeof(compatible));
196097d8cafcSkettenis 	if (mac_addr == -1)
196197d8cafcSkettenis 		mac_addr = 0x00144ff80000 + (arc4random() & 0x3ffff);
196297d8cafcSkettenis 	md_add_prop_val(md, node, "local-mac-address", mac_addr);
196397d8cafcSkettenis 	md_add_prop_val(md, node, "mtu", mtu);
196497d8cafcSkettenis 
196597d8cafcSkettenis 	return node;
196697d8cafcSkettenis }
196797d8cafcSkettenis 
196897d8cafcSkettenis 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)196997d8cafcSkettenis guest_add_vnet_port(struct guest *guest, struct md_node *vdc,
197092aafd32Skettenis     uint64_t mac_addr, uint64_t remote_mac_addr, uint64_t mtu, uint64_t cfghandle,
197192aafd32Skettenis     uint64_t id, uint64_t channel)
197297d8cafcSkettenis {
197397d8cafcSkettenis 	struct md *md = guest->md;
197497d8cafcSkettenis 	struct md_node *node;
197597d8cafcSkettenis 	struct md_node *child;
197697d8cafcSkettenis 
197797d8cafcSkettenis 	if (vdc == NULL)
197897d8cafcSkettenis 		vdc = guest_add_vnet(guest, mac_addr, mtu, cfghandle);
197997d8cafcSkettenis 
198097d8cafcSkettenis 	node = md_add_node(md, "virtual-device-port");
198197d8cafcSkettenis 	md_link_node(md, vdc, node);
198297d8cafcSkettenis 	md_add_prop_str(md, node, "name", "vnet-port");
198397d8cafcSkettenis 	md_add_prop_val(md, node, "id", id);
198492aafd32Skettenis 	md_add_prop_val(md, node, "switch-port", 0);
198592aafd32Skettenis 	md_add_prop_data(md, node, "remote-mac-address",
198692aafd32Skettenis 	    (uint8_t *)&remote_mac_addr, sizeof(remote_mac_addr));
198797d8cafcSkettenis 
198897d8cafcSkettenis 	child = guest_add_endpoint(guest, channel);
198997d8cafcSkettenis 	md_link_node(md, node, child);
199097d8cafcSkettenis 
199197d8cafcSkettenis 	return node;
199297d8cafcSkettenis }
199397d8cafcSkettenis 
199497d8cafcSkettenis struct md_node *
guest_add_channel_devices(struct guest * guest)199597d8cafcSkettenis guest_add_channel_devices(struct guest *guest)
199697d8cafcSkettenis {
199797d8cafcSkettenis 	const char compatible[] = "SUNW,sun4v-channel-devices";
199897d8cafcSkettenis 	struct md *md = guest->md;
199997d8cafcSkettenis 	struct md_node *parent;
200097d8cafcSkettenis 	struct md_node *node;
200197d8cafcSkettenis 
200297d8cafcSkettenis 	parent = md_find_node(md, "virtual-devices");
200397d8cafcSkettenis 	assert(parent);
200497d8cafcSkettenis 
200597d8cafcSkettenis 	node = md_add_node(md, "channel-devices");
200697d8cafcSkettenis 	md_link_node(md, parent, node);
200797d8cafcSkettenis 	md_add_prop_str(md, node, "name", "channel-devices");
200897d8cafcSkettenis 	md_add_prop_str(md, node, "device-type", "channel-devices");
200997d8cafcSkettenis 	md_add_prop_data(md, node, "compatible", compatible,
201097d8cafcSkettenis 	    sizeof(compatible));
201197d8cafcSkettenis 	md_add_prop_val(md, node, "cfg-handle", 0x200);
201297d8cafcSkettenis 
201397d8cafcSkettenis 	return node;
201497d8cafcSkettenis }
201597d8cafcSkettenis 
201697d8cafcSkettenis struct md_node *
guest_add_domain_services(struct guest * guest)201797d8cafcSkettenis guest_add_domain_services(struct guest *guest)
201897d8cafcSkettenis {
201997d8cafcSkettenis 	struct md *md = guest->md;
202097d8cafcSkettenis 	struct md_node *parent;
202197d8cafcSkettenis 	struct md_node *node;
202297d8cafcSkettenis 
202397d8cafcSkettenis 	parent = md_find_node(md, "root");
202497d8cafcSkettenis 	assert(parent);
202597d8cafcSkettenis 
202697d8cafcSkettenis 	node = md_add_node(md, "domain-services");
202797d8cafcSkettenis 	md_link_node(md, parent, node);
202897d8cafcSkettenis 
202997d8cafcSkettenis 	return node;
203097d8cafcSkettenis }
203197d8cafcSkettenis 
203297d8cafcSkettenis struct md_node *
guest_add_domain_services_port(struct guest * guest,uint64_t id)203397d8cafcSkettenis guest_add_domain_services_port(struct guest *guest, uint64_t id)
203497d8cafcSkettenis {
203597d8cafcSkettenis 	struct md *md = guest->md;
203697d8cafcSkettenis 	struct md_node *parent;
203797d8cafcSkettenis 	struct md_node *node;
203897d8cafcSkettenis 	struct md_node *child;
203997d8cafcSkettenis 
204097d8cafcSkettenis 	parent = md_find_node(md, "domain-services");
204197d8cafcSkettenis 	if (parent == NULL)
204297d8cafcSkettenis 		parent = guest_add_domain_services(guest);
204397d8cafcSkettenis 
204497d8cafcSkettenis 	node = md_add_node(md, "domain-services-port");
204597d8cafcSkettenis 	md_link_node(md, parent, node);
204697d8cafcSkettenis 	md_add_prop_val(md, node, "id", id);
204797d8cafcSkettenis 
204897d8cafcSkettenis 	child = guest_add_endpoint(guest,
204997d8cafcSkettenis 	    guest->domain_services.client_endpoint->channel);
205097d8cafcSkettenis 	md_link_node(md, node, child);
205197d8cafcSkettenis 
205297d8cafcSkettenis 	return node;
205397d8cafcSkettenis }
205497d8cafcSkettenis 
205597d8cafcSkettenis void
guest_add_devalias(struct guest * guest,const char * name,const char * path)205697d8cafcSkettenis guest_add_devalias(struct guest *guest, const char *name, const char *path)
205797d8cafcSkettenis {
205897d8cafcSkettenis 	struct md *md = guest->md;
205997d8cafcSkettenis 	struct md_node *parent;
206097d8cafcSkettenis 	struct md_node *node;
206197d8cafcSkettenis 
206297d8cafcSkettenis 	parent = md_find_node(md, "openboot");
206397d8cafcSkettenis 	assert(parent);
206497d8cafcSkettenis 
2065d27a0d69Skettenis 	node = md_find_subnode(md, parent, "devalias");
2066d27a0d69Skettenis 	if (node == NULL) {
206797d8cafcSkettenis 		node = md_add_node(md, "devalias");
206897d8cafcSkettenis 		md_link_node(md, parent, node);
206997d8cafcSkettenis 	}
207097d8cafcSkettenis 
207197d8cafcSkettenis 	md_add_prop_str(md, node, name, path);
207297d8cafcSkettenis }
207397d8cafcSkettenis 
207497d8cafcSkettenis void
guest_set_domaining_enabled(struct guest * guest)207597d8cafcSkettenis guest_set_domaining_enabled(struct guest *guest)
207697d8cafcSkettenis {
207797d8cafcSkettenis 	struct md *md = guest->md;
207897d8cafcSkettenis 	struct md_node *node;
207997d8cafcSkettenis 
208097d8cafcSkettenis 	node = md_find_node(md, "platform");
208197d8cafcSkettenis 	assert(node);
208297d8cafcSkettenis 
208397d8cafcSkettenis 	md_set_prop_val(md, node, "domaining-enabled", 0x1);
208497d8cafcSkettenis }
208597d8cafcSkettenis 
208697d8cafcSkettenis void
guest_set_mac_address(struct guest * guest)208797d8cafcSkettenis guest_set_mac_address(struct guest *guest)
208897d8cafcSkettenis {
208997d8cafcSkettenis 	struct md *md = guest->md;
209097d8cafcSkettenis 	struct md_node *node;
209197d8cafcSkettenis 	uint64_t mac_address;
209297d8cafcSkettenis 	uint64_t hostid;
209397d8cafcSkettenis 
209497d8cafcSkettenis 	node = md_find_node(md, "platform");
209597d8cafcSkettenis 	assert(node);
209697d8cafcSkettenis 
209797d8cafcSkettenis 	mac_address = 0x00144ff80000 + (arc4random() & 0x3ffff);
209897d8cafcSkettenis 	md_set_prop_val(md, node, "mac-address", mac_address);
209997d8cafcSkettenis 
210097d8cafcSkettenis 	hostid = 0x84000000 | (mac_address & 0x00ffffff);
210197d8cafcSkettenis 	md_set_prop_val(md, node, "hostid", hostid);
210297d8cafcSkettenis }
210397d8cafcSkettenis 
210497d8cafcSkettenis struct md_node *
guest_find_vc(struct guest * guest)210597d8cafcSkettenis guest_find_vc(struct guest *guest)
210697d8cafcSkettenis {
210797d8cafcSkettenis 	struct md *md = guest->md;
210897d8cafcSkettenis 	struct md_node *node, *node2;
210997d8cafcSkettenis 	struct md_node *vc = NULL;
211097d8cafcSkettenis 	struct md_prop *prop;
211197d8cafcSkettenis 	const char *name;
211297d8cafcSkettenis 
211397d8cafcSkettenis 	node = md_find_node(md, "channel-devices");
211497d8cafcSkettenis 	assert(node != NULL);
211597d8cafcSkettenis 
211697d8cafcSkettenis 	TAILQ_FOREACH(prop, &node->prop_list, link) {
211797d8cafcSkettenis 		if (prop->tag == MD_PROP_ARC &&
211897d8cafcSkettenis 		    strcmp(prop->name->str, "fwd") == 0) {
211997d8cafcSkettenis 			node2 = prop->d.arc.node;
212097d8cafcSkettenis 			if (!md_get_prop_str(md, node2, "name", &name))
212197d8cafcSkettenis 				continue;
212297d8cafcSkettenis 			if (strcmp(name, "virtual-channel") == 0)
212397d8cafcSkettenis 				vc = node2;
212497d8cafcSkettenis 		}
212597d8cafcSkettenis 	}
212697d8cafcSkettenis 
212797d8cafcSkettenis 	return vc;
212897d8cafcSkettenis }
212997d8cafcSkettenis 
213097d8cafcSkettenis struct md_node *
guest_add_vc_port(struct guest * guest,struct md_node * vc,const char * domain,uint64_t id,uint64_t channel)213197d8cafcSkettenis guest_add_vc_port(struct guest *guest, struct md_node *vc,
213297d8cafcSkettenis     const char *domain, uint64_t id, uint64_t channel)
213397d8cafcSkettenis {
213497d8cafcSkettenis 	struct md *md = guest->md;
213597d8cafcSkettenis 	struct md_node *node;
213697d8cafcSkettenis 	struct md_node *child;
213797d8cafcSkettenis 	char *str;
213897d8cafcSkettenis 
213997d8cafcSkettenis 	if (vc == NULL)
214097d8cafcSkettenis 		vc = guest_find_vc(guest);
214197d8cafcSkettenis 	assert(vc);
214297d8cafcSkettenis 
214397d8cafcSkettenis 	node = md_add_node(md, "virtual-device-port");
214497d8cafcSkettenis 	md_link_node(md, vc, node);
214597d8cafcSkettenis 	md_add_prop_str(md, node, "name", "vldc-port");
214697d8cafcSkettenis 	md_add_prop_val(md, node, "id", id);
214797d8cafcSkettenis 	xasprintf(&str, "ldom-%s", domain);
214897d8cafcSkettenis 	md_add_prop_str(md, node, "vldc-svc-name", str);
214997d8cafcSkettenis 	free(str);
215097d8cafcSkettenis 
215197d8cafcSkettenis 	child = guest_add_endpoint(guest, channel);
215297d8cafcSkettenis 	md_link_node(md, node, child);
215397d8cafcSkettenis 
215497d8cafcSkettenis 	return node;
215597d8cafcSkettenis }
215697d8cafcSkettenis 
215797d8cafcSkettenis struct guest *
guest_create(const char * name)215897d8cafcSkettenis guest_create(const char *name)
215997d8cafcSkettenis {
216097d8cafcSkettenis 	struct guest *guest;
216197d8cafcSkettenis 	struct guest *primary;
216297d8cafcSkettenis 	struct md_node *node;
216397d8cafcSkettenis 
216497d8cafcSkettenis 	primary = guest_lookup("primary");
216597d8cafcSkettenis 
2166e099dd74Skettenis 	guest = hvmd_add_guest(name);
216797d8cafcSkettenis 	guest->md = md_copy(protomd);
216897d8cafcSkettenis 
216997d8cafcSkettenis 	md_find_delete_node(guest->md, "dimm_configuration");
217097d8cafcSkettenis 	md_find_delete_node(guest->md, "platform_services");
217197d8cafcSkettenis 	md_collect_garbage(guest->md);
217297d8cafcSkettenis 
217397d8cafcSkettenis 	guest_set_domaining_enabled(guest);
217497d8cafcSkettenis 	guest_set_mac_address(guest);
217597d8cafcSkettenis 	guest_add_channel_devices(guest);
217697d8cafcSkettenis 	guest_add_domain_services_port(guest, 0);
217797d8cafcSkettenis 	guest_add_console_device(guest);
217897d8cafcSkettenis 	guest_add_devalias(guest, "virtual-console",
217997d8cafcSkettenis 	    "/virtual-devices/console@1");
218097d8cafcSkettenis 
218197d8cafcSkettenis 	guest_add_vcc_port(primary, NULL, guest->name, guest->gid - 1,
218297d8cafcSkettenis 	    guest->console->server_endpoint->channel);
218397d8cafcSkettenis 
218497d8cafcSkettenis 	guest_add_vc_port(primary, NULL, guest->name, guest->gid + 2,
218597d8cafcSkettenis 	    guest->domain_services.server_endpoint->channel);
218697d8cafcSkettenis 
218797d8cafcSkettenis 	node = md_find_node(guest->md, "root");
218897d8cafcSkettenis 	md_add_prop_val(guest->md, node, "reset-reason", 0);
218997d8cafcSkettenis 
219097d8cafcSkettenis 	return guest;
219197d8cafcSkettenis }
219297d8cafcSkettenis 
21938cfaec25Skettenis int
guest_match_path(struct guest * guest,const char * path)21948cfaec25Skettenis guest_match_path(struct guest *guest, const char *path)
21958cfaec25Skettenis {
21968cfaec25Skettenis 	struct subdevice *subdevice;
21978cfaec25Skettenis 	size_t len = strlen(path);
21988cfaec25Skettenis 
21998cfaec25Skettenis 	TAILQ_FOREACH(subdevice, &guest->subdevice_list, link) {
22008cfaec25Skettenis 		const char *path2 = subdevice->path;
22018cfaec25Skettenis 		size_t len2 = strlen(path2);
22028cfaec25Skettenis 
22038cfaec25Skettenis 		if (strncmp(path, path2, len < len2 ? len : len2) == 0)
22048cfaec25Skettenis 			return 1;
22058cfaec25Skettenis 	}
22068cfaec25Skettenis 
22078cfaec25Skettenis 	return 0;
22088cfaec25Skettenis }
22098cfaec25Skettenis 
22108cfaec25Skettenis void
guest_prune_phys_io(struct guest * guest)22118cfaec25Skettenis guest_prune_phys_io(struct guest *guest)
22128cfaec25Skettenis {
22138cfaec25Skettenis 	const char compatible[] = "SUNW,sun4v-vpci";
22148cfaec25Skettenis 	struct md *md = guest->md;
22158cfaec25Skettenis 	struct md_node *node, *node2;
22168cfaec25Skettenis 	struct md_prop *prop, *prop2;
22178cfaec25Skettenis 	const char *device_type;
22188cfaec25Skettenis 	uint64_t cfg_handle;
22198cfaec25Skettenis 	char *path;
22208cfaec25Skettenis 
22218cfaec25Skettenis 	node = md_find_node(guest->md, "phys_io");
22228cfaec25Skettenis 	TAILQ_FOREACH_SAFE(prop, &node->prop_list, link, prop2) {
22238cfaec25Skettenis 		if (prop->tag == MD_PROP_ARC &&
22248cfaec25Skettenis 		    strcmp(prop->name->str, "fwd") == 0) {
22258cfaec25Skettenis 			node2 = prop->d.arc.node;
22268cfaec25Skettenis 			if (!md_get_prop_str(md, node2, "device-type",
22278cfaec25Skettenis 			    &device_type))
22288cfaec25Skettenis 				device_type = "unknown";
22298cfaec25Skettenis 			if (strcmp(device_type, "pciex") != 0) {
22308cfaec25Skettenis 				md_delete_node(md, node2);
22318cfaec25Skettenis 				continue;
22328cfaec25Skettenis 			}
22338cfaec25Skettenis 
22348cfaec25Skettenis 			if (!md_get_prop_val(md, node2, "cfg-handle",
22358cfaec25Skettenis 			    &cfg_handle)) {
22368cfaec25Skettenis 				md_delete_node(md, node2);
22378cfaec25Skettenis 				continue;
22388cfaec25Skettenis 			}
22398cfaec25Skettenis 
22408cfaec25Skettenis 			xasprintf(&path, "/@%llx", cfg_handle);
22418cfaec25Skettenis 			if (!guest_match_path(guest, path)) {
22428cfaec25Skettenis 				md_delete_node(md, node2);
22438cfaec25Skettenis 				continue;
22448cfaec25Skettenis 			}
22458cfaec25Skettenis 
22468cfaec25Skettenis 			md_set_prop_data(md, node2, "compatible",
22478cfaec25Skettenis 			    compatible, sizeof(compatible));
22488cfaec25Skettenis 			md_add_prop_val(md, node2, "virtual-root-complex", 1);
22498cfaec25Skettenis 			guest_prune_pcie(guest, node2, path);
22508cfaec25Skettenis 			free(path);
22518cfaec25Skettenis 
22528cfaec25Skettenis 			guest_add_vpcie(guest, cfg_handle);
22538cfaec25Skettenis 		}
22548cfaec25Skettenis 	}
22558cfaec25Skettenis }
22568cfaec25Skettenis 
22578cfaec25Skettenis void
guest_prune_pcie(struct guest * guest,struct md_node * node,const char * path)22588cfaec25Skettenis guest_prune_pcie(struct guest *guest, struct md_node *node, const char *path)
22598cfaec25Skettenis {
22608cfaec25Skettenis 	struct md *md = guest->md;
22618cfaec25Skettenis 	struct md_node *node2;
22628cfaec25Skettenis 	struct md_prop *prop, *prop2;
22638cfaec25Skettenis 	uint64_t device_number;
22648cfaec25Skettenis 	char *path2;
22658cfaec25Skettenis 
22668cfaec25Skettenis 	TAILQ_FOREACH_SAFE(prop, &node->prop_list, link, prop2) {
22678cfaec25Skettenis 		if (prop->tag == MD_PROP_ARC &&
22688cfaec25Skettenis 		    strcmp(prop->name->str, "fwd") == 0) {
22698cfaec25Skettenis 			node2 = prop->d.arc.node;
22708cfaec25Skettenis 			if (strcmp(node2->name->str, "wart") == 0) {
22718cfaec25Skettenis 				md_delete_node(md, node2);
22728cfaec25Skettenis 				continue;
22738cfaec25Skettenis 			}
22748cfaec25Skettenis 			if (!md_get_prop_val(md, node2, "device-number",
22758cfaec25Skettenis 			    &device_number))
22768cfaec25Skettenis 				continue;
22778cfaec25Skettenis 			xasprintf(&path2, "%s/@%llx", path, device_number);
22788cfaec25Skettenis 			if (guest_match_path(guest, path2))
22798cfaec25Skettenis 				guest_prune_pcie(guest, node2, path2);
22808cfaec25Skettenis 			else
22818cfaec25Skettenis 				md_delete_node(md, node2);
22828cfaec25Skettenis 			free(path2);
22838cfaec25Skettenis 		}
22848cfaec25Skettenis 	}
22858cfaec25Skettenis }
22868cfaec25Skettenis 
22878cfaec25Skettenis void
guest_add_vpcie(struct guest * guest,uint64_t cfghandle)22888cfaec25Skettenis guest_add_vpcie(struct guest *guest, uint64_t cfghandle)
22898cfaec25Skettenis {
22908cfaec25Skettenis 	struct device *device, *phys_device = NULL;
22918cfaec25Skettenis 	uint64_t resource_id;
22928cfaec25Skettenis 
22938cfaec25Skettenis 	for (resource_id = 0; resource_id < max_devices; resource_id++) {
22948cfaec25Skettenis 		if (pcie_busses[resource_id] &&
22958cfaec25Skettenis 		    pcie_busses[resource_id]->cfghandle == cfghandle) {
22968cfaec25Skettenis 			phys_device = pcie_busses[resource_id];
22978cfaec25Skettenis 			break;
22988cfaec25Skettenis 		}
22998cfaec25Skettenis 	}
23008cfaec25Skettenis 	if (phys_device == NULL)
23018cfaec25Skettenis 		errx(1, "no matching physical device");
23028cfaec25Skettenis 
23038cfaec25Skettenis 	for (resource_id = 0; resource_id < max_devices; resource_id++) {
23048cfaec25Skettenis 		if (pcie_busses[resource_id] == NULL)
23058cfaec25Skettenis 			break;
23068cfaec25Skettenis 	}
23078cfaec25Skettenis 	if (resource_id >= max_devices)
23088cfaec25Skettenis 		errx(1, "no available resource_id");
23098cfaec25Skettenis 
23108cfaec25Skettenis 	device = xzalloc(sizeof(*device));
23118cfaec25Skettenis 	device->gid = guest->gid;
23128cfaec25Skettenis 	device->cfghandle = cfghandle;
23138cfaec25Skettenis 	device->resource_id = resource_id;
23148cfaec25Skettenis 	device->rcid = phys_device->rcid;
23158cfaec25Skettenis 	device->virtual = 1;
23168cfaec25Skettenis 	device->guest = guest;
23178cfaec25Skettenis 
23188cfaec25Skettenis 	device->num_msi_eqs = phys_device->msi_eqs_per_vpci;
23198cfaec25Skettenis 	device->num_msis = phys_device->msis_per_vpci;
23208cfaec25Skettenis 	phys_device->msi_base -= phys_device->msis_per_vpci;
23218cfaec25Skettenis 	device->msi_ranges[0] = phys_device->msi_base;
23228cfaec25Skettenis 	device->msi_ranges[1] = device->num_msis;
23238cfaec25Skettenis 
23248cfaec25Skettenis 	pcie_busses[resource_id] = device;
23258cfaec25Skettenis 	TAILQ_INSERT_TAIL(&guest->device_list, device, link);
23268cfaec25Skettenis }
23278cfaec25Skettenis 
23288cfaec25Skettenis void
guest_fixup_phys_io(struct guest * guest)23298cfaec25Skettenis guest_fixup_phys_io(struct guest *guest)
23308cfaec25Skettenis {
23318cfaec25Skettenis 	struct md *md = guest->md;
23328cfaec25Skettenis 	struct md_node *node, *node2;
23338cfaec25Skettenis 	struct md_prop *prop, *prop2;
23348cfaec25Skettenis 	struct device *device;
23358cfaec25Skettenis 	uint64_t cfg_handle;
23368cfaec25Skettenis 	uint64_t mapping[3];
23378cfaec25Skettenis 	const void *buf;
23388cfaec25Skettenis 	size_t len;
23398cfaec25Skettenis 
23408cfaec25Skettenis 	if (!directio_capability)
23418cfaec25Skettenis 		return;
23428cfaec25Skettenis 
23438cfaec25Skettenis 	node = md_find_node(guest->md, "phys_io");
23448cfaec25Skettenis 	TAILQ_FOREACH_SAFE(prop, &node->prop_list, link, prop2) {
23458cfaec25Skettenis 		if (prop->tag == MD_PROP_ARC &&
23468cfaec25Skettenis 		    strcmp(prop->name->str, "fwd") == 0) {
23478cfaec25Skettenis 			node2 = prop->d.arc.node;
23488cfaec25Skettenis 
23498cfaec25Skettenis 			if (!md_get_prop_val(md, node2, "cfg-handle",
23508cfaec25Skettenis 			    &cfg_handle))
23518cfaec25Skettenis 				continue;
23528cfaec25Skettenis 
23538cfaec25Skettenis 			TAILQ_FOREACH(device, &guest->device_list, link) {
23548cfaec25Skettenis 				if (device->cfghandle == cfg_handle)
23558cfaec25Skettenis 					break;
23568cfaec25Skettenis 			}
23578cfaec25Skettenis 			if (device == NULL)
23588cfaec25Skettenis 				continue;
23598cfaec25Skettenis 
23608cfaec25Skettenis 			md_set_prop_val(md, node2, "#msi-eqs",
23618cfaec25Skettenis 			    device->num_msi_eqs);
23628cfaec25Skettenis 			md_set_prop_val(md, node2, "#msi",
23638cfaec25Skettenis 			    device->num_msis);
23648cfaec25Skettenis 			md_set_prop_data(md, node2, "msi-ranges",
23658cfaec25Skettenis 			    (void *)device->msi_ranges,
23668cfaec25Skettenis 			    sizeof(device->msi_ranges));
23678cfaec25Skettenis 
23688cfaec25Skettenis 			md_get_prop_data(md, node2, "msi-eq-to-devino",
23698cfaec25Skettenis 			    &buf, &len);
23708cfaec25Skettenis 			memcpy(mapping, buf, sizeof(mapping));
23718cfaec25Skettenis 			mapping[1] = device->num_msi_eqs;
23728cfaec25Skettenis 			md_set_prop_data(md, node2, "msi-eq-to-devino",
23738cfaec25Skettenis 			    (void *)mapping, sizeof(mapping));
23748cfaec25Skettenis 		}
23758cfaec25Skettenis 	}
23768cfaec25Skettenis }
23778cfaec25Skettenis 
237897d8cafcSkettenis struct guest *
guest_lookup(const char * name)237997d8cafcSkettenis guest_lookup(const char *name)
238097d8cafcSkettenis {
238197d8cafcSkettenis 	uint64_t resource_id;
238297d8cafcSkettenis 
238397d8cafcSkettenis 	for (resource_id = 0; resource_id < max_guests; resource_id++) {
238497d8cafcSkettenis 		if (guests[resource_id] &&
238597d8cafcSkettenis 		    strcmp(guests[resource_id]->name, name) == 0)
238697d8cafcSkettenis 			return guests[resource_id];
238797d8cafcSkettenis 	}
238897d8cafcSkettenis 
238997d8cafcSkettenis 	return NULL;
239097d8cafcSkettenis }
239197d8cafcSkettenis 
239297d8cafcSkettenis void
guest_delete_virtual_device_port(struct guest * guest,struct md_node * port)23933bafda9bSkettenis guest_delete_virtual_device_port(struct guest *guest, struct md_node *port)
23943bafda9bSkettenis {
23953bafda9bSkettenis 	struct md *md = guest->md;
23963bafda9bSkettenis 	struct md_node *node;
23973bafda9bSkettenis 	struct md_prop *prop;
23983bafda9bSkettenis 
23993bafda9bSkettenis 	TAILQ_FOREACH(node, &md->node_list, link) {
24003bafda9bSkettenis 		if (strcmp(node->name->str, "virtual-device-port") != 0)
24013bafda9bSkettenis 			continue;
24023bafda9bSkettenis 		TAILQ_FOREACH(prop, &node->prop_list, link) {
24033bafda9bSkettenis 			if (prop->tag == MD_PROP_ARC &&
24043bafda9bSkettenis 			    prop->d.arc.node == port) {
24053bafda9bSkettenis 				md_delete_node(md, node);
24063bafda9bSkettenis 				return;
24073bafda9bSkettenis 			}
24083bafda9bSkettenis 		}
24093bafda9bSkettenis 	}
24103bafda9bSkettenis }
24113bafda9bSkettenis 
24123bafda9bSkettenis void
guest_delete_endpoint(struct guest * guest,struct ldc_endpoint * endpoint)24133bafda9bSkettenis guest_delete_endpoint(struct guest *guest, struct ldc_endpoint *endpoint)
24143bafda9bSkettenis {
24153bafda9bSkettenis 	struct md *md = guest->md;
24163bafda9bSkettenis 	struct md_node *node, *node2;
24173bafda9bSkettenis 	struct md_prop *prop;
24183bafda9bSkettenis 	uint64_t id, resource_id;
24193bafda9bSkettenis 
24203bafda9bSkettenis 	node = md_find_node(md, "channel-endpoints");
24213bafda9bSkettenis 	TAILQ_FOREACH(prop, &node->prop_list, link) {
24223bafda9bSkettenis 		if (prop->tag == MD_PROP_ARC &&
24233bafda9bSkettenis 		    strcmp(prop->name->str, "fwd") == 0) {
24243bafda9bSkettenis 			node2 = prop->d.arc.node;
24253bafda9bSkettenis 			if (!md_get_prop_val(hvmd, node2, "id", &id))
24263bafda9bSkettenis 				continue;
24273bafda9bSkettenis 			if (id == endpoint->channel) {
24283bafda9bSkettenis 				guest_delete_virtual_device_port(guest, node2);
24293bafda9bSkettenis 				md_delete_node(md, node2);
24303bafda9bSkettenis 				break;
24313bafda9bSkettenis 			}
24323bafda9bSkettenis 		}
24333bafda9bSkettenis 	}
24343bafda9bSkettenis 
24353bafda9bSkettenis 	TAILQ_REMOVE(&guest->endpoint_list, endpoint, link);
24363bafda9bSkettenis 	ldc_endpoints[endpoint->resource_id] = NULL;
24373bafda9bSkettenis 
24383bafda9bSkettenis 	/* Delete peer as well. */
24393bafda9bSkettenis 	for (resource_id = 0; resource_id < max_guest_ldcs; resource_id++) {
24403bafda9bSkettenis 		struct ldc_endpoint *peer = ldc_endpoints[resource_id];
24413bafda9bSkettenis 
24423bafda9bSkettenis 		if (peer && peer->target_type == LDC_GUEST &&
24433bafda9bSkettenis 		    peer->target_channel == endpoint->channel &&
24443bafda9bSkettenis 		    peer->channel == endpoint->target_channel &&
24453bafda9bSkettenis 		    peer->target_guest == guest->gid)
24463bafda9bSkettenis 			guest_delete_endpoint(peer->guest, peer);
24473bafda9bSkettenis 	}
24483bafda9bSkettenis 
24493bafda9bSkettenis 	free(endpoint);
24503bafda9bSkettenis }
24513bafda9bSkettenis 
24523bafda9bSkettenis void
guest_delete(struct guest * guest)2453644bca12Skettenis guest_delete(struct guest *guest)
2454644bca12Skettenis {
2455644bca12Skettenis 	struct cpu *cpu, *cpu2;
2456644bca12Skettenis 	struct mblock *mblock, *mblock2;
2457644bca12Skettenis 	struct ldc_endpoint *endpoint, *endpoint2;
2458644bca12Skettenis 
2459644bca12Skettenis 	consoles[guest->console->resource_id] = NULL;
2460644bca12Skettenis 	free(guest->console);
2461644bca12Skettenis 
2462644bca12Skettenis 	TAILQ_FOREACH_SAFE(cpu, &guest->cpu_list, link, cpu2) {
2463644bca12Skettenis 		TAILQ_REMOVE(&guest->cpu_list, cpu, link);
2464644bca12Skettenis 		cpus[cpu->resource_id] = NULL;
2465644bca12Skettenis 		pri_free_cpu(cpu);
2466644bca12Skettenis 	}
2467644bca12Skettenis 
2468644bca12Skettenis 	TAILQ_FOREACH_SAFE(mblock, &guest->mblock_list, link, mblock2) {
2469644bca12Skettenis 		TAILQ_REMOVE(&guest->mblock_list, mblock, link);
2470644bca12Skettenis 		mblocks[mblock->resource_id] = NULL;
2471644bca12Skettenis 		free(mblock);
2472644bca12Skettenis 	}
2473644bca12Skettenis 
24743bafda9bSkettenis 	TAILQ_FOREACH_SAFE(endpoint, &guest->endpoint_list, link, endpoint2)
24753bafda9bSkettenis 		guest_delete_endpoint(guest, endpoint);
2476644bca12Skettenis 
2477644bca12Skettenis 	hvmd_free_frag(guest->mdpa);
2478644bca12Skettenis 
2479644bca12Skettenis 	guests[guest->resource_id] = NULL;
2480644bca12Skettenis 	free(guest);
2481644bca12Skettenis }
2482644bca12Skettenis 
2483644bca12Skettenis void
guest_delete_cpu(struct guest * guest,uint64_t vid)248497d8cafcSkettenis guest_delete_cpu(struct guest *guest, uint64_t vid)
248597d8cafcSkettenis {
248697d8cafcSkettenis 	struct cpu *cpu;
248797d8cafcSkettenis 
248897d8cafcSkettenis 	TAILQ_FOREACH(cpu, &guest->cpu_list, link) {
248997d8cafcSkettenis 		if (cpu->vid == vid) {
249097d8cafcSkettenis 			TAILQ_REMOVE(&guest->cpu_list, cpu, link);
249197d8cafcSkettenis 			cpus[cpu->resource_id] = NULL;
249297d8cafcSkettenis 			pri_free_cpu(cpu);
249397d8cafcSkettenis 			return;
249497d8cafcSkettenis 		}
249597d8cafcSkettenis 	}
249697d8cafcSkettenis }
249797d8cafcSkettenis 
249897d8cafcSkettenis void
guest_add_cpu(struct guest * guest,uint64_t stride)249959eb6c85Skettenis guest_add_cpu(struct guest *guest, uint64_t stride)
250097d8cafcSkettenis {
250197d8cafcSkettenis 	struct cpu *cpu;
250297d8cafcSkettenis 
250397d8cafcSkettenis 	cpu = pri_alloc_cpu(-1);
250497d8cafcSkettenis 
250559eb6c85Skettenis 	/*
250659eb6c85Skettenis 	 * Allocate (but don't assign) additional virtual CPUs if the
250759eb6c85Skettenis 	 * specified stride is bigger than one.
250859eb6c85Skettenis 	 */
250959eb6c85Skettenis 	while (stride-- > 1)
251059eb6c85Skettenis 		pri_alloc_cpu(-1);
251159eb6c85Skettenis 
251297d8cafcSkettenis 	if (cpu->resource_id == -1) {
251397d8cafcSkettenis 		uint64_t resource_id;
251497d8cafcSkettenis 
251597d8cafcSkettenis 		for (resource_id = 0; resource_id < max_cpus; resource_id++)
251697d8cafcSkettenis 			if (cpus[resource_id] == NULL)
251797d8cafcSkettenis 				break;
251897d8cafcSkettenis 		assert(resource_id < max_cpus);
251997d8cafcSkettenis 		cpu->resource_id = resource_id;
252097d8cafcSkettenis 	}
252197d8cafcSkettenis 	cpus[cpu->resource_id] = cpu;
252297d8cafcSkettenis 
252397d8cafcSkettenis 	cpu->vid = guest->cpu_vid++;
252497d8cafcSkettenis 	cpu->gid = guest->gid;
252597d8cafcSkettenis 	cpu->partid = 1;
252697d8cafcSkettenis 
252797d8cafcSkettenis 	TAILQ_INSERT_TAIL(&guest->cpu_list, cpu, link);
252897d8cafcSkettenis 	cpu->guest = guest;
252997d8cafcSkettenis }
253097d8cafcSkettenis 
253197d8cafcSkettenis void
guest_delete_memory(struct guest * guest)2532ecf7be60Skettenis guest_delete_memory(struct guest *guest)
253397d8cafcSkettenis {
2534ecf7be60Skettenis 	struct mblock *mblock, *tmp;
253597d8cafcSkettenis 
2536ecf7be60Skettenis 	TAILQ_FOREACH_SAFE(mblock, &guest->mblock_list, link, tmp) {
2537ecf7be60Skettenis 		if (mblock->resource_id != -1)
2538ecf7be60Skettenis 			mblocks[mblock->resource_id] = NULL;
2539ecf7be60Skettenis 		TAILQ_REMOVE(&guest->mblock_list, mblock, link);
2540ecf7be60Skettenis 		free(mblock);
254197d8cafcSkettenis 	}
254297d8cafcSkettenis }
254397d8cafcSkettenis 
254497d8cafcSkettenis void
guest_add_memory(struct guest * guest,uint64_t base,uint64_t size)254597d8cafcSkettenis guest_add_memory(struct guest *guest, uint64_t base, uint64_t size)
254697d8cafcSkettenis {
254797d8cafcSkettenis 	struct mblock *mblock;
254897d8cafcSkettenis 	uint64_t resource_id;
254997d8cafcSkettenis 
2550ecf7be60Skettenis 	mblock = pri_alloc_memory(base, size);
25512151b4ddSkettenis 	if (mblock == NULL)
25522151b4ddSkettenis 		errx(1, "unable to allocate guest memory");
255397d8cafcSkettenis 	for (resource_id = 0; resource_id < max_cpus; resource_id++)
255497d8cafcSkettenis 		if (mblocks[resource_id] == NULL)
255597d8cafcSkettenis 			break;
255697d8cafcSkettenis 	assert(resource_id < max_mblocks);
255797d8cafcSkettenis 	mblock->resource_id = resource_id;
255897d8cafcSkettenis 	mblocks[resource_id] = mblock;
255997d8cafcSkettenis 
2560ecf7be60Skettenis 	mblock->realbase = mblock->membase & (max_page_size - 1);
256197d8cafcSkettenis 	if (mblock->realbase == 0)
2562ecf7be60Skettenis 		mblock->realbase = max_page_size;
256397d8cafcSkettenis 
256497d8cafcSkettenis 	TAILQ_INSERT_TAIL(&guest->mblock_list, mblock, link);
256597d8cafcSkettenis 	mblock->guest = guest;
256697d8cafcSkettenis }
256797d8cafcSkettenis 
256897d8cafcSkettenis void
guest_add_vdisk(struct guest * guest,uint64_t id,const char * path,const char * user_devalias)2569693255e2Skn guest_add_vdisk(struct guest *guest, uint64_t id, const char *path,
2570693255e2Skn     const char *user_devalias)
257197d8cafcSkettenis {
257297d8cafcSkettenis 	struct guest *primary;
257397d8cafcSkettenis 	struct ldc_channel *lc;
257497d8cafcSkettenis 	char *devalias;
257597d8cafcSkettenis 	char *devpath;
257697d8cafcSkettenis 
257797d8cafcSkettenis 	primary = guest_lookup("primary");
257897d8cafcSkettenis 
2579e099dd74Skettenis 	lc = hvmd_add_vio(guest);
258097d8cafcSkettenis 	guest_add_vds_port(primary, NULL, path, id,
258197d8cafcSkettenis 	    lc->server_endpoint->channel);
258297d8cafcSkettenis 	guest_add_vdc_port(guest, NULL, id, 0, lc->client_endpoint->channel);
258397d8cafcSkettenis 
258497d8cafcSkettenis 	xasprintf(&devalias, "disk%d", id);
258597d8cafcSkettenis 	xasprintf(&devpath,
258697d8cafcSkettenis 	    "/virtual-devices@100/channel-devices@200/disk@%d", id);
258797d8cafcSkettenis 	if (id == 0)
258897d8cafcSkettenis 		guest_add_devalias(guest, "disk", devpath);
258997d8cafcSkettenis 	guest_add_devalias(guest, devalias, devpath);
2590693255e2Skn 	if (user_devalias != NULL)
2591693255e2Skn 		guest_add_devalias(guest, user_devalias, devpath);
259297d8cafcSkettenis 	free(devalias);
259397d8cafcSkettenis 	free(devpath);
259497d8cafcSkettenis }
259597d8cafcSkettenis 
259697d8cafcSkettenis void
guest_add_vnetwork(struct guest * guest,uint64_t id,uint64_t mac_addr,uint64_t mtu,const char * user_devalias)259797d8cafcSkettenis guest_add_vnetwork(struct guest *guest, uint64_t id, uint64_t mac_addr,
2598a3b2112fSkn     uint64_t mtu, const char *user_devalias)
259997d8cafcSkettenis {
260097d8cafcSkettenis 	struct guest *primary;
260197d8cafcSkettenis 	struct ldc_channel *lc;
260297d8cafcSkettenis 	char *devalias;
260397d8cafcSkettenis 	char *devpath;
260492aafd32Skettenis 	struct md_node *node;
2605b6c9b98cSkettenis 	uint64_t remote_mac_addr = -1;
260697d8cafcSkettenis 
260797d8cafcSkettenis 	primary = guest_lookup("primary");
260897d8cafcSkettenis 
2609e099dd74Skettenis 	lc = hvmd_add_vio(guest);
261097d8cafcSkettenis 	guest_add_vsw_port(primary, NULL, id, lc->server_endpoint->channel);
261192aafd32Skettenis 	node = guest_find_vsw(primary);
2612b6c9b98cSkettenis 	md_get_prop_val(primary->md, node, "local-mac-address", &remote_mac_addr);
261392aafd32Skettenis 	guest_add_vnet_port(guest, NULL, mac_addr, remote_mac_addr, mtu, id, 0,
261497d8cafcSkettenis 	    lc->client_endpoint->channel);
261597d8cafcSkettenis 
261697d8cafcSkettenis 	xasprintf(&devalias, "net%d", id);
261797d8cafcSkettenis 	xasprintf(&devpath,
261897d8cafcSkettenis 	    "/virtual-devices@100/channel-devices@200/network@%d", id);
261997d8cafcSkettenis 	if (id == 0)
262097d8cafcSkettenis 		guest_add_devalias(guest, "net", devpath);
262197d8cafcSkettenis 	guest_add_devalias(guest, devalias, devpath);
2622a3b2112fSkn 	if (user_devalias != NULL)
2623a3b2112fSkn 		guest_add_devalias(guest, user_devalias, devpath);
262497d8cafcSkettenis 	free(devalias);
262597d8cafcSkettenis 	free(devpath);
262697d8cafcSkettenis }
262797d8cafcSkettenis 
26288e765095Skettenis void
guest_add_variable(struct guest * guest,const char * name,const char * str)26298e765095Skettenis guest_add_variable(struct guest *guest, const char *name, const char *str)
26308e765095Skettenis {
26318e765095Skettenis 	struct md *md = guest->md;
26328e765095Skettenis 	struct md_node *parent;
26338e765095Skettenis 	struct md_node *node;
26348e765095Skettenis 
26358e765095Skettenis 	node = md_find_node(md, "variables");
26368e765095Skettenis 	if (node == NULL) {
26378e765095Skettenis 		parent = md_find_node(md, "root");
26388e765095Skettenis 		assert(parent);
26398e765095Skettenis 
26408e765095Skettenis 		node = md_add_node(md, "variables");
26418e765095Skettenis 		md_link_node(md, parent, node);
26428e765095Skettenis 	}
26438e765095Skettenis 
26448e765095Skettenis 	md_add_prop_str(md, node, name, str);
26458e765095Skettenis }
26468e765095Skettenis 
26478cfaec25Skettenis void
guest_add_iodev(struct guest * guest,const char * dev)2648*ee96180dSkn guest_add_iodev(struct guest *guest, const char *dev)
26498cfaec25Skettenis {
26508cfaec25Skettenis 	struct component *component;
26518cfaec25Skettenis 	struct subdevice *subdevice;
26528cfaec25Skettenis 
26538cfaec25Skettenis 	if (!directio_capability)
26548cfaec25Skettenis 		errx(1, "direct I/O not supported by hypervisor");
26558cfaec25Skettenis 
26568cfaec25Skettenis 	TAILQ_FOREACH(component, &components, link) {
2657*ee96180dSkn 		if (strcmp(component->nac, dev) == 0 ||
2658*ee96180dSkn 		    strcmp(component->path, dev) == 0)
26598cfaec25Skettenis 			break;
26608cfaec25Skettenis 	}
26618cfaec25Skettenis 
26628cfaec25Skettenis 	if (component == NULL)
2663*ee96180dSkn 		errx(1, "incorrect device path %s", dev);
26648cfaec25Skettenis 	if (component->assigned)
2665*ee96180dSkn 		errx(1, "device path %s already assigned", dev);
26668cfaec25Skettenis 
26678cfaec25Skettenis 	subdevice = xzalloc(sizeof(*subdevice));
2668*ee96180dSkn 	subdevice->path = component->path;
26698cfaec25Skettenis 	TAILQ_INSERT_TAIL(&guest->subdevice_list, subdevice, link);
26708cfaec25Skettenis 	component->assigned = 1;
26718cfaec25Skettenis }
26728cfaec25Skettenis 
267397d8cafcSkettenis struct cpu *
guest_find_cpu(struct guest * guest,uint64_t pid)267497d8cafcSkettenis guest_find_cpu(struct guest *guest, uint64_t pid)
267597d8cafcSkettenis {
267697d8cafcSkettenis 	struct cpu *cpu;
267797d8cafcSkettenis 
267897d8cafcSkettenis 	TAILQ_FOREACH(cpu, &guest->cpu_list, link)
267997d8cafcSkettenis 		if (cpu->pid == pid)
268097d8cafcSkettenis 			return cpu;
268197d8cafcSkettenis 
268297d8cafcSkettenis 	return NULL;
268397d8cafcSkettenis }
268497d8cafcSkettenis 
268597d8cafcSkettenis void
guest_finalize(struct guest * guest)268697d8cafcSkettenis guest_finalize(struct guest *guest)
268797d8cafcSkettenis {
268897d8cafcSkettenis 	struct md *md = guest->md;
268997d8cafcSkettenis 	struct md_node *node, *node2;
2690aa782199Skettenis 	struct md_prop *prop, *prop2;
269197d8cafcSkettenis 	struct mblock *mblock;
269297d8cafcSkettenis 	struct md_node *parent;
269397d8cafcSkettenis 	struct md_node *child;
269497d8cafcSkettenis 	struct cpu *cpu;
269597d8cafcSkettenis 	uint64_t pid;
2696764a0ebaSkettenis 	const char *name;
269797d8cafcSkettenis 	char *path;
269897d8cafcSkettenis 
269997d8cafcSkettenis 	node = md_find_node(md, "cpus");
2700aa782199Skettenis 	TAILQ_FOREACH_SAFE(prop, &node->prop_list, link, prop2) {
270197d8cafcSkettenis 		if (prop->tag == MD_PROP_ARC &&
270297d8cafcSkettenis 		    strcmp(prop->name->str, "fwd") == 0) {
270397d8cafcSkettenis 			node2 = prop->d.arc.node;
270497d8cafcSkettenis 			if (!md_get_prop_val(md, node2, "pid", &pid))
27059e5c6997Skettenis 				if (!md_get_prop_val(md, node2, "id", &pid))
270697d8cafcSkettenis 					continue;
270797d8cafcSkettenis 			cpu = guest_find_cpu(guest, pid);
270897d8cafcSkettenis 			if (cpu == NULL) {
270997d8cafcSkettenis 				md_delete_node(md, node2);
271097d8cafcSkettenis 				continue;
271197d8cafcSkettenis 			}
271297d8cafcSkettenis 			md_set_prop_val(md, node2, "id", cpu->vid);
271397d8cafcSkettenis 		}
271497d8cafcSkettenis 	}
2715764a0ebaSkettenis 
2716764a0ebaSkettenis 	/*
2717764a0ebaSkettenis 	 * We don't support crypto units yet, so delete any "ncp" and
2718764a0ebaSkettenis 	 * "n2cp" nodes.  If we don't, Solaris whines about not being
2719764a0ebaSkettenis 	 * able to configure crypto work queues.
2720764a0ebaSkettenis 	 */
2721764a0ebaSkettenis 	node = md_find_node(md, "virtual-devices");
2722aa782199Skettenis 	TAILQ_FOREACH_SAFE(prop, &node->prop_list, link, prop2) {
2723764a0ebaSkettenis 		if (prop->tag == MD_PROP_ARC &&
2724764a0ebaSkettenis 		    strcmp(prop->name->str, "fwd") == 0) {
2725764a0ebaSkettenis 			node2 = prop->d.arc.node;
2726764a0ebaSkettenis 			if (!md_get_prop_str(md, node2, "name", &name))
2727764a0ebaSkettenis 				continue;
2728764a0ebaSkettenis 			if (strcmp(name, "ncp") == 0)
2729764a0ebaSkettenis 				md_delete_node(md, node2);
2730764a0ebaSkettenis 			if (strcmp(name, "n2cp") == 0)
2731764a0ebaSkettenis 				md_delete_node(md, node2);
2732764a0ebaSkettenis 		}
2733764a0ebaSkettenis 	}
2734764a0ebaSkettenis 
273597d8cafcSkettenis 	node = md_find_node(md, "memory");
2736d27a0d69Skettenis 	TAILQ_FOREACH_SAFE(prop, &node->prop_list, link, prop2) {
2737d27a0d69Skettenis 		if (prop->tag == MD_PROP_ARC &&
2738d27a0d69Skettenis 		    strcmp(prop->name->str, "fwd") == 0) {
2739d27a0d69Skettenis 			node2 = prop->d.arc.node;
2740d27a0d69Skettenis 			md_delete_node(md, node2);
2741d27a0d69Skettenis 		}
2742d27a0d69Skettenis 	}
2743d27a0d69Skettenis 
27448cfaec25Skettenis 	if (strcmp(guest->name, "primary") != 0)
27458cfaec25Skettenis 		guest_prune_phys_io(guest);
27468cfaec25Skettenis 	guest_fixup_phys_io(guest);
27478cfaec25Skettenis 
274897d8cafcSkettenis 	md_collect_garbage(md);
274997d8cafcSkettenis 
2750d27a0d69Skettenis 	parent = md_find_node(md, "memory");
275197d8cafcSkettenis 	TAILQ_FOREACH(mblock, &guest->mblock_list, link) {
275297d8cafcSkettenis 		child = md_add_node(md, "mblock");
275397d8cafcSkettenis 		md_add_prop_val(md, child, "base", mblock->realbase);
275497d8cafcSkettenis 		md_add_prop_val(md, child, "size", mblock->memsize);
2755d27a0d69Skettenis 		md_link_node(md, parent, child);
275697d8cafcSkettenis 	}
275797d8cafcSkettenis 
275897d8cafcSkettenis 	xasprintf(&path, "%s.md", guest->name);
275997d8cafcSkettenis 	md_write(guest->md, path);
276097d8cafcSkettenis 	free(path);
276197d8cafcSkettenis }
276297d8cafcSkettenis 
276397d8cafcSkettenis struct guest *
primary_init(void)276497d8cafcSkettenis primary_init(void)
276597d8cafcSkettenis {
276697d8cafcSkettenis 	struct guest *guest;
276797d8cafcSkettenis 
276897d8cafcSkettenis 	guest = guest_lookup("primary");
276997d8cafcSkettenis 	assert(guest);
277097d8cafcSkettenis 
277197d8cafcSkettenis 	guest_set_domaining_enabled(guest);
277297d8cafcSkettenis 
277397d8cafcSkettenis 	return guest;
277497d8cafcSkettenis }
277597d8cafcSkettenis 
277697d8cafcSkettenis void
build_config(const char * filename,int noaction)277799a0bfacSkn build_config(const char *filename, int noaction)
277897d8cafcSkettenis {
277997d8cafcSkettenis 	struct guest *primary;
278097d8cafcSkettenis 	struct guest *guest;
2781644bca12Skettenis 	struct ldc_endpoint *endpoint;
27828cfaec25Skettenis 	struct component *component;
2783644bca12Skettenis 	uint64_t resource_id;
278497d8cafcSkettenis 	int i;
278597d8cafcSkettenis 
278697d8cafcSkettenis 	struct ldom_config conf;
278797d8cafcSkettenis 	struct domain *domain;
278897d8cafcSkettenis 	struct vdisk *vdisk;
278997d8cafcSkettenis 	struct vnet *vnet;
27908e765095Skettenis 	struct var *var;
27918cfaec25Skettenis 	struct iodev *iodev;
27925899a108Skn 	uint64_t num_cpus = 0, primary_num_cpus = 0;
279359eb6c85Skettenis 	uint64_t primary_stride = 1;
27945899a108Skn 	uint64_t memory = 0, primary_memory = 0;
279597d8cafcSkettenis 
279697d8cafcSkettenis 	SIMPLEQ_INIT(&conf.domain_list);
279732cf627cSotto 	if (parse_config(filename, &conf) < 0)
279832cf627cSotto 		exit(1);
27993247d7f3Skn 
28003247d7f3Skn 	pri = md_read("pri");
28013247d7f3Skn 	if (pri == NULL)
28023247d7f3Skn 		err(1, "unable to get PRI");
28033247d7f3Skn 	hvmd = md_read("hv.md");
28043247d7f3Skn 	if (hvmd == NULL)
28053247d7f3Skn 		err(1, "unable to get Hypervisor MD");
28063247d7f3Skn 
28073247d7f3Skn 	pri_init(pri);
28083247d7f3Skn 	pri_alloc_memory(hv_membase, hv_memsize);
280997d8cafcSkettenis 
2810ecf7be60Skettenis 	SIMPLEQ_FOREACH(domain, &conf.domain_list, entry) {
28115d201785Skettenis 		if (strcmp(domain->name, "primary") == 0) {
28125d201785Skettenis 			primary_num_cpus = domain->vcpu;
281359eb6c85Skettenis 			primary_stride = domain->vcpu_stride;
28145d201785Skettenis 			primary_memory = domain->memory;
28155d201785Skettenis 		}
281659eb6c85Skettenis 		num_cpus += (domain->vcpu * domain->vcpu_stride);
2817ecf7be60Skettenis 		memory += domain->memory;
2818ecf7be60Skettenis 	}
28195d201785Skettenis 	if (primary_num_cpus == 0 && total_cpus > num_cpus)
28205d201785Skettenis 		primary_num_cpus = total_cpus - num_cpus;
28215d201785Skettenis 	if (primary_memory == 0 && total_memory > memory)
28225d201785Skettenis 		primary_memory = total_memory - memory;
28235d201785Skettenis 	if (num_cpus > total_cpus || primary_num_cpus == 0)
2824ecf7be60Skettenis 		errx(1, "not enough VCPU resources available");
28255d201785Skettenis 	if (memory > total_memory || primary_memory == 0)
2826ecf7be60Skettenis 		errx(1, "not enough memory available");
2827ecf7be60Skettenis 
2828b5073d68Skn 	if (noaction)
2829b5073d68Skn 		exit(0);
2830b5073d68Skn 
2831ecf7be60Skettenis 	hvmd_init(hvmd);
283297d8cafcSkettenis 	primary = primary_init();
2833ecf7be60Skettenis 
2834644bca12Skettenis 	for (resource_id = 0; resource_id <max_guests; resource_id++)
2835644bca12Skettenis 		if (guests[resource_id] &&
2836644bca12Skettenis 		    strcmp(guests[resource_id]->name, "primary") != 0)
2837644bca12Skettenis 			guest_delete(guests[resource_id]);
2838644bca12Skettenis 
2839644bca12Skettenis 	primary->endpoint_id = 0;
2840644bca12Skettenis 	TAILQ_FOREACH(endpoint, &primary->endpoint_list, link) {
2841644bca12Skettenis 		if (endpoint->channel >= primary->endpoint_id)
2842644bca12Skettenis 			primary->endpoint_id = endpoint->channel + 1;
2843644bca12Skettenis 	}
2844644bca12Skettenis 
28452f008923Skettenis 	for (i = 0; i < max_cpus; i++)
284697d8cafcSkettenis 		guest_delete_cpu(primary, i);
28472f008923Skettenis 	for (i = 0; i < primary_num_cpus; i++)
284859eb6c85Skettenis 		guest_add_cpu(primary, primary_stride);
2849ecf7be60Skettenis 	guest_delete_memory(primary);
28505d201785Skettenis 	guest_add_memory(primary, -1, primary_memory);
2851ecf7be60Skettenis 
285297d8cafcSkettenis 	SIMPLEQ_FOREACH(domain, &conf.domain_list, entry) {
28538e765095Skettenis 		if (strcmp(domain->name, "primary") != 0)
28548e765095Skettenis 			continue;
28558e765095Skettenis 		SIMPLEQ_FOREACH(var, &domain->var_list, entry)
28568e765095Skettenis 			guest_add_variable(primary, var->name, var->str);
28578e765095Skettenis 	}
28588e765095Skettenis 
28598e765095Skettenis 	SIMPLEQ_FOREACH(domain, &conf.domain_list, entry) {
28605d201785Skettenis 		if (strcmp(domain->name, "primary") == 0)
28615d201785Skettenis 			continue;
286297d8cafcSkettenis 		guest = guest_create(domain->name);
286397d8cafcSkettenis 		for (i = 0; i < domain->vcpu; i++)
286459eb6c85Skettenis 			guest_add_cpu(guest, domain->vcpu_stride);
2865ecf7be60Skettenis 		guest_add_memory(guest, -1, domain->memory);
286697d8cafcSkettenis 		i = 0;
286797d8cafcSkettenis 		SIMPLEQ_FOREACH(vdisk, &domain->vdisk_list, entry)
2868693255e2Skn 			guest_add_vdisk(guest, i++, vdisk->path,
2869693255e2Skn 			    vdisk->devalias);
287097d8cafcSkettenis 		i = 0;
287197d8cafcSkettenis 		SIMPLEQ_FOREACH(vnet, &domain->vnet_list, entry)
287297d8cafcSkettenis 			guest_add_vnetwork(guest, i++, vnet->mac_addr,
2873a3b2112fSkn 			    vnet->mtu, vnet->devalias);
28748e765095Skettenis 		SIMPLEQ_FOREACH(var, &domain->var_list, entry)
28758e765095Skettenis 			guest_add_variable(guest, var->name, var->str);
28768cfaec25Skettenis 		SIMPLEQ_FOREACH(iodev, &domain->iodev_list, entry)
2877*ee96180dSkn 			guest_add_iodev(guest, iodev->dev);
287897d8cafcSkettenis 
287997d8cafcSkettenis 		guest_finalize(guest);
288097d8cafcSkettenis 	}
288197d8cafcSkettenis 
28828cfaec25Skettenis 	TAILQ_FOREACH(component, &components, link) {
28838cfaec25Skettenis 		if (component->assigned)
28848cfaec25Skettenis 			continue;
28858cfaec25Skettenis 		guest_add_iodev(primary, component->path);
28868cfaec25Skettenis 	}
28878cfaec25Skettenis 
288897d8cafcSkettenis 	guest_finalize(primary);
2889e099dd74Skettenis 	hvmd_finalize();
289097d8cafcSkettenis }
2891b300726bSkn 
2892b300726bSkn void
list_components(void)2893b300726bSkn list_components(void)
2894b300726bSkn {
2895b300726bSkn 	struct component *component;
2896b300726bSkn 
2897b300726bSkn 	pri = md_read("pri");
2898b300726bSkn 	if (pri == NULL)
2899b300726bSkn 		err(1, "unable to get PRI");
2900b300726bSkn 
29016b2c09b1Skn 	pri_init_components(pri);
2902b300726bSkn 
2903fea9819cSkn 	printf("%-16s %s\n", "PATH", "NAME");
2904b300726bSkn 	TAILQ_FOREACH(component, &components, link) {
2905fea9819cSkn 		printf("%-16s %s\n", component->path, component->nac);
2906b300726bSkn 	}
2907b300726bSkn }
2908