xref: /openbsd-src/usr.sbin/vmd/virtio.c (revision f2da64fbbbf1b03f09f390ab01267c93dfd77c4c)
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