]> CyberLeo.Net >> Repos - FreeBSD/stable/10.git/blob - usr.sbin/bhyve/pci_passthru.c
MFC 258859,259081,259085,259205,259213,259275,259482,259537,259702,259779:
[FreeBSD/stable/10.git] / usr.sbin / bhyve / pci_passthru.c
1 /*-
2  * Copyright (c) 2011 NetApp, Inc.
3  * All rights reserved.
4  *
5  * Redistribution and use in source and binary forms, with or without
6  * modification, are permitted provided that the following conditions
7  * are met:
8  * 1. Redistributions of source code must retain the above copyright
9  *    notice, this list of conditions and the following disclaimer.
10  * 2. Redistributions in binary form must reproduce the above copyright
11  *    notice, this list of conditions and the following disclaimer in the
12  *    documentation and/or other materials provided with the distribution.
13  *
14  * THIS SOFTWARE IS PROVIDED BY NETAPP, INC ``AS IS'' AND
15  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
16  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
17  * ARE DISCLAIMED.  IN NO EVENT SHALL NETAPP, INC OR CONTRIBUTORS BE LIABLE
18  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
19  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
20  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
21  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
22  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
23  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
24  * SUCH DAMAGE.
25  *
26  * $FreeBSD$
27  */
28
29 #include <sys/cdefs.h>
30 __FBSDID("$FreeBSD$");
31
32 #include <sys/param.h>
33 #include <sys/types.h>
34 #include <sys/pciio.h>
35 #include <sys/ioctl.h>
36
37 #include <dev/io/iodev.h>
38 #include <dev/pci/pcireg.h>
39
40 #include <machine/iodev.h>
41
42 #include <stdio.h>
43 #include <stdlib.h>
44 #include <string.h>
45 #include <errno.h>
46 #include <fcntl.h>
47 #include <unistd.h>
48
49 #include <machine/vmm.h>
50 #include <vmmapi.h>
51 #include "pci_emul.h"
52 #include "mem.h"
53
54 #ifndef _PATH_DEVPCI
55 #define _PATH_DEVPCI    "/dev/pci"
56 #endif
57
58 #ifndef _PATH_DEVIO
59 #define _PATH_DEVIO     "/dev/io"
60 #endif
61
62 #define LEGACY_SUPPORT  1
63
64 #define MSIX_TABLE_COUNT(ctrl) (((ctrl) & PCIM_MSIXCTRL_TABLE_SIZE) + 1)
65 #define MSIX_CAPLEN 12
66
67 static int pcifd = -1;
68 static int iofd = -1;
69
70 struct passthru_softc {
71         struct pci_devinst *psc_pi;
72         struct pcibar psc_bar[PCI_BARMAX + 1];
73         struct {
74                 int             capoff;
75                 int             msgctrl;
76                 int             emulated;
77         } psc_msi;
78         struct {
79                 int             capoff;
80         } psc_msix;
81         struct pcisel psc_sel;
82 };
83
84 static int
85 msi_caplen(int msgctrl)
86 {
87         int len;
88         
89         len = 10;               /* minimum length of msi capability */
90
91         if (msgctrl & PCIM_MSICTRL_64BIT)
92                 len += 4;
93
94 #if 0
95         /*
96          * Ignore the 'mask' and 'pending' bits in the MSI capability.
97          * We'll let the guest manipulate them directly.
98          */
99         if (msgctrl & PCIM_MSICTRL_VECTOR)
100                 len += 10;
101 #endif
102
103         return (len);
104 }
105
106 static uint32_t
107 read_config(const struct pcisel *sel, long reg, int width)
108 {
109         struct pci_io pi;
110
111         bzero(&pi, sizeof(pi));
112         pi.pi_sel = *sel;
113         pi.pi_reg = reg;
114         pi.pi_width = width;
115
116         if (ioctl(pcifd, PCIOCREAD, &pi) < 0)
117                 return (0);                             /* XXX */
118         else
119                 return (pi.pi_data);
120 }
121
122 static void
123 write_config(const struct pcisel *sel, long reg, int width, uint32_t data)
124 {
125         struct pci_io pi;
126
127         bzero(&pi, sizeof(pi));
128         pi.pi_sel = *sel;
129         pi.pi_reg = reg;
130         pi.pi_width = width;
131         pi.pi_data = data;
132
133         (void)ioctl(pcifd, PCIOCWRITE, &pi);            /* XXX */
134 }
135
136 #ifdef LEGACY_SUPPORT
137 static int
138 passthru_add_msicap(struct pci_devinst *pi, int msgnum, int nextptr)
139 {
140         int capoff, i;
141         struct msicap msicap;
142         u_char *capdata;
143
144         pci_populate_msicap(&msicap, msgnum, nextptr);
145
146         /*
147          * XXX
148          * Copy the msi capability structure in the last 16 bytes of the
149          * config space. This is wrong because it could shadow something
150          * useful to the device.
151          */
152         capoff = 256 - roundup(sizeof(msicap), 4);
153         capdata = (u_char *)&msicap;
154         for (i = 0; i < sizeof(msicap); i++)
155                 pci_set_cfgdata8(pi, capoff + i, capdata[i]);
156
157         return (capoff);
158 }
159 #endif  /* LEGACY_SUPPORT */
160
161 static int
162 cfginitmsi(struct passthru_softc *sc)
163 {
164         int i, ptr, capptr, cap, sts, caplen, table_size;
165         uint32_t u32;
166         struct pcisel sel;
167         struct pci_devinst *pi;
168         struct msixcap msixcap;
169         uint32_t *msixcap_ptr;
170
171         pi = sc->psc_pi;
172         sel = sc->psc_sel;
173
174         /*
175          * Parse the capabilities and cache the location of the MSI
176          * and MSI-X capabilities.
177          */
178         sts = read_config(&sel, PCIR_STATUS, 2);
179         if (sts & PCIM_STATUS_CAPPRESENT) {
180                 ptr = read_config(&sel, PCIR_CAP_PTR, 1);
181                 while (ptr != 0 && ptr != 0xff) {
182                         cap = read_config(&sel, ptr + PCICAP_ID, 1);
183                         if (cap == PCIY_MSI) {
184                                 /*
185                                  * Copy the MSI capability into the config
186                                  * space of the emulated pci device
187                                  */
188                                 sc->psc_msi.capoff = ptr;
189                                 sc->psc_msi.msgctrl = read_config(&sel,
190                                                                   ptr + 2, 2);
191                                 sc->psc_msi.emulated = 0;
192                                 caplen = msi_caplen(sc->psc_msi.msgctrl);
193                                 capptr = ptr;
194                                 while (caplen > 0) {
195                                         u32 = read_config(&sel, capptr, 4);
196                                         pci_set_cfgdata32(pi, capptr, u32);
197                                         caplen -= 4;
198                                         capptr += 4;
199                                 }
200                         } else if (cap == PCIY_MSIX) {
201                                 /*
202                                  * Copy the MSI-X capability 
203                                  */
204                                 sc->psc_msix.capoff = ptr;
205                                 caplen = 12;
206                                 msixcap_ptr = (uint32_t*) &msixcap;
207                                 capptr = ptr;
208                                 while (caplen > 0) {
209                                         u32 = read_config(&sel, capptr, 4);
210                                         *msixcap_ptr = u32;
211                                         pci_set_cfgdata32(pi, capptr, u32);
212                                         caplen -= 4;
213                                         capptr += 4;
214                                         msixcap_ptr++;
215                                 }
216                         }
217                         ptr = read_config(&sel, ptr + PCICAP_NEXTPTR, 1);
218                 }
219         }
220
221         if (sc->psc_msix.capoff != 0) {
222                 pi->pi_msix.pba_bar =
223                     msixcap.pba_info & PCIM_MSIX_BIR_MASK;
224                 pi->pi_msix.pba_offset =
225                     msixcap.pba_info & ~PCIM_MSIX_BIR_MASK;
226                 pi->pi_msix.table_bar =
227                     msixcap.table_info & PCIM_MSIX_BIR_MASK;
228                 pi->pi_msix.table_offset =
229                     msixcap.table_info & ~PCIM_MSIX_BIR_MASK;
230                 pi->pi_msix.table_count = MSIX_TABLE_COUNT(msixcap.msgctrl);
231
232                 /* Allocate the emulated MSI-X table array */
233                 table_size = pi->pi_msix.table_count * MSIX_TABLE_ENTRY_SIZE;
234                 pi->pi_msix.table = malloc(table_size);
235                 bzero(pi->pi_msix.table, table_size);
236
237                 /* Mask all table entries */
238                 for (i = 0; i < pi->pi_msix.table_count; i++) {
239                         pi->pi_msix.table[i].vector_control |=
240                                                 PCIM_MSIX_VCTRL_MASK;
241                 }
242         }
243
244 #ifdef LEGACY_SUPPORT
245         /*
246          * If the passthrough device does not support MSI then craft a
247          * MSI capability for it. We link the new MSI capability at the
248          * head of the list of capabilities.
249          */
250         if ((sts & PCIM_STATUS_CAPPRESENT) != 0 && sc->psc_msi.capoff == 0) {
251                 int origptr, msiptr;
252                 origptr = read_config(&sel, PCIR_CAP_PTR, 1);
253                 msiptr = passthru_add_msicap(pi, 1, origptr);
254                 sc->psc_msi.capoff = msiptr;
255                 sc->psc_msi.msgctrl = pci_get_cfgdata16(pi, msiptr + 2);
256                 sc->psc_msi.emulated = 1;
257                 pci_set_cfgdata8(pi, PCIR_CAP_PTR, msiptr);
258         }
259 #endif
260
261         /* Make sure one of the capabilities is present */
262         if (sc->psc_msi.capoff == 0 && sc->psc_msix.capoff == 0) 
263                 return (-1);
264         else
265                 return (0);
266 }
267
268 static uint64_t
269 msix_table_read(struct passthru_softc *sc, uint64_t offset, int size)
270 {
271         struct pci_devinst *pi;
272         struct msix_table_entry *entry;
273         uint8_t *src8;
274         uint16_t *src16;
275         uint32_t *src32;
276         uint64_t *src64;
277         uint64_t data;
278         size_t entry_offset;
279         int index;
280
281         pi = sc->psc_pi;
282         offset -= pi->pi_msix.table_offset;
283
284         index = offset / MSIX_TABLE_ENTRY_SIZE;
285         if (index >= pi->pi_msix.table_count)
286                 return (-1);
287
288         entry = &pi->pi_msix.table[index];
289         entry_offset = offset % MSIX_TABLE_ENTRY_SIZE;
290
291         switch(size) {
292         case 1:
293                 src8 = (uint8_t *)((void *)entry + entry_offset);
294                 data = *src8;
295                 break;
296         case 2:
297                 src16 = (uint16_t *)((void *)entry + entry_offset);
298                 data = *src16;
299                 break;
300         case 4:
301                 src32 = (uint32_t *)((void *)entry + entry_offset);
302                 data = *src32;
303                 break;
304         case 8:
305                 src64 = (uint64_t *)((void *)entry + entry_offset);
306                 data = *src64;
307                 break;
308         default:
309                 return (-1);
310         }
311
312         return (data);
313 }
314
315 static void
316 msix_table_write(struct vmctx *ctx, int vcpu, struct passthru_softc *sc,
317                  uint64_t offset, int size, uint64_t data)
318 {
319         struct pci_devinst *pi;
320         struct msix_table_entry *entry;
321         uint32_t *dest;
322         size_t entry_offset;
323         uint32_t vector_control;
324         int error, index;
325
326         pi = sc->psc_pi;
327         offset -= pi->pi_msix.table_offset;
328
329         index = offset / MSIX_TABLE_ENTRY_SIZE;
330         if (index >= pi->pi_msix.table_count)
331                 return;
332
333         entry = &pi->pi_msix.table[index];
334         entry_offset = offset % MSIX_TABLE_ENTRY_SIZE;
335
336         /* Only 4 byte naturally-aligned writes are supported */
337         assert(size == 4);
338         assert(entry_offset % 4 == 0);
339
340         vector_control = entry->vector_control;
341         dest = (uint32_t *)((void *)entry + entry_offset);
342         *dest = data;
343         /* If MSI-X hasn't been enabled, do nothing */
344         if (pi->pi_msix.enabled) {
345                 /* If the entry is masked, don't set it up */
346                 if ((entry->vector_control & PCIM_MSIX_VCTRL_MASK) == 0 ||
347                     (vector_control & PCIM_MSIX_VCTRL_MASK) == 0) {
348                         error = vm_setup_pptdev_msix(ctx, vcpu,
349                             sc->psc_sel.pc_bus, sc->psc_sel.pc_dev, 
350                             sc->psc_sel.pc_func, index, entry->addr,
351                             entry->msg_data, entry->vector_control);
352                 }
353         }
354 }
355
356 static int
357 init_msix_table(struct vmctx *ctx, struct passthru_softc *sc, uint64_t base)
358 {
359         int b, s, f;
360         int error, idx;
361         size_t len, remaining, table_size;
362         vm_paddr_t start;
363         struct pci_devinst *pi = sc->psc_pi;
364
365         assert(pci_msix_table_bar(pi) >= 0 && pci_msix_pba_bar(pi) >= 0);
366
367         b = sc->psc_sel.pc_bus;
368         s = sc->psc_sel.pc_dev;
369         f = sc->psc_sel.pc_func;
370
371         /* 
372          * If the MSI-X table BAR maps memory intended for
373          * other uses, it is at least assured that the table 
374          * either resides in its own page within the region, 
375          * or it resides in a page shared with only the PBA.
376          */
377         if (pi->pi_msix.pba_bar == pi->pi_msix.table_bar && 
378             ((pi->pi_msix.pba_offset - pi->pi_msix.table_offset) < 4096)) {
379                 /* Need to also emulate the PBA, not supported yet */
380                 printf("Unsupported MSI-X configuration: %d/%d/%d\n", b, s, f);
381                 return (-1);
382         }
383
384         /* Compute the MSI-X table size */
385         table_size = pi->pi_msix.table_count * MSIX_TABLE_ENTRY_SIZE;
386         table_size = roundup2(table_size, 4096);
387
388         idx = pi->pi_msix.table_bar;
389         start = pi->pi_bar[idx].addr;
390         remaining = pi->pi_bar[idx].size;
391
392         /* Map everything before the MSI-X table */
393         if (pi->pi_msix.table_offset > 0) {
394                 len = pi->pi_msix.table_offset;
395                 error = vm_map_pptdev_mmio(ctx, b, s, f, start, len, base);
396                 if (error)
397                         return (error);
398
399                 base += len;
400                 start += len;
401                 remaining -= len;
402         }
403
404         /* Skip the MSI-X table */
405         base += table_size;
406         start += table_size;
407         remaining -= table_size;
408
409         /* Map everything beyond the end of the MSI-X table */
410         if (remaining > 0) {
411                 len = remaining;
412                 error = vm_map_pptdev_mmio(ctx, b, s, f, start, len, base);
413                 if (error)
414                         return (error);
415         }
416
417         return (0);
418 }
419
420 static int
421 cfginitbar(struct vmctx *ctx, struct passthru_softc *sc)
422 {
423         int i, error;
424         struct pci_devinst *pi;
425         struct pci_bar_io bar;
426         enum pcibar_type bartype;
427         uint64_t base;
428
429         pi = sc->psc_pi;
430
431         /*
432          * Initialize BAR registers
433          */
434         for (i = 0; i <= PCI_BARMAX; i++) {
435                 bzero(&bar, sizeof(bar));
436                 bar.pbi_sel = sc->psc_sel;
437                 bar.pbi_reg = PCIR_BAR(i);
438
439                 if (ioctl(pcifd, PCIOCGETBAR, &bar) < 0)
440                         continue;
441
442                 if (PCI_BAR_IO(bar.pbi_base)) {
443                         bartype = PCIBAR_IO;
444                         base = bar.pbi_base & PCIM_BAR_IO_BASE;
445                 } else {
446                         switch (bar.pbi_base & PCIM_BAR_MEM_TYPE) {
447                         case PCIM_BAR_MEM_64:
448                                 bartype = PCIBAR_MEM64;
449                                 break;
450                         default:
451                                 bartype = PCIBAR_MEM32;
452                                 break;
453                         }
454                         base = bar.pbi_base & PCIM_BAR_MEM_BASE;
455                 }
456
457                 /* Cache information about the "real" BAR */
458                 sc->psc_bar[i].type = bartype;
459                 sc->psc_bar[i].size = bar.pbi_length;
460                 sc->psc_bar[i].addr = base;
461
462                 /* Allocate the BAR in the guest I/O or MMIO space */
463                 error = pci_emul_alloc_pbar(pi, i, base, bartype,
464                                             bar.pbi_length);
465                 if (error)
466                         return (-1);
467
468                 /* The MSI-X table needs special handling */
469                 if (i == pci_msix_table_bar(pi)) {
470                         error = init_msix_table(ctx, sc, base);
471                         if (error) 
472                                 return (-1);
473                 } else if (bartype != PCIBAR_IO) {
474                         /* Map the physical MMIO space in the guest MMIO space */
475                         error = vm_map_pptdev_mmio(ctx, sc->psc_sel.pc_bus,
476                                 sc->psc_sel.pc_dev, sc->psc_sel.pc_func,
477                                 pi->pi_bar[i].addr, pi->pi_bar[i].size, base);
478                         if (error)
479                                 return (-1);
480                 }
481
482                 /*
483                  * 64-bit BAR takes up two slots so skip the next one.
484                  */
485                 if (bartype == PCIBAR_MEM64) {
486                         i++;
487                         assert(i <= PCI_BARMAX);
488                         sc->psc_bar[i].type = PCIBAR_MEMHI64;
489                 }
490         }
491         return (0);
492 }
493
494 static int
495 cfginit(struct vmctx *ctx, struct pci_devinst *pi, int bus, int slot, int func)
496 {
497         int error;
498         struct passthru_softc *sc;
499
500         error = 1;
501         sc = pi->pi_arg;
502
503         bzero(&sc->psc_sel, sizeof(struct pcisel));
504         sc->psc_sel.pc_bus = bus;
505         sc->psc_sel.pc_dev = slot;
506         sc->psc_sel.pc_func = func;
507
508         if (cfginitmsi(sc) != 0)
509                 goto done;
510
511         if (cfginitbar(ctx, sc) != 0)
512                 goto done;
513
514         error = 0;                              /* success */
515 done:
516         return (error);
517 }
518
519 static int
520 passthru_init(struct vmctx *ctx, struct pci_devinst *pi, char *opts)
521 {
522         int bus, slot, func, error;
523         struct passthru_softc *sc;
524
525         sc = NULL;
526         error = 1;
527
528         if (pcifd < 0) {
529                 pcifd = open(_PATH_DEVPCI, O_RDWR, 0);
530                 if (pcifd < 0)
531                         goto done;
532         }
533
534         if (iofd < 0) {
535                 iofd = open(_PATH_DEVIO, O_RDWR, 0);
536                 if (iofd < 0)
537                         goto done;
538         }
539
540         if (opts == NULL ||
541             sscanf(opts, "%d/%d/%d", &bus, &slot, &func) != 3)
542                 goto done;
543
544         if (vm_assign_pptdev(ctx, bus, slot, func) != 0)
545                 goto done;
546
547         sc = malloc(sizeof(struct passthru_softc));
548         memset(sc, 0, sizeof(struct passthru_softc));
549
550         pi->pi_arg = sc;
551         sc->psc_pi = pi;
552
553         /* initialize config space */
554         if ((error = cfginit(ctx, pi, bus, slot, func)) != 0)
555                 goto done;
556         
557         error = 0;              /* success */
558 done:
559         if (error) {
560                 free(sc);
561                 vm_unassign_pptdev(ctx, bus, slot, func);
562         }
563         return (error);
564 }
565
566 static int
567 bar_access(int coff)
568 {
569         if (coff >= PCIR_BAR(0) && coff < PCIR_BAR(PCI_BARMAX + 1))
570                 return (1);
571         else
572                 return (0);
573 }
574
575 static int
576 msicap_access(struct passthru_softc *sc, int coff)
577 {
578         int caplen;
579
580         if (sc->psc_msi.capoff == 0)
581                 return (0);
582
583         caplen = msi_caplen(sc->psc_msi.msgctrl);
584
585         if (coff >= sc->psc_msi.capoff && coff < sc->psc_msi.capoff + caplen)
586                 return (1);
587         else
588                 return (0);
589 }
590
591 static int 
592 msixcap_access(struct passthru_softc *sc, int coff)
593 {
594         if (sc->psc_msix.capoff == 0) 
595                 return (0);
596
597         return (coff >= sc->psc_msix.capoff && 
598                 coff < sc->psc_msix.capoff + MSIX_CAPLEN);
599 }
600
601 static int
602 passthru_cfgread(struct vmctx *ctx, int vcpu, struct pci_devinst *pi,
603                  int coff, int bytes, uint32_t *rv)
604 {
605         struct passthru_softc *sc;
606
607         sc = pi->pi_arg;
608
609         /*
610          * PCI BARs and MSI capability is emulated.
611          */
612         if (bar_access(coff) || msicap_access(sc, coff))
613                 return (-1);
614
615 #ifdef LEGACY_SUPPORT
616         /*
617          * Emulate PCIR_CAP_PTR if this device does not support MSI capability
618          * natively.
619          */
620         if (sc->psc_msi.emulated) {
621                 if (coff >= PCIR_CAP_PTR && coff < PCIR_CAP_PTR + 4)
622                         return (-1);
623         }
624 #endif
625
626         /* Everything else just read from the device's config space */
627         *rv = read_config(&sc->psc_sel, coff, bytes);
628
629         return (0);
630 }
631
632 static int
633 passthru_cfgwrite(struct vmctx *ctx, int vcpu, struct pci_devinst *pi,
634                   int coff, int bytes, uint32_t val)
635 {
636         int error, msix_table_entries, i;
637         struct passthru_softc *sc;
638
639         sc = pi->pi_arg;
640
641         /*
642          * PCI BARs are emulated
643          */
644         if (bar_access(coff))
645                 return (-1);
646
647         /*
648          * MSI capability is emulated
649          */
650         if (msicap_access(sc, coff)) {
651                 msicap_cfgwrite(pi, sc->psc_msi.capoff, coff, bytes, val);
652
653                 error = vm_setup_pptdev_msi(ctx, vcpu, sc->psc_sel.pc_bus,
654                         sc->psc_sel.pc_dev, sc->psc_sel.pc_func,
655                         pi->pi_msi.addr, pi->pi_msi.msg_data,
656                         pi->pi_msi.maxmsgnum);
657                 if (error != 0) {
658                         printf("vm_setup_pptdev_msi error %d\r\n", errno);
659                         exit(1);
660                 }
661                 return (0);
662         }
663
664         if (msixcap_access(sc, coff)) {
665                 msixcap_cfgwrite(pi, sc->psc_msix.capoff, coff, bytes, val);
666                 if (pi->pi_msix.enabled) {
667                         msix_table_entries = pi->pi_msix.table_count;
668                         for (i = 0; i < msix_table_entries; i++) {
669                                 error = vm_setup_pptdev_msix(ctx, vcpu,
670                                     sc->psc_sel.pc_bus, sc->psc_sel.pc_dev, 
671                                     sc->psc_sel.pc_func, i, 
672                                     pi->pi_msix.table[i].addr,
673                                     pi->pi_msix.table[i].msg_data,
674                                     pi->pi_msix.table[i].vector_control);
675                 
676                                 if (error) {
677                                         printf("vm_setup_pptdev_msix error "
678                                             "%d\r\n", errno);
679                                         exit(1);        
680                                 }
681                         }
682                 }
683                 return (0);
684         }
685
686 #ifdef LEGACY_SUPPORT
687         /*
688          * If this device does not support MSI natively then we cannot let
689          * the guest disable legacy interrupts from the device. It is the
690          * legacy interrupt that is triggering the virtual MSI to the guest.
691          */
692         if (sc->psc_msi.emulated && pci_msi_enabled(pi)) {
693                 if (coff == PCIR_COMMAND && bytes == 2)
694                         val &= ~PCIM_CMD_INTxDIS;
695         }
696 #endif
697
698         write_config(&sc->psc_sel, coff, bytes, val);
699
700         return (0);
701 }
702
703 static void
704 passthru_write(struct vmctx *ctx, int vcpu, struct pci_devinst *pi, int baridx,
705                uint64_t offset, int size, uint64_t value)
706 {
707         struct passthru_softc *sc;
708         struct iodev_pio_req pio;
709
710         sc = pi->pi_arg;
711
712         if (baridx == pci_msix_table_bar(pi)) {
713                 msix_table_write(ctx, vcpu, sc, offset, size, value);
714         } else {
715                 assert(pi->pi_bar[baridx].type == PCIBAR_IO);
716                 bzero(&pio, sizeof(struct iodev_pio_req));
717                 pio.access = IODEV_PIO_WRITE;
718                 pio.port = sc->psc_bar[baridx].addr + offset;
719                 pio.width = size;
720                 pio.val = value;
721                 
722                 (void)ioctl(iofd, IODEV_PIO, &pio);
723         }
724 }
725
726 static uint64_t
727 passthru_read(struct vmctx *ctx, int vcpu, struct pci_devinst *pi, int baridx,
728               uint64_t offset, int size)
729 {
730         struct passthru_softc *sc;
731         struct iodev_pio_req pio;
732         uint64_t val;
733
734         sc = pi->pi_arg;
735
736         if (baridx == pci_msix_table_bar(pi)) {
737                 val = msix_table_read(sc, offset, size);
738         } else {
739                 assert(pi->pi_bar[baridx].type == PCIBAR_IO);
740                 bzero(&pio, sizeof(struct iodev_pio_req));
741                 pio.access = IODEV_PIO_READ;
742                 pio.port = sc->psc_bar[baridx].addr + offset;
743                 pio.width = size;
744                 pio.val = 0;
745
746                 (void)ioctl(iofd, IODEV_PIO, &pio);
747
748                 val = pio.val;
749         }
750
751         return (val);
752 }
753
754 struct pci_devemu passthru = {
755         .pe_emu         = "passthru",
756         .pe_init        = passthru_init,
757         .pe_cfgwrite    = passthru_cfgwrite,
758         .pe_cfgread     = passthru_cfgread,
759         .pe_barwrite    = passthru_write,
760         .pe_barread     = passthru_read,
761 };
762 PCI_EMUL_SET(passthru);