1 /* $OpenBSD: virtio.c,v 1.19 2016/09/03 11:35:24 nayden Exp $ */ 2 3 /* 4 * Copyright (c) 2015 Mike Larkin <mlarkin@openbsd.org> 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/param.h> /* PAGE_SIZE */ 20 21 #include <machine/vmmvar.h> 22 #include <dev/pci/pcireg.h> 23 #include <dev/pci/pcidevs.h> 24 #include <dev/pci/virtioreg.h> 25 #include <dev/pci/vioblkreg.h> 26 27 #include <errno.h> 28 #include <event.h> 29 #include <poll.h> 30 #include <stddef.h> 31 #include <stdlib.h> 32 #include <string.h> 33 #include <unistd.h> 34 35 #include "pci.h" 36 #include "vmd.h" 37 #include "vmm.h" 38 #include "virtio.h" 39 #include "loadfile.h" 40 41 extern char *__progname; 42 43 struct viornd_dev viornd; 44 struct vioblk_dev *vioblk; 45 struct vionet_dev *vionet; 46 47 int nr_vionet; 48 49 #define MAXPHYS (64 * 1024) /* max raw I/O transfer size */ 50 51 #define VIRTIO_NET_F_MAC (1<<5) 52 53 54 const char * 55 vioblk_cmd_name(uint32_t type) 56 { 57 switch (type) { 58 case VIRTIO_BLK_T_IN: return "read"; 59 case VIRTIO_BLK_T_OUT: return "write"; 60 case VIRTIO_BLK_T_SCSI_CMD: return "scsi read"; 61 case VIRTIO_BLK_T_SCSI_CMD_OUT: return "scsi write"; 62 case VIRTIO_BLK_T_FLUSH: return "flush"; 63 case VIRTIO_BLK_T_FLUSH_OUT: return "flush out"; 64 case VIRTIO_BLK_T_GET_ID: return "get id"; 65 default: return "unknown"; 66 } 67 } 68 69 static void 70 dump_descriptor_chain(struct vring_desc *desc, int16_t dxx) 71 { 72 log_debug("descriptor chain @ %d", dxx); 73 do { 74 log_debug("desc @%d addr/len/flags/next = 0x%llx / 0x%x " 75 "/ 0x%x / 0x%x", 76 dxx, 77 desc[dxx].addr, 78 desc[dxx].len, 79 desc[dxx].flags, 80 desc[dxx].next); 81 dxx = desc[dxx].next; 82 } while (desc[dxx].flags & VRING_DESC_F_NEXT); 83 84 log_debug("desc @%d addr/len/flags/next = 0x%llx / 0x%x / 0x%x " 85 "/ 0x%x", 86 dxx, 87 desc[dxx].addr, 88 desc[dxx].len, 89 desc[dxx].flags, 90 desc[dxx].next); 91 } 92 93 static const char * 94 virtio_reg_name(uint8_t reg) 95 { 96 switch (reg) { 97 case VIRTIO_CONFIG_DEVICE_FEATURES: return "device feature"; 98 case VIRTIO_CONFIG_GUEST_FEATURES: return "guest feature"; 99 case VIRTIO_CONFIG_QUEUE_ADDRESS: return "queue address"; 100 case VIRTIO_CONFIG_QUEUE_SIZE: return "queue size"; 101 case VIRTIO_CONFIG_QUEUE_SELECT: return "queue select"; 102 case VIRTIO_CONFIG_QUEUE_NOTIFY: return "queue notify"; 103 case VIRTIO_CONFIG_DEVICE_STATUS: return "device status"; 104 case VIRTIO_CONFIG_ISR_STATUS: return "isr status"; 105 case VIRTIO_CONFIG_DEVICE_CONFIG_NOMSI: return "device config 0"; 106 case VIRTIO_CONFIG_DEVICE_CONFIG_NOMSI + 4: return "device config 1"; 107 case VIRTIO_CONFIG_DEVICE_CONFIG_NOMSI + 8: return "device config 2"; 108 default: return "unknown"; 109 } 110 } 111 112 uint32_t 113 vring_size(uint32_t vq_size) 114 { 115 uint32_t allocsize1, allocsize2; 116 117 /* allocsize1: descriptor table + avail ring + pad */ 118 allocsize1 = VIRTQUEUE_ALIGN(sizeof(struct vring_desc) * vq_size 119 + sizeof(uint16_t) * (2 + vq_size)); 120 /* allocsize2: used ring + pad */ 121 allocsize2 = VIRTQUEUE_ALIGN(sizeof(uint16_t) * 2 122 + sizeof(struct vring_used_elem) * vq_size); 123 124 return allocsize1 + allocsize2; 125 } 126 127 /* Update queue select */ 128 void 129 viornd_update_qs(void) 130 { 131 /* Invalid queue? */ 132 if (viornd.cfg.queue_select > 0) 133 return; 134 135 /* Update queue address/size based on queue select */ 136 viornd.cfg.queue_address = viornd.vq[viornd.cfg.queue_select].qa; 137 viornd.cfg.queue_size = viornd.vq[viornd.cfg.queue_select].qs; 138 } 139 140 /* Update queue address */ 141 void 142 viornd_update_qa(void) 143 { 144 /* Invalid queue? */ 145 if (viornd.cfg.queue_select > 0) 146 return; 147 148 viornd.vq[viornd.cfg.queue_select].qa = viornd.cfg.queue_address; 149 } 150 151 int 152 viornd_notifyq(void) 153 { 154 uint64_t q_gpa; 155 uint32_t vr_sz; 156 size_t sz; 157 int ret; 158 char *buf, *rnd_data; 159 struct vring_desc *desc; 160 struct vring_avail *avail; 161 struct vring_used *used; 162 163 ret = 0; 164 165 /* Invalid queue? */ 166 if (viornd.cfg.queue_notify > 0) 167 return (0); 168 169 vr_sz = vring_size(VIORND_QUEUE_SIZE); 170 q_gpa = viornd.vq[viornd.cfg.queue_notify].qa; 171 q_gpa = q_gpa * VIRTIO_PAGE_SIZE; 172 173 buf = calloc(1, vr_sz); 174 if (buf == NULL) { 175 log_warn("calloc error getting viornd ring"); 176 return (0); 177 } 178 179 if (read_mem(q_gpa, buf, vr_sz)) { 180 free(buf); 181 return (0); 182 } 183 184 desc = (struct vring_desc *)(buf); 185 avail = (struct vring_avail *)(buf + 186 viornd.vq[viornd.cfg.queue_notify].vq_availoffset); 187 used = (struct vring_used *)(buf + 188 viornd.vq[viornd.cfg.queue_notify].vq_usedoffset); 189 190 sz = desc[avail->ring[avail->idx]].len; 191 if (sz > MAXPHYS) 192 fatal("viornd descriptor size too large (%zu)", sz); 193 194 rnd_data = malloc(sz); 195 196 if (rnd_data != NULL) { 197 arc4random_buf(rnd_data, desc[avail->ring[avail->idx]].len); 198 if (write_mem(desc[avail->ring[avail->idx]].addr, 199 rnd_data, desc[avail->ring[avail->idx]].len)) { 200 log_warnx("viornd: can't write random data @ " 201 "0x%llx", 202 desc[avail->ring[avail->idx]].addr); 203 } else { 204 /* ret == 1 -> interrupt needed */ 205 /* XXX check VIRTIO_F_NO_INTR */ 206 ret = 1; 207 viornd.cfg.isr_status = 1; 208 used->ring[used->idx].id = avail->ring[avail->idx]; 209 used->ring[used->idx].len = 210 desc[avail->ring[avail->idx]].len; 211 used->idx++; 212 213 if (write_mem(q_gpa, buf, vr_sz)) { 214 log_warnx("viornd: error writing vio ring"); 215 } 216 } 217 free(rnd_data); 218 } else 219 fatal("memory allocation error for viornd data"); 220 221 free(buf); 222 223 return (ret); 224 } 225 226 int 227 virtio_rnd_io(int dir, uint16_t reg, uint32_t *data, uint8_t *intr, 228 void *unused) 229 { 230 *intr = 0xFF; 231 232 if (dir == 0) { 233 switch (reg) { 234 case VIRTIO_CONFIG_DEVICE_FEATURES: 235 case VIRTIO_CONFIG_QUEUE_SIZE: 236 case VIRTIO_CONFIG_ISR_STATUS: 237 log_warnx("%s: illegal write %x to %s", 238 __progname, *data, virtio_reg_name(reg)); 239 break; 240 case VIRTIO_CONFIG_GUEST_FEATURES: 241 viornd.cfg.guest_feature = *data; 242 break; 243 case VIRTIO_CONFIG_QUEUE_ADDRESS: 244 viornd.cfg.queue_address = *data; 245 viornd_update_qa(); 246 break; 247 case VIRTIO_CONFIG_QUEUE_SELECT: 248 viornd.cfg.queue_select = *data; 249 viornd_update_qs(); 250 break; 251 case VIRTIO_CONFIG_QUEUE_NOTIFY: 252 viornd.cfg.queue_notify = *data; 253 if (viornd_notifyq()) 254 *intr = 1; 255 break; 256 case VIRTIO_CONFIG_DEVICE_STATUS: 257 viornd.cfg.device_status = *data; 258 break; 259 } 260 } else { 261 switch (reg) { 262 case VIRTIO_CONFIG_DEVICE_FEATURES: 263 *data = viornd.cfg.device_feature; 264 break; 265 case VIRTIO_CONFIG_GUEST_FEATURES: 266 *data = viornd.cfg.guest_feature; 267 break; 268 case VIRTIO_CONFIG_QUEUE_ADDRESS: 269 *data = viornd.cfg.queue_address; 270 break; 271 case VIRTIO_CONFIG_QUEUE_SIZE: 272 *data = viornd.cfg.queue_size; 273 break; 274 case VIRTIO_CONFIG_QUEUE_SELECT: 275 *data = viornd.cfg.queue_select; 276 break; 277 case VIRTIO_CONFIG_QUEUE_NOTIFY: 278 *data = viornd.cfg.queue_notify; 279 break; 280 case VIRTIO_CONFIG_DEVICE_STATUS: 281 *data = viornd.cfg.device_status; 282 break; 283 case VIRTIO_CONFIG_ISR_STATUS: 284 *data = viornd.cfg.isr_status; 285 break; 286 } 287 } 288 return (0); 289 } 290 291 void 292 vioblk_update_qa(struct vioblk_dev *dev) 293 { 294 /* Invalid queue? */ 295 if (dev->cfg.queue_select > 0) 296 return; 297 298 dev->vq[dev->cfg.queue_select].qa = dev->cfg.queue_address; 299 } 300 301 void 302 vioblk_update_qs(struct vioblk_dev *dev) 303 { 304 /* Invalid queue? */ 305 if (dev->cfg.queue_select > 0) 306 return; 307 308 /* Update queue address/size based on queue select */ 309 dev->cfg.queue_address = dev->vq[dev->cfg.queue_select].qa; 310 dev->cfg.queue_size = dev->vq[dev->cfg.queue_select].qs; 311 } 312 313 static char * 314 vioblk_do_read(struct vioblk_dev *dev, off_t sector, ssize_t sz) 315 { 316 char *buf; 317 318 buf = malloc(sz); 319 if (buf == NULL) { 320 log_warn("malloc errror vioblk read"); 321 return (NULL); 322 } 323 324 if (lseek(dev->fd, sector * VIRTIO_BLK_SECTOR_SIZE, 325 SEEK_SET) == -1) { 326 log_warn("seek error in vioblk read"); 327 free(buf); 328 return (NULL); 329 } 330 331 if (read(dev->fd, buf, sz) != sz) { 332 log_warn("vioblk read error"); 333 free(buf); 334 return (NULL); 335 } 336 337 return buf; 338 } 339 340 static int 341 vioblk_do_write(struct vioblk_dev *dev, off_t sector, char *buf, ssize_t sz) 342 { 343 if (lseek(dev->fd, sector * VIRTIO_BLK_SECTOR_SIZE, 344 SEEK_SET) == -1) { 345 log_warn("seek error in vioblk write"); 346 return (1); 347 } 348 349 if (write(dev->fd, buf, sz) != sz) { 350 log_warn("vioblk write error"); 351 return (1); 352 } 353 354 return (0); 355 } 356 357 /* 358 * XXX in various cases, ds should be set to VIRTIO_BLK_S_IOERR, if we can 359 * XXX cant trust ring data from VM, be extra cautious. 360 */ 361 int 362 vioblk_notifyq(struct vioblk_dev *dev) 363 { 364 uint64_t q_gpa; 365 uint32_t vr_sz; 366 uint16_t idx, cmd_desc_idx, secdata_desc_idx, ds_desc_idx; 367 uint8_t ds; 368 int ret; 369 off_t secbias; 370 char *vr, *secdata; 371 struct vring_desc *desc, *cmd_desc, *secdata_desc, *ds_desc; 372 struct vring_avail *avail; 373 struct vring_used *used; 374 struct virtio_blk_req_hdr cmd; 375 376 ret = 0; 377 378 /* Invalid queue? */ 379 if (dev->cfg.queue_notify > 0) 380 return (0); 381 382 vr_sz = vring_size(VIOBLK_QUEUE_SIZE); 383 q_gpa = dev->vq[dev->cfg.queue_notify].qa; 384 q_gpa = q_gpa * VIRTIO_PAGE_SIZE; 385 386 vr = calloc(1, vr_sz); 387 if (vr == NULL) { 388 log_warn("calloc error getting vioblk ring"); 389 return (0); 390 } 391 392 if (read_mem(q_gpa, vr, vr_sz)) { 393 log_warnx("error reading gpa 0x%llx", q_gpa); 394 goto out; 395 } 396 397 /* Compute offsets in ring of descriptors, avail ring, and used ring */ 398 desc = (struct vring_desc *)(vr); 399 avail = (struct vring_avail *)(vr + 400 dev->vq[dev->cfg.queue_notify].vq_availoffset); 401 used = (struct vring_used *)(vr + 402 dev->vq[dev->cfg.queue_notify].vq_usedoffset); 403 404 405 idx = dev->vq[dev->cfg.queue_notify].last_avail & VIOBLK_QUEUE_MASK; 406 407 if ((avail->idx & VIOBLK_QUEUE_MASK) == idx) { 408 log_warnx("vioblk queue notify - nothing to do?"); 409 goto out; 410 } 411 412 cmd_desc_idx = avail->ring[idx] & VIOBLK_QUEUE_MASK; 413 cmd_desc = &desc[cmd_desc_idx]; 414 415 if ((cmd_desc->flags & VRING_DESC_F_NEXT) == 0) { 416 log_warnx("unchained vioblk cmd descriptor received " 417 "(idx %d)", cmd_desc_idx); 418 goto out; 419 } 420 421 /* Read command from descriptor ring */ 422 if (read_mem(cmd_desc->addr, &cmd, cmd_desc->len)) { 423 log_warnx("vioblk: command read_mem error @ 0x%llx", 424 cmd_desc->addr); 425 goto out; 426 } 427 428 switch (cmd.type) { 429 case VIRTIO_BLK_T_IN: 430 /* first descriptor */ 431 secdata_desc_idx = cmd_desc->next & VIOBLK_QUEUE_MASK; 432 secdata_desc = &desc[secdata_desc_idx]; 433 434 if ((secdata_desc->flags & VRING_DESC_F_NEXT) == 0) { 435 log_warnx("unchained vioblk data descriptor " 436 "received (idx %d)", cmd_desc_idx); 437 goto out; 438 } 439 440 secbias = 0; 441 do { 442 /* read the data (use current data descriptor) */ 443 /* 444 * XXX waste to malloc secdata in vioblk_do_read 445 * and free it here over and over 446 */ 447 secdata = vioblk_do_read(dev, cmd.sector + secbias, 448 (ssize_t)secdata_desc->len); 449 if (secdata == NULL) { 450 log_warnx("vioblk: block read error, " 451 "sector %lld", cmd.sector); 452 goto out; 453 } 454 455 if (write_mem(secdata_desc->addr, secdata, 456 secdata_desc->len)) { 457 log_warnx("can't write sector " 458 "data to gpa @ 0x%llx", 459 secdata_desc->addr); 460 dump_descriptor_chain(desc, cmd_desc_idx); 461 free(secdata); 462 goto out; 463 } 464 465 free(secdata); 466 467 secbias += (secdata_desc->len / VIRTIO_BLK_SECTOR_SIZE); 468 secdata_desc_idx = secdata_desc->next & 469 VIOBLK_QUEUE_MASK; 470 secdata_desc = &desc[secdata_desc_idx]; 471 } while (secdata_desc->flags & VRING_DESC_F_NEXT); 472 473 ds_desc_idx = secdata_desc_idx; 474 ds_desc = secdata_desc; 475 476 ds = VIRTIO_BLK_S_OK; 477 if (write_mem(ds_desc->addr, &ds, ds_desc->len)) { 478 log_warnx("can't write device status data @ " 479 "0x%llx", ds_desc->addr); 480 dump_descriptor_chain(desc, cmd_desc_idx); 481 goto out; 482 } 483 484 485 ret = 1; 486 dev->cfg.isr_status = 1; 487 used->ring[used->idx & VIOBLK_QUEUE_MASK].id = cmd_desc_idx; 488 used->ring[used->idx & VIOBLK_QUEUE_MASK].len = cmd_desc->len; 489 used->idx++; 490 491 dev->vq[dev->cfg.queue_notify].last_avail = avail->idx & 492 VIOBLK_QUEUE_MASK; 493 494 if (write_mem(q_gpa, vr, vr_sz)) { 495 log_warnx("vioblk: error writing vio ring"); 496 } 497 break; 498 case VIRTIO_BLK_T_OUT: 499 secdata_desc_idx = cmd_desc->next & VIOBLK_QUEUE_MASK; 500 secdata_desc = &desc[secdata_desc_idx]; 501 502 if ((secdata_desc->flags & VRING_DESC_F_NEXT) == 0) { 503 log_warnx("wr vioblk: unchained vioblk data " 504 "descriptor received (idx %d)", cmd_desc_idx); 505 goto out; 506 } 507 508 secdata = malloc(MAXPHYS); 509 if (secdata == NULL) { 510 log_warn("wr vioblk: malloc error, len %d", 511 secdata_desc->len); 512 goto out; 513 } 514 515 secbias = 0; 516 do { 517 if (read_mem(secdata_desc->addr, secdata, 518 secdata_desc->len)) { 519 log_warnx("wr vioblk: can't read " 520 "sector data @ 0x%llx", 521 secdata_desc->addr); 522 dump_descriptor_chain(desc, cmd_desc_idx); 523 free(secdata); 524 goto out; 525 } 526 527 if (vioblk_do_write(dev, cmd.sector + secbias, 528 secdata, (ssize_t)secdata_desc->len)) { 529 log_warnx("wr vioblk: disk write error"); 530 free(secdata); 531 goto out; 532 } 533 534 secbias += secdata_desc->len / VIRTIO_BLK_SECTOR_SIZE; 535 536 secdata_desc_idx = secdata_desc->next & 537 VIOBLK_QUEUE_MASK; 538 secdata_desc = &desc[secdata_desc_idx]; 539 } while (secdata_desc->flags & VRING_DESC_F_NEXT); 540 541 free(secdata); 542 543 ds_desc_idx = secdata_desc_idx; 544 ds_desc = secdata_desc; 545 546 ds = VIRTIO_BLK_S_OK; 547 if (write_mem(ds_desc->addr, &ds, ds_desc->len)) { 548 log_warnx("wr vioblk: can't write device status " 549 "data @ 0x%llx", ds_desc->addr); 550 dump_descriptor_chain(desc, cmd_desc_idx); 551 goto out; 552 } 553 554 ret = 1; 555 dev->cfg.isr_status = 1; 556 used->ring[used->idx & VIOBLK_QUEUE_MASK].id = cmd_desc_idx; 557 used->ring[used->idx & VIOBLK_QUEUE_MASK].len = cmd_desc->len; 558 used->idx++; 559 560 dev->vq[dev->cfg.queue_notify].last_avail = avail->idx & 561 VIOBLK_QUEUE_MASK; 562 if (write_mem(q_gpa, vr, vr_sz)) 563 log_warnx("wr vioblk: error writing vio ring"); 564 break; 565 case VIRTIO_BLK_T_FLUSH: 566 case VIRTIO_BLK_T_FLUSH_OUT: 567 ds_desc_idx = cmd_desc->next & VIOBLK_QUEUE_MASK; 568 ds_desc = &desc[ds_desc_idx]; 569 570 ds = VIRTIO_BLK_S_OK; 571 if (write_mem(ds_desc->addr, &ds, ds_desc->len)) { 572 log_warnx("fl vioblk: can't write device status " 573 "data @ 0x%llx", ds_desc->addr); 574 dump_descriptor_chain(desc, cmd_desc_idx); 575 goto out; 576 } 577 578 ret = 1; 579 dev->cfg.isr_status = 1; 580 used->ring[used->idx & VIOBLK_QUEUE_MASK].id = cmd_desc_idx; 581 used->ring[used->idx & VIOBLK_QUEUE_MASK].len = cmd_desc->len; 582 used->idx++; 583 584 dev->vq[dev->cfg.queue_notify].last_avail = avail->idx & 585 VIOBLK_QUEUE_MASK; 586 if (write_mem(q_gpa, vr, vr_sz)) { 587 log_warnx("fl vioblk: error writing vio ring"); 588 } 589 break; 590 } 591 out: 592 free(vr); 593 return (ret); 594 } 595 596 int 597 virtio_blk_io(int dir, uint16_t reg, uint32_t *data, uint8_t *intr, 598 void *cookie) 599 { 600 struct vioblk_dev *dev = (struct vioblk_dev *)cookie; 601 602 *intr = 0xFF; 603 604 if (dir == 0) { 605 switch (reg) { 606 case VIRTIO_CONFIG_DEVICE_FEATURES: 607 case VIRTIO_CONFIG_QUEUE_SIZE: 608 case VIRTIO_CONFIG_ISR_STATUS: 609 log_warnx("%s: illegal write %x to %s", 610 __progname, *data, virtio_reg_name(reg)); 611 break; 612 case VIRTIO_CONFIG_GUEST_FEATURES: 613 dev->cfg.guest_feature = *data; 614 break; 615 case VIRTIO_CONFIG_QUEUE_ADDRESS: 616 dev->cfg.queue_address = *data; 617 vioblk_update_qa(dev); 618 break; 619 case VIRTIO_CONFIG_QUEUE_SELECT: 620 dev->cfg.queue_select = *data; 621 vioblk_update_qs(dev); 622 break; 623 case VIRTIO_CONFIG_QUEUE_NOTIFY: 624 dev->cfg.queue_notify = *data; 625 if (vioblk_notifyq(dev)) 626 *intr = 1; 627 break; 628 case VIRTIO_CONFIG_DEVICE_STATUS: 629 dev->cfg.device_status = *data; 630 break; 631 default: 632 break; 633 } 634 } else { 635 switch (reg) { 636 case VIRTIO_CONFIG_DEVICE_CONFIG_NOMSI + 4: 637 *data = (uint32_t)(dev->sz >> 32); 638 break; 639 case VIRTIO_CONFIG_DEVICE_CONFIG_NOMSI: 640 *data = (uint32_t)(dev->sz); 641 break; 642 case VIRTIO_CONFIG_DEVICE_FEATURES: 643 *data = dev->cfg.device_feature; 644 break; 645 case VIRTIO_CONFIG_GUEST_FEATURES: 646 *data = dev->cfg.guest_feature; 647 break; 648 case VIRTIO_CONFIG_QUEUE_ADDRESS: 649 *data = dev->cfg.queue_address; 650 break; 651 case VIRTIO_CONFIG_QUEUE_SIZE: 652 *data = dev->cfg.queue_size; 653 break; 654 case VIRTIO_CONFIG_QUEUE_SELECT: 655 *data = dev->cfg.queue_select; 656 break; 657 case VIRTIO_CONFIG_QUEUE_NOTIFY: 658 *data = dev->cfg.queue_notify; 659 break; 660 case VIRTIO_CONFIG_DEVICE_STATUS: 661 *data = dev->cfg.device_status; 662 break; 663 case VIRTIO_CONFIG_ISR_STATUS: 664 *data = dev->cfg.isr_status; 665 break; 666 } 667 } 668 return (0); 669 } 670 671 int 672 virtio_net_io(int dir, uint16_t reg, uint32_t *data, uint8_t *intr, 673 void *cookie) 674 { 675 struct vionet_dev *dev = (struct vionet_dev *)cookie; 676 677 *intr = 0xFF; 678 mutex_lock(&dev->mutex); 679 680 if (dir == 0) { 681 switch (reg) { 682 case VIRTIO_CONFIG_DEVICE_FEATURES: 683 case VIRTIO_CONFIG_QUEUE_SIZE: 684 case VIRTIO_CONFIG_ISR_STATUS: 685 log_warnx("%s: illegal write %x to %s", 686 __progname, *data, virtio_reg_name(reg)); 687 break; 688 case VIRTIO_CONFIG_GUEST_FEATURES: 689 dev->cfg.guest_feature = *data; 690 break; 691 case VIRTIO_CONFIG_QUEUE_ADDRESS: 692 dev->cfg.queue_address = *data; 693 vionet_update_qa(dev); 694 break; 695 case VIRTIO_CONFIG_QUEUE_SELECT: 696 dev->cfg.queue_select = *data; 697 vionet_update_qs(dev); 698 break; 699 case VIRTIO_CONFIG_QUEUE_NOTIFY: 700 dev->cfg.queue_notify = *data; 701 if (vionet_notifyq(dev)) 702 *intr = 1; 703 break; 704 case VIRTIO_CONFIG_DEVICE_STATUS: 705 dev->cfg.device_status = *data; 706 break; 707 default: 708 break; 709 } 710 } else { 711 switch (reg) { 712 case VIRTIO_CONFIG_DEVICE_CONFIG_NOMSI: 713 case VIRTIO_CONFIG_DEVICE_CONFIG_NOMSI + 1: 714 case VIRTIO_CONFIG_DEVICE_CONFIG_NOMSI + 2: 715 case VIRTIO_CONFIG_DEVICE_CONFIG_NOMSI + 3: 716 case VIRTIO_CONFIG_DEVICE_CONFIG_NOMSI + 4: 717 case VIRTIO_CONFIG_DEVICE_CONFIG_NOMSI + 5: 718 *data = dev->mac[reg - 719 VIRTIO_CONFIG_DEVICE_CONFIG_NOMSI]; 720 break; 721 case VIRTIO_CONFIG_DEVICE_FEATURES: 722 *data = dev->cfg.device_feature; 723 break; 724 case VIRTIO_CONFIG_GUEST_FEATURES: 725 *data = dev->cfg.guest_feature; 726 break; 727 case VIRTIO_CONFIG_QUEUE_ADDRESS: 728 *data = dev->cfg.queue_address; 729 break; 730 case VIRTIO_CONFIG_QUEUE_SIZE: 731 *data = dev->cfg.queue_size; 732 break; 733 case VIRTIO_CONFIG_QUEUE_SELECT: 734 *data = dev->cfg.queue_select; 735 break; 736 case VIRTIO_CONFIG_QUEUE_NOTIFY: 737 *data = dev->cfg.queue_notify; 738 break; 739 case VIRTIO_CONFIG_DEVICE_STATUS: 740 *data = dev->cfg.device_status; 741 break; 742 case VIRTIO_CONFIG_ISR_STATUS: 743 *data = dev->cfg.isr_status; 744 break; 745 } 746 } 747 748 mutex_unlock(&dev->mutex); 749 return (0); 750 } 751 752 /* 753 * Must be called with dev->mutex acquired. 754 */ 755 void 756 vionet_update_qa(struct vionet_dev *dev) 757 { 758 /* Invalid queue? */ 759 if (dev->cfg.queue_select > 1) 760 return; 761 762 dev->vq[dev->cfg.queue_select].qa = dev->cfg.queue_address; 763 } 764 765 /* 766 * Must be called with dev->mutex acquired. 767 */ 768 void 769 vionet_update_qs(struct vionet_dev *dev) 770 { 771 /* Invalid queue? */ 772 if (dev->cfg.queue_select > 1) 773 return; 774 775 /* Update queue address/size based on queue select */ 776 dev->cfg.queue_address = dev->vq[dev->cfg.queue_select].qa; 777 dev->cfg.queue_size = dev->vq[dev->cfg.queue_select].qs; 778 } 779 780 /* 781 * Must be called with dev->mutex acquired. 782 */ 783 int 784 vionet_enq_rx(struct vionet_dev *dev, char *pkt, ssize_t sz, int *spc) 785 { 786 uint64_t q_gpa; 787 uint32_t vr_sz; 788 uint16_t idx, pkt_desc_idx, hdr_desc_idx; 789 ptrdiff_t off; 790 int ret; 791 char *vr; 792 struct vring_desc *desc, *pkt_desc, *hdr_desc; 793 struct vring_avail *avail; 794 struct vring_used *used; 795 struct vring_used_elem *ue; 796 797 ret = 0; 798 799 vr_sz = vring_size(VIONET_QUEUE_SIZE); 800 q_gpa = dev->vq[0].qa; 801 q_gpa = q_gpa * VIRTIO_PAGE_SIZE; 802 803 vr = calloc(1, vr_sz); 804 if (vr == NULL) { 805 log_warn("rx enq: calloc error getting vionet ring"); 806 return (0); 807 } 808 809 if (read_mem(q_gpa, vr, vr_sz)) { 810 log_warnx("rx enq: error reading gpa 0x%llx", q_gpa); 811 goto out; 812 } 813 814 /* Compute offsets in ring of descriptors, avail ring, and used ring */ 815 desc = (struct vring_desc *)(vr); 816 avail = (struct vring_avail *)(vr + 817 dev->vq[0].vq_availoffset); 818 used = (struct vring_used *)(vr + 819 dev->vq[0].vq_usedoffset); 820 821 idx = dev->vq[0].last_avail & VIONET_QUEUE_MASK; 822 823 if ((dev->vq[0].notified_avail & VIONET_QUEUE_MASK) == idx) { 824 log_warnx("vionet queue notify - no space, dropping packet"); 825 goto out; 826 } 827 828 hdr_desc_idx = avail->ring[idx] & VIONET_QUEUE_MASK; 829 hdr_desc = &desc[hdr_desc_idx]; 830 831 pkt_desc_idx = hdr_desc->next & VIONET_QUEUE_MASK; 832 pkt_desc = &desc[pkt_desc_idx]; 833 834 /* must be not readable */ 835 if ((pkt_desc->flags & VRING_DESC_F_WRITE) == 0) { 836 log_warnx("unexpected readable rx descriptor %d", 837 pkt_desc_idx); 838 goto out; 839 } 840 841 /* Write packet to descriptor ring */ 842 if (write_mem(pkt_desc->addr, pkt, sz)) { 843 log_warnx("vionet: rx enq packet write_mem error @ " 844 "0x%llx", pkt_desc->addr); 845 goto out; 846 } 847 848 ret = 1; 849 dev->cfg.isr_status = 1; 850 ue = &used->ring[used->idx & VIONET_QUEUE_MASK]; 851 ue->id = hdr_desc_idx; 852 ue->len = hdr_desc->len + sz; 853 used->idx++; 854 dev->vq[0].last_avail = (dev->vq[0].last_avail + 1); 855 *spc = dev->vq[0].notified_avail - dev->vq[0].last_avail; 856 857 off = (char *)ue - vr; 858 if (write_mem(q_gpa + off, ue, sizeof *ue)) 859 log_warnx("vionet: error writing vio ring"); 860 else { 861 off = (char *)&used->idx - vr; 862 if (write_mem(q_gpa + off, &used->idx, sizeof used->idx)) 863 log_warnx("vionet: error writing vio ring"); 864 } 865 out: 866 free(vr); 867 return (ret); 868 } 869 870 /* 871 * vionet_rx 872 * 873 * Enqueue data that was received on a tap file descriptor 874 * to the vionet device queue. 875 * 876 * Must be called with dev->mutex acquired. 877 */ 878 static int 879 vionet_rx(struct vionet_dev *dev) 880 { 881 char buf[PAGE_SIZE]; 882 int hasdata, num_enq = 0, spc = 0; 883 ssize_t sz; 884 885 do { 886 sz = read(dev->fd, buf, sizeof buf); 887 if (sz == -1) { 888 /* 889 * If we get EAGAIN, No data is currently available. 890 * Do not treat this as an error. 891 */ 892 if (errno != EAGAIN) 893 log_warn("unexpected read error on vionet " 894 "device"); 895 } else if (sz != 0) 896 num_enq += vionet_enq_rx(dev, buf, sz, &spc); 897 else if (sz == 0) { 898 log_debug("process_rx: no data"); 899 hasdata = 0; 900 break; 901 } 902 903 hasdata = fd_hasdata(dev->fd); 904 } while (spc && hasdata); 905 906 dev->rx_pending = hasdata; 907 return (num_enq); 908 } 909 910 /* 911 * vionet_rx_event 912 * 913 * Called from the event handling thread when new data can be 914 * received on the tap fd of a vionet device. 915 */ 916 static void 917 vionet_rx_event(int fd, short kind, void *arg) 918 { 919 struct vionet_dev *dev = arg; 920 921 mutex_lock(&dev->mutex); 922 923 /* 924 * We already have other data pending to be received. The data that 925 * has become available now will be enqueued to the vionet_dev 926 * later. 927 */ 928 if (dev->rx_pending) { 929 mutex_unlock(&dev->mutex); 930 return; 931 } 932 933 if (vionet_rx(dev) > 0) { 934 /* XXX: vcpu_id */ 935 vcpu_assert_pic_irq(dev->vm_id, 0, dev->irq); 936 } 937 938 mutex_unlock(&dev->mutex); 939 } 940 941 /* 942 * vionet_process_rx 943 * 944 * Processes any remaining pending receivable data for a vionet device. 945 * Called on VCPU exit. Although we poll on the tap file descriptor of 946 * a vionet_dev in a separate thread, this function still needs to be 947 * called on VCPU exit: it can happen that not all data fits into the 948 * receive queue of the vionet_dev immediately. So any outstanding data 949 * is handled here. 950 */ 951 int 952 vionet_process_rx(void) 953 { 954 int i, num_enq; 955 956 num_enq = 0; 957 for (i = 0 ; i < nr_vionet; i++) { 958 mutex_lock(&vionet[i].mutex); 959 if (!vionet[i].rx_added) { 960 mutex_unlock(&vionet[i].mutex); 961 continue; 962 } 963 964 if (vionet[i].rx_pending) 965 num_enq += vionet_rx(&vionet[i]); 966 mutex_unlock(&vionet[i].mutex); 967 } 968 969 /* 970 * XXX returns the number of packets enqueued across all vionet, which 971 * may not be right for VMs with more than one vionet. 972 */ 973 return (num_enq); 974 } 975 976 /* 977 * Must be called with dev->mutex acquired. 978 */ 979 void 980 vionet_notify_rx(struct vionet_dev *dev) 981 { 982 uint64_t q_gpa; 983 uint32_t vr_sz; 984 char *vr; 985 struct vring_avail *avail; 986 987 vr_sz = vring_size(VIONET_QUEUE_SIZE); 988 q_gpa = dev->vq[dev->cfg.queue_notify].qa; 989 q_gpa = q_gpa * VIRTIO_PAGE_SIZE; 990 991 vr = malloc(vr_sz); 992 if (vr == NULL) { 993 log_warn("malloc error getting vionet ring"); 994 return; 995 } 996 997 if (read_mem(q_gpa, vr, vr_sz)) { 998 log_warnx("error reading gpa 0x%llx", q_gpa); 999 free(vr); 1000 return; 1001 } 1002 1003 /* Compute offset into avail ring */ 1004 avail = (struct vring_avail *)(vr + 1005 dev->vq[dev->cfg.queue_notify].vq_availoffset); 1006 1007 dev->rx_added = 1; 1008 dev->vq[0].notified_avail = avail->idx; 1009 1010 free(vr); 1011 } 1012 1013 /* 1014 * Must be called with dev->mutex acquired. 1015 * 1016 * XXX cant trust ring data from VM, be extra cautious. 1017 * XXX advertise link status to guest 1018 */ 1019 int 1020 vionet_notifyq(struct vionet_dev *dev) 1021 { 1022 uint64_t q_gpa; 1023 uint32_t vr_sz; 1024 uint16_t idx, pkt_desc_idx, hdr_desc_idx, dxx; 1025 size_t pktsz; 1026 int ret, num_enq, ofs; 1027 char *vr, *pkt; 1028 struct vring_desc *desc, *pkt_desc, *hdr_desc; 1029 struct vring_avail *avail; 1030 struct vring_used *used; 1031 1032 vr = pkt = NULL; 1033 ret = 0; 1034 1035 /* Invalid queue? */ 1036 if (dev->cfg.queue_notify != 1) { 1037 vionet_notify_rx(dev); 1038 goto out; 1039 } 1040 1041 vr_sz = vring_size(VIONET_QUEUE_SIZE); 1042 q_gpa = dev->vq[dev->cfg.queue_notify].qa; 1043 q_gpa = q_gpa * VIRTIO_PAGE_SIZE; 1044 1045 vr = calloc(1, vr_sz); 1046 if (vr == NULL) { 1047 log_warn("calloc error getting vionet ring"); 1048 goto out; 1049 } 1050 1051 if (read_mem(q_gpa, vr, vr_sz)) { 1052 log_warnx("error reading gpa 0x%llx", q_gpa); 1053 goto out; 1054 } 1055 1056 /* Compute offsets in ring of descriptors, avail ring, and used ring */ 1057 desc = (struct vring_desc *)(vr); 1058 avail = (struct vring_avail *)(vr + 1059 dev->vq[dev->cfg.queue_notify].vq_availoffset); 1060 used = (struct vring_used *)(vr + 1061 dev->vq[dev->cfg.queue_notify].vq_usedoffset); 1062 1063 num_enq = 0; 1064 1065 idx = dev->vq[dev->cfg.queue_notify].last_avail & VIONET_QUEUE_MASK; 1066 1067 if ((avail->idx & VIONET_QUEUE_MASK) == idx) { 1068 log_warnx("vionet tx queue notify - nothing to do?"); 1069 goto out; 1070 } 1071 1072 while ((avail->idx & VIONET_QUEUE_MASK) != idx) { 1073 hdr_desc_idx = avail->ring[idx] & VIONET_QUEUE_MASK; 1074 hdr_desc = &desc[hdr_desc_idx]; 1075 pktsz = 0; 1076 1077 dxx = hdr_desc_idx; 1078 do { 1079 pktsz += desc[dxx].len; 1080 dxx = desc[dxx].next; 1081 } while (desc[dxx].flags & VRING_DESC_F_NEXT); 1082 1083 pktsz += desc[dxx].len; 1084 1085 /* Remove virtio header descriptor len */ 1086 pktsz -= hdr_desc->len; 1087 1088 /* 1089 * XXX check sanity pktsz 1090 * XXX too long and > PAGE_SIZE checks 1091 * (PAGE_SIZE can be relaxed to 16384 later) 1092 */ 1093 pkt = malloc(pktsz); 1094 if (pkt == NULL) { 1095 log_warn("malloc error alloc packet buf"); 1096 goto out; 1097 } 1098 1099 ofs = 0; 1100 pkt_desc_idx = hdr_desc->next & VIONET_QUEUE_MASK; 1101 pkt_desc = &desc[pkt_desc_idx]; 1102 1103 while (pkt_desc->flags & VRING_DESC_F_NEXT) { 1104 /* must be not writable */ 1105 if (pkt_desc->flags & VRING_DESC_F_WRITE) { 1106 log_warnx("unexpected writable tx desc " 1107 "%d", pkt_desc_idx); 1108 goto out; 1109 } 1110 1111 /* Read packet from descriptor ring */ 1112 if (read_mem(pkt_desc->addr, pkt + ofs, 1113 pkt_desc->len)) { 1114 log_warnx("vionet: packet read_mem error " 1115 "@ 0x%llx", pkt_desc->addr); 1116 goto out; 1117 } 1118 1119 ofs += pkt_desc->len; 1120 pkt_desc_idx = pkt_desc->next & VIONET_QUEUE_MASK; 1121 pkt_desc = &desc[pkt_desc_idx]; 1122 } 1123 1124 /* Now handle tail descriptor - must be not writable */ 1125 if (pkt_desc->flags & VRING_DESC_F_WRITE) { 1126 log_warnx("unexpected writable tx descriptor %d", 1127 pkt_desc_idx); 1128 goto out; 1129 } 1130 1131 /* Read packet from descriptor ring */ 1132 if (read_mem(pkt_desc->addr, pkt + ofs, 1133 pkt_desc->len)) { 1134 log_warnx("vionet: packet read_mem error @ " 1135 "0x%llx", pkt_desc->addr); 1136 goto out; 1137 } 1138 1139 /* XXX signed vs unsigned here, funky cast */ 1140 if (write(dev->fd, pkt, pktsz) != (int)pktsz) { 1141 log_warnx("vionet: tx failed writing to tap: " 1142 "%d", errno); 1143 goto out; 1144 } 1145 1146 ret = 1; 1147 dev->cfg.isr_status = 1; 1148 used->ring[used->idx & VIONET_QUEUE_MASK].id = hdr_desc_idx; 1149 used->ring[used->idx & VIONET_QUEUE_MASK].len = hdr_desc->len; 1150 used->idx++; 1151 1152 dev->vq[dev->cfg.queue_notify].last_avail = 1153 (dev->vq[dev->cfg.queue_notify].last_avail + 1); 1154 num_enq++; 1155 1156 idx = dev->vq[dev->cfg.queue_notify].last_avail & 1157 VIONET_QUEUE_MASK; 1158 } 1159 1160 if (write_mem(q_gpa, vr, vr_sz)) { 1161 log_warnx("vionet: tx error writing vio ring"); 1162 } 1163 1164 out: 1165 free(vr); 1166 free(pkt); 1167 1168 return (ret); 1169 } 1170 1171 void 1172 virtio_init(struct vm_create_params *vcp, int *child_disks, int *child_taps) 1173 { 1174 uint8_t id; 1175 uint8_t i; 1176 int ret; 1177 off_t sz; 1178 1179 /* Virtio entropy device */ 1180 if (pci_add_device(&id, PCI_VENDOR_QUMRANET, 1181 PCI_PRODUCT_QUMRANET_VIO_RNG, PCI_CLASS_SYSTEM, 1182 PCI_SUBCLASS_SYSTEM_MISC, 1183 PCI_VENDOR_OPENBSD, 1184 PCI_PRODUCT_VIRTIO_ENTROPY, 1, NULL)) { 1185 log_warnx("%s: can't add PCI virtio rng device", 1186 __progname); 1187 return; 1188 } 1189 1190 if (pci_add_bar(id, PCI_MAPREG_TYPE_IO, virtio_rnd_io, NULL)) { 1191 log_warnx("%s: can't add bar for virtio rng device", 1192 __progname); 1193 return; 1194 } 1195 1196 memset(&viornd, 0, sizeof(viornd)); 1197 viornd.vq[0].qs = VIORND_QUEUE_SIZE; 1198 viornd.vq[0].vq_availoffset = sizeof(struct vring_desc) * 1199 VIORND_QUEUE_SIZE; 1200 viornd.vq[0].vq_usedoffset = VIRTQUEUE_ALIGN( 1201 sizeof(struct vring_desc) * VIORND_QUEUE_SIZE 1202 + sizeof(uint16_t) * (2 + VIORND_QUEUE_SIZE)); 1203 1204 if (vcp->vcp_ndisks > 0) { 1205 vioblk = calloc(vcp->vcp_ndisks, sizeof(struct vioblk_dev)); 1206 if (vioblk == NULL) { 1207 log_warn("%s: calloc failure allocating vioblks", 1208 __progname); 1209 return; 1210 } 1211 1212 /* One virtio block device for each disk defined in vcp */ 1213 for (i = 0; i < vcp->vcp_ndisks; i++) { 1214 if ((sz = lseek(child_disks[i], 0, SEEK_END)) == -1) 1215 continue; 1216 1217 if (pci_add_device(&id, PCI_VENDOR_QUMRANET, 1218 PCI_PRODUCT_QUMRANET_VIO_BLOCK, 1219 PCI_CLASS_MASS_STORAGE, 1220 PCI_SUBCLASS_MASS_STORAGE_SCSI, 1221 PCI_VENDOR_OPENBSD, 1222 PCI_PRODUCT_VIRTIO_BLOCK, 1, NULL)) { 1223 log_warnx("%s: can't add PCI virtio block " 1224 "device", __progname); 1225 return; 1226 } 1227 if (pci_add_bar(id, PCI_MAPREG_TYPE_IO, virtio_blk_io, 1228 &vioblk[i])) { 1229 log_warnx("%s: can't add bar for virtio block " 1230 "device", __progname); 1231 return; 1232 } 1233 vioblk[i].vq[0].qs = VIOBLK_QUEUE_SIZE; 1234 vioblk[i].vq[0].vq_availoffset = 1235 sizeof(struct vring_desc) * VIORND_QUEUE_SIZE; 1236 vioblk[i].vq[0].vq_usedoffset = VIRTQUEUE_ALIGN( 1237 sizeof(struct vring_desc) * VIOBLK_QUEUE_SIZE 1238 + sizeof(uint16_t) * (2 + VIOBLK_QUEUE_SIZE)); 1239 vioblk[i].vq[0].last_avail = 0; 1240 vioblk[i].fd = child_disks[i]; 1241 vioblk[i].sz = sz / 512; 1242 } 1243 } 1244 1245 if (vcp->vcp_nnics > 0) { 1246 vionet = calloc(vcp->vcp_nnics, sizeof(struct vionet_dev)); 1247 if (vionet == NULL) { 1248 log_warn("%s: calloc failure allocating vionets", 1249 __progname); 1250 return; 1251 } 1252 1253 nr_vionet = vcp->vcp_nnics; 1254 /* Virtio network */ 1255 for (i = 0; i < vcp->vcp_nnics; i++) { 1256 if (pci_add_device(&id, PCI_VENDOR_QUMRANET, 1257 PCI_PRODUCT_QUMRANET_VIO_NET, PCI_CLASS_SYSTEM, 1258 PCI_SUBCLASS_SYSTEM_MISC, 1259 PCI_VENDOR_OPENBSD, 1260 PCI_PRODUCT_VIRTIO_NETWORK, 1, NULL)) { 1261 log_warnx("%s: can't add PCI virtio net device", 1262 __progname); 1263 return; 1264 } 1265 1266 if (pci_add_bar(id, PCI_MAPREG_TYPE_IO, virtio_net_io, 1267 &vionet[i])) { 1268 log_warnx("%s: can't add bar for virtio net " 1269 "device", __progname); 1270 return; 1271 } 1272 1273 ret = pthread_mutex_init(&vionet[i].mutex, NULL); 1274 if (ret) { 1275 errno = ret; 1276 log_warn("%s: could not initialize mutex " 1277 "for vionet device", __progname); 1278 return; 1279 } 1280 1281 vionet[i].vq[0].qs = VIONET_QUEUE_SIZE; 1282 vionet[i].vq[0].vq_availoffset = 1283 sizeof(struct vring_desc) * VIONET_QUEUE_SIZE; 1284 vionet[i].vq[0].vq_usedoffset = VIRTQUEUE_ALIGN( 1285 sizeof(struct vring_desc) * VIONET_QUEUE_SIZE 1286 + sizeof(uint16_t) * (2 + VIONET_QUEUE_SIZE)); 1287 vionet[i].vq[0].last_avail = 0; 1288 vionet[i].vq[1].qs = VIONET_QUEUE_SIZE; 1289 vionet[i].vq[1].vq_availoffset = 1290 sizeof(struct vring_desc) * VIONET_QUEUE_SIZE; 1291 vionet[i].vq[1].vq_usedoffset = VIRTQUEUE_ALIGN( 1292 sizeof(struct vring_desc) * VIONET_QUEUE_SIZE 1293 + sizeof(uint16_t) * (2 + VIONET_QUEUE_SIZE)); 1294 vionet[i].vq[1].last_avail = 0; 1295 vionet[i].vq[1].notified_avail = 0; 1296 vionet[i].fd = child_taps[i]; 1297 vionet[i].rx_pending = 0; 1298 vionet[i].vm_id = vcp->vcp_id; 1299 vionet[i].irq = 9; /* XXX */ 1300 1301 event_set(&vionet[i].event, vionet[i].fd, 1302 EV_READ | EV_PERSIST, vionet_rx_event, &vionet[i]); 1303 if (event_add(&vionet[i].event, NULL)) { 1304 log_warn("could not initialize vionet event " 1305 "handler"); 1306 return; 1307 } 1308 1309 #if 0 1310 /* User defined MAC */ 1311 vionet[i].cfg.device_feature = VIRTIO_NET_F_MAC; 1312 bcopy(&vcp->vcp_macs[i], &vionet[i].mac, 6); 1313 #endif 1314 } 1315 } 1316 } 1317