1 /* $OpenBSD: config.c,v 1.21 2014/09/28 18:42:50 kettenis Exp $ */ 2 3 /* 4 * Copyright (c) 2012 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 "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 frag { 50 TAILQ_ENTRY(frag) link; 51 uint64_t base; 52 }; 53 54 struct guest **guests; 55 struct console **consoles; 56 struct cpu **cpus; 57 struct device **pcie_busses; 58 struct device **network_devices; 59 struct mblock **mblocks; 60 struct ldc_endpoint **ldc_endpoints; 61 62 uint64_t max_cpus; 63 bool have_cwqs; 64 bool have_rngs; 65 66 uint64_t max_guests; 67 uint64_t max_hv_ldcs; 68 uint64_t max_guest_ldcs; 69 uint64_t md_maxsize; 70 uint64_t md_elbow_room; 71 uint64_t max_mblocks; 72 73 uint64_t max_devices = 16; 74 75 uint64_t rombase; 76 uint64_t romsize; 77 78 uint64_t max_page_size; 79 80 uint64_t content_version; 81 uint64_t stick_frequency; 82 uint64_t tod_frequency; 83 uint64_t tod; 84 uint64_t erpt_pa; 85 uint64_t erpt_size; 86 87 struct md *pri; 88 struct md *hvmd; 89 struct md *protomd; 90 91 struct guest *guest_lookup(const char *); 92 93 TAILQ_HEAD(, frag) free_frags = TAILQ_HEAD_INITIALIZER(free_frags); 94 TAILQ_HEAD(, cpu) free_cpus = TAILQ_HEAD_INITIALIZER(free_cpus); 95 int total_cpus; 96 TAILQ_HEAD(, mblock) free_memory = TAILQ_HEAD_INITIALIZER(free_memory); 97 uint64_t total_memory; 98 99 struct cpu * 100 pri_find_cpu(uint64_t pid) 101 { 102 struct cpu *cpu = NULL; 103 104 TAILQ_FOREACH(cpu, &free_cpus, link) { 105 if (cpu->pid == pid) 106 break; 107 } 108 109 return cpu; 110 } 111 112 void 113 pri_link_core(struct md *md, struct md_node *node, struct core *core) 114 { 115 struct md_node *node2; 116 struct md_prop *prop; 117 struct cpu *cpu; 118 uint64_t pid; 119 120 TAILQ_FOREACH(prop, &node->prop_list, link) { 121 if (prop->tag == MD_PROP_ARC && 122 strcmp(prop->name->str, "back") == 0) { 123 node2 = prop->d.arc.node; 124 if (strcmp(node2->name->str, "cpu") != 0) { 125 pri_link_core(md, node2, core); 126 continue; 127 } 128 129 pid = -1; 130 if (!md_get_prop_val(md, node2, "pid", &pid)) 131 md_get_prop_val(md, node2, "id", &pid); 132 133 cpu = pri_find_cpu(pid); 134 if (cpu == NULL) 135 errx(1, "couldn't determine core for VCPU %lld\n", pid); 136 cpu->core = core; 137 } 138 } 139 } 140 141 void 142 pri_add_core(struct md *md, struct md_node *node) 143 { 144 struct core *core; 145 146 core = xzalloc(sizeof(*core)); 147 TAILQ_INSERT_TAIL(&cores, core, link); 148 149 pri_link_core(md, node, core); 150 } 151 152 void 153 pri_init_cores(struct md *md) 154 { 155 struct md_node *node; 156 const void *type; 157 size_t len; 158 159 TAILQ_INIT(&cores); 160 161 TAILQ_FOREACH(node, &md->node_list, link) { 162 if (strcmp(node->name->str, "tlb") == 0 && 163 md_get_prop_data(md, node, "type", &type, &len) && 164 strcmp(type, "data") == 0) { 165 pri_add_core(md, node); 166 } 167 } 168 } 169 170 void 171 pri_add_cpu(struct md *md, struct md_node *node) 172 { 173 struct cpu *cpu; 174 uint64_t mmu_page_size_list; 175 uint64_t page_size; 176 177 cpu = xzalloc(sizeof(*cpu)); 178 /* 179 * Only UltraSPARC T1 CPUs have a "pid" property. All other 180 * just have a "id" property that can be used as the physical ID. 181 */ 182 if (!md_get_prop_val(md, node, "pid", &cpu->pid)) 183 md_get_prop_val(md, node, "id", &cpu->pid); 184 cpu->vid = -1; 185 cpu->gid = -1; 186 cpu->partid = -1; 187 cpu->resource_id = -1; 188 TAILQ_INSERT_TAIL(&free_cpus, cpu, link); 189 total_cpus++; 190 191 mmu_page_size_list = 0x9; 192 md_get_prop_val(md, node, "mmu-page-size-list", &mmu_page_size_list); 193 194 page_size = 1024; 195 while (mmu_page_size_list) { 196 page_size *= 8; 197 mmu_page_size_list >>= 1; 198 } 199 200 if (page_size > max_page_size) 201 max_page_size = page_size; 202 } 203 204 struct cpu * 205 pri_alloc_cpu(uint64_t pid) 206 { 207 struct cpu *cpu; 208 209 if (pid == -1 && !TAILQ_EMPTY(&free_cpus)) { 210 cpu = TAILQ_FIRST(&free_cpus); 211 TAILQ_REMOVE(&free_cpus, cpu, link); 212 return cpu; 213 } 214 215 TAILQ_FOREACH(cpu, &free_cpus, link) { 216 if (cpu->pid == pid) { 217 TAILQ_REMOVE(&free_cpus, cpu, link); 218 return cpu; 219 } 220 } 221 222 return NULL; 223 } 224 225 void 226 pri_free_cpu(struct cpu *cpu) 227 { 228 TAILQ_INSERT_TAIL(&free_cpus, cpu, link); 229 } 230 231 void 232 pri_add_mblock(struct md *md, struct md_node *node) 233 { 234 struct mblock *mblock; 235 236 mblock = xzalloc(sizeof(*mblock)); 237 md_get_prop_val(md, node, "base", &mblock->membase); 238 md_get_prop_val(md, node, "size", &mblock->memsize); 239 mblock->resource_id = -1; 240 TAILQ_INSERT_TAIL(&free_memory, mblock, link); 241 total_memory += mblock->memsize; 242 } 243 244 struct mblock * 245 pri_alloc_memory(uint64_t base, uint64_t size) 246 { 247 struct mblock *mblock, *new_mblock; 248 uint64_t memend; 249 250 if (base == -1 && !TAILQ_EMPTY(&free_memory)) { 251 mblock = TAILQ_FIRST(&free_memory); 252 base = mblock->membase; 253 } 254 255 TAILQ_FOREACH(mblock, &free_memory, link) { 256 if (base >= mblock->membase && 257 base < mblock->membase + mblock->memsize) { 258 if (base > mblock->membase) { 259 new_mblock = xzalloc(sizeof(*new_mblock)); 260 new_mblock->membase = mblock->membase; 261 new_mblock->memsize = base - mblock->membase; 262 new_mblock->resource_id = -1; 263 TAILQ_INSERT_BEFORE(mblock, new_mblock, link); 264 } 265 266 memend = mblock->membase + mblock->memsize; 267 mblock->membase = base + size; 268 mblock->memsize = memend - mblock->membase; 269 if (mblock->memsize == 0) { 270 TAILQ_REMOVE(&free_memory, mblock, link); 271 free(mblock); 272 } 273 274 total_memory -= size; 275 276 new_mblock = xzalloc(sizeof(*new_mblock)); 277 new_mblock->membase = base; 278 new_mblock->memsize = size; 279 new_mblock->resource_id = -1; 280 return new_mblock;; 281 } 282 } 283 284 return NULL; 285 } 286 287 void 288 pri_init(struct md *md) 289 { 290 struct md_node *node, *node2; 291 struct md_prop *prop; 292 uint64_t base, size; 293 uint64_t offset, guest_use; 294 295 node = md_find_node(pri, "platform"); 296 if (node == NULL) 297 errx(1, "platform node not found"); 298 299 md_get_prop_val(md, node, "max-cpus", &max_cpus); 300 301 node = md_find_node(pri, "firmware"); 302 if (node == NULL) 303 errx(1, "firmware node not found"); 304 305 md_get_prop_val(md, node, "max_guests", &max_guests); 306 md_get_prop_val(md, node, "max_hv_ldcs", &max_hv_ldcs); 307 md_get_prop_val(md, node, "max_guest_ldcs", &max_guest_ldcs); 308 md_get_prop_val(md, node, "md_elbow_room", &md_elbow_room); 309 md_get_prop_val(md, node, "max_mblocks", &max_mblocks); 310 311 node = md_find_node(md, "read_only_memory"); 312 if (node == NULL) 313 errx(1, "read_only_memory node not found"); 314 if (!md_get_prop_val(md, node, "base", &base)) 315 errx(1, "missing base property in read_only_memory node"); 316 if (!md_get_prop_val(md, node, "size", &size)) 317 errx(1, "missing size property in read_only_memory node"); 318 TAILQ_FOREACH(prop, &node->prop_list, link) { 319 if (prop->tag == MD_PROP_ARC && 320 strcmp(prop->name->str, "fwd") == 0) { 321 node2 = prop->d.arc.node; 322 if (!md_get_prop_val(md, node2, "guest_use", 323 &guest_use) || guest_use == 0) 324 continue; 325 if (!md_get_prop_val(md, node2, "offset", &offset) || 326 !md_get_prop_val(md, node2, "size", &size)) 327 continue; 328 rombase = base + offset; 329 romsize = size; 330 } 331 } 332 if (romsize == 0) 333 errx(1, "no suitable firmware image found"); 334 335 node = md_find_node(md, "platform"); 336 assert(node); 337 md_set_prop_val(md, node, "domaining-enabled", 0x1); 338 339 md_write(md, "pri"); 340 341 protomd = md_copy(md); 342 md_find_delete_node(protomd, "components"); 343 md_find_delete_node(protomd, "devalias"); 344 md_find_delete_node(protomd, "domain-services"); 345 md_find_delete_node(protomd, "channel-devices"); 346 md_find_delete_node(protomd, "channel-endpoints"); 347 md_find_delete_node(protomd, "firmware"); 348 md_find_delete_node(protomd, "ldc_endpoints"); 349 md_find_delete_node(protomd, "memory-segments"); 350 md_collect_garbage(protomd); 351 md_write(protomd, "protomd"); 352 353 guests = xzalloc(max_guests * sizeof(*guests)); 354 consoles = xzalloc(max_guests * sizeof(*consoles)); 355 cpus = xzalloc(max_cpus * sizeof(*cpus)); 356 pcie_busses = xzalloc(max_devices * sizeof(*pcie_busses)); 357 network_devices = xzalloc(max_devices * sizeof(*network_devices)); 358 mblocks = xzalloc(max_mblocks * sizeof(*mblocks)); 359 ldc_endpoints = xzalloc(max_guest_ldcs * sizeof(*ldc_endpoints)); 360 361 node = md_find_node(md, "cpus"); 362 TAILQ_FOREACH(prop, &node->prop_list, link) { 363 if (prop->tag == MD_PROP_ARC && 364 strcmp(prop->name->str, "fwd") == 0) 365 pri_add_cpu(md, prop->d.arc.node); 366 } 367 368 node = md_find_node(md, "memory"); 369 TAILQ_FOREACH(prop, &node->prop_list, link) { 370 if (prop->tag == MD_PROP_ARC && 371 strcmp(prop->name->str, "fwd") == 0) 372 pri_add_mblock(md, prop->d.arc.node); 373 } 374 375 pri_init_cores(md); 376 } 377 378 void 379 hvmd_fixup_guest(struct md *md, struct md_node *guest, struct md_node *node) 380 { 381 struct md_prop *prop; 382 383 TAILQ_FOREACH(prop, &guest->prop_list, link) { 384 if (prop->tag == MD_PROP_ARC && 385 strcmp(prop->name->str, "fwd") == 0) { 386 if (prop->d.arc.node == node) 387 return; 388 } 389 } 390 391 md_add_prop_arc(md, guest, "fwd", node); 392 } 393 394 uint64_t fragsize; 395 TAILQ_HEAD(, mblock) frag_mblocks; 396 struct mblock *hvmd_mblock; 397 398 void 399 hvmd_init_frag(struct md *md, struct md_node *node) 400 { 401 struct frag *frag; 402 struct mblock *mblock; 403 uint64_t base, size; 404 405 md_get_prop_val(md, node, "base", &base); 406 md_get_prop_val(md, node, "size", &size); 407 408 pri_alloc_memory(base, size); 409 410 mblock = xzalloc(sizeof(*mblock)); 411 mblock->membase = base; 412 mblock->memsize = size; 413 TAILQ_INSERT_TAIL(&frag_mblocks, mblock, link); 414 415 while (size > fragsize) { 416 frag = xmalloc(sizeof(*frag)); 417 frag->base = base; 418 TAILQ_INSERT_TAIL(&free_frags, frag, link); 419 base += fragsize; 420 size -= fragsize; 421 } 422 } 423 424 uint64_t 425 hvmd_alloc_frag(uint64_t base) 426 { 427 struct frag *frag = TAILQ_FIRST(&free_frags); 428 429 if (base != -1) { 430 TAILQ_FOREACH(frag, &free_frags, link) { 431 if (frag->base == base) 432 break; 433 } 434 } 435 436 if (frag == NULL) 437 return -1; 438 439 TAILQ_REMOVE(&free_frags, frag, link); 440 base = frag->base; 441 free(frag); 442 443 return base; 444 } 445 446 void 447 hvmd_free_frag(uint64_t base) 448 { 449 struct frag *frag; 450 451 frag = xmalloc(sizeof(*frag)); 452 frag->base = base; 453 TAILQ_INSERT_TAIL(&free_frags, frag, link); 454 } 455 456 void 457 hvmd_init_mblock(struct md *md, struct md_node *node) 458 { 459 struct mblock *mblock; 460 uint64_t resource_id; 461 struct md_node *node2; 462 struct md_prop *prop; 463 464 if (!md_get_prop_val(md, node, "resource_id", &resource_id)) 465 errx(1, "missing resource_id property in mblock node"); 466 467 if (resource_id >= max_mblocks) 468 errx(1, "resource_id larger than max_mblocks"); 469 470 mblock = xzalloc(sizeof(*mblock)); 471 md_get_prop_val(md, node, "membase", &mblock->membase); 472 md_get_prop_val(md, node, "memsize", &mblock->memsize); 473 md_get_prop_val(md, node, "realbase", &mblock->realbase); 474 mblock->resource_id = resource_id; 475 mblocks[resource_id] = mblock; 476 mblock->hv_node = node; 477 478 /* Fixup missing links. */ 479 TAILQ_FOREACH(prop, &node->prop_list, link) { 480 if (prop->tag == MD_PROP_ARC && 481 strcmp(prop->name->str, "back") == 0) { 482 node2 = prop->d.arc.node; 483 if (strcmp(node2->name->str, "guest") == 0) 484 hvmd_fixup_guest(md, node2, node); 485 } 486 } 487 } 488 489 void 490 hvmd_init_console(struct md *md, struct md_node *node) 491 { 492 struct console *console; 493 uint64_t resource_id; 494 495 if (!md_get_prop_val(md, node, "resource_id", &resource_id)) 496 errx(1, "missing resource_id property in console node"); 497 498 if (resource_id >= max_guests) 499 errx(1, "resource_id larger than max_guests"); 500 501 console = xmalloc(sizeof(*console)); 502 md_get_prop_val(md, node, "ino", &console->ino); 503 console->resource_id = resource_id; 504 consoles[resource_id] = console; 505 console->hv_node = node; 506 } 507 508 void 509 hvmd_init_cpu(struct md *md, struct md_node *node) 510 { 511 struct cpu *cpu; 512 uint64_t pid; 513 uint64_t resource_id; 514 struct md_node *node2; 515 struct md_prop *prop; 516 517 if (!md_get_prop_val(md, node, "resource_id", &resource_id)) 518 errx(1, "missing resource_id property in cpu node"); 519 520 if (resource_id >= max_cpus) 521 errx(1, "resource_id larger than max-cpus"); 522 523 if (!md_get_prop_val(md, node, "pid", &pid)) 524 errx(1, "missing pid property in cpu node"); 525 526 cpu = pri_alloc_cpu(pid); 527 md_get_prop_val(md, node, "vid", &cpu->vid); 528 if (!md_get_prop_val(md, node, "gid", &cpu->gid)) 529 cpu->gid = 0; 530 md_get_prop_val(md, node, "partid", &cpu->partid); 531 cpu->resource_id = resource_id; 532 cpus[resource_id] = cpu; 533 cpu->hv_node = node; 534 535 /* Fixup missing links. */ 536 TAILQ_FOREACH(prop, &node->prop_list, link) { 537 if (prop->tag == MD_PROP_ARC && 538 strcmp(prop->name->str, "back") == 0) { 539 node2 = prop->d.arc.node; 540 if (strcmp(node2->name->str, "guest") == 0) 541 hvmd_fixup_guest(md, node2, node); 542 } 543 } 544 } 545 546 void 547 hvmd_init_device(struct md *md, struct md_node *node) 548 { 549 struct device *device; 550 uint64_t resource_id; 551 struct md_node *node2; 552 struct md_prop *prop; 553 554 if (strcmp(node->name->str, "pcie_bus") != 0 && 555 strcmp(node->name->str, "network_device") != 0) 556 return; 557 558 if (!md_get_prop_val(md, node, "resource_id", &resource_id)) 559 errx(1, "missing resource_id property in ldc_endpoint node"); 560 561 if (resource_id >= max_devices) 562 errx(1, "resource_id larger than max_devices"); 563 564 device = xzalloc(sizeof(*device)); 565 md_get_prop_val(md, node, "gid", &device->gid); 566 md_get_prop_val(md, node, "cfghandle", &device->cfghandle); 567 device->resource_id = resource_id; 568 if (strcmp(node->name->str, "pcie_bus") == 0) 569 pcie_busses[resource_id] = device; 570 else 571 network_devices[resource_id] = device; 572 device->hv_node = node; 573 574 /* Fixup missing links. */ 575 TAILQ_FOREACH(prop, &node->prop_list, link) { 576 if (prop->tag == MD_PROP_ARC && 577 strcmp(prop->name->str, "back") == 0) { 578 node2 = prop->d.arc.node; 579 if (strcmp(node2->name->str, "guest") == 0) 580 hvmd_fixup_guest(md, node2, node); 581 } 582 } 583 } 584 585 void 586 hvmd_init_endpoint(struct md *md, struct md_node *node) 587 { 588 struct ldc_endpoint *endpoint; 589 uint64_t resource_id; 590 591 if (!md_get_prop_val(md, node, "resource_id", &resource_id)) 592 errx(1, "missing resource_id property in ldc_endpoint node"); 593 594 if (resource_id >= max_guest_ldcs) 595 errx(1, "resource_id larger than max_guest_ldcs"); 596 597 if (ldc_endpoints[resource_id]) { 598 /* 599 * Some machine descriptions seem to have duplicate 600 * arcs. Fortunately, these can be easily detected 601 * and ignored. 602 */ 603 if (ldc_endpoints[resource_id]->hv_node == node) 604 return; 605 errx(1, "duplicate resource_id"); 606 } 607 608 endpoint = xzalloc(sizeof(*endpoint)); 609 endpoint->target_guest = -1; 610 endpoint->tx_ino = -1; 611 endpoint->rx_ino = -1; 612 endpoint->private_svc = -1; 613 endpoint->svc_id = -1; 614 md_get_prop_val(md, node, "target_type", &endpoint->target_type); 615 md_get_prop_val(md, node, "target_guest", &endpoint->target_guest); 616 md_get_prop_val(md, node, "channel", &endpoint->channel); 617 md_get_prop_val(md, node, "target_channel", &endpoint->target_channel); 618 md_get_prop_val(md, node, "tx-ino", &endpoint->tx_ino); 619 md_get_prop_val(md, node, "rx-ino", &endpoint->rx_ino); 620 md_get_prop_val(md, node, "private_svc", &endpoint->private_svc); 621 md_get_prop_val(md, node, "svc_id", &endpoint->svc_id); 622 endpoint->resource_id = resource_id; 623 ldc_endpoints[resource_id] = endpoint; 624 endpoint->hv_node = node; 625 } 626 627 void 628 hvmd_init_guest(struct md *md, struct md_node *node) 629 { 630 struct guest *guest; 631 struct md_node *node2; 632 struct md_prop *prop; 633 uint64_t resource_id; 634 struct ldc_endpoint *endpoint; 635 char *path; 636 637 if (!md_get_prop_val(md, node, "resource_id", &resource_id)) 638 errx(1, "missing resource_id property in guest node"); 639 640 if (resource_id >= max_guests) 641 errx(1, "resource_id larger than max_guests"); 642 643 guest = xzalloc(sizeof(*guest)); 644 TAILQ_INIT(&guest->cpu_list); 645 TAILQ_INIT(&guest->device_list); 646 TAILQ_INIT(&guest->mblock_list); 647 TAILQ_INIT(&guest->endpoint_list); 648 md_get_prop_str(md, node, "name", &guest->name); 649 md_get_prop_val(md, node, "gid", &guest->gid); 650 md_get_prop_val(md, node, "pid", &guest->pid); 651 md_get_prop_val(md, node, "tod-offset", &guest->tod_offset); 652 md_get_prop_val(md, node, "perfctraccess", &guest->perfctraccess); 653 md_get_prop_val(md, node, "perfctrhtaccess", &guest->perfctrhtaccess); 654 md_get_prop_val(md, node, "rngctlaccessible", &guest->rngctlaccessible); 655 md_get_prop_val(md, node, "mdpa", &guest->mdpa); 656 guest->resource_id = resource_id; 657 guests[resource_id] = guest; 658 guest->hv_node = node; 659 660 if (strcmp(guest->name, "primary") == 0 && guest->gid != 0) 661 errx(1, "gid of primary domain isn't 0"); 662 663 hvmd_alloc_frag(guest->mdpa); 664 665 TAILQ_FOREACH(prop, &node->prop_list, link) { 666 if (prop->tag == MD_PROP_ARC && 667 strcmp(prop->name->str, "fwd") == 0) { 668 node2 = prop->d.arc.node; 669 if (strcmp(node2->name->str, "console") == 0) { 670 md_get_prop_val(md, node2, "resource_id", 671 &resource_id); 672 guest->console = consoles[resource_id]; 673 consoles[resource_id]->guest = guest; 674 } 675 if (strcmp(node2->name->str, "cpu") == 0) { 676 md_get_prop_val(md, node2, "resource_id", 677 &resource_id); 678 TAILQ_INSERT_TAIL(&guest->cpu_list, 679 cpus[resource_id], link); 680 cpus[resource_id]->guest = guest; 681 } 682 if (strcmp(node2->name->str, "pcie_bus") == 0) { 683 md_get_prop_val(md, node2, "resource_id", 684 &resource_id); 685 TAILQ_INSERT_TAIL(&guest->device_list, 686 pcie_busses[resource_id], link); 687 pcie_busses[resource_id]->guest = guest; 688 } 689 if (strcmp(node2->name->str, "network_device") == 0) { 690 md_get_prop_val(md, node2, "resource_id", 691 &resource_id); 692 TAILQ_INSERT_TAIL(&guest->device_list, 693 network_devices[resource_id], link); 694 network_devices[resource_id]->guest = guest; 695 } 696 if (strcmp(node2->name->str, "mblock") == 0) { 697 md_get_prop_val(md, node2, "resource_id", 698 &resource_id); 699 TAILQ_INSERT_TAIL(&guest->mblock_list, 700 mblocks[resource_id], link); 701 mblocks[resource_id]->guest = guest; 702 } 703 if (strcmp(node2->name->str, "ldc_endpoint") == 0) { 704 md_get_prop_val(md, node2, "resource_id", 705 &resource_id); 706 TAILQ_INSERT_TAIL(&guest->endpoint_list, 707 ldc_endpoints[resource_id], link); 708 ldc_endpoints[resource_id]->guest = guest; 709 } 710 } 711 } 712 713 TAILQ_FOREACH(endpoint, &guest->endpoint_list, link) { 714 if (endpoint->channel >= guest->endpoint_id) 715 guest->endpoint_id = endpoint->channel + 1; 716 } 717 718 xasprintf(&path, "%s.md", guest->name); 719 guest->md = md_read(path); 720 721 if (guest->md == NULL) 722 err(1, "unable to get guest MD"); 723 724 free(path); 725 } 726 727 void 728 hvmd_init(struct md *md) 729 { 730 struct md_node *node; 731 struct md_prop *prop; 732 733 node = md_find_node(md, "root"); 734 md_get_prop_val(md, node, "content-version", &content_version); 735 md_get_prop_val(md, node, "stick-frequency", &stick_frequency); 736 md_get_prop_val(md, node, "tod-frequency", &tod_frequency); 737 md_get_prop_val(md, node, "tod", &tod); 738 md_get_prop_val(md, node, "erpt-pa", &erpt_pa); 739 md_get_prop_val(md, node, "erpt-size", &erpt_size); 740 741 node = md_find_node(md, "frag_space"); 742 md_get_prop_val(md, node, "fragsize", &fragsize); 743 TAILQ_INIT(&frag_mblocks); 744 TAILQ_FOREACH(prop, &node->prop_list, link) { 745 if (prop->tag == MD_PROP_ARC && 746 strcmp(prop->name->str, "fwd") == 0) 747 hvmd_init_frag(md, prop->d.arc.node); 748 } 749 pri_alloc_memory(0, fragsize); 750 751 node = md_find_node(md, "hvmd_mblock"); 752 if (node) { 753 hvmd_mblock = xzalloc(sizeof(*hvmd_mblock)); 754 md_get_prop_val(md, node, "base", &hvmd_mblock->membase); 755 md_get_prop_val(md, node, "size", &hvmd_mblock->memsize); 756 md_get_prop_val(md, node, "md_maxsize", &md_maxsize); 757 pri_alloc_memory(hvmd_mblock->membase, hvmd_mblock->memsize); 758 } 759 760 node = md_find_node(md, "consoles"); 761 TAILQ_FOREACH(prop, &node->prop_list, link) { 762 if (prop->tag == MD_PROP_ARC && 763 strcmp(prop->name->str, "fwd") == 0) 764 hvmd_init_console(md, prop->d.arc.node); 765 } 766 767 node = md_find_node(md, "cpus"); 768 TAILQ_FOREACH(prop, &node->prop_list, link) { 769 if (prop->tag == MD_PROP_ARC && 770 strcmp(prop->name->str, "fwd") == 0) 771 hvmd_init_cpu(md, prop->d.arc.node); 772 } 773 774 have_cwqs = (md_find_node(md, "cwqs") != NULL); 775 have_rngs = (md_find_node(md, "rngs") != NULL); 776 777 node = md_find_node(md, "devices"); 778 TAILQ_FOREACH(prop, &node->prop_list, link) { 779 if (prop->tag == MD_PROP_ARC && 780 strcmp(prop->name->str, "fwd") == 0) 781 hvmd_init_device(md, prop->d.arc.node); 782 } 783 784 node = md_find_node(md, "memory"); 785 TAILQ_FOREACH(prop, &node->prop_list, link) { 786 if (prop->tag == MD_PROP_ARC && 787 strcmp(prop->name->str, "fwd") == 0) 788 hvmd_init_mblock(md, prop->d.arc.node); 789 } 790 791 node = md_find_node(md, "ldc_endpoints"); 792 TAILQ_FOREACH(prop, &node->prop_list, link) { 793 if (prop->tag == MD_PROP_ARC && 794 strcmp(prop->name->str, "fwd") == 0) 795 hvmd_init_endpoint(md, prop->d.arc.node); 796 } 797 798 node = md_find_node(md, "guests"); 799 TAILQ_FOREACH(prop, &node->prop_list, link) { 800 if (prop->tag == MD_PROP_ARC && 801 strcmp(prop->name->str, "fwd") == 0) 802 hvmd_init_guest(md, prop->d.arc.node); 803 } 804 805 hvmd_alloc_frag(-1); 806 } 807 808 void 809 hvmd_finalize_cpu(struct md *md, struct cpu *cpu) 810 { 811 struct md_node *parent; 812 struct md_node *node; 813 int i; 814 815 for (i = 0; i < MAX_STRANDS_PER_CORE; i++) { 816 if (cpu->core->guests[i] == cpu->guest) { 817 cpu->partid = i + 1; 818 break; 819 } 820 if (cpu->core->guests[i] == NULL) { 821 cpu->core->guests[i] = cpu->guest; 822 cpu->partid = i + 1; 823 break; 824 } 825 } 826 827 parent = md_find_node(md, "cpus"); 828 assert(parent); 829 830 node = md_add_node(md, "cpu"); 831 md_link_node(md, parent, node); 832 md_add_prop_val(md, node, "pid", cpu->pid); 833 md_add_prop_val(md, node, "vid", cpu->vid); 834 md_add_prop_val(md, node, "gid", cpu->gid); 835 md_add_prop_val(md, node, "partid", cpu->partid); 836 md_add_prop_val(md, node, "resource_id", cpu->resource_id); 837 cpu->hv_node = node; 838 } 839 840 void 841 hvmd_finalize_cpus(struct md *md) 842 { 843 struct md_node *parent; 844 struct md_node *node; 845 uint64_t resource_id; 846 847 parent = md_find_node(md, "root"); 848 assert(parent); 849 850 node = md_add_node(md, "cpus"); 851 md_link_node(md, parent, node); 852 853 for (resource_id = 0; resource_id < max_cpus; resource_id++) { 854 if (cpus[resource_id]) 855 hvmd_finalize_cpu(md, cpus[resource_id]); 856 } 857 } 858 859 void 860 hvmd_finalize_maus(struct md *md) 861 { 862 struct md_node *parent; 863 struct md_node *node; 864 struct md_node *child; 865 int i; 866 867 parent = md_find_node(md, "root"); 868 assert(parent); 869 870 node = md_add_node(md, "maus"); 871 md_link_node(md, parent, node); 872 873 if (have_cwqs) { 874 node = md_add_node(md, "cwqs"); 875 md_link_node(md, parent, node); 876 } 877 878 if (have_rngs) { 879 node = md_add_node(md, "rngs"); 880 md_link_node(md, parent, node); 881 child = md_add_node(md, "rng"); 882 md_link_node(md, node, child); 883 for (i = 0; i < max_cpus; i++) { 884 if (cpus[i]) 885 md_link_node(md, cpus[i]->hv_node, child); 886 } 887 } 888 } 889 890 void 891 hvmd_finalize_device(struct md *md, struct device *device, const char *name) 892 { 893 struct md_node *parent; 894 struct md_node *node; 895 896 parent = md_find_node(md, "devices"); 897 assert(parent); 898 899 node = md_add_node(md, name); 900 md_link_node(md, parent, node); 901 md_add_prop_val(md, node, "resource_id", device->resource_id); 902 md_add_prop_val(md, node, "cfghandle", device->cfghandle); 903 md_add_prop_val(md, node, "gid", device->gid); 904 device->hv_node = node; 905 } 906 907 void 908 hvmd_finalize_devices(struct md *md) 909 { 910 struct md_node *parent; 911 struct md_node *node; 912 uint64_t resource_id; 913 914 parent = md_find_node(md, "root"); 915 assert(parent); 916 917 node = md_add_node(md, "devices"); 918 md_link_node(md, parent, node); 919 920 for (resource_id = 0; resource_id < max_devices; resource_id++) { 921 if (pcie_busses[resource_id]) 922 hvmd_finalize_device(md, pcie_busses[resource_id], 923 "pcie_bus"); 924 } 925 for (resource_id = 0; resource_id < max_devices; resource_id++) { 926 if (network_devices[resource_id]) 927 hvmd_finalize_device(md, network_devices[resource_id], 928 "network_device"); 929 } 930 } 931 932 void 933 hvmd_finalize_mblock(struct md *md, struct mblock *mblock) 934 { 935 struct md_node *parent; 936 struct md_node *node; 937 938 parent = md_find_node(md, "memory"); 939 assert(parent); 940 941 node = md_add_node(md, "mblock"); 942 md_link_node(md, parent, node); 943 md_add_prop_val(md, node, "membase", mblock->membase); 944 md_add_prop_val(md, node, "memsize", mblock->memsize); 945 md_add_prop_val(md, node, "realbase", mblock->realbase); 946 md_add_prop_val(md, node, "resource_id", mblock->resource_id); 947 mblock->hv_node = node; 948 } 949 950 void 951 hvmd_finalize_memory(struct md *md) 952 { 953 struct md_node *parent; 954 struct md_node *node; 955 uint64_t resource_id; 956 957 parent = md_find_node(md, "root"); 958 assert(parent); 959 960 node = md_add_node(md, "memory"); 961 md_link_node(md, parent, node); 962 963 for (resource_id = 0; resource_id < max_mblocks; resource_id++) { 964 if (mblocks[resource_id]) 965 hvmd_finalize_mblock(md, mblocks[resource_id]); 966 } 967 } 968 969 void 970 hvmd_finalize_endpoint(struct md *md, struct ldc_endpoint *endpoint) 971 { 972 struct md_node *parent; 973 struct md_node *node; 974 975 parent = md_find_node(md, "ldc_endpoints"); 976 assert(parent); 977 978 node = md_add_node(md, "ldc_endpoint"); 979 md_link_node(md, parent, node); 980 md_add_prop_val(md, node, "resource_id", endpoint->resource_id); 981 md_add_prop_val(md, node, "target_type", endpoint->target_type); 982 md_add_prop_val(md, node, "channel", endpoint->channel); 983 if (endpoint->target_guest != -1) 984 md_add_prop_val(md, node, "target_guest", 985 endpoint->target_guest); 986 md_add_prop_val(md, node, "target_channel", endpoint->target_channel); 987 if (endpoint->tx_ino != -1) 988 md_add_prop_val(md, node, "tx-ino", endpoint->tx_ino); 989 if (endpoint->rx_ino != -1) 990 md_add_prop_val(md, node, "rx-ino", endpoint->rx_ino); 991 if (endpoint->private_svc != -1) 992 md_add_prop_val(md, node, "private_svc", 993 endpoint->private_svc); 994 if (endpoint->svc_id != -1) 995 md_add_prop_val(md, node, "svc_id", endpoint->svc_id); 996 endpoint->hv_node = node; 997 } 998 999 void 1000 hvmd_finalize_endpoints(struct md *md) 1001 { 1002 struct md_node *parent; 1003 struct md_node *node; 1004 uint64_t resource_id; 1005 1006 parent = md_find_node(md, "root"); 1007 assert(parent); 1008 1009 node = md_add_node(md, "ldc_endpoints"); 1010 md_link_node(md, parent, node); 1011 1012 for (resource_id = 0; resource_id < max_guest_ldcs; resource_id++) { 1013 if (ldc_endpoints[resource_id]) 1014 hvmd_finalize_endpoint(md, ldc_endpoints[resource_id]); 1015 } 1016 } 1017 1018 void 1019 hvmd_finalize_console(struct md *md, struct console *console) 1020 { 1021 struct md_node *parent; 1022 struct md_node *node; 1023 struct ldc_endpoint *endpoint; 1024 1025 parent = md_find_node(md, "consoles"); 1026 assert(parent); 1027 1028 node = md_add_node(md, "console"); 1029 md_link_node(md, parent, node); 1030 md_add_prop_val(md, node, "resource_id", console->resource_id); 1031 md_add_prop_val(md, node, "ino", console->ino); 1032 console->hv_node = node; 1033 1034 TAILQ_FOREACH(endpoint, &console->guest->endpoint_list, link) { 1035 if (endpoint->rx_ino == console->ino) { 1036 md_link_node(md, node, endpoint->hv_node); 1037 break; 1038 } 1039 } 1040 } 1041 1042 void 1043 hvmd_finalize_consoles(struct md *md) 1044 { 1045 struct md_node *parent; 1046 struct md_node *node; 1047 uint64_t resource_id; 1048 1049 parent = md_find_node(md, "root"); 1050 assert(parent); 1051 1052 node = md_add_node(md, "consoles"); 1053 md_link_node(md, parent, node); 1054 1055 for (resource_id = 0; resource_id < max_guests; resource_id++) { 1056 if (consoles[resource_id]) 1057 hvmd_finalize_console(md, consoles[resource_id]); 1058 } 1059 } 1060 1061 void 1062 hvmd_finalize_guest(struct md *md, struct guest *guest) 1063 { 1064 struct md_node *node; 1065 struct md_node *parent; 1066 struct cpu *cpu; 1067 struct device *device; 1068 struct mblock *mblock; 1069 struct ldc_endpoint *endpoint; 1070 1071 parent = md_find_node(md, "guests"); 1072 assert(parent); 1073 1074 node = md_add_node(md, "guest"); 1075 md_link_node(md, parent, node); 1076 md_add_prop_str(md, node, "name", guest->name); 1077 md_add_prop_val(md, node, "gid", guest->gid); 1078 md_add_prop_val(md, node, "pid", guest->pid); 1079 md_add_prop_val(md, node, "resource_id", guest->resource_id); 1080 md_add_prop_val(md, node, "tod-offset", guest->tod_offset); 1081 md_add_prop_val(md, node, "reset-reason", 0); 1082 md_add_prop_val(md, node, "perfctraccess", guest->perfctraccess); 1083 md_add_prop_val(md, node, "perfctrhtaccess", guest->perfctrhtaccess); 1084 md_add_prop_val(md, node, "rngctlaccessible", guest->rngctlaccessible); 1085 md_add_prop_val(md, node, "diagpriv", 0); 1086 md_add_prop_val(md, node, "mdpa", guest->mdpa); 1087 md_add_prop_val(md, node, "rombase", rombase); 1088 md_add_prop_val(md, node, "romsize", romsize); 1089 guest->hv_node = node; 1090 1091 node = md_add_node(md, "virtual_devices"); 1092 md_link_node(md, guest->hv_node, node); 1093 md_add_prop_val(md, node, "cfghandle", 0x100); 1094 1095 node = md_add_node(md, "channel_devices"); 1096 md_link_node(md, guest->hv_node, node); 1097 md_add_prop_val(md, node, "cfghandle", 0x200); 1098 1099 if (guest->console) 1100 md_link_node(md, guest->hv_node, guest->console->hv_node); 1101 TAILQ_FOREACH(cpu, &guest->cpu_list, link) 1102 md_link_node(md, guest->hv_node, cpu->hv_node); 1103 TAILQ_FOREACH(device, &guest->device_list, link) 1104 md_link_node(md, guest->hv_node, device->hv_node); 1105 TAILQ_FOREACH(mblock, &guest->mblock_list, link) 1106 md_link_node(md, guest->hv_node, mblock->hv_node); 1107 TAILQ_FOREACH(endpoint, &guest->endpoint_list, link) 1108 md_link_node(md, guest->hv_node, endpoint->hv_node); 1109 } 1110 1111 void 1112 hvmd_finalize_guests(struct md *md) 1113 { 1114 struct md_node *parent; 1115 struct md_node *node; 1116 uint64_t resource_id; 1117 1118 parent = md_find_node(md, "root"); 1119 assert(parent); 1120 1121 node = md_add_node(md, "guests"); 1122 md_link_node(md, parent, node); 1123 1124 for (resource_id = 0; resource_id < max_guests; resource_id++) { 1125 if (guests[resource_id]) 1126 hvmd_finalize_guest(md, guests[resource_id]); 1127 } 1128 } 1129 1130 void 1131 hvmd_finalize(void) 1132 { 1133 struct md *md; 1134 struct md_node *node; 1135 struct md_node *parent; 1136 struct mblock *mblock; 1137 1138 md = md_alloc(); 1139 node = md_add_node(md, "root"); 1140 md_add_prop_val(md, node, "content-version", content_version); 1141 if (content_version <= 0x100000000) { 1142 md_add_prop_val(md, node, "stick-frequency", stick_frequency); 1143 if (tod_frequency != 0) 1144 md_add_prop_val(md, node, "tod-frequency", 1145 tod_frequency); 1146 if (tod != 0) 1147 md_add_prop_val(md, node, "tod", tod); 1148 if (erpt_pa != 0) 1149 md_add_prop_val(md, node, "erpt-pa", erpt_pa); 1150 if (erpt_size != 0) 1151 md_add_prop_val(md, node, "erpt-size", erpt_size); 1152 1153 parent = node; 1154 node = md_add_node(md, "platform"); 1155 md_link_node(md, parent, node); 1156 md_add_prop_val(md, node, "stick-frequency", stick_frequency); 1157 } 1158 1159 parent = md_find_node(md, "root"); 1160 assert(parent); 1161 1162 node = md_add_node(md, "frag_space"); 1163 md_link_node(md, parent, node); 1164 md_add_prop_val(md, node, "fragsize", fragsize); 1165 1166 parent = md_find_node(md, "frag_space"); 1167 TAILQ_FOREACH(mblock, &frag_mblocks, link) { 1168 node = md_add_node(md, "frag_mblock"); 1169 md_link_node(md, parent, node); 1170 md_add_prop_val(md, node, "base", mblock->membase); 1171 md_add_prop_val(md, node, "size", mblock->memsize); 1172 } 1173 1174 if (hvmd_mblock) { 1175 parent = md_find_node(md, "root"); 1176 assert(parent); 1177 1178 node = md_add_node(md, "hvmd_mblock"); 1179 md_link_node(md, parent, node); 1180 md_add_prop_val(md, node, "base", hvmd_mblock->membase); 1181 md_add_prop_val(md, node, "size", hvmd_mblock->memsize); 1182 md_add_prop_val(md, node, "md_maxsize", md_maxsize); 1183 } 1184 1185 hvmd_finalize_cpus(md); 1186 hvmd_finalize_maus(md); 1187 hvmd_finalize_devices(md); 1188 hvmd_finalize_memory(md); 1189 hvmd_finalize_endpoints(md); 1190 hvmd_finalize_consoles(md); 1191 hvmd_finalize_guests(md); 1192 1193 md_write(md, "hv.md"); 1194 } 1195 1196 struct ldc_endpoint * 1197 hvmd_add_endpoint(struct guest *guest) 1198 { 1199 struct ldc_endpoint *endpoint; 1200 uint64_t resource_id; 1201 1202 for (resource_id = 0; resource_id < max_guest_ldcs; resource_id++) 1203 if (ldc_endpoints[resource_id] == NULL) 1204 break; 1205 assert(resource_id < max_guest_ldcs); 1206 1207 endpoint = xzalloc(sizeof(*endpoint)); 1208 endpoint->target_guest = -1; 1209 endpoint->tx_ino = -1; 1210 endpoint->rx_ino = -1; 1211 endpoint->private_svc = -1; 1212 endpoint->svc_id = -1; 1213 endpoint->resource_id = resource_id; 1214 ldc_endpoints[resource_id] = endpoint; 1215 1216 TAILQ_INSERT_TAIL(&guest->endpoint_list, endpoint, link); 1217 endpoint->guest = guest; 1218 1219 return endpoint; 1220 } 1221 1222 struct console * 1223 hvmd_add_console(struct guest *guest) 1224 { 1225 struct guest *primary; 1226 struct console *console; 1227 uint64_t resource_id; 1228 uint64_t client_channel, server_channel; 1229 1230 primary = guest_lookup("primary"); 1231 client_channel = guest->endpoint_id++; 1232 server_channel = primary->endpoint_id++; 1233 1234 for (resource_id = 0; resource_id < max_guests; resource_id++) 1235 if (consoles[resource_id] == NULL) 1236 break; 1237 assert(resource_id < max_guests); 1238 1239 console = xzalloc(sizeof(*console)); 1240 console->ino = 0x11; 1241 console->resource_id = resource_id; 1242 consoles[resource_id] = console; 1243 1244 console->client_endpoint = hvmd_add_endpoint(guest); 1245 console->client_endpoint->tx_ino = 0x11; 1246 console->client_endpoint->rx_ino = 0x11; 1247 console->client_endpoint->target_type = LDC_GUEST; 1248 console->client_endpoint->target_guest = primary->gid; 1249 console->client_endpoint->target_channel = server_channel; 1250 console->client_endpoint->channel = client_channel; 1251 console->client_endpoint->private_svc = LDC_CONSOLE_SVC; 1252 1253 console->server_endpoint = hvmd_add_endpoint(primary); 1254 console->server_endpoint->tx_ino = 2 * server_channel; 1255 console->server_endpoint->rx_ino = 2 * server_channel + 1; 1256 console->server_endpoint->target_type = LDC_GUEST; 1257 console->server_endpoint->target_guest = guest->gid; 1258 console->server_endpoint->channel = server_channel; 1259 console->server_endpoint->target_channel = client_channel; 1260 1261 guest->console = console; 1262 console->guest = guest; 1263 1264 return console; 1265 } 1266 1267 void 1268 hvmd_add_domain_services(struct guest *guest) 1269 { 1270 struct guest *primary; 1271 struct ldc_channel *ds = &guest->domain_services; 1272 uint64_t client_channel, server_channel; 1273 1274 primary = guest_lookup("primary"); 1275 client_channel = guest->endpoint_id++; 1276 server_channel = primary->endpoint_id++; 1277 1278 ds->client_endpoint = hvmd_add_endpoint(guest); 1279 ds->client_endpoint->tx_ino = 2 * client_channel; 1280 ds->client_endpoint->rx_ino = 2 * client_channel + 1; 1281 ds->client_endpoint->target_type = LDC_GUEST; 1282 ds->client_endpoint->target_guest = primary->gid; 1283 ds->client_endpoint->target_channel = server_channel; 1284 ds->client_endpoint->channel = client_channel; 1285 1286 ds->server_endpoint = hvmd_add_endpoint(primary); 1287 ds->server_endpoint->tx_ino = 2 * server_channel; 1288 ds->server_endpoint->rx_ino = 2 * server_channel + 1; 1289 ds->server_endpoint->target_type = LDC_GUEST; 1290 ds->server_endpoint->target_guest = guest->gid; 1291 ds->server_endpoint->channel = server_channel; 1292 ds->server_endpoint->target_channel = client_channel; 1293 } 1294 1295 struct ldc_channel * 1296 hvmd_add_vio(struct guest *guest) 1297 { 1298 struct guest *primary; 1299 struct ldc_channel *lc = &guest->vio[guest->num_vios++]; 1300 uint64_t client_channel, server_channel; 1301 1302 primary = guest_lookup("primary"); 1303 client_channel = guest->endpoint_id++; 1304 server_channel = primary->endpoint_id++; 1305 1306 lc->client_endpoint = hvmd_add_endpoint(guest); 1307 lc->client_endpoint->tx_ino = 2 * client_channel; 1308 lc->client_endpoint->rx_ino = 2 * client_channel + 1; 1309 lc->client_endpoint->target_type = LDC_GUEST; 1310 lc->client_endpoint->target_guest = primary->gid; 1311 lc->client_endpoint->target_channel = server_channel; 1312 lc->client_endpoint->channel = client_channel; 1313 1314 lc->server_endpoint = hvmd_add_endpoint(primary); 1315 lc->server_endpoint->tx_ino = 2 * server_channel; 1316 lc->server_endpoint->rx_ino = 2 * server_channel + 1; 1317 lc->server_endpoint->target_type = LDC_GUEST; 1318 lc->server_endpoint->target_guest = guest->gid; 1319 lc->server_endpoint->channel = server_channel; 1320 lc->server_endpoint->target_channel = client_channel; 1321 1322 return lc; 1323 } 1324 1325 struct guest * 1326 hvmd_add_guest(const char *name) 1327 { 1328 struct guest *guest; 1329 uint64_t resource_id; 1330 1331 for (resource_id = 0; resource_id < max_guests; resource_id++) 1332 if (guests[resource_id] == NULL) 1333 break; 1334 assert(resource_id < max_guests); 1335 1336 guest = xzalloc(sizeof(*guest)); 1337 TAILQ_INIT(&guest->cpu_list); 1338 TAILQ_INIT(&guest->device_list); 1339 TAILQ_INIT(&guest->mblock_list); 1340 TAILQ_INIT(&guest->endpoint_list); 1341 guests[resource_id] = guest; 1342 guest->name = name; 1343 guest->gid = resource_id; 1344 guest->pid = resource_id + 1; 1345 guest->resource_id = resource_id; 1346 guest->mdpa = hvmd_alloc_frag(-1); 1347 1348 hvmd_add_console(guest); 1349 hvmd_add_domain_services(guest); 1350 1351 return guest; 1352 } 1353 1354 struct md_node * 1355 guest_add_channel_endpoints(struct guest *guest) 1356 { 1357 struct md *md = guest->md; 1358 struct md_node *parent; 1359 struct md_node *node; 1360 1361 parent = md_find_node(md, "root"); 1362 assert(parent); 1363 1364 node = md_add_node(md, "channel-endpoints"); 1365 md_link_node(md, parent, node); 1366 1367 return node; 1368 } 1369 1370 struct md_node * 1371 guest_add_endpoint(struct guest *guest, uint64_t id) 1372 { 1373 struct md *md = guest->md; 1374 struct md_node *parent; 1375 struct md_node *node; 1376 1377 parent = md_find_node(md, "channel-endpoints"); 1378 if (parent == NULL) 1379 parent = guest_add_channel_endpoints(guest); 1380 1381 node = md_add_node(md, "channel-endpoint"); 1382 md_link_node(md, parent, node); 1383 md_add_prop_val(md, node, "id", id); 1384 md_add_prop_val(md, node, "tx-ino", 2 * id); 1385 md_add_prop_val(md, node, "rx-ino", 2 * id + 1); 1386 1387 return node; 1388 } 1389 1390 struct md_node * 1391 guest_add_vcc(struct guest *guest) 1392 { 1393 const char compatible[] = "SUNW,sun4v-virtual-console-concentrator"; 1394 struct md *md = guest->md; 1395 struct md_node *parent; 1396 struct md_node *node; 1397 1398 parent = md_find_node(md, "channel-devices"); 1399 assert(parent != NULL); 1400 1401 node = md_add_node(md, "virtual-device"); 1402 md_link_node(md, parent, node); 1403 md_add_prop_str(md, node, "name", "virtual-console-concentrator"); 1404 md_add_prop_data(md, node, "compatible", compatible, 1405 sizeof(compatible)); 1406 md_add_prop_str(md, node, "device_type", "vcc"); 1407 md_add_prop_val(md, node, "cfg-handle", 0x0); 1408 md_add_prop_str(md, node, "svc-name", "primary-vcc0"); 1409 1410 return node; 1411 } 1412 1413 struct md_node * 1414 guest_find_vcc(struct guest *guest) 1415 { 1416 struct md *md = guest->md; 1417 struct md_node *node, *node2; 1418 struct md_prop *prop; 1419 const char *name; 1420 1421 node = md_find_node(md, "channel-devices"); 1422 assert(node != NULL); 1423 1424 TAILQ_FOREACH(prop, &node->prop_list, link) { 1425 if (prop->tag == MD_PROP_ARC && 1426 strcmp(prop->name->str, "fwd") == 0) { 1427 node2 = prop->d.arc.node; 1428 if (!md_get_prop_str(md, node2, "name", &name)) 1429 continue; 1430 if (strcmp(name, "virtual-console-concentrator") == 0) 1431 return node2; 1432 } 1433 } 1434 1435 return NULL; 1436 } 1437 1438 struct md_node * 1439 guest_add_vcc_port(struct guest *guest, struct md_node *vcc, 1440 const char *domain, uint64_t id, uint64_t channel) 1441 { 1442 struct md *md = guest->md; 1443 struct md_node *node; 1444 struct md_node *child; 1445 1446 if (vcc == NULL) 1447 vcc = guest_find_vcc(guest); 1448 if (vcc == NULL) 1449 vcc = guest_add_vcc(guest); 1450 1451 node = md_add_node(md, "virtual-device-port"); 1452 md_link_node(md, vcc, node); 1453 md_add_prop_str(md, node, "name", "vcc-port"); 1454 md_add_prop_val(md, node, "id", id); 1455 md_add_prop_str(md, node, "vcc-domain-name", domain); 1456 md_add_prop_str(md, node, "vcc-group-name", domain); 1457 /* OpenBSD doesn't care about this, but Solaris might. */ 1458 md_add_prop_val(md, node, "vcc-tcp-port", 5000 + id); 1459 1460 child = guest_add_endpoint(guest, channel); 1461 md_link_node(md, node, child); 1462 1463 return node; 1464 } 1465 1466 struct md_node * 1467 guest_add_vds(struct guest *guest) 1468 { 1469 const char compatible[] = "SUNW,sun4v-disk-server"; 1470 struct md *md = guest->md; 1471 struct md_node *parent; 1472 struct md_node *node; 1473 1474 parent = md_find_node(md, "channel-devices"); 1475 assert(parent != NULL); 1476 1477 node = md_add_node(md, "virtual-device"); 1478 md_link_node(md, parent, node); 1479 md_add_prop_str(md, node, "name", "virtual-disk-server"); 1480 md_add_prop_data(md, node, "compatible", compatible, 1481 sizeof(compatible)); 1482 md_add_prop_str(md, node, "device_type", "vds"); 1483 md_add_prop_val(md, node, "cfg-handle", 0x0); 1484 md_add_prop_str(md, node, "svc-name", "primary-vds0"); 1485 1486 return node; 1487 } 1488 1489 struct md_node * 1490 guest_find_vds(struct guest *guest) 1491 { 1492 struct md *md = guest->md; 1493 struct md_node *node, *node2; 1494 struct md_prop *prop; 1495 const char *name; 1496 1497 node = md_find_node(md, "channel-devices"); 1498 assert(node != NULL); 1499 1500 TAILQ_FOREACH(prop, &node->prop_list, link) { 1501 if (prop->tag == MD_PROP_ARC && 1502 strcmp(prop->name->str, "fwd") == 0) { 1503 node2 = prop->d.arc.node; 1504 if (!md_get_prop_str(md, node2, "name", &name)) 1505 continue; 1506 if (strcmp(name, "virtual-disk-server") == 0) 1507 return node2; 1508 } 1509 } 1510 1511 return NULL; 1512 } 1513 1514 struct md_node * 1515 guest_add_vds_port(struct guest *guest, struct md_node *vds, 1516 const char *path, uint64_t id, uint64_t channel) 1517 { 1518 struct md *md = guest->md; 1519 struct md_node *node; 1520 struct md_node *child; 1521 1522 if (vds == NULL) 1523 vds = guest_find_vds(guest); 1524 if (vds == NULL) 1525 vds = guest_add_vds(guest); 1526 1527 node = md_add_node(md, "virtual-device-port"); 1528 md_link_node(md, vds, node); 1529 md_add_prop_str(md, node, "name", "vds-port"); 1530 md_add_prop_val(md, node, "id", id); 1531 md_add_prop_str(md, node, "vds-block-device", path); 1532 1533 child = guest_add_endpoint(guest, channel); 1534 md_link_node(md, node, child); 1535 1536 return node; 1537 } 1538 1539 struct md_node * 1540 guest_add_vsw(struct guest *guest) 1541 { 1542 const char compatible[] = "SUNW,sun4v-network-switch"; 1543 struct md *md = guest->md; 1544 struct md_node *parent; 1545 struct md_node *node; 1546 1547 parent = md_find_node(md, "channel-devices"); 1548 assert(parent != NULL); 1549 1550 node = md_add_node(md, "virtual-device"); 1551 md_link_node(md, parent, node); 1552 md_add_prop_str(md, node, "name", "virtual-network-switch"); 1553 md_add_prop_data(md, node, "compatible", compatible, 1554 sizeof(compatible)); 1555 md_add_prop_str(md, node, "device_type", "vsw"); 1556 md_add_prop_val(md, node, "cfg-handle", 0x0); 1557 md_add_prop_str(md, node, "svc-name", "primary-vsw0"); 1558 1559 return node; 1560 } 1561 1562 struct md_node * 1563 guest_find_vsw(struct guest *guest) 1564 { 1565 struct md *md = guest->md; 1566 struct md_node *node, *node2; 1567 struct md_prop *prop; 1568 const char *name; 1569 1570 node = md_find_node(md, "channel-devices"); 1571 assert(node != NULL); 1572 1573 TAILQ_FOREACH(prop, &node->prop_list, link) { 1574 if (prop->tag == MD_PROP_ARC && 1575 strcmp(prop->name->str, "fwd") == 0) { 1576 node2 = prop->d.arc.node; 1577 if (!md_get_prop_str(md, node2, "name", &name)) 1578 continue; 1579 if (strcmp(name, "virtual-network-switch") == 0) 1580 return node2; 1581 } 1582 } 1583 1584 return NULL; 1585 } 1586 1587 struct md_node * 1588 guest_add_vsw_port(struct guest *guest, struct md_node *vds, 1589 uint64_t id, uint64_t channel) 1590 { 1591 struct md *md = guest->md; 1592 struct md_node *node; 1593 struct md_node *child; 1594 uint64_t mac_addr; 1595 1596 if (vds == NULL) 1597 vds = guest_find_vsw(guest); 1598 if (vds == NULL) 1599 vds = guest_add_vsw(guest); 1600 if (!md_get_prop_val(md, vds, "local-mac-address", &mac_addr)) { 1601 mac_addr = 0x00144ff80000 + (arc4random() & 0x3ffff); 1602 md_add_prop_val(md, vds, "local-mac-address", mac_addr); 1603 } 1604 1605 node = md_add_node(md, "virtual-device-port"); 1606 md_link_node(md, vds, node); 1607 md_add_prop_str(md, node, "name", "vsw-port"); 1608 md_add_prop_val(md, node, "id", id); 1609 1610 child = guest_add_endpoint(guest, channel); 1611 md_link_node(md, node, child); 1612 1613 return node; 1614 } 1615 1616 struct md_node * 1617 guest_add_console_device(struct guest *guest) 1618 { 1619 const char compatible[] = "SUNW,sun4v-console"; 1620 struct md *md = guest->md; 1621 struct md_node *parent; 1622 struct md_node *node; 1623 1624 parent = md_find_node(md, "virtual-devices"); 1625 assert(parent); 1626 1627 node = md_add_node(md, "virtual-device"); 1628 md_link_node(md, parent, node); 1629 md_add_prop_str(md, node, "name", "console"); 1630 md_add_prop_str(md, node, "device-type", "serial"); 1631 md_add_prop_val(md, node, "intr", 0x1); 1632 md_add_prop_val(md, node, "ino", 0x11); 1633 md_add_prop_val(md, node, "channel#", 0); 1634 md_add_prop_val(md, node, "cfg-handle", 0x1); 1635 md_add_prop_data(md, node, "compatible", compatible, 1636 sizeof(compatible)); 1637 1638 return node; 1639 } 1640 1641 struct md_node * 1642 guest_add_vdc(struct guest *guest, uint64_t cfghandle) 1643 { 1644 const char compatible[] = "SUNW,sun4v-disk"; 1645 struct md *md = guest->md; 1646 struct md_node *parent; 1647 struct md_node *node; 1648 1649 parent = md_find_node(md, "channel-devices"); 1650 assert(parent); 1651 1652 node = md_add_node(md, "virtual-device"); 1653 md_link_node(md, parent, node); 1654 md_add_prop_str(md, node, "name", "disk"); 1655 md_add_prop_str(md, node, "device-type", "block"); 1656 md_add_prop_val(md, node, "cfg-handle", cfghandle); 1657 md_add_prop_data(md, node, "compatible", compatible, 1658 sizeof(compatible)); 1659 1660 return node; 1661 } 1662 1663 struct md_node * 1664 guest_add_vdc_port(struct guest *guest, struct md_node *vdc, 1665 uint64_t cfghandle, uint64_t id, uint64_t channel) 1666 { 1667 struct md *md = guest->md; 1668 struct md_node *node; 1669 struct md_node *child; 1670 1671 if (vdc == NULL) 1672 vdc = guest_add_vdc(guest, cfghandle); 1673 1674 node = md_add_node(md, "virtual-device-port"); 1675 md_link_node(md, vdc, node); 1676 md_add_prop_str(md, node, "name", "vdc-port"); 1677 md_add_prop_val(md, node, "id", id); 1678 1679 child = guest_add_endpoint(guest, channel); 1680 md_link_node(md, node, child); 1681 1682 return node; 1683 } 1684 1685 struct md_node * 1686 guest_add_vnet(struct guest *guest, uint64_t mac_addr, uint64_t mtu, 1687 uint64_t cfghandle) 1688 { 1689 const char compatible[] = "SUNW,sun4v-network"; 1690 struct md *md = guest->md; 1691 struct md_node *parent; 1692 struct md_node *node; 1693 1694 parent = md_find_node(md, "channel-devices"); 1695 assert(parent); 1696 1697 node = md_add_node(md, "virtual-device"); 1698 md_link_node(md, parent, node); 1699 md_add_prop_str(md, node, "name", "network"); 1700 md_add_prop_str(md, node, "device-type", "network"); 1701 md_add_prop_val(md, node, "cfg-handle", cfghandle); 1702 md_add_prop_data(md, node, "compatible", compatible, 1703 sizeof(compatible)); 1704 if (mac_addr == -1) 1705 mac_addr = 0x00144ff80000 + (arc4random() & 0x3ffff); 1706 md_add_prop_val(md, node, "local-mac-address", mac_addr); 1707 md_add_prop_val(md, node, "mtu", mtu); 1708 1709 return node; 1710 } 1711 1712 struct md_node * 1713 guest_add_vnet_port(struct guest *guest, struct md_node *vdc, 1714 uint64_t mac_addr, uint64_t remote_mac_addr, uint64_t mtu, uint64_t cfghandle, 1715 uint64_t id, uint64_t channel) 1716 { 1717 struct md *md = guest->md; 1718 struct md_node *node; 1719 struct md_node *child; 1720 1721 if (vdc == NULL) 1722 vdc = guest_add_vnet(guest, mac_addr, mtu, cfghandle); 1723 1724 node = md_add_node(md, "virtual-device-port"); 1725 md_link_node(md, vdc, node); 1726 md_add_prop_str(md, node, "name", "vnet-port"); 1727 md_add_prop_val(md, node, "id", id); 1728 md_add_prop_val(md, node, "switch-port", 0); 1729 md_add_prop_data(md, node, "remote-mac-address", 1730 (uint8_t *)&remote_mac_addr, sizeof(remote_mac_addr)); 1731 1732 child = guest_add_endpoint(guest, channel); 1733 md_link_node(md, node, child); 1734 1735 return node; 1736 } 1737 1738 struct md_node * 1739 guest_add_channel_devices(struct guest *guest) 1740 { 1741 const char compatible[] = "SUNW,sun4v-channel-devices"; 1742 struct md *md = guest->md; 1743 struct md_node *parent; 1744 struct md_node *node; 1745 1746 parent = md_find_node(md, "virtual-devices"); 1747 assert(parent); 1748 1749 node = md_add_node(md, "channel-devices"); 1750 md_link_node(md, parent, node); 1751 md_add_prop_str(md, node, "name", "channel-devices"); 1752 md_add_prop_str(md, node, "device-type", "channel-devices"); 1753 md_add_prop_data(md, node, "compatible", compatible, 1754 sizeof(compatible)); 1755 md_add_prop_val(md, node, "cfg-handle", 0x200); 1756 1757 return node; 1758 } 1759 1760 struct md_node * 1761 guest_add_domain_services(struct guest *guest) 1762 { 1763 struct md *md = guest->md; 1764 struct md_node *parent; 1765 struct md_node *node; 1766 1767 parent = md_find_node(md, "root"); 1768 assert(parent); 1769 1770 node = md_add_node(md, "domain-services"); 1771 md_link_node(md, parent, node); 1772 1773 return node; 1774 } 1775 1776 struct md_node * 1777 guest_add_domain_services_port(struct guest *guest, uint64_t id) 1778 { 1779 struct md *md = guest->md; 1780 struct md_node *parent; 1781 struct md_node *node; 1782 struct md_node *child; 1783 1784 parent = md_find_node(md, "domain-services"); 1785 if (parent == NULL) 1786 parent = guest_add_domain_services(guest); 1787 1788 node = md_add_node(md, "domain-services-port"); 1789 md_link_node(md, parent, node); 1790 md_add_prop_val(md, node, "id", id); 1791 1792 child = guest_add_endpoint(guest, 1793 guest->domain_services.client_endpoint->channel); 1794 md_link_node(md, node, child); 1795 1796 return node; 1797 } 1798 1799 void 1800 guest_add_devalias(struct guest *guest, const char *name, const char *path) 1801 { 1802 struct md *md = guest->md; 1803 struct md_node *parent; 1804 struct md_node *node; 1805 1806 node = md_find_node(md, "devalias"); 1807 if (node == NULL) { 1808 parent = md_find_node(md, "openboot"); 1809 assert(parent); 1810 1811 node = md_add_node(md, "devalias"); 1812 md_link_node(md, parent, node); 1813 } 1814 1815 md_add_prop_str(md, node, name, path); 1816 } 1817 1818 void 1819 guest_set_domaining_enabled(struct guest *guest) 1820 { 1821 struct md *md = guest->md; 1822 struct md_node *node; 1823 1824 node = md_find_node(md, "platform"); 1825 assert(node); 1826 1827 md_set_prop_val(md, node, "domaining-enabled", 0x1); 1828 } 1829 1830 void 1831 guest_set_mac_address(struct guest *guest) 1832 { 1833 struct md *md = guest->md; 1834 struct md_node *node; 1835 uint64_t mac_address; 1836 uint64_t hostid; 1837 1838 node = md_find_node(md, "platform"); 1839 assert(node); 1840 1841 mac_address = 0x00144ff80000 + (arc4random() & 0x3ffff); 1842 md_set_prop_val(md, node, "mac-address", mac_address); 1843 1844 hostid = 0x84000000 | (mac_address & 0x00ffffff); 1845 md_set_prop_val(md, node, "hostid", hostid); 1846 } 1847 1848 struct md_node * 1849 guest_find_vc(struct guest *guest) 1850 { 1851 struct md *md = guest->md; 1852 struct md_node *node, *node2; 1853 struct md_node *vc = NULL; 1854 struct md_prop *prop; 1855 const char *name; 1856 1857 node = md_find_node(md, "channel-devices"); 1858 assert(node != NULL); 1859 1860 TAILQ_FOREACH(prop, &node->prop_list, link) { 1861 if (prop->tag == MD_PROP_ARC && 1862 strcmp(prop->name->str, "fwd") == 0) { 1863 node2 = prop->d.arc.node; 1864 if (!md_get_prop_str(md, node2, "name", &name)) 1865 continue; 1866 if (strcmp(name, "virtual-channel") == 0) 1867 vc = node2; 1868 } 1869 } 1870 1871 return vc; 1872 } 1873 1874 struct md_node * 1875 guest_add_vc_port(struct guest *guest, struct md_node *vc, 1876 const char *domain, uint64_t id, uint64_t channel) 1877 { 1878 struct md *md = guest->md; 1879 struct md_node *node; 1880 struct md_node *child; 1881 char *str; 1882 1883 if (vc == NULL) 1884 vc = guest_find_vc(guest); 1885 assert(vc); 1886 1887 node = md_add_node(md, "virtual-device-port"); 1888 md_link_node(md, vc, node); 1889 md_add_prop_str(md, node, "name", "vldc-port"); 1890 md_add_prop_val(md, node, "id", id); 1891 xasprintf(&str, "ldom-%s", domain); 1892 md_add_prop_str(md, node, "vldc-svc-name", str); 1893 free(str); 1894 1895 child = guest_add_endpoint(guest, channel); 1896 md_link_node(md, node, child); 1897 1898 return node; 1899 } 1900 1901 struct guest * 1902 guest_create(const char *name) 1903 { 1904 struct guest *guest; 1905 struct guest *primary; 1906 struct md_node *node; 1907 1908 primary = guest_lookup("primary"); 1909 1910 guest = hvmd_add_guest(name); 1911 guest->md = md_copy(protomd); 1912 1913 md_find_delete_node(guest->md, "dimm_configuration"); 1914 md_find_delete_node(guest->md, "platform_services"); 1915 md_find_delete_node(guest->md, "phys_io"); 1916 md_collect_garbage(guest->md); 1917 1918 guest_set_domaining_enabled(guest); 1919 guest_set_mac_address(guest); 1920 guest_add_channel_devices(guest); 1921 guest_add_domain_services_port(guest, 0); 1922 guest_add_console_device(guest); 1923 guest_add_devalias(guest, "virtual-console", 1924 "/virtual-devices/console@1"); 1925 1926 guest_add_vcc_port(primary, NULL, guest->name, guest->gid - 1, 1927 guest->console->server_endpoint->channel); 1928 1929 guest_add_vc_port(primary, NULL, guest->name, guest->gid + 2, 1930 guest->domain_services.server_endpoint->channel); 1931 1932 node = md_find_node(guest->md, "root"); 1933 md_add_prop_val(guest->md, node, "reset-reason", 0); 1934 1935 return guest; 1936 } 1937 1938 struct guest * 1939 guest_lookup(const char *name) 1940 { 1941 uint64_t resource_id; 1942 1943 for (resource_id = 0; resource_id < max_guests; resource_id++) { 1944 if (guests[resource_id] && 1945 strcmp(guests[resource_id]->name, name) == 0) 1946 return guests[resource_id]; 1947 } 1948 1949 return NULL; 1950 } 1951 1952 void 1953 guest_delete_virtual_device_port(struct guest *guest, struct md_node *port) 1954 { 1955 struct md *md = guest->md; 1956 struct md_node *node; 1957 struct md_prop *prop; 1958 1959 TAILQ_FOREACH(node, &md->node_list, link) { 1960 if (strcmp(node->name->str, "virtual-device-port") != 0) 1961 continue; 1962 TAILQ_FOREACH(prop, &node->prop_list, link) { 1963 if (prop->tag == MD_PROP_ARC && 1964 prop->d.arc.node == port) { 1965 md_delete_node(md, node); 1966 return; 1967 } 1968 } 1969 } 1970 } 1971 1972 void 1973 guest_delete_endpoint(struct guest *guest, struct ldc_endpoint *endpoint) 1974 { 1975 struct md *md = guest->md; 1976 struct md_node *node, *node2; 1977 struct md_prop *prop; 1978 uint64_t id, resource_id; 1979 1980 node = md_find_node(md, "channel-endpoints"); 1981 TAILQ_FOREACH(prop, &node->prop_list, link) { 1982 if (prop->tag == MD_PROP_ARC && 1983 strcmp(prop->name->str, "fwd") == 0) { 1984 node2 = prop->d.arc.node; 1985 if (!md_get_prop_val(hvmd, node2, "id", &id)) 1986 continue; 1987 if (id == endpoint->channel) { 1988 guest_delete_virtual_device_port(guest, node2); 1989 md_delete_node(md, node2); 1990 break; 1991 } 1992 } 1993 } 1994 1995 TAILQ_REMOVE(&guest->endpoint_list, endpoint, link); 1996 ldc_endpoints[endpoint->resource_id] = NULL; 1997 1998 /* Delete peer as well. */ 1999 for (resource_id = 0; resource_id < max_guest_ldcs; resource_id++) { 2000 struct ldc_endpoint *peer = ldc_endpoints[resource_id]; 2001 2002 if (peer && peer->target_type == LDC_GUEST && 2003 peer->target_channel == endpoint->channel && 2004 peer->channel == endpoint->target_channel && 2005 peer->target_guest == guest->gid) 2006 guest_delete_endpoint(peer->guest, peer); 2007 } 2008 2009 free(endpoint); 2010 } 2011 2012 void 2013 guest_delete(struct guest *guest) 2014 { 2015 struct cpu *cpu, *cpu2; 2016 struct mblock *mblock, *mblock2; 2017 struct ldc_endpoint *endpoint, *endpoint2; 2018 2019 consoles[guest->console->resource_id] = NULL; 2020 free(guest->console); 2021 2022 TAILQ_FOREACH_SAFE(cpu, &guest->cpu_list, link, cpu2) { 2023 TAILQ_REMOVE(&guest->cpu_list, cpu, link); 2024 cpus[cpu->resource_id] = NULL; 2025 pri_free_cpu(cpu); 2026 } 2027 2028 TAILQ_FOREACH_SAFE(mblock, &guest->mblock_list, link, mblock2) { 2029 TAILQ_REMOVE(&guest->mblock_list, mblock, link); 2030 mblocks[mblock->resource_id] = NULL; 2031 free(mblock); 2032 } 2033 2034 TAILQ_FOREACH_SAFE(endpoint, &guest->endpoint_list, link, endpoint2) 2035 guest_delete_endpoint(guest, endpoint); 2036 2037 hvmd_free_frag(guest->mdpa); 2038 2039 guests[guest->resource_id] = NULL; 2040 free(guest); 2041 } 2042 2043 void 2044 guest_delete_cpu(struct guest *guest, uint64_t vid) 2045 { 2046 struct cpu *cpu; 2047 2048 TAILQ_FOREACH(cpu, &guest->cpu_list, link) { 2049 if (cpu->vid == vid) { 2050 TAILQ_REMOVE(&guest->cpu_list, cpu, link); 2051 cpus[cpu->resource_id] = NULL; 2052 pri_free_cpu(cpu); 2053 return; 2054 } 2055 } 2056 } 2057 2058 void 2059 guest_add_cpu(struct guest *guest) 2060 { 2061 struct cpu *cpu; 2062 2063 cpu = pri_alloc_cpu(-1); 2064 2065 if (cpu->resource_id == -1) { 2066 uint64_t resource_id; 2067 2068 for (resource_id = 0; resource_id < max_cpus; resource_id++) 2069 if (cpus[resource_id] == NULL) 2070 break; 2071 assert(resource_id < max_cpus); 2072 cpu->resource_id = resource_id; 2073 } 2074 cpus[cpu->resource_id] = cpu; 2075 2076 cpu->vid = guest->cpu_vid++; 2077 cpu->gid = guest->gid; 2078 cpu->partid = 1; 2079 2080 TAILQ_INSERT_TAIL(&guest->cpu_list, cpu, link); 2081 cpu->guest = guest; 2082 } 2083 2084 void 2085 guest_delete_memory(struct guest *guest) 2086 { 2087 struct mblock *mblock, *tmp; 2088 2089 TAILQ_FOREACH_SAFE(mblock, &guest->mblock_list, link, tmp) { 2090 if (mblock->resource_id != -1) 2091 mblocks[mblock->resource_id] = NULL; 2092 TAILQ_REMOVE(&guest->mblock_list, mblock, link); 2093 free(mblock); 2094 } 2095 } 2096 2097 void 2098 guest_add_memory(struct guest *guest, uint64_t base, uint64_t size) 2099 { 2100 struct mblock *mblock; 2101 uint64_t resource_id; 2102 2103 mblock = pri_alloc_memory(base, size); 2104 if (mblock == NULL) 2105 errx(1, "unable to allocate guest memory"); 2106 for (resource_id = 0; resource_id < max_cpus; resource_id++) 2107 if (mblocks[resource_id] == NULL) 2108 break; 2109 assert(resource_id < max_mblocks); 2110 mblock->resource_id = resource_id; 2111 mblocks[resource_id] = mblock; 2112 2113 mblock->realbase = mblock->membase & (max_page_size - 1); 2114 if (mblock->realbase == 0) 2115 mblock->realbase = max_page_size; 2116 2117 TAILQ_INSERT_TAIL(&guest->mblock_list, mblock, link); 2118 mblock->guest = guest; 2119 } 2120 2121 void 2122 guest_add_vdisk(struct guest *guest, uint64_t id, const char *path) 2123 { 2124 struct guest *primary; 2125 struct ldc_channel *lc; 2126 char *devalias; 2127 char *devpath; 2128 2129 primary = guest_lookup("primary"); 2130 2131 lc = hvmd_add_vio(guest); 2132 guest_add_vds_port(primary, NULL, path, id, 2133 lc->server_endpoint->channel); 2134 guest_add_vdc_port(guest, NULL, id, 0, lc->client_endpoint->channel); 2135 2136 xasprintf(&devalias, "disk%d", id); 2137 xasprintf(&devpath, 2138 "/virtual-devices@100/channel-devices@200/disk@%d", id); 2139 if (id == 0) 2140 guest_add_devalias(guest, "disk", devpath); 2141 guest_add_devalias(guest, devalias, devpath); 2142 free(devalias); 2143 free(devpath); 2144 } 2145 2146 void 2147 guest_add_vnetwork(struct guest *guest, uint64_t id, uint64_t mac_addr, 2148 uint64_t mtu) 2149 { 2150 struct guest *primary; 2151 struct ldc_channel *lc; 2152 char *devalias; 2153 char *devpath; 2154 struct md_node *node; 2155 uint64_t remote_mac_addr = -1; 2156 2157 primary = guest_lookup("primary"); 2158 2159 lc = hvmd_add_vio(guest); 2160 guest_add_vsw_port(primary, NULL, id, lc->server_endpoint->channel); 2161 node = guest_find_vsw(primary); 2162 md_get_prop_val(primary->md, node, "local-mac-address", &remote_mac_addr); 2163 guest_add_vnet_port(guest, NULL, mac_addr, remote_mac_addr, mtu, id, 0, 2164 lc->client_endpoint->channel); 2165 2166 xasprintf(&devalias, "net%d", id); 2167 xasprintf(&devpath, 2168 "/virtual-devices@100/channel-devices@200/network@%d", id); 2169 if (id == 0) 2170 guest_add_devalias(guest, "net", devpath); 2171 guest_add_devalias(guest, devalias, devpath); 2172 free(devalias); 2173 free(devpath); 2174 } 2175 2176 struct cpu * 2177 guest_find_cpu(struct guest *guest, uint64_t pid) 2178 { 2179 struct cpu *cpu; 2180 2181 TAILQ_FOREACH(cpu, &guest->cpu_list, link) 2182 if (cpu->pid == pid) 2183 return cpu; 2184 2185 return NULL; 2186 } 2187 2188 void 2189 guest_finalize(struct guest *guest) 2190 { 2191 struct md *md = guest->md; 2192 struct md_node *node, *node2; 2193 struct md_prop *prop, *prop2; 2194 struct mblock *mblock; 2195 struct md_node *parent; 2196 struct md_node *child; 2197 struct cpu *cpu; 2198 uint64_t pid; 2199 uint64_t id; 2200 const char *name; 2201 char *path; 2202 2203 node = md_find_node(md, "cpus"); 2204 TAILQ_FOREACH_SAFE(prop, &node->prop_list, link, prop2) { 2205 if (prop->tag == MD_PROP_ARC && 2206 strcmp(prop->name->str, "fwd") == 0) { 2207 node2 = prop->d.arc.node; 2208 if (!md_get_prop_val(md, node2, "pid", &pid)) 2209 if (!md_get_prop_val(md, node2, "id", &pid)) 2210 continue; 2211 cpu = guest_find_cpu(guest, pid); 2212 if (cpu == NULL) { 2213 md_delete_node(md, node2); 2214 continue; 2215 } 2216 md_set_prop_val(md, node2, "id", cpu->vid); 2217 } 2218 } 2219 2220 /* 2221 * We don't support crypto units yet, so delete any "ncp" and 2222 * "n2cp" nodes. If we don't, Solaris whines about not being 2223 * able to configure crypto work queues. 2224 */ 2225 node = md_find_node(md, "virtual-devices"); 2226 TAILQ_FOREACH_SAFE(prop, &node->prop_list, link, prop2) { 2227 if (prop->tag == MD_PROP_ARC && 2228 strcmp(prop->name->str, "fwd") == 0) { 2229 node2 = prop->d.arc.node; 2230 if (!md_get_prop_str(md, node2, "name", &name)) 2231 continue; 2232 if (strcmp(name, "ncp") == 0) 2233 md_delete_node(md, node2); 2234 if (strcmp(name, "n2cp") == 0) 2235 md_delete_node(md, node2); 2236 } 2237 } 2238 2239 md_collect_garbage(md); 2240 2241 node = md_find_node(md, "memory"); 2242 md_get_prop_val(md, node, "memory-generation-id#", &id); 2243 md_delete_node(md, node); 2244 md_collect_garbage(md); 2245 2246 parent = md_find_node(md, "root"); 2247 assert(parent); 2248 2249 node = md_add_node(md, "memory"); 2250 md_add_prop_val(md, node, "memory-generation-id#", id); 2251 md_link_node(md, parent, node); 2252 2253 TAILQ_FOREACH(mblock, &guest->mblock_list, link) { 2254 child = md_add_node(md, "mblock"); 2255 md_add_prop_val(md, child, "base", mblock->realbase); 2256 md_add_prop_val(md, child, "size", mblock->memsize); 2257 md_link_node(md, node, child); 2258 } 2259 2260 xasprintf(&path, "%s.md", guest->name); 2261 md_write(guest->md, path); 2262 free(path); 2263 } 2264 2265 struct guest * 2266 primary_init(void) 2267 { 2268 struct guest *guest; 2269 2270 guest = guest_lookup("primary"); 2271 assert(guest); 2272 2273 guest_set_domaining_enabled(guest); 2274 2275 return guest; 2276 } 2277 2278 void 2279 build_config(const char *filename) 2280 { 2281 struct guest *primary; 2282 struct guest *guest; 2283 struct ldc_endpoint *endpoint; 2284 uint64_t resource_id; 2285 int i; 2286 2287 struct ldom_config conf; 2288 struct domain *domain; 2289 struct vdisk *vdisk; 2290 struct vnet *vnet; 2291 uint64_t num_cpus, primary_num_cpus; 2292 uint64_t memory, primary_memory; 2293 2294 SIMPLEQ_INIT(&conf.domain_list); 2295 if (parse_config(filename, &conf) < 0) 2296 exit(1); 2297 2298 pri = md_read("pri"); 2299 if (pri == NULL) 2300 err(1, "unable to get PRI"); 2301 hvmd = md_read("hv.md"); 2302 if (hvmd == NULL) 2303 err(1, "unable to get Hypervisor MD"); 2304 2305 pri_init(pri); 2306 pri_alloc_memory(hv_membase, hv_memsize); 2307 2308 num_cpus = primary_num_cpus = 0; 2309 memory = primary_memory = 0; 2310 SIMPLEQ_FOREACH(domain, &conf.domain_list, entry) { 2311 if (strcmp(domain->name, "primary") == 0) { 2312 primary_num_cpus = domain->vcpu; 2313 primary_memory = domain->memory; 2314 } 2315 num_cpus += domain->vcpu; 2316 memory += domain->memory; 2317 } 2318 if (primary_num_cpus == 0 && total_cpus > num_cpus) 2319 primary_num_cpus = total_cpus - num_cpus; 2320 if (primary_memory == 0 && total_memory > memory) 2321 primary_memory = total_memory - memory; 2322 if (num_cpus > total_cpus || primary_num_cpus == 0) 2323 errx(1, "not enough VCPU resources available"); 2324 if (memory > total_memory || primary_memory == 0) 2325 errx(1, "not enough memory available"); 2326 2327 hvmd_init(hvmd); 2328 primary = primary_init(); 2329 2330 for (resource_id = 0; resource_id <max_guests; resource_id++) 2331 if (guests[resource_id] && 2332 strcmp(guests[resource_id]->name, "primary") != 0) 2333 guest_delete(guests[resource_id]); 2334 2335 primary->endpoint_id = 0; 2336 TAILQ_FOREACH(endpoint, &primary->endpoint_list, link) { 2337 if (endpoint->channel >= primary->endpoint_id) 2338 primary->endpoint_id = endpoint->channel + 1; 2339 } 2340 2341 for (i = primary_num_cpus; i < max_cpus; i++) 2342 guest_delete_cpu(primary, i); 2343 guest_delete_memory(primary); 2344 guest_add_memory(primary, -1, primary_memory); 2345 2346 SIMPLEQ_FOREACH(domain, &conf.domain_list, entry) { 2347 if (strcmp(domain->name, "primary") == 0) 2348 continue; 2349 guest = guest_create(domain->name); 2350 for (i = 0; i < domain->vcpu; i++) 2351 guest_add_cpu(guest); 2352 guest_add_memory(guest, -1, domain->memory); 2353 i = 0; 2354 SIMPLEQ_FOREACH(vdisk, &domain->vdisk_list, entry) 2355 guest_add_vdisk(guest, i++, vdisk->path); 2356 i = 0; 2357 SIMPLEQ_FOREACH(vnet, &domain->vnet_list, entry) 2358 guest_add_vnetwork(guest, i++, vnet->mac_addr, 2359 vnet->mtu); 2360 2361 guest_finalize(guest); 2362 } 2363 2364 guest_finalize(primary); 2365 hvmd_finalize(); 2366 } 2367