Changeset View
Changeset View
Standalone View
Standalone View
usr.sbin/bhyve/pci_lpc.c
Show All 26 Lines | |||||
* SUCH DAMAGE. | * SUCH DAMAGE. | ||||
* | * | ||||
* $FreeBSD$ | * $FreeBSD$ | ||||
*/ | */ | ||||
#include <sys/cdefs.h> | #include <sys/cdefs.h> | ||||
__FBSDID("$FreeBSD$"); | __FBSDID("$FreeBSD$"); | ||||
#ifndef WITHOUT_CAPSICUM | |||||
#include <sys/capsicum.h> | |||||
#endif | |||||
#include <sys/types.h> | #include <sys/types.h> | ||||
#include <sys/pciio.h> | |||||
#include <machine/vmm.h> | #include <machine/vmm.h> | ||||
#include <machine/vmm_snapshot.h> | #include <machine/vmm_snapshot.h> | ||||
#ifndef WITHOUT_CAPSICUM | |||||
#include <capsicum_helpers.h> | |||||
#endif | |||||
#include <err.h> | |||||
#include <errno.h> | |||||
#include <fcntl.h> | |||||
#include <stdio.h> | #include <stdio.h> | ||||
#include <stdlib.h> | #include <stdlib.h> | ||||
#include <string.h> | #include <string.h> | ||||
#include <sysexits.h> | |||||
#include <vmmapi.h> | #include <vmmapi.h> | ||||
#include "acpi.h" | #include "acpi.h" | ||||
#include "debug.h" | #include "debug.h" | ||||
#include "bootrom.h" | #include "bootrom.h" | ||||
#include "config.h" | #include "config.h" | ||||
#include "inout.h" | #include "inout.h" | ||||
Show All 30 Lines | |||||
static const char *lpc_uart_names[LPC_UART_NUM] = { | static const char *lpc_uart_names[LPC_UART_NUM] = { | ||||
"com1", "com2", "com3", "com4" | "com1", "com2", "com3", "com4" | ||||
}; | }; | ||||
static const char *lpc_uart_acpi_names[LPC_UART_NUM] = { | static const char *lpc_uart_acpi_names[LPC_UART_NUM] = { | ||||
"COM1", "COM2", "COM3", "COM4" | "COM1", "COM2", "COM3", "COM4" | ||||
}; | }; | ||||
#ifndef _PATH_DEVPCI | |||||
#define _PATH_DEVPCI "/dev/pci" | |||||
#endif | |||||
static int pcifd = -1; | |||||
static uint32_t | |||||
read_config(const struct pcisel *const sel, const long reg, const int width) | |||||
{ | |||||
struct pci_io pi; | |||||
pi.pi_sel.pc_domain = sel->pc_domain; | |||||
pi.pi_sel.pc_bus = sel->pc_bus; | |||||
pi.pi_sel.pc_dev = sel->pc_dev; | |||||
pi.pi_sel.pc_func = sel->pc_func; | |||||
pi.pi_reg = reg; | |||||
pi.pi_width = width; | |||||
if (ioctl(pcifd, PCIOCREAD, &pi) < 0) | |||||
return (0); | |||||
return (pi.pi_data); | |||||
} | |||||
/* | /* | ||||
* LPC device configuration is in the following form: | * LPC device configuration is in the following form: | ||||
* <lpc_device_name>[,<options>] | * <lpc_device_name>[,<options>] | ||||
* For e.g. "com1,stdio" or "bootrom,/var/romfile" | * For e.g. "com1,stdio" or "bootrom,/var/romfile" | ||||
*/ | */ | ||||
int | int | ||||
lpc_device_parse(const char *opts) | lpc_device_parse(const char *opts) | ||||
{ | { | ||||
int unit, error; | int unit, error; | ||||
char *str, *cpy, *lpcdev, *node_name; | char *str, *cpy, *lpcdev, *node_name; | ||||
error = -1; | error = -1; | ||||
str = cpy = strdup(opts); | str = cpy = strdup(opts); | ||||
lpcdev = strsep(&str, ","); | lpcdev = strsep(&str, ","); | ||||
if (lpcdev != NULL) { | if (lpcdev != NULL) { | ||||
if (strcasecmp(lpcdev, "bootrom") == 0) { | if (strcasecmp(lpcdev, "bootrom") == 0) { | ||||
set_config_value("lpc.bootrom", str); | nvlist_t *const nvl = create_config_node("lpc.bootrom"); | ||||
/* use qemu as default fwcfg */ | |||||
set_config_value_node(nvl, "fwcfg", "qemu"); | |||||
const char *const code = strsep(&str, ","); | |||||
set_config_value_node(nvl, "code", code); | |||||
pci_parse_legacy_config(nvl, str); | |||||
error = 0; | error = 0; | ||||
goto done; | goto done; | ||||
} | } | ||||
for (unit = 0; unit < LPC_UART_NUM; unit++) { | for (unit = 0; unit < LPC_UART_NUM; unit++) { | ||||
if (strcasecmp(lpcdev, lpc_uart_names[unit]) == 0) { | if (strcasecmp(lpcdev, lpc_uart_names[unit]) == 0) { | ||||
asprintf(&node_name, "lpc.%s.path", | asprintf(&node_name, "lpc.%s.path", | ||||
lpc_uart_names[unit]); | lpc_uart_names[unit]); | ||||
set_config_value(node_name, str); | set_config_value(node_name, str); | ||||
Show All 27 Lines | for (i = 0; i < LPC_UART_NUM; i++) | ||||
printf("%s\n", lpc_uart_names[i]); | printf("%s\n", lpc_uart_names[i]); | ||||
printf("%s\n", pctestdev_getname()); | printf("%s\n", pctestdev_getname()); | ||||
} | } | ||||
const char * | const char * | ||||
lpc_bootrom(void) | lpc_bootrom(void) | ||||
{ | { | ||||
return (get_config_value("lpc.bootrom")); | return (get_config_value("lpc.bootrom.code")); | ||||
} | } | ||||
const char * | |||||
lpc_fwcfg(void) | |||||
{ | |||||
return (get_config_value("lpc.bootrom.fwcfg")); | |||||
} | |||||
static void | static void | ||||
lpc_uart_intr_assert(void *arg) | lpc_uart_intr_assert(void *arg) | ||||
{ | { | ||||
struct lpc_uart_softc *sc = arg; | struct lpc_uart_softc *sc = arg; | ||||
assert(sc->irq >= 0); | assert(sc->irq >= 0); | ||||
vm_isa_pulse_irq(lpc_bridge->pi_vmctx, sc->irq, sc->irq); | vm_isa_pulse_irq(lpc_bridge->pi_vmctx, sc->irq, sc->irq); | ||||
▲ Show 20 Lines • Show All 44 Lines • ▼ Show 20 Lines | |||||
lpc_init(struct vmctx *ctx) | lpc_init(struct vmctx *ctx) | ||||
{ | { | ||||
struct lpc_uart_softc *sc; | struct lpc_uart_softc *sc; | ||||
struct inout_port iop; | struct inout_port iop; | ||||
const char *backend, *name, *romfile; | const char *backend, *name, *romfile; | ||||
char *node_name; | char *node_name; | ||||
int unit, error; | int unit, error; | ||||
romfile = get_config_value("lpc.bootrom"); | romfile = get_config_value("lpc.bootrom.code"); | ||||
if (romfile != NULL) { | if (romfile != NULL) { | ||||
error = bootrom_loadrom(ctx, romfile); | error = bootrom_loadrom(ctx, romfile); | ||||
if (error) | if (error) | ||||
return (error); | return (error); | ||||
} | } | ||||
/* COM1 and COM2 */ | /* COM1 and COM2 */ | ||||
for (unit = 0; unit < LPC_UART_NUM; unit++) { | for (unit = 0; unit < LPC_UART_NUM; unit++) { | ||||
▲ Show 20 Lines • Show All 226 Lines • ▼ Show 20 Lines | pci_lpc_init(struct vmctx *ctx, struct pci_devinst *pi, nvlist_t *nvl) | ||||
if (lpc_init(ctx) != 0) | if (lpc_init(ctx) != 0) | ||||
return (-1); | return (-1); | ||||
/* initialize config space */ | /* initialize config space */ | ||||
pci_set_cfgdata16(pi, PCIR_DEVICE, LPC_DEV); | pci_set_cfgdata16(pi, PCIR_DEVICE, LPC_DEV); | ||||
pci_set_cfgdata16(pi, PCIR_VENDOR, LPC_VENDOR); | pci_set_cfgdata16(pi, PCIR_VENDOR, LPC_VENDOR); | ||||
pci_set_cfgdata8(pi, PCIR_CLASS, PCIC_BRIDGE); | pci_set_cfgdata8(pi, PCIR_CLASS, PCIC_BRIDGE); | ||||
pci_set_cfgdata8(pi, PCIR_SUBCLASS, PCIS_BRIDGE_ISA); | pci_set_cfgdata8(pi, PCIR_SUBCLASS, PCIS_BRIDGE_ISA); | ||||
pcifd = open(_PATH_DEVPCI, O_RDWR, 0); | |||||
if (pcifd < 0) { | |||||
warn("failed to open %s", _PATH_DEVPCI); | |||||
return (-1); | |||||
} | |||||
#ifndef WITHOUT_CAPSICUM | |||||
cap_rights_t pcifd_rights; | |||||
cap_rights_init(&pcifd_rights, CAP_IOCTL, CAP_READ); | |||||
const cap_ioctl_t pcifd_ioctls[] = { PCIOCREAD }; | |||||
if (caph_rights_limit(pcifd, &pcifd_rights) == -1) | |||||
errx(EX_OSERR, "Unable to apply rights for sandbox"); | |||||
if (caph_ioctls_limit(pcifd, pcifd_ioctls, nitems(pcifd_ioctls)) == -1) | |||||
errx(EX_OSERR, "Unable to apply rights for sandbox"); | |||||
#endif | |||||
/* on Intel systems lpc is always connected to 0:1f.0 */ | |||||
const struct pcisel sel = { .pc_dev = 0x1f }; | |||||
if (read_config(&sel, PCIR_VENDOR, 2) == PCI_VENDOR_INTEL) { | |||||
/* | |||||
* The VID, DID, REVID, SUBVID and SUBDID of igd-lpc need to be | |||||
* aligned with the physical ones. Without these physical | |||||
* values, GVT-d GOP driver couldn't work. | |||||
*/ | |||||
pci_set_cfgdata16(pi, PCIR_DEVICE, | |||||
read_config(&sel, PCIR_DEVICE, 2)); | |||||
pci_set_cfgdata16(pi, PCIR_VENDOR, | |||||
read_config(&sel, PCIR_VENDOR, 2)); | |||||
pci_set_cfgdata8(pi, PCIR_REVID, | |||||
read_config(&sel, PCIR_REVID, 1)); | |||||
pci_set_cfgdata16(pi, PCIR_SUBVEND_0, | |||||
read_config(&sel, PCIR_SUBVEND_0, 2)); | |||||
pci_set_cfgdata16(pi, PCIR_SUBDEV_0, | |||||
read_config(&sel, PCIR_SUBDEV_0, 2)); | |||||
} | |||||
close(pcifd); | |||||
pcifd = -1; | |||||
lpc_bridge = pi; | lpc_bridge = pi; | ||||
return (0); | return (0); | ||||
} | } | ||||
char * | char * | ||||
lpc_pirq_name(int pin) | lpc_pirq_name(int pin) | ||||
▲ Show 20 Lines • Show All 55 Lines • Show Last 20 Lines |