1 /* $OpenBSD: config.c,v 1.42 2021/01/31 05:14:24 deraadt 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 * 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 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 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 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 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 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 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 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 * 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 344 pri_free_cpu(struct cpu *cpu) 345 { 346 TAILQ_INSERT_TAIL(&free_cpus, cpu, link); 347 } 348 349 void 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 * 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 * 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 * 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 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 * 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 * 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 * 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 * 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 * 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 * 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 * 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 * 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 * 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 * 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 * 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 * 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 * 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 * 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 * 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 * 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 * 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 * 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 * 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 * 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 * 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 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 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 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 * 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 * 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 * 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 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 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 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 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 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 * 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 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 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 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 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 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 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 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 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 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 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 2648 guest_add_iodev(struct guest *guest, const char *path) 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->path, path) == 0) 2658 break; 2659 } 2660 2661 if (component == NULL) 2662 errx(1, "incorrect device path %s", path); 2663 if (component->assigned) 2664 errx(1, "device path %s already assigned", path); 2665 2666 subdevice = xzalloc(sizeof(*subdevice)); 2667 subdevice->path = path; 2668 TAILQ_INSERT_TAIL(&guest->subdevice_list, subdevice, link); 2669 component->assigned = 1; 2670 } 2671 2672 struct cpu * 2673 guest_find_cpu(struct guest *guest, uint64_t pid) 2674 { 2675 struct cpu *cpu; 2676 2677 TAILQ_FOREACH(cpu, &guest->cpu_list, link) 2678 if (cpu->pid == pid) 2679 return cpu; 2680 2681 return NULL; 2682 } 2683 2684 void 2685 guest_finalize(struct guest *guest) 2686 { 2687 struct md *md = guest->md; 2688 struct md_node *node, *node2; 2689 struct md_prop *prop, *prop2; 2690 struct mblock *mblock; 2691 struct md_node *parent; 2692 struct md_node *child; 2693 struct cpu *cpu; 2694 uint64_t pid; 2695 const char *name; 2696 char *path; 2697 2698 node = md_find_node(md, "cpus"); 2699 TAILQ_FOREACH_SAFE(prop, &node->prop_list, link, prop2) { 2700 if (prop->tag == MD_PROP_ARC && 2701 strcmp(prop->name->str, "fwd") == 0) { 2702 node2 = prop->d.arc.node; 2703 if (!md_get_prop_val(md, node2, "pid", &pid)) 2704 if (!md_get_prop_val(md, node2, "id", &pid)) 2705 continue; 2706 cpu = guest_find_cpu(guest, pid); 2707 if (cpu == NULL) { 2708 md_delete_node(md, node2); 2709 continue; 2710 } 2711 md_set_prop_val(md, node2, "id", cpu->vid); 2712 } 2713 } 2714 2715 /* 2716 * We don't support crypto units yet, so delete any "ncp" and 2717 * "n2cp" nodes. If we don't, Solaris whines about not being 2718 * able to configure crypto work queues. 2719 */ 2720 node = md_find_node(md, "virtual-devices"); 2721 TAILQ_FOREACH_SAFE(prop, &node->prop_list, link, prop2) { 2722 if (prop->tag == MD_PROP_ARC && 2723 strcmp(prop->name->str, "fwd") == 0) { 2724 node2 = prop->d.arc.node; 2725 if (!md_get_prop_str(md, node2, "name", &name)) 2726 continue; 2727 if (strcmp(name, "ncp") == 0) 2728 md_delete_node(md, node2); 2729 if (strcmp(name, "n2cp") == 0) 2730 md_delete_node(md, node2); 2731 } 2732 } 2733 2734 node = md_find_node(md, "memory"); 2735 TAILQ_FOREACH_SAFE(prop, &node->prop_list, link, prop2) { 2736 if (prop->tag == MD_PROP_ARC && 2737 strcmp(prop->name->str, "fwd") == 0) { 2738 node2 = prop->d.arc.node; 2739 md_delete_node(md, node2); 2740 } 2741 } 2742 2743 if (strcmp(guest->name, "primary") != 0) 2744 guest_prune_phys_io(guest); 2745 guest_fixup_phys_io(guest); 2746 2747 md_collect_garbage(md); 2748 2749 parent = md_find_node(md, "memory"); 2750 TAILQ_FOREACH(mblock, &guest->mblock_list, link) { 2751 child = md_add_node(md, "mblock"); 2752 md_add_prop_val(md, child, "base", mblock->realbase); 2753 md_add_prop_val(md, child, "size", mblock->memsize); 2754 md_link_node(md, parent, child); 2755 } 2756 2757 xasprintf(&path, "%s.md", guest->name); 2758 md_write(guest->md, path); 2759 free(path); 2760 } 2761 2762 struct guest * 2763 primary_init(void) 2764 { 2765 struct guest *guest; 2766 2767 guest = guest_lookup("primary"); 2768 assert(guest); 2769 2770 guest_set_domaining_enabled(guest); 2771 2772 return guest; 2773 } 2774 2775 void 2776 build_config(const char *filename, int noaction) 2777 { 2778 struct guest *primary; 2779 struct guest *guest; 2780 struct ldc_endpoint *endpoint; 2781 struct component *component; 2782 uint64_t resource_id; 2783 int i; 2784 2785 struct ldom_config conf; 2786 struct domain *domain; 2787 struct vdisk *vdisk; 2788 struct vnet *vnet; 2789 struct var *var; 2790 struct iodev *iodev; 2791 uint64_t num_cpus = 0, primary_num_cpus = 0; 2792 uint64_t primary_stride = 1; 2793 uint64_t memory = 0, primary_memory = 0; 2794 2795 SIMPLEQ_INIT(&conf.domain_list); 2796 if (parse_config(filename, &conf) < 0) 2797 exit(1); 2798 2799 pri = md_read("pri"); 2800 if (pri == NULL) 2801 err(1, "unable to get PRI"); 2802 hvmd = md_read("hv.md"); 2803 if (hvmd == NULL) 2804 err(1, "unable to get Hypervisor MD"); 2805 2806 pri_init(pri); 2807 pri_alloc_memory(hv_membase, hv_memsize); 2808 2809 SIMPLEQ_FOREACH(domain, &conf.domain_list, entry) { 2810 if (strcmp(domain->name, "primary") == 0) { 2811 primary_num_cpus = domain->vcpu; 2812 primary_stride = domain->vcpu_stride; 2813 primary_memory = domain->memory; 2814 } 2815 num_cpus += (domain->vcpu * domain->vcpu_stride); 2816 memory += domain->memory; 2817 } 2818 if (primary_num_cpus == 0 && total_cpus > num_cpus) 2819 primary_num_cpus = total_cpus - num_cpus; 2820 if (primary_memory == 0 && total_memory > memory) 2821 primary_memory = total_memory - memory; 2822 if (num_cpus > total_cpus || primary_num_cpus == 0) 2823 errx(1, "not enough VCPU resources available"); 2824 if (memory > total_memory || primary_memory == 0) 2825 errx(1, "not enough memory available"); 2826 2827 if (noaction) 2828 exit(0); 2829 2830 hvmd_init(hvmd); 2831 primary = primary_init(); 2832 2833 for (resource_id = 0; resource_id <max_guests; resource_id++) 2834 if (guests[resource_id] && 2835 strcmp(guests[resource_id]->name, "primary") != 0) 2836 guest_delete(guests[resource_id]); 2837 2838 primary->endpoint_id = 0; 2839 TAILQ_FOREACH(endpoint, &primary->endpoint_list, link) { 2840 if (endpoint->channel >= primary->endpoint_id) 2841 primary->endpoint_id = endpoint->channel + 1; 2842 } 2843 2844 for (i = 0; i < max_cpus; i++) 2845 guest_delete_cpu(primary, i); 2846 for (i = 0; i < primary_num_cpus; i++) 2847 guest_add_cpu(primary, primary_stride); 2848 guest_delete_memory(primary); 2849 guest_add_memory(primary, -1, primary_memory); 2850 2851 SIMPLEQ_FOREACH(domain, &conf.domain_list, entry) { 2852 if (strcmp(domain->name, "primary") != 0) 2853 continue; 2854 SIMPLEQ_FOREACH(var, &domain->var_list, entry) 2855 guest_add_variable(primary, var->name, var->str); 2856 } 2857 2858 SIMPLEQ_FOREACH(domain, &conf.domain_list, entry) { 2859 if (strcmp(domain->name, "primary") == 0) 2860 continue; 2861 guest = guest_create(domain->name); 2862 for (i = 0; i < domain->vcpu; i++) 2863 guest_add_cpu(guest, domain->vcpu_stride); 2864 guest_add_memory(guest, -1, domain->memory); 2865 i = 0; 2866 SIMPLEQ_FOREACH(vdisk, &domain->vdisk_list, entry) 2867 guest_add_vdisk(guest, i++, vdisk->path, 2868 vdisk->devalias); 2869 i = 0; 2870 SIMPLEQ_FOREACH(vnet, &domain->vnet_list, entry) 2871 guest_add_vnetwork(guest, i++, vnet->mac_addr, 2872 vnet->mtu, vnet->devalias); 2873 SIMPLEQ_FOREACH(var, &domain->var_list, entry) 2874 guest_add_variable(guest, var->name, var->str); 2875 SIMPLEQ_FOREACH(iodev, &domain->iodev_list, entry) 2876 guest_add_iodev(guest, iodev->path); 2877 2878 guest_finalize(guest); 2879 } 2880 2881 TAILQ_FOREACH(component, &components, link) { 2882 if (component->assigned) 2883 continue; 2884 guest_add_iodev(primary, component->path); 2885 } 2886 2887 guest_finalize(primary); 2888 hvmd_finalize(); 2889 } 2890 2891 void 2892 list_components(void) 2893 { 2894 struct component *component; 2895 2896 pri = md_read("pri"); 2897 if (pri == NULL) 2898 err(1, "unable to get PRI"); 2899 2900 pri_init_components(pri); 2901 2902 printf("%-16s %s\n", "PATH", "NAME"); 2903 TAILQ_FOREACH(component, &components, link) { 2904 printf("%-16s %s\n", component->path, component->nac); 2905 } 2906 } 2907