2 * SPDX-License-Identifier: BSD-2-Clause-FreeBSD
4 * Copyright (c) 2011 NetApp, Inc.
7 * Redistribution and use in source and binary forms, with or without
8 * modification, are permitted provided that the following conditions
10 * 1. Redistributions of source code must retain the above copyright
11 * notice, this list of conditions and the following disclaimer.
12 * 2. Redistributions in binary form must reproduce the above copyright
13 * notice, this list of conditions and the following disclaimer in the
14 * documentation and/or other materials provided with the distribution.
16 * THIS SOFTWARE IS PROVIDED BY NETAPP, INC ``AS IS'' AND
17 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
18 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
19 * ARE DISCLAIMED. IN NO EVENT SHALL NETAPP, INC OR CONTRIBUTORS BE LIABLE
20 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
21 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
22 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
23 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
24 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
25 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
31 #include <sys/cdefs.h>
32 __FBSDID("$FreeBSD$");
34 #include <sys/param.h>
35 #include <sys/types.h>
37 #include <sys/pciio.h>
38 #include <sys/ioctl.h>
43 #include <dev/io/iodev.h>
44 #include <dev/pci/pcireg.h>
46 #include <machine/iodev.h>
57 #include <machine/vmm.h>
59 #include <sys/ppt_dev.h>
63 #include "pci_passthru.h"
66 #define LEGACY_SUPPORT 1
68 #define MSIX_TABLE_COUNT(ctrl) (((ctrl) & PCIM_MSIXCTRL_TABLE_SIZE) + 1)
69 #define MSIX_CAPLEN 12
71 struct passthru_softc
{
72 struct pci_devinst
*psc_pi
;
73 /* ROM is handled like a BAR */
74 struct pcibar psc_bar
[PCI_BARMAX_WITH_ROM
+ 1];
89 msi_caplen(int msgctrl
)
93 len
= 10; /* minimum length of msi capability */
95 if (msgctrl
& PCIM_MSICTRL_64BIT
)
100 * Ignore the 'mask' and 'pending' bits in the MSI capability.
101 * We'll let the guest manipulate them directly.
103 if (msgctrl
& PCIM_MSICTRL_VECTOR
)
111 passthru_read_config(const struct passthru_softc
*sc
, long reg
, int width
)
113 struct ppt_cfg_io pi
;
116 pi
.pci_width
= width
;
118 if (ioctl(sc
->pptfd
, PPT_CFG_READ
, &pi
) != 0) {
121 return (pi
.pci_data
);
125 passthru_write_config(const struct passthru_softc
*sc
, long reg
, int width
,
128 struct ppt_cfg_io pi
;
131 pi
.pci_width
= width
;
134 (void) ioctl(sc
->pptfd
, PPT_CFG_WRITE
, &pi
);
138 read_config(struct pci_devinst
*pi
, long reg
, int width
)
140 struct passthru_softc
*sc
= pi
->pi_arg
;
142 return (passthru_read_config(sc
, reg
, width
));
146 write_config(struct pci_devinst
*pi
, long reg
, int width
, uint32_t data
)
148 struct passthru_softc
*sc
= pi
->pi_arg
;
150 passthru_write_config(sc
, reg
, width
, data
);
154 passthru_get_bar(struct passthru_softc
*sc
, int bar
, enum pcibar_type
*type
,
155 uint64_t *base
, uint64_t *size
)
157 struct ppt_bar_query pb
;
161 if (ioctl(sc
->pptfd
, PPT_BAR_QUERY
, &pb
) != 0) {
165 switch (pb
.pbq_type
) {
170 *type
= PCIBAR_MEM32
;
173 *type
= PCIBAR_MEM64
;
176 err(1, "unrecognized BAR type: %u\n", pb
.pbq_type
);
186 passthru_dev_open(const char *path
, int *pptfdp
)
190 if ((pptfd
= open(path
, O_RDWR
)) < 0) {
194 /* XXX: verify fd with ioctl? */
199 #ifdef LEGACY_SUPPORT
201 passthru_add_msicap(struct pci_devinst
*pi
, int msgnum
, int nextptr
)
204 struct msicap msicap
;
207 pci_populate_msicap(&msicap
, msgnum
, nextptr
);
211 * Copy the msi capability structure in the last 16 bytes of the
212 * config space. This is wrong because it could shadow something
213 * useful to the device.
215 capoff
= 256 - roundup(sizeof(msicap
), 4);
216 capdata
= (u_char
*)&msicap
;
217 for (size_t i
= 0; i
< sizeof(msicap
); i
++)
218 pci_set_cfgdata8(pi
, capoff
+ i
, capdata
[i
]);
222 #endif /* LEGACY_SUPPORT */
225 passthru_intr_limit(struct passthru_softc
*sc
, struct msixcap
*msixcap
)
227 struct pci_devinst
*pi
= sc
->psc_pi
;
230 /* Reduce the number of MSI vectors if higher than OS limit */
231 if ((off
= sc
->psc_msi
.capoff
) != 0 && sc
->msi_limit
!= -1) {
235 sc
->msi_limit
> 16 ? PCIM_MSICTRL_MMC_32
:
236 sc
->msi_limit
> 8 ? PCIM_MSICTRL_MMC_16
:
237 sc
->msi_limit
> 4 ? PCIM_MSICTRL_MMC_8
:
238 sc
->msi_limit
> 2 ? PCIM_MSICTRL_MMC_4
:
239 sc
->msi_limit
> 1 ? PCIM_MSICTRL_MMC_2
:
241 mmc
= sc
->psc_msi
.msgctrl
& PCIM_MSICTRL_MMC_MASK
;
243 if (mmc
> msi_limit
) {
244 sc
->psc_msi
.msgctrl
&= ~PCIM_MSICTRL_MMC_MASK
;
245 sc
->psc_msi
.msgctrl
|= msi_limit
;
246 pci_set_cfgdata16(pi
, off
+ 2, sc
->psc_msi
.msgctrl
);
250 /* Reduce the number of MSI-X vectors if higher than OS limit */
251 if ((off
= sc
->psc_msix
.capoff
) != 0 && sc
->msix_limit
!= -1) {
252 if (MSIX_TABLE_COUNT(msixcap
->msgctrl
) > sc
->msix_limit
) {
253 msixcap
->msgctrl
&= ~PCIM_MSIXCTRL_TABLE_SIZE
;
254 msixcap
->msgctrl
|= sc
->msix_limit
- 1;
255 pci_set_cfgdata16(pi
, off
+ 2, msixcap
->msgctrl
);
261 cfginitmsi(struct passthru_softc
*sc
)
263 int i
, ptr
, capptr
, cap
, sts
, caplen
, table_size
;
265 struct pci_devinst
*pi
= sc
->psc_pi
;
266 struct msixcap msixcap
;
270 * Parse the capabilities and cache the location of the MSI
271 * and MSI-X capabilities.
273 sts
= passthru_read_config(sc
, PCIR_STATUS
, 2);
274 if (sts
& PCIM_STATUS_CAPPRESENT
) {
275 ptr
= passthru_read_config(sc
, PCIR_CAP_PTR
, 1);
276 while (ptr
!= 0 && ptr
!= 0xff) {
277 cap
= passthru_read_config(sc
, ptr
+ PCICAP_ID
, 1);
278 if (cap
== PCIY_MSI
) {
280 * Copy the MSI capability into the config
281 * space of the emulated pci device
283 sc
->psc_msi
.capoff
= ptr
;
284 sc
->psc_msi
.msgctrl
= passthru_read_config(sc
,
286 sc
->psc_msi
.emulated
= 0;
287 caplen
= msi_caplen(sc
->psc_msi
.msgctrl
);
290 u32
= passthru_read_config(sc
,
292 pci_set_cfgdata32(pi
, capptr
, u32
);
296 } else if (cap
== PCIY_MSIX
) {
298 * Copy the MSI-X capability
300 sc
->psc_msix
.capoff
= ptr
;
302 msixcap_ptr
= (char *)&msixcap
;
305 u32
= passthru_read_config(sc
,
307 memcpy(msixcap_ptr
, &u32
, 4);
308 pci_set_cfgdata32(pi
, capptr
, u32
);
314 ptr
= passthru_read_config(sc
, ptr
+ PCICAP_NEXTPTR
, 1);
318 passthru_intr_limit(sc
, &msixcap
);
320 if (sc
->psc_msix
.capoff
!= 0) {
321 pi
->pi_msix
.pba_bar
=
322 msixcap
.pba_info
& PCIM_MSIX_BIR_MASK
;
323 pi
->pi_msix
.pba_offset
=
324 msixcap
.pba_info
& ~PCIM_MSIX_BIR_MASK
;
325 pi
->pi_msix
.table_bar
=
326 msixcap
.table_info
& PCIM_MSIX_BIR_MASK
;
327 pi
->pi_msix
.table_offset
=
328 msixcap
.table_info
& ~PCIM_MSIX_BIR_MASK
;
329 pi
->pi_msix
.table_count
= MSIX_TABLE_COUNT(msixcap
.msgctrl
);
330 pi
->pi_msix
.pba_size
= PBA_SIZE(pi
->pi_msix
.table_count
);
332 /* Allocate the emulated MSI-X table array */
333 table_size
= pi
->pi_msix
.table_count
* MSIX_TABLE_ENTRY_SIZE
;
334 pi
->pi_msix
.table
= calloc(1, table_size
);
336 /* Mask all table entries */
337 for (i
= 0; i
< pi
->pi_msix
.table_count
; i
++) {
338 pi
->pi_msix
.table
[i
].vector_control
|=
339 PCIM_MSIX_VCTRL_MASK
;
343 #ifdef LEGACY_SUPPORT
345 * If the passthrough device does not support MSI then craft a
346 * MSI capability for it. We link the new MSI capability at the
347 * head of the list of capabilities.
349 if ((sts
& PCIM_STATUS_CAPPRESENT
) != 0 && sc
->psc_msi
.capoff
== 0) {
351 origptr
= passthru_read_config(sc
, PCIR_CAP_PTR
, 1);
352 msiptr
= passthru_add_msicap(pi
, 1, origptr
);
353 sc
->psc_msi
.capoff
= msiptr
;
354 sc
->psc_msi
.msgctrl
= pci_get_cfgdata16(pi
, msiptr
+ 2);
355 sc
->psc_msi
.emulated
= 1;
356 pci_set_cfgdata8(pi
, PCIR_CAP_PTR
, msiptr
);
360 /* Make sure one of the capabilities is present */
361 if (sc
->psc_msi
.capoff
== 0 && sc
->psc_msix
.capoff
== 0)
368 msix_table_read(struct passthru_softc
*sc
, uint64_t offset
, int size
)
370 struct pci_devinst
*pi
;
371 struct msix_table_entry
*entry
;
378 uint32_t table_offset
;
379 int index
, table_count
;
383 table_offset
= pi
->pi_msix
.table_offset
;
384 table_count
= pi
->pi_msix
.table_count
;
385 if (offset
< table_offset
||
386 offset
>= table_offset
+ table_count
* MSIX_TABLE_ENTRY_SIZE
) {
389 src8
= (uint8_t *)(pi
->pi_msix
.mapped_addr
+ offset
);
393 src16
= (uint16_t *)(pi
->pi_msix
.mapped_addr
+ offset
);
397 src32
= (uint32_t *)(pi
->pi_msix
.mapped_addr
+ offset
);
401 src64
= (uint64_t *)(pi
->pi_msix
.mapped_addr
+ offset
);
410 offset
-= table_offset
;
411 index
= offset
/ MSIX_TABLE_ENTRY_SIZE
;
412 assert(index
< table_count
);
414 entry
= &pi
->pi_msix
.table
[index
];
415 entry_offset
= offset
% MSIX_TABLE_ENTRY_SIZE
;
419 src8
= (uint8_t *)((uint8_t *)entry
+ entry_offset
);
423 src16
= (uint16_t *)((uint8_t *)entry
+ entry_offset
);
427 src32
= (uint32_t *)((uint8_t *)entry
+ entry_offset
);
431 src64
= (uint64_t *)((uint8_t *)entry
+ entry_offset
);
442 msix_table_write(struct vmctx
*ctx
, struct passthru_softc
*sc
,
443 uint64_t offset
, int size
, uint64_t data
)
445 struct pci_devinst
*pi
;
446 struct msix_table_entry
*entry
;
452 uint32_t table_offset
, vector_control
;
453 int index
, table_count
;
457 table_offset
= pi
->pi_msix
.table_offset
;
458 table_count
= pi
->pi_msix
.table_count
;
459 if (offset
< table_offset
||
460 offset
>= table_offset
+ table_count
* MSIX_TABLE_ENTRY_SIZE
) {
463 dest8
= (uint8_t *)(pi
->pi_msix
.mapped_addr
+ offset
);
467 dest16
= (uint16_t *)(pi
->pi_msix
.mapped_addr
+ offset
);
471 dest32
= (uint32_t *)(pi
->pi_msix
.mapped_addr
+ offset
);
475 dest64
= (uint64_t *)(pi
->pi_msix
.mapped_addr
+ offset
);
482 offset
-= table_offset
;
483 index
= offset
/ MSIX_TABLE_ENTRY_SIZE
;
484 assert(index
< table_count
);
486 entry
= &pi
->pi_msix
.table
[index
];
487 entry_offset
= offset
% MSIX_TABLE_ENTRY_SIZE
;
489 /* Only 4 byte naturally-aligned writes are supported */
491 assert(entry_offset
% 4 == 0);
493 vector_control
= entry
->vector_control
;
494 dest32
= (uint32_t *)((uint8_t *)entry
+ entry_offset
);
496 /* If MSI-X hasn't been enabled, do nothing */
497 if (pi
->pi_msix
.enabled
) {
498 /* If the entry is masked, don't set it up */
499 if ((entry
->vector_control
& PCIM_MSIX_VCTRL_MASK
) == 0 ||
500 (vector_control
& PCIM_MSIX_VCTRL_MASK
) == 0) {
501 (void) vm_setup_pptdev_msix(ctx
, 0, sc
->pptfd
,
502 index
, entry
->addr
, entry
->msg_data
,
503 entry
->vector_control
);
509 init_msix_table(struct vmctx
*ctx __unused
, struct passthru_softc
*sc
)
511 struct pci_devinst
*pi
= sc
->psc_pi
;
512 uint32_t table_size
, table_offset
;
515 i
= pci_msix_table_bar(pi
);
519 * Map the region of the BAR containing the MSI-X table. This is
520 * necessary for two reasons:
521 * 1. The PBA may reside in the first or last page containing the MSI-X
523 * 2. While PCI devices are not supposed to use the page(s) containing
524 * the MSI-X table for other purposes, some do in practice.
528 * Mapping pptfd provides access to the BAR containing the MSI-X
529 * table. See ppt_devmap() in usr/src/uts/intel/io/vmm/io/ppt.c
531 * This maps the whole BAR and then mprotect(PROT_NONE) is used below
532 * to prevent access to pages that don't contain the MSI-X table.
533 * When porting this, it was tempting to just map the MSI-X table pages
534 * but that would mean updating everywhere that assumes that
535 * pi->pi_msix.mapped_addr points to the start of the BAR. For now,
536 * keep closer to upstream.
538 pi
->pi_msix
.mapped_size
= sc
->psc_bar
[i
].size
;
539 pi
->pi_msix
.mapped_addr
= (uint8_t *)mmap(NULL
, pi
->pi_msix
.mapped_size
,
540 PROT_READ
| PROT_WRITE
, MAP_SHARED
, sc
->pptfd
, 0);
541 if (pi
->pi_msix
.mapped_addr
== MAP_FAILED
) {
542 warn("Failed to map MSI-X table BAR on %d", sc
->pptfd
);
546 table_offset
= rounddown2(pi
->pi_msix
.table_offset
, 4096);
548 table_size
= pi
->pi_msix
.table_offset
- table_offset
;
549 table_size
+= pi
->pi_msix
.table_count
* MSIX_TABLE_ENTRY_SIZE
;
550 table_size
= roundup2(table_size
, 4096);
553 * Unmap any pages not containing the table, we do not need to emulate
554 * accesses to them. Avoid releasing address space to help ensure that
555 * a buggy out-of-bounds access causes a crash.
557 if (table_offset
!= 0)
558 if (mprotect((caddr_t
)pi
->pi_msix
.mapped_addr
, table_offset
,
560 warn("Failed to unmap MSI-X table BAR region");
561 if (table_offset
+ table_size
!= pi
->pi_msix
.mapped_size
)
562 if (mprotect((caddr_t
)
563 pi
->pi_msix
.mapped_addr
+ table_offset
+ table_size
,
564 pi
->pi_msix
.mapped_size
- (table_offset
+ table_size
),
566 warn("Failed to unmap MSI-X table BAR region");
572 cfginitbar(struct vmctx
*ctx __unused
, struct passthru_softc
*sc
)
574 struct pci_devinst
*pi
= sc
->psc_pi
;
578 * Initialize BAR registers
580 for (i
= 0; i
<= PCI_BARMAX
; i
++) {
581 enum pcibar_type bartype
;
585 if (passthru_get_bar(sc
, i
, &bartype
, &base
, &size
) != 0) {
589 if (bartype
!= PCIBAR_IO
) {
590 if (((base
| size
) & PAGE_MASK
) != 0) {
591 warnx("passthru device %d BAR %d: "
592 "base %#lx or size %#lx not page aligned\n",
593 sc
->pptfd
, i
, base
, size
);
598 /* Cache information about the "real" BAR */
599 sc
->psc_bar
[i
].type
= bartype
;
600 sc
->psc_bar
[i
].size
= size
;
601 sc
->psc_bar
[i
].addr
= base
;
602 sc
->psc_bar
[i
].lobits
= 0;
604 /* Allocate the BAR in the guest I/O or MMIO space */
605 error
= pci_emul_alloc_bar(pi
, i
, bartype
, size
);
609 /* Use same lobits as physical bar */
610 uint8_t lobits
= passthru_read_config(sc
, PCIR_BAR(i
), 0x01);
611 if (bartype
== PCIBAR_MEM32
|| bartype
== PCIBAR_MEM64
) {
612 lobits
&= ~PCIM_BAR_MEM_BASE
;
614 lobits
&= ~PCIM_BAR_IO_BASE
;
616 sc
->psc_bar
[i
].lobits
= lobits
;
617 pi
->pi_bar
[i
].lobits
= lobits
;
620 * 64-bit BAR takes up two slots so skip the next one.
622 if (bartype
== PCIBAR_MEM64
) {
624 assert(i
<= PCI_BARMAX
);
625 sc
->psc_bar
[i
].type
= PCIBAR_MEMHI64
;
632 cfginit(struct vmctx
*ctx
, struct passthru_softc
*sc
)
634 struct pci_devinst
*pi
= sc
->psc_pi
;
637 if (cfginitmsi(sc
) != 0) {
638 warnx("failed to initialize MSI for PCI %d", sc
->pptfd
);
642 if (cfginitbar(ctx
, sc
) != 0) {
643 warnx("failed to initialize BARs for PCI %d", sc
->pptfd
);
647 passthru_write_config(sc
, PCIR_COMMAND
, 2,
648 pci_get_cfgdata16(pi
, PCIR_COMMAND
));
651 * We need to do this after PCIR_COMMAND got possibly updated, e.g.,
654 if (pci_msix_table_bar(pi
) >= 0) {
655 error
= init_msix_table(ctx
, sc
);
657 warnx("failed to initialize MSI-X table for PCI %d",
663 error
= 0; /* success */
669 passthru_legacy_config(nvlist_t
*nvl
, const char *opt
)
671 char *config
, *name
, *tofree
, *value
;
676 config
= tofree
= strdup(opt
);
677 while ((name
= strsep(&config
, ",")) != NULL
) {
678 value
= strchr(name
, '=');
681 set_config_value_node(nvl
, name
, value
);
683 if (strncmp(name
, "/dev/ppt", 8) != 0) {
684 EPRINTLN("passthru: invalid path \"%s\"", name
);
688 set_config_value_node(nvl
, "path", name
);
696 passthru_init_rom(struct vmctx
*const ctx __unused
,
697 struct passthru_softc
*const sc
, const char *const romfile
)
699 if (romfile
== NULL
) {
703 const int fd
= open(romfile
, O_RDONLY
);
705 warnx("%s: can't open romfile \"%s\"", __func__
, romfile
);
710 if (fstat(fd
, &sbuf
) < 0) {
711 warnx("%s: can't fstat romfile \"%s\"", __func__
, romfile
);
715 const uint64_t rom_size
= sbuf
.st_size
;
717 void *const rom_data
= mmap(NULL
, rom_size
, PROT_READ
, MAP_SHARED
, fd
,
719 if (rom_data
== MAP_FAILED
) {
720 warnx("%s: unable to mmap romfile \"%s\" (%d)", __func__
,
727 int error
= pci_emul_alloc_rom(sc
->psc_pi
, rom_size
, &rom_addr
);
729 warnx("%s: failed to alloc rom segment", __func__
);
730 munmap(rom_data
, rom_size
);
734 memcpy(rom_addr
, rom_data
, rom_size
);
736 sc
->psc_bar
[PCI_ROM_IDX
].type
= PCIBAR_ROM
;
737 sc
->psc_bar
[PCI_ROM_IDX
].addr
= (uint64_t)rom_addr
;
738 sc
->psc_bar
[PCI_ROM_IDX
].size
= rom_size
;
740 munmap(rom_data
, rom_size
);
747 passthru_init(struct vmctx
*ctx
, struct pci_devinst
*pi
, nvlist_t
*nvl
)
749 int error
, memflags
, pptfd
;
750 struct passthru_softc
*sc
;
757 memflags
= vm_get_memflags(ctx
);
758 if (!(memflags
& VM_MEM_F_WIRED
)) {
759 warnx("passthru requires guest memory to be wired");
763 path
= get_config_value_node(nvl
, "path");
764 if (path
== NULL
|| passthru_dev_open(path
, &pptfd
) != 0) {
765 warnx("invalid passthru options");
769 if (vm_assign_pptdev(ctx
, pptfd
) != 0) {
770 warnx("PCI device at %d is not using the ppt driver", pptfd
);
774 sc
= calloc(1, sizeof(struct passthru_softc
));
780 if ((error
= vm_get_pptdev_limits(ctx
, pptfd
, &sc
->msi_limit
,
781 &sc
->msix_limit
)) != 0)
784 /* initialize config space */
785 if ((error
= cfginit(ctx
, sc
)) != 0)
789 if ((error
= passthru_init_rom(ctx
, sc
,
790 get_config_value_node(nvl
, "rom"))) != 0) {
798 vm_unassign_pptdev(ctx
, pptfd
);
806 if ((coff
>= PCIR_BAR(0) && coff
< PCIR_BAR(PCI_BARMAX
+ 1)) ||
814 msicap_access(struct passthru_softc
*sc
, int coff
)
818 if (sc
->psc_msi
.capoff
== 0)
821 caplen
= msi_caplen(sc
->psc_msi
.msgctrl
);
823 if (coff
>= sc
->psc_msi
.capoff
&& coff
< sc
->psc_msi
.capoff
+ caplen
)
830 msixcap_access(struct passthru_softc
*sc
, int coff
)
832 if (sc
->psc_msix
.capoff
== 0)
835 return (coff
>= sc
->psc_msix
.capoff
&&
836 coff
< sc
->psc_msix
.capoff
+ MSIX_CAPLEN
);
840 passthru_cfgread(struct vmctx
*ctx __unused
, struct pci_devinst
*pi
, int coff
,
841 int bytes
, uint32_t *rv
)
843 struct passthru_softc
*sc
;
848 * PCI BARs and MSI capability is emulated.
850 if (bar_access(coff
) || msicap_access(sc
, coff
) ||
851 msixcap_access(sc
, coff
))
855 * MSI-X is also emulated since a limit on interrupts may be imposed by
856 * the OS, altering the perceived register state.
858 if (msixcap_access(sc
, coff
))
861 #ifdef LEGACY_SUPPORT
863 * Emulate PCIR_CAP_PTR if this device does not support MSI capability
866 if (sc
->psc_msi
.emulated
) {
867 if (coff
>= PCIR_CAP_PTR
&& coff
< PCIR_CAP_PTR
+ 4)
873 * Emulate the command register. If a single read reads both the
874 * command and status registers, read the status register from the
875 * device's config space.
877 if (coff
== PCIR_COMMAND
) {
880 *rv
= passthru_read_config(sc
, PCIR_STATUS
, 2) << 16 |
881 pci_get_cfgdata16(pi
, PCIR_COMMAND
);
885 /* Everything else just read from the device's config space */
886 *rv
= passthru_read_config(sc
, coff
, bytes
);
892 passthru_cfgwrite(struct vmctx
*ctx
, struct pci_devinst
*pi
, int coff
,
893 int bytes
, uint32_t val
)
895 int error
, msix_table_entries
, i
;
896 struct passthru_softc
*sc
;
902 * PCI BARs are emulated
904 if (bar_access(coff
))
908 * MSI capability is emulated
910 if (msicap_access(sc
, coff
)) {
911 pci_emul_capwrite(pi
, coff
, bytes
, val
, sc
->psc_msi
.capoff
,
913 error
= vm_setup_pptdev_msi(ctx
, 0, sc
->pptfd
,
914 pi
->pi_msi
.addr
, pi
->pi_msi
.msg_data
, pi
->pi_msi
.maxmsgnum
);
916 err(1, "vm_setup_pptdev_msi");
920 if (msixcap_access(sc
, coff
)) {
921 pci_emul_capwrite(pi
, coff
, bytes
, val
, sc
->psc_msix
.capoff
,
923 if (pi
->pi_msix
.enabled
) {
924 msix_table_entries
= pi
->pi_msix
.table_count
;
925 for (i
= 0; i
< msix_table_entries
; i
++) {
926 error
= vm_setup_pptdev_msix(ctx
, 0,
928 pi
->pi_msix
.table
[i
].addr
,
929 pi
->pi_msix
.table
[i
].msg_data
,
930 pi
->pi_msix
.table
[i
].vector_control
);
933 err(1, "vm_setup_pptdev_msix");
936 error
= vm_disable_pptdev_msix(ctx
, sc
->pptfd
);
938 err(1, "vm_disable_pptdev_msix");
943 #ifdef LEGACY_SUPPORT
945 * If this device does not support MSI natively then we cannot let
946 * the guest disable legacy interrupts from the device. It is the
947 * legacy interrupt that is triggering the virtual MSI to the guest.
949 if (sc
->psc_msi
.emulated
&& pci_msi_enabled(pi
)) {
950 if (coff
== PCIR_COMMAND
&& bytes
== 2)
951 val
&= ~PCIM_CMD_INTxDIS
;
955 passthru_write_config(sc
, coff
, bytes
, val
);
956 if (coff
== PCIR_COMMAND
) {
957 cmd_old
= pci_get_cfgdata16(pi
, PCIR_COMMAND
);
959 pci_set_cfgdata8(pi
, PCIR_COMMAND
, val
);
961 pci_set_cfgdata16(pi
, PCIR_COMMAND
, val
);
962 pci_emul_cmd_changed(pi
, cmd_old
);
969 passthru_write(struct vmctx
*ctx
, struct pci_devinst
*pi
, int baridx
,
970 uint64_t offset
, int size
, uint64_t value
)
972 struct passthru_softc
*sc
= pi
->pi_arg
;
974 if (baridx
== pci_msix_table_bar(pi
)) {
975 msix_table_write(ctx
, sc
, offset
, size
, value
);
977 struct ppt_bar_io pbi
;
979 assert(pi
->pi_bar
[baridx
].type
== PCIBAR_IO
);
981 pbi
.pbi_bar
= baridx
;
982 pbi
.pbi_width
= size
;
983 pbi
.pbi_off
= offset
;
984 pbi
.pbi_data
= value
;
985 (void) ioctl(sc
->pptfd
, PPT_BAR_WRITE
, &pbi
);
990 passthru_read(struct vmctx
*ctx __unused
, struct pci_devinst
*pi
, int baridx
,
991 uint64_t offset
, int size
)
993 struct passthru_softc
*sc
= pi
->pi_arg
;
996 if (baridx
== pci_msix_table_bar(pi
)) {
997 val
= msix_table_read(sc
, offset
, size
);
999 struct ppt_bar_io pbi
;
1001 assert(pi
->pi_bar
[baridx
].type
== PCIBAR_IO
);
1003 pbi
.pbi_bar
= baridx
;
1004 pbi
.pbi_width
= size
;
1005 pbi
.pbi_off
= offset
;
1006 if (ioctl(sc
->pptfd
, PPT_BAR_READ
, &pbi
) == 0) {
1017 passthru_msix_addr(struct vmctx
*ctx
, struct pci_devinst
*pi
, int baridx
,
1018 int enabled
, uint64_t address
)
1020 struct passthru_softc
*sc
;
1022 uint32_t table_size
, table_offset
;
1025 table_offset
= rounddown2(pi
->pi_msix
.table_offset
, 4096);
1026 if (table_offset
> 0) {
1028 if (vm_unmap_pptdev_mmio(ctx
, sc
->pptfd
, address
,
1030 warnx("pci_passthru: unmap_pptdev_mmio failed");
1032 if (vm_map_pptdev_mmio(ctx
, sc
->pptfd
, address
,
1033 table_offset
, sc
->psc_bar
[baridx
].addr
) != 0)
1034 warnx("pci_passthru: map_pptdev_mmio failed");
1037 table_size
= pi
->pi_msix
.table_offset
- table_offset
;
1038 table_size
+= pi
->pi_msix
.table_count
* MSIX_TABLE_ENTRY_SIZE
;
1039 table_size
= roundup2(table_size
, 4096);
1040 remaining
= pi
->pi_bar
[baridx
].size
- table_offset
- table_size
;
1041 if (remaining
> 0) {
1042 address
+= table_offset
+ table_size
;
1044 if (vm_unmap_pptdev_mmio(ctx
, sc
->pptfd
, address
,
1046 warnx("pci_passthru: unmap_pptdev_mmio failed");
1048 if (vm_map_pptdev_mmio(ctx
, sc
->pptfd
, address
,
1049 remaining
, sc
->psc_bar
[baridx
].addr
+
1050 table_offset
+ table_size
) != 0)
1051 warnx("pci_passthru: map_pptdev_mmio failed");
1057 passthru_mmio_addr(struct vmctx
*ctx
, struct pci_devinst
*pi
, int baridx
,
1058 int enabled
, uint64_t address
)
1060 struct passthru_softc
*sc
;
1064 if (vm_unmap_pptdev_mmio(ctx
, sc
->pptfd
, address
,
1065 sc
->psc_bar
[baridx
].size
) != 0)
1066 warnx("pci_passthru: unmap_pptdev_mmio failed");
1068 if (vm_map_pptdev_mmio(ctx
, sc
->pptfd
, address
,
1069 sc
->psc_bar
[baridx
].size
, sc
->psc_bar
[baridx
].addr
) != 0)
1070 warnx("pci_passthru: map_pptdev_mmio failed");
1075 passthru_addr_rom(struct pci_devinst
*const pi
, const int idx
,
1078 const uint64_t addr
= pi
->pi_bar
[idx
].addr
;
1079 const uint64_t size
= pi
->pi_bar
[idx
].size
;
1082 if (vm_munmap_memseg(pi
->pi_vmctx
, addr
, size
) != 0) {
1083 errx(4, "%s: munmap_memseg @ [%016lx - %016lx] failed",
1084 __func__
, addr
, addr
+ size
);
1088 if (vm_mmap_memseg(pi
->pi_vmctx
, addr
, VM_PCIROM
,
1089 pi
->pi_romoffset
, size
, PROT_READ
| PROT_EXEC
) != 0) {
1090 errx(4, "%s: mmap_memseg @ [%016lx - %016lx] failed",
1091 __func__
, addr
, addr
+ size
);
1097 passthru_addr(struct vmctx
*ctx
, struct pci_devinst
*pi
, int baridx
,
1098 int enabled
, uint64_t address
)
1100 switch (pi
->pi_bar
[baridx
].type
) {
1102 /* IO BARs are emulated */
1105 passthru_addr_rom(pi
, baridx
, enabled
);
1109 if (baridx
== pci_msix_table_bar(pi
))
1110 passthru_msix_addr(ctx
, pi
, baridx
, enabled
, address
);
1112 passthru_mmio_addr(ctx
, pi
, baridx
, enabled
, address
);
1115 errx(4, "%s: invalid BAR type %d", __func__
,
1116 pi
->pi_bar
[baridx
].type
);
1120 static const struct pci_devemu passthru
= {
1121 .pe_emu
= "passthru",
1122 .pe_init
= passthru_init
,
1123 .pe_legacy_config
= passthru_legacy_config
,
1124 .pe_cfgwrite
= passthru_cfgwrite
,
1125 .pe_cfgread
= passthru_cfgread
,
1126 .pe_barwrite
= passthru_write
,
1127 .pe_barread
= passthru_read
,
1128 .pe_baraddr
= passthru_addr
,
1130 PCI_EMUL_SET(passthru
);