Changeset View
Changeset View
Standalone View
Standalone View
usr.sbin/bhyve/pci_passthru.c
Show First 20 Lines • Show All 63 Lines • ▼ Show 20 Lines | |||||
#include "debug.h" | #include "debug.h" | ||||
#include "pci_emul.h" | #include "pci_emul.h" | ||||
#include "mem.h" | #include "mem.h" | ||||
#ifndef _PATH_DEVPCI | #ifndef _PATH_DEVPCI | ||||
#define _PATH_DEVPCI "/dev/pci" | #define _PATH_DEVPCI "/dev/pci" | ||||
#endif | #endif | ||||
#ifndef _PATH_DEVIO | |||||
#define _PATH_DEVIO "/dev/io" | |||||
#endif | |||||
#ifndef _PATH_MEM | #ifndef _PATH_MEM | ||||
#define _PATH_MEM "/dev/mem" | #define _PATH_MEM "/dev/mem" | ||||
#endif | #endif | ||||
#define LEGACY_SUPPORT 1 | #define LEGACY_SUPPORT 1 | ||||
#define MSIX_TABLE_COUNT(ctrl) (((ctrl) & PCIM_MSIXCTRL_TABLE_SIZE) + 1) | #define MSIX_TABLE_COUNT(ctrl) (((ctrl) & PCIM_MSIXCTRL_TABLE_SIZE) + 1) | ||||
#define MSIX_CAPLEN 12 | #define MSIX_CAPLEN 12 | ||||
static int pcifd = -1; | static int pcifd = -1; | ||||
static int iofd = -1; | |||||
static int memfd = -1; | static int memfd = -1; | ||||
struct passthru_softc { | struct passthru_softc { | ||||
struct pci_devinst *psc_pi; | struct pci_devinst *psc_pi; | ||||
struct pcibar psc_bar[PCI_BARMAX + 1]; | struct pcibar psc_bar[PCI_BARMAX + 1]; | ||||
struct { | struct { | ||||
int capoff; | int capoff; | ||||
int msgctrl; | int msgctrl; | ||||
▲ Show 20 Lines • Show All 549 Lines • ▼ Show 20 Lines | |||||
static int | static int | ||||
passthru_init(struct vmctx *ctx, struct pci_devinst *pi, nvlist_t *nvl) | passthru_init(struct vmctx *ctx, struct pci_devinst *pi, nvlist_t *nvl) | ||||
{ | { | ||||
int bus, slot, func, error, memflags; | int bus, slot, func, error, memflags; | ||||
struct passthru_softc *sc; | struct passthru_softc *sc; | ||||
const char *value; | const char *value; | ||||
#ifndef WITHOUT_CAPSICUM | #ifndef WITHOUT_CAPSICUM | ||||
cap_rights_t rights; | cap_rights_t rights; | ||||
cap_ioctl_t pci_ioctls[] = { PCIOCREAD, PCIOCWRITE, PCIOCGETBAR }; | cap_ioctl_t pci_ioctls[] = | ||||
cap_ioctl_t io_ioctls[] = { IODEV_PIO }; | { PCIOCREAD, PCIOCWRITE, PCIOCGETBAR, PCIOCBARIO }; | ||||
#endif | #endif | ||||
sc = NULL; | sc = NULL; | ||||
error = 1; | error = 1; | ||||
#ifndef WITHOUT_CAPSICUM | #ifndef WITHOUT_CAPSICUM | ||||
cap_rights_init(&rights, CAP_IOCTL, CAP_READ, CAP_WRITE); | cap_rights_init(&rights, CAP_IOCTL, CAP_READ, CAP_WRITE); | ||||
#endif | #endif | ||||
Show All 14 Lines | |||||
#ifndef WITHOUT_CAPSICUM | #ifndef WITHOUT_CAPSICUM | ||||
if (caph_rights_limit(pcifd, &rights) == -1) | if (caph_rights_limit(pcifd, &rights) == -1) | ||||
errx(EX_OSERR, "Unable to apply rights for sandbox"); | errx(EX_OSERR, "Unable to apply rights for sandbox"); | ||||
if (caph_ioctls_limit(pcifd, pci_ioctls, nitems(pci_ioctls)) == -1) | if (caph_ioctls_limit(pcifd, pci_ioctls, nitems(pci_ioctls)) == -1) | ||||
errx(EX_OSERR, "Unable to apply rights for sandbox"); | errx(EX_OSERR, "Unable to apply rights for sandbox"); | ||||
#endif | #endif | ||||
if (iofd < 0) { | |||||
iofd = open(_PATH_DEVIO, O_RDWR, 0); | |||||
if (iofd < 0) { | |||||
warn("failed to open %s", _PATH_DEVIO); | |||||
return (error); | |||||
} | |||||
} | |||||
#ifndef WITHOUT_CAPSICUM | |||||
if (caph_rights_limit(iofd, &rights) == -1) | |||||
errx(EX_OSERR, "Unable to apply rights for sandbox"); | |||||
if (caph_ioctls_limit(iofd, io_ioctls, nitems(io_ioctls)) == -1) | |||||
errx(EX_OSERR, "Unable to apply rights for sandbox"); | |||||
#endif | |||||
if (memfd < 0) { | if (memfd < 0) { | ||||
memfd = open(_PATH_MEM, O_RDWR, 0); | memfd = open(_PATH_MEM, O_RDWR, 0); | ||||
if (memfd < 0) { | if (memfd < 0) { | ||||
warn("failed to open %s", _PATH_MEM); | warn("failed to open %s", _PATH_MEM); | ||||
return (error); | return (error); | ||||
} | } | ||||
} | } | ||||
▲ Show 20 Lines • Show All 198 Lines • ▼ Show 20 Lines | #endif | ||||
return (0); | return (0); | ||||
} | } | ||||
static void | static void | ||||
passthru_write(struct vmctx *ctx, int vcpu, struct pci_devinst *pi, int baridx, | passthru_write(struct vmctx *ctx, int vcpu, struct pci_devinst *pi, int baridx, | ||||
uint64_t offset, int size, uint64_t value) | uint64_t offset, int size, uint64_t value) | ||||
{ | { | ||||
struct passthru_softc *sc; | struct passthru_softc *sc; | ||||
struct iodev_pio_req pio; | struct pci_bar_ioreq pio; | ||||
sc = pi->pi_arg; | sc = pi->pi_arg; | ||||
if (baridx == pci_msix_table_bar(pi)) { | if (baridx == pci_msix_table_bar(pi)) { | ||||
msix_table_write(ctx, vcpu, sc, offset, size, value); | msix_table_write(ctx, vcpu, sc, offset, size, value); | ||||
} else { | } else { | ||||
assert(pi->pi_bar[baridx].type == PCIBAR_IO); | assert(pi->pi_bar[baridx].type == PCIBAR_IO); | ||||
bzero(&pio, sizeof(struct iodev_pio_req)); | assert(size == 1 || size == 2 || size == 4); | ||||
pio.access = IODEV_PIO_WRITE; | assert(offset <= UINT32_MAX && offset + size <= UINT32_MAX); | ||||
pio.port = sc->psc_bar[baridx].addr + offset; | |||||
pio.width = size; | |||||
pio.val = value; | |||||
(void)ioctl(iofd, IODEV_PIO, &pio); | bzero(&pio, sizeof(pio)); | ||||
pio.pbi_sel = sc->psc_sel; | |||||
pio.pbi_op = PCIBARIO_WRITE; | |||||
pio.pbi_bar = baridx; | |||||
pio.pbi_offset = (uint32_t)offset; | |||||
pio.pbi_width = size; | |||||
pio.pbi_value = (uint32_t)value; | |||||
(void)ioctl(pcifd, PCIOCBARIO, &pio); | |||||
} | } | ||||
} | } | ||||
static uint64_t | static uint64_t | ||||
passthru_read(struct vmctx *ctx, int vcpu, struct pci_devinst *pi, int baridx, | passthru_read(struct vmctx *ctx, int vcpu, struct pci_devinst *pi, int baridx, | ||||
uint64_t offset, int size) | uint64_t offset, int size) | ||||
{ | { | ||||
struct passthru_softc *sc; | struct passthru_softc *sc; | ||||
struct iodev_pio_req pio; | struct pci_bar_ioreq pio; | ||||
uint64_t val; | uint64_t val; | ||||
sc = pi->pi_arg; | sc = pi->pi_arg; | ||||
if (baridx == pci_msix_table_bar(pi)) { | if (baridx == pci_msix_table_bar(pi)) { | ||||
val = msix_table_read(sc, offset, size); | val = msix_table_read(sc, offset, size); | ||||
} else { | } else { | ||||
assert(pi->pi_bar[baridx].type == PCIBAR_IO); | assert(pi->pi_bar[baridx].type == PCIBAR_IO); | ||||
bzero(&pio, sizeof(struct iodev_pio_req)); | assert(size == 1 || size == 2 || size == 4); | ||||
pio.access = IODEV_PIO_READ; | assert(offset <= UINT32_MAX && offset + size <= UINT32_MAX); | ||||
pio.port = sc->psc_bar[baridx].addr + offset; | |||||
pio.width = size; | |||||
pio.val = 0; | |||||
(void)ioctl(iofd, IODEV_PIO, &pio); | bzero(&pio, sizeof(pio)); | ||||
pio.pbi_sel = sc->psc_sel; | |||||
pio.pbi_op = PCIBARIO_READ; | |||||
pio.pbi_bar = baridx; | |||||
pio.pbi_offset = (uint32_t)offset; | |||||
pio.pbi_width = size; | |||||
val = pio.val; | (void)ioctl(pcifd, PCIOCBARIO, &pio); | ||||
val = pio.pbi_value; | |||||
} | } | ||||
return (val); | return (val); | ||||
} | } | ||||
static void | static void | ||||
passthru_msix_addr(struct vmctx *ctx, struct pci_devinst *pi, int baridx, | passthru_msix_addr(struct vmctx *ctx, struct pci_devinst *pi, int baridx, | ||||
int enabled, uint64_t address) | int enabled, uint64_t address) | ||||
▲ Show 20 Lines • Show All 94 Lines • Show Last 20 Lines |