diff --git a/devicemodel/hw/pci/uart.c b/devicemodel/hw/pci/uart.c index 1a3104e8f..c3bf821fc 100644 --- a/devicemodel/hw/pci/uart.c +++ b/devicemodel/hw/pci/uart.c @@ -28,17 +28,25 @@ #include #include +#include +#include +#include +#include #include "pci_core.h" #include "uart_core.h" +#include "dm_string.h" +#include "vmmapi.h" /* * Pick a PCI vid/did of a chip with a single uart at * BAR0, that most versions of FreeBSD can understand: * Siig CyberSerial 1-port. */ -#define COM_VENDOR 0x131f -#define COM_DEV 0x2000 +#define COM_VENDOR 0x9710 +#define COM_DEV 0x9900 + +#define VUART_IDX "vuart_idx" static void pci_uart_intr_assert(void *arg) @@ -78,31 +86,79 @@ pci_uart_read(struct vmctx *ctx, int vcpu, struct pci_vdev *dev, static int pci_uart_init(struct vmctx *ctx, struct pci_vdev *dev, char *opts) { - pci_emul_alloc_bar(dev, 0, PCIBAR_IO, UART_IO_BAR_SIZE); - pci_lintr_request(dev); + char *tmp, *val = NULL; + bool is_hv_land = false; + uint32_t vuart_idx; + struct acrn_emul_dev vdev = {}; + int32_t err = 0; - /* initialize config space */ - pci_set_cfgdata16(dev, PCIR_DEVICE, COM_DEV); - pci_set_cfgdata16(dev, PCIR_VENDOR, COM_VENDOR); - pci_set_cfgdata8(dev, PCIR_CLASS, PCIC_SIMPLECOMM); - - dev->arg = uart_set_backend(pci_uart_intr_assert, pci_uart_intr_deassert, dev, opts); - if (dev->arg == NULL) { - pr_err("Unable to initialize backend '%s' for " - "pci uart at %d:%d\n", opts, dev->slot, dev->func); - return -1; + if (opts != NULL) { + tmp = val= strdup(opts); + if (!tmp) { + pr_err("No memory for strdup, can't parse uart args!!!!\n"); + } else { + if (!strncmp(tmp, VUART_IDX, strlen(VUART_IDX))) { + tmp = strsep(&val, ":"); + if (!val) { + pr_err("pci vuart miss vuart_idx value!!!!\n"); + } else { + if (dm_strtoui(val, &val, 10, &vuart_idx)) { + pr_err("wrong vuart_idx value!!!!\n"); + } else { + is_hv_land = true; + } + } + } + } } - return 0; + if (is_hv_land) { + pci_emul_alloc_bar(dev, 0, PCIBAR_MEM32, 256); + pci_emul_alloc_bar(dev, 1, PCIBAR_MEM32, PAGE_SIZE); + dev->arg = NULL; + vdev.dev_id.fields.vendor_id = COM_VENDOR; + vdev.dev_id.fields.device_id = COM_DEV; + vdev.slot = PCI_BDF(dev->bus, dev->slot, dev->func); + vdev.io_addr[0] = pci_get_cfgdata32(dev, PCIR_BAR(0)); + vdev.io_addr[1] = pci_get_cfgdata32(dev, PCIR_BAR(1)); + *((uint32_t *)vdev.args) = vuart_idx; + err = vm_create_hv_vdev(ctx, &vdev); + if (err) { + pr_err("HV can't create vuart with vuart_idx=%d\n", vuart_idx); + } + } else { + pci_emul_alloc_bar(dev, 0, PCIBAR_IO, UART_IO_BAR_SIZE); + pci_lintr_request(dev); + + /* initialize config space */ + pci_set_cfgdata16(dev, PCIR_DEVICE, COM_DEV); + pci_set_cfgdata16(dev, PCIR_VENDOR, COM_VENDOR); + pci_set_cfgdata8(dev, PCIR_CLASS, PCIC_SIMPLECOMM); + + dev->arg = uart_set_backend(pci_uart_intr_assert, pci_uart_intr_deassert, dev, opts); + if (dev->arg == NULL) { + pr_err("Unable to initialize backend '%s' for " + "pci uart at %d:%d\n", opts, dev->slot, dev->func); + err = -1; + } + } + + return err; } static void pci_uart_deinit(struct vmctx *ctx, struct pci_vdev *dev, char *opts) { struct uart_vdev *uart = (struct uart_vdev *)dev->arg; + struct acrn_emul_dev emul_dev = {}; - if (uart == NULL) + if (uart == NULL) { + emul_dev.dev_id.fields.vendor_id = COM_VENDOR; + emul_dev.dev_id.fields.device_id = COM_DEV; + emul_dev.slot = PCI_BDF(dev->bus, dev->slot, dev->func); + vm_destroy_hv_vdev(ctx, &emul_dev); return; + } uart_release_backend(uart, opts); }