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 | |||||