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