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