Changeset View
Changeset View
Standalone View
Standalone View
usr.sbin/bhyve/pci_passthru.c
Show First 20 Lines • Show All 55 Lines • ▼ Show 20 Lines | |||||
#include <fcntl.h> | #include <fcntl.h> | ||||
#include <sysexits.h> | #include <sysexits.h> | ||||
#include <unistd.h> | #include <unistd.h> | ||||
#include <machine/vmm.h> | #include <machine/vmm.h> | ||||
#include <vmmapi.h> | #include <vmmapi.h> | ||||
#include "pci_emul.h" | #include "pci_emul.h" | ||||
#include "mem.h" | #include "mem.h" | ||||
#include "pci_passthru.h" | |||||
#ifndef _PATH_DEVPCI | #ifndef _PATH_DEVPCI | ||||
#define _PATH_DEVPCI "/dev/pci" | #define _PATH_DEVPCI "/dev/pci" | ||||
#endif | #endif | ||||
#ifndef _PATH_DEVIO | #ifndef _PATH_DEVIO | ||||
#define _PATH_DEVIO "/dev/io" | #define _PATH_DEVIO "/dev/io" | ||||
#endif | #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 iofd = -1; | ||||
static int memfd = -1; | static int memfd = -1; | ||||
struct passthru_softc { | |||||
struct pci_devinst *psc_pi; | |||||
struct pcibar psc_bar[PCI_BARMAX + 1]; | |||||
struct { | |||||
int capoff; | |||||
int msgctrl; | |||||
int emulated; | |||||
} psc_msi; | |||||
struct { | |||||
int capoff; | |||||
} psc_msix; | |||||
struct pcisel psc_sel; | |||||
}; | |||||
static int | static int | ||||
msi_caplen(int msgctrl) | msi_caplen(int msgctrl) | ||||
{ | { | ||||
int len; | int len; | ||||
len = 10; /* minimum length of msi capability */ | len = 10; /* minimum length of msi capability */ | ||||
if (msgctrl & PCIM_MSICTRL_64BIT) | if (msgctrl & PCIM_MSICTRL_64BIT) | ||||
len += 4; | len += 4; | ||||
#if 0 | #if 0 | ||||
/* | /* | ||||
* Ignore the 'mask' and 'pending' bits in the MSI capability. | * Ignore the 'mask' and 'pending' bits in the MSI capability. | ||||
* We'll let the guest manipulate them directly. | * We'll let the guest manipulate them directly. | ||||
*/ | */ | ||||
if (msgctrl & PCIM_MSICTRL_VECTOR) | if (msgctrl & PCIM_MSICTRL_VECTOR) | ||||
len += 10; | len += 10; | ||||
#endif | #endif | ||||
return (len); | return (len); | ||||
} | } | ||||
static uint32_t | uint32_t | ||||
read_config(const struct pcisel *sel, long reg, int width) | read_config(const struct pcisel *sel, long reg, int width) | ||||
{ | { | ||||
struct pci_io pi; | struct pci_io pi; | ||||
bzero(&pi, sizeof(pi)); | bzero(&pi, sizeof(pi)); | ||||
pi.pi_sel = *sel; | pi.pi_sel = *sel; | ||||
pi.pi_reg = reg; | pi.pi_reg = reg; | ||||
pi.pi_width = width; | pi.pi_width = width; | ||||
if (ioctl(pcifd, PCIOCREAD, &pi) < 0) | if (ioctl(pcifd, PCIOCREAD, &pi) < 0) | ||||
return (0); /* XXX */ | return (0); /* XXX */ | ||||
else | else | ||||
return (pi.pi_data); | return (pi.pi_data); | ||||
} | } | ||||
static void | void | ||||
write_config(const struct pcisel *sel, long reg, int width, uint32_t data) | write_config(const struct pcisel *sel, long reg, int width, uint32_t data) | ||||
{ | { | ||||
struct pci_io pi; | struct pci_io pi; | ||||
bzero(&pi, sizeof(pi)); | bzero(&pi, sizeof(pi)); | ||||
pi.pi_sel = *sel; | pi.pi_sel = *sel; | ||||
pi.pi_reg = reg; | pi.pi_reg = reg; | ||||
pi.pi_width = width; | pi.pi_width = width; | ||||
▲ Show 20 Lines • Show All 495 Lines • ▼ Show 20 Lines | cfginit(struct vmctx *ctx, struct pci_devinst *pi, int bus, int slot, int func) | ||||
pci_set_cfgdata16(pi, PCIR_COMMAND, read_config(&sc->psc_sel, | pci_set_cfgdata16(pi, PCIR_COMMAND, read_config(&sc->psc_sel, | ||||
PCIR_COMMAND, 2)); | PCIR_COMMAND, 2)); | ||||
error = 0; /* success */ | error = 0; /* success */ | ||||
done: | done: | ||||
return (error); | return (error); | ||||
} | } | ||||
static int | int | ||||
passthru_init(struct vmctx *ctx, struct pci_devinst *pi, char *opts) | passthru_init(struct vmctx *ctx, struct pci_devinst *pi, char *opts) | ||||
{ | { | ||||
int bus, slot, func, error, memflags; | int bus, slot, func, error, memflags; | ||||
struct passthru_softc *sc; | struct passthru_softc *sc; | ||||
#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[] = { PCIOCREAD, PCIOCWRITE, PCIOCGETBAR }; | ||||
cap_ioctl_t io_ioctls[] = { IODEV_PIO }; | cap_ioctl_t io_ioctls[] = { IODEV_PIO }; | ||||
▲ Show 20 Lines • Show All 79 Lines • ▼ Show 20 Lines | |||||
done: | done: | ||||
if (error) { | if (error) { | ||||
free(sc); | free(sc); | ||||
vm_unassign_pptdev(ctx, bus, slot, func); | vm_unassign_pptdev(ctx, bus, slot, func); | ||||
} | } | ||||
return (error); | return (error); | ||||
} | } | ||||
static int | int | ||||
bar_access(int coff) | bar_access(int coff) | ||||
{ | { | ||||
if (coff >= PCIR_BAR(0) && coff < PCIR_BAR(PCI_BARMAX + 1)) | if (coff >= PCIR_BAR(0) && coff < PCIR_BAR(PCI_BARMAX + 1)) | ||||
return (1); | return (1); | ||||
else | else | ||||
return (0); | return (0); | ||||
} | } | ||||
Show All 18 Lines | |||||
{ | { | ||||
if (sc->psc_msix.capoff == 0) | if (sc->psc_msix.capoff == 0) | ||||
return (0); | return (0); | ||||
return (coff >= sc->psc_msix.capoff && | return (coff >= sc->psc_msix.capoff && | ||||
coff < sc->psc_msix.capoff + MSIX_CAPLEN); | coff < sc->psc_msix.capoff + MSIX_CAPLEN); | ||||
} | } | ||||
static int | int | ||||
passthru_cfgread(struct vmctx *ctx, int vcpu, struct pci_devinst *pi, | passthru_cfgread(struct vmctx *ctx, int vcpu, struct pci_devinst *pi, | ||||
int coff, int bytes, uint32_t *rv) | int coff, int bytes, uint32_t *rv) | ||||
{ | { | ||||
struct passthru_softc *sc; | struct passthru_softc *sc; | ||||
sc = pi->pi_arg; | sc = pi->pi_arg; | ||||
/* | /* | ||||
Show All 27 Lines | #endif | ||||
} | } | ||||
/* Everything else just read from the device's config space */ | /* Everything else just read from the device's config space */ | ||||
*rv = read_config(&sc->psc_sel, coff, bytes); | *rv = read_config(&sc->psc_sel, coff, bytes); | ||||
return (0); | return (0); | ||||
} | } | ||||
static int | int | ||||
passthru_cfgwrite(struct vmctx *ctx, int vcpu, struct pci_devinst *pi, | passthru_cfgwrite(struct vmctx *ctx, int vcpu, struct pci_devinst *pi, | ||||
int coff, int bytes, uint32_t val) | int coff, int bytes, uint32_t val) | ||||
{ | { | ||||
int error, msix_table_entries, i; | int error, msix_table_entries, i; | ||||
struct passthru_softc *sc; | struct passthru_softc *sc; | ||||
uint16_t cmd_old; | uint16_t cmd_old; | ||||
sc = pi->pi_arg; | sc = pi->pi_arg; | ||||
▲ Show 20 Lines • Show All 59 Lines • ▼ Show 20 Lines | if (coff == PCIR_COMMAND) { | ||||
else if (bytes == 2) | else if (bytes == 2) | ||||
pci_set_cfgdata16(pi, PCIR_COMMAND, val); | pci_set_cfgdata16(pi, PCIR_COMMAND, val); | ||||
pci_emul_cmd_changed(pi, cmd_old); | pci_emul_cmd_changed(pi, cmd_old); | ||||
} | } | ||||
return (0); | return (0); | ||||
} | } | ||||
static void | 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 iodev_pio_req 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)); | bzero(&pio, sizeof(struct iodev_pio_req)); | ||||
pio.access = IODEV_PIO_WRITE; | pio.access = IODEV_PIO_WRITE; | ||||
pio.port = sc->psc_bar[baridx].addr + offset; | pio.port = sc->psc_bar[baridx].addr + offset; | ||||
pio.width = size; | pio.width = size; | ||||
pio.val = value; | pio.val = value; | ||||
(void)ioctl(iofd, IODEV_PIO, &pio); | (void)ioctl(iofd, IODEV_PIO, &pio); | ||||
} | } | ||||
} | } | ||||
static uint64_t | 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 iodev_pio_req pio; | ||||
uint64_t val; | uint64_t val; | ||||
sc = pi->pi_arg; | sc = pi->pi_arg; | ||||
Show All 28 Lines |