Changeset View
Changeset View
Standalone View
Standalone View
usr.sbin/bhyve/pci_lpc.c
| Show All 39 Lines | |||||
| #include <stdlib.h> | #include <stdlib.h> | ||||
| #include <string.h> | #include <string.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 "inout.h" | #include "inout.h" | ||||
| #include "pci_emul.h" | #include "pci_emul.h" | ||||
| #include "pci_irq.h" | #include "pci_irq.h" | ||||
| #include "pci_lpc.h" | #include "pci_lpc.h" | ||||
| #include "pctestdev.h" | #include "pctestdev.h" | ||||
| #include "uart_emul.h" | #include "uart_emul.h" | ||||
| #define IO_ICU1 0x20 | #define IO_ICU1 0x20 | ||||
| #define IO_ICU2 0xA0 | #define IO_ICU2 0xA0 | ||||
| SET_DECLARE(lpc_dsdt_set, struct lpc_dsdt); | SET_DECLARE(lpc_dsdt_set, struct lpc_dsdt); | ||||
| SET_DECLARE(lpc_sysres_set, struct lpc_sysres); | SET_DECLARE(lpc_sysres_set, struct lpc_sysres); | ||||
| #define ELCR_PORT 0x4d0 | #define ELCR_PORT 0x4d0 | ||||
| SYSRES_IO(ELCR_PORT, 2); | SYSRES_IO(ELCR_PORT, 2); | ||||
| #define IO_TIMER1_PORT 0x40 | #define IO_TIMER1_PORT 0x40 | ||||
| #define NMISC_PORT 0x61 | #define NMISC_PORT 0x61 | ||||
| SYSRES_IO(NMISC_PORT, 1); | SYSRES_IO(NMISC_PORT, 1); | ||||
| static struct pci_devinst *lpc_bridge; | static struct pci_devinst *lpc_bridge; | ||||
| static const char *romfile; | |||||
| #define LPC_UART_NUM 4 | #define LPC_UART_NUM 4 | ||||
| static struct lpc_uart_softc { | static struct lpc_uart_softc { | ||||
| struct uart_softc *uart_softc; | struct uart_softc *uart_softc; | ||||
| const char *opts; | |||||
| int iobase; | int iobase; | ||||
| int irq; | int irq; | ||||
| int enabled; | int enabled; | ||||
| } lpc_uart_softc[LPC_UART_NUM]; | } lpc_uart_softc[LPC_UART_NUM]; | ||||
| static const char *lpc_uart_names[LPC_UART_NUM] = { "COM1", "COM2", "COM3", "COM4" }; | static const char *lpc_uart_names[LPC_UART_NUM] = { | ||||
| "com1", "com2", "com3", "com4" | |||||
| }; | |||||
| static bool pctestdev_present; | static const char *lpc_uart_acpi_names[LPC_UART_NUM] = { | ||||
| "COM1", "COM2", "COM3", "COM4" | |||||
| }; | |||||
rew: The following gets printed to terminal on boot:
/tmp/bhyve.lXJmgyl 656: Device… | |||||
Done Inline ActionsI decided to just fix the warning by using uppercase names in the DSDT instead. Thanks for reporting it though, I had missed it. jhb: I decided to just fix the warning by using uppercase names in the DSDT instead. Thanks for… | |||||
| /* | /* | ||||
| * 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; | 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) { | ||||
| romfile = str; | set_config_value("lpc.bootrom", 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) { | ||||
| lpc_uart_softc[unit].opts = str; | asprintf(&node_name, "lpc.%s.path", | ||||
| lpc_uart_names[unit]); | |||||
| set_config_value(node_name, str); | |||||
| free(node_name); | |||||
| error = 0; | error = 0; | ||||
| goto done; | goto done; | ||||
| } | } | ||||
| } | } | ||||
| if (strcasecmp(lpcdev, pctestdev_getname()) == 0) { | if (strcasecmp(lpcdev, pctestdev_getname()) == 0) { | ||||
| if (pctestdev_present) { | asprintf(&node_name, "lpc.%s", pctestdev_getname()); | ||||
| EPRINTLN("More than one %s device conf is " | set_config_bool(node_name, true); | ||||
| "specified; only one is allowed.", | free(node_name); | ||||
| pctestdev_getname()); | |||||
| } else if (pctestdev_parse(str) == 0) { | |||||
| pctestdev_present = true; | |||||
| error = 0; | error = 0; | ||||
| free(cpy); | |||||
| goto done; | goto done; | ||||
| } | } | ||||
| } | } | ||||
| } | |||||
| done: | done: | ||||
| if (error) | |||||
| free(cpy); | free(cpy); | ||||
| return (error); | return (error); | ||||
| } | } | ||||
| void | void | ||||
| lpc_print_supported_devices() | lpc_print_supported_devices() | ||||
| { | { | ||||
| size_t i; | size_t i; | ||||
| printf("bootrom\n"); | printf("bootrom\n"); | ||||
| for (i = 0; i < LPC_UART_NUM; i++) | 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 (romfile); | return (get_config_value("lpc.bootrom")); | ||||
| } | } | ||||
| 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); | ||||
| ▲ Show 20 Lines • Show All 42 Lines • ▼ Show 20 Lines | lpc_uart_io_handler(struct vmctx *ctx, int vcpu, int in, int port, int bytes, | ||||
| return (0); | return (0); | ||||
| } | } | ||||
| static int | static int | ||||
| 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 *name; | const char *backend, *name, *romfile; | ||||
| char *node_name; | |||||
| int unit, error; | int unit, error; | ||||
| romfile = get_config_value("lpc.bootrom"); | |||||
| 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++) { | ||||
| sc = &lpc_uart_softc[unit]; | sc = &lpc_uart_softc[unit]; | ||||
| name = lpc_uart_names[unit]; | name = lpc_uart_names[unit]; | ||||
| if (uart_legacy_alloc(unit, &sc->iobase, &sc->irq) != 0) { | if (uart_legacy_alloc(unit, &sc->iobase, &sc->irq) != 0) { | ||||
| EPRINTLN("Unable to allocate resources for " | EPRINTLN("Unable to allocate resources for " | ||||
| "LPC device %s", name); | "LPC device %s", name); | ||||
| return (-1); | return (-1); | ||||
| } | } | ||||
| pci_irq_reserve(sc->irq); | pci_irq_reserve(sc->irq); | ||||
| sc->uart_softc = uart_init(lpc_uart_intr_assert, | sc->uart_softc = uart_init(lpc_uart_intr_assert, | ||||
| lpc_uart_intr_deassert, sc); | lpc_uart_intr_deassert, sc); | ||||
| if (uart_set_backend(sc->uart_softc, sc->opts) != 0) { | asprintf(&node_name, "lpc.%s.path", name); | ||||
| backend = get_config_value(node_name); | |||||
| free(node_name); | |||||
| if (uart_set_backend(sc->uart_softc, backend) != 0) { | |||||
| EPRINTLN("Unable to initialize backend '%s' " | EPRINTLN("Unable to initialize backend '%s' " | ||||
| "for LPC device %s", sc->opts, name); | "for LPC device %s", backend, name); | ||||
| return (-1); | return (-1); | ||||
| } | } | ||||
| bzero(&iop, sizeof(struct inout_port)); | bzero(&iop, sizeof(struct inout_port)); | ||||
| iop.name = name; | iop.name = name; | ||||
| iop.port = sc->iobase; | iop.port = sc->iobase; | ||||
| iop.size = UART_IO_BAR_SIZE; | iop.size = UART_IO_BAR_SIZE; | ||||
| iop.flags = IOPORT_F_INOUT; | iop.flags = IOPORT_F_INOUT; | ||||
| iop.handler = lpc_uart_io_handler; | iop.handler = lpc_uart_io_handler; | ||||
| iop.arg = sc; | iop.arg = sc; | ||||
| error = register_inout(&iop); | error = register_inout(&iop); | ||||
| assert(error == 0); | assert(error == 0); | ||||
| sc->enabled = 1; | sc->enabled = 1; | ||||
| } | } | ||||
| /* pc-testdev */ | /* pc-testdev */ | ||||
| if (pctestdev_present) { | asprintf(&node_name, "lpc.%s", pctestdev_getname()); | ||||
| if (get_config_bool_default(node_name, false)) { | |||||
| error = pctestdev_init(ctx); | error = pctestdev_init(ctx); | ||||
| if (error) | if (error) | ||||
| return (error); | return (error); | ||||
| } | } | ||||
| free(node_name); | |||||
| return (0); | return (0); | ||||
| } | } | ||||
| static void | static void | ||||
| pci_lpc_write_dsdt(struct pci_devinst *pi) | pci_lpc_write_dsdt(struct pci_devinst *pi) | ||||
| { | { | ||||
| struct lpc_dsdt **ldpp, *ldp; | struct lpc_dsdt **ldpp, *ldp; | ||||
| ▲ Show 20 Lines • Show All 92 Lines • ▼ Show 20 Lines | pci_lpc_uart_dsdt(void) | ||||
| struct lpc_uart_softc *sc; | struct lpc_uart_softc *sc; | ||||
| int unit; | int unit; | ||||
| for (unit = 0; unit < LPC_UART_NUM; unit++) { | for (unit = 0; unit < LPC_UART_NUM; unit++) { | ||||
| sc = &lpc_uart_softc[unit]; | sc = &lpc_uart_softc[unit]; | ||||
| if (!sc->enabled) | if (!sc->enabled) | ||||
| continue; | continue; | ||||
| dsdt_line(""); | dsdt_line(""); | ||||
| dsdt_line("Device (%s)", lpc_uart_names[unit]); | dsdt_line("Device (%s)", lpc_uart_acpi_names[unit]); | ||||
| dsdt_line("{"); | dsdt_line("{"); | ||||
| dsdt_line(" Name (_HID, EisaId (\"PNP0501\"))"); | dsdt_line(" Name (_HID, EisaId (\"PNP0501\"))"); | ||||
| dsdt_line(" Name (_UID, %d)", unit + 1); | dsdt_line(" Name (_UID, %d)", unit + 1); | ||||
| dsdt_line(" Name (_CRS, ResourceTemplate ()"); | dsdt_line(" Name (_CRS, ResourceTemplate ()"); | ||||
| dsdt_line(" {"); | dsdt_line(" {"); | ||||
| dsdt_indent(2); | dsdt_indent(2); | ||||
| dsdt_fixed_ioport(sc->iobase, UART_IO_BAR_SIZE); | dsdt_fixed_ioport(sc->iobase, UART_IO_BAR_SIZE); | ||||
| dsdt_fixed_irq(sc->irq); | dsdt_fixed_irq(sc->irq); | ||||
| Show All 37 Lines | |||||
| { | { | ||||
| return (0); | return (0); | ||||
| } | } | ||||
| #define LPC_DEV 0x7000 | #define LPC_DEV 0x7000 | ||||
| #define LPC_VENDOR 0x8086 | #define LPC_VENDOR 0x8086 | ||||
| static int | static int | ||||
| pci_lpc_init(struct vmctx *ctx, struct pci_devinst *pi, char *opts) | pci_lpc_init(struct vmctx *ctx, struct pci_devinst *pi, nvlist_t *nvl) | ||||
| { | { | ||||
| /* | /* | ||||
| * Do not allow more than one LPC bridge to be configured. | * Do not allow more than one LPC bridge to be configured. | ||||
| */ | */ | ||||
| if (lpc_bridge != NULL) { | if (lpc_bridge != NULL) { | ||||
| EPRINTLN("Only one LPC bridge is allowed."); | EPRINTLN("Only one LPC bridge is allowed."); | ||||
| return (-1); | return (-1); | ||||
| ▲ Show 20 Lines • Show All 83 Lines • Show Last 20 Lines | |||||
The following gets printed to terminal on boot:
From main(), acpi_build() gets called, then basl_compile() where iasl(8) gets called via system(). The iasl command has stdout going /dev/null but not stderr (which are where the messages are printed to).
passing the -vi flag to iasl(8) will suppress the warnings, here's a diff for context, https://reviews.freebsd.org/differential/diff/82835/
I haven't figured out how to add a suggestion on a file that isn't in the review, hence the provided diff.