pci, pc, virtio: features, fixes

reconnect for vhost blk
 tests for UEFI
 misc other stuff
 
 Signed-off-by: Michael S. Tsirkin <mst@redhat.com>
 -----BEGIN PGP SIGNATURE-----
 
 iQEcBAABAgAGBQJc5AAMAAoJECgfDbjSjVRp57wIAKUAF8mvTaFfl/ge9IKJ0ZSO
 +dZS+2Zdc52n3Qk2K511hMvMmWD6xO98+VSXzwax2KgfIVCcQyYSCSbkyqZ4XiFg
 JUobhLHs6W24zn+2T8vZoqe4XWU6Pm1Y6NM72EFuhag8mhFlwWyMjpTwsISbjhGM
 /FpHsPpB2/c7Uofe8CVmPl55PDqOoIm35YlbH5v6zUtBiPNRgZTDOMtYjl/tyuZC
 VExs41/G15psNDIFd4dL1Zq6UjQBdu3ALIjIXTmPfg0nFXZn7FrOBRHbXWyzR9Tb
 rqEDauxb3iGHphgNqeumfrSPXNrfB91Z8AD2aerTcvgUEdbc9QykxS/YM3erkGo=
 =kkcS
 -----END PGP SIGNATURE-----

Merge remote-tracking branch 'remotes/mst/tags/for_upstream' into staging

pci, pc, virtio: features, fixes

reconnect for vhost blk
tests for UEFI
misc other stuff

Signed-off-by: Michael S. Tsirkin <mst@redhat.com>

# gpg: Signature made Tue 21 May 2019 14:41:32 BST
# gpg:                using RSA key 281F0DB8D28D5469
# gpg: Good signature from "Michael S. Tsirkin <mst@kernel.org>" [full]
# gpg:                 aka "Michael S. Tsirkin <mst@redhat.com>" [full]
# Primary key fingerprint: 0270 606B 6F3C DF3D 0B17  0970 C350 3912 AFBE 8E67
#      Subkey fingerprint: 5D09 FD08 71C8 F85B 94CA  8A0D 281F 0DB8 D28D 5469

* remotes/mst/tags/for_upstream: (34 commits)
  tests: acpi: print error unable to dump ACPI table during rebuild
  tests: acpi: refactor rebuild-expected-aml.sh to dump ACPI tables for a specified list of targets
  tests: acpi: allow to override default accelerator
  tests: acpi: ignore SMBIOS tests when UEFI firmware is used
  tests: acpi: add a way to start tests with UEFI firmware
  tests: acpi: add acpi_find_rsdp_address_uefi() helper
  tests: acpi: move boot_sector_init() into x86 tests branch
  tests: acpi: skip FACS table if board uses hw reduced ACPI profile
  tests: acpi: fetch X_DSDT if pointer to DSDT is 0
  tests: acpi: make pointer to RSDP 64bit
  tests: acpi: make RSDT test routine handle XSDT
  tests: acpi: make acpi_fetch_table() take size of fetched table pointer
  tests: acpi: rename acpi_parse_rsdp_table() into acpi_fetch_rsdp_table()
  pci: Simplify pci_bus_is_root()
  pcie: Remove redundant test in pcie_mmcfg_data_{read,write}()
  libvhost-user: fix bad vu_log_write
  hw/arm/virt-acpi-build: pass AcpiMcfgInfo to build_mcfg()
  i386, acpi: remove mcfg_ prefix in AcpiMcfgInfo members
  hw/arm/virt-acpi-build: remove unnecessary variable mcfg_start
  do not call vhost_net_cleanup() on running net from char user event
  ...

Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
This commit is contained in:
Peter Maydell 2019-05-21 14:56:57 +01:00
commit 247ba27c52
36 changed files with 1889 additions and 1452 deletions

View File

@ -1484,7 +1484,7 @@ M: Michael S. Tsirkin <mst@redhat.com>
S: Supported S: Supported
F: hw/*/*vhost* F: hw/*/*vhost*
F: docs/interop/vhost-user.json F: docs/interop/vhost-user.json
F: docs/interop/vhost-user.txt F: docs/interop/vhost-user.rst
F: contrib/vhost-user-*/ F: contrib/vhost-user-*/
F: backends/vhost-user.c F: backends/vhost-user.c
F: include/sysemu/vhost-user-backend.h F: include/sysemu/vhost-user-backend.h

View File

@ -433,7 +433,7 @@ vu_log_write(VuDev *dev, uint64_t address, uint64_t length)
page = address / VHOST_LOG_PAGE; page = address / VHOST_LOG_PAGE;
while (page * VHOST_LOG_PAGE < address + length) { while (page * VHOST_LOG_PAGE < address + length) {
vu_log_page(dev->log_table, page); vu_log_page(dev->log_table, page);
page += VHOST_LOG_PAGE; page += 1;
} }
vu_log_kick(dev); vu_log_kick(dev);

View File

@ -398,7 +398,8 @@ vub_get_features(VuDev *dev)
static uint64_t static uint64_t
vub_get_protocol_features(VuDev *dev) vub_get_protocol_features(VuDev *dev)
{ {
return 1ull << VHOST_USER_PROTOCOL_F_CONFIG; return 1ull << VHOST_USER_PROTOCOL_F_CONFIG |
1ull << VHOST_USER_PROTOCOL_F_INFLIGHT_SHMFD;
} }
static int static int

View File

@ -15,4 +15,4 @@ Contents:
bitmaps bitmaps
live-block-operations live-block-operations
pr-helper pr-helper
vhost-user

1351
docs/interop/vhost-user.rst Normal file

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

View File

@ -37,14 +37,7 @@
#include "hw/pci/pci_bus.h" #include "hw/pci/pci_bus.h"
#include "qapi/error.h" #include "qapi/error.h"
#include "qom/qom-qobject.h" #include "qom/qom-qobject.h"
#include "trace.h"
//#define DEBUG
#ifdef DEBUG
# define ACPI_PCIHP_DPRINTF(format, ...) printf(format, ## __VA_ARGS__)
#else
# define ACPI_PCIHP_DPRINTF(format, ...) do { } while (0)
#endif
#define ACPI_PCIHP_ADDR 0xae00 #define ACPI_PCIHP_ADDR 0xae00
#define ACPI_PCIHP_SIZE 0x0014 #define ACPI_PCIHP_SIZE 0x0014
@ -159,6 +152,8 @@ static void acpi_pcihp_eject_slot(AcpiPciHpState *s, unsigned bsel, unsigned slo
int slot = ctz32(slots); int slot = ctz32(slots);
PCIBus *bus = acpi_pcihp_find_hotplug_bus(s, bsel); PCIBus *bus = acpi_pcihp_find_hotplug_bus(s, bsel);
trace_acpi_pci_eject_slot(bsel, slot);
if (!bus) { if (!bus) {
return; return;
} }
@ -270,6 +265,8 @@ void acpi_pcihp_device_plug_cb(HotplugHandler *hotplug_dev, AcpiPciHpState *s,
void acpi_pcihp_device_unplug_cb(HotplugHandler *hotplug_dev, AcpiPciHpState *s, void acpi_pcihp_device_unplug_cb(HotplugHandler *hotplug_dev, AcpiPciHpState *s,
DeviceState *dev, Error **errp) DeviceState *dev, Error **errp)
{ {
trace_acpi_pci_unplug(PCI_SLOT(PCI_DEVICE(dev)->devfn),
acpi_pcihp_get_bsel(pci_get_bus(PCI_DEVICE(dev))));
object_property_set_bool(OBJECT(dev), false, "realized", NULL); object_property_set_bool(OBJECT(dev), false, "realized", NULL);
} }
@ -280,6 +277,9 @@ void acpi_pcihp_device_unplug_request_cb(HotplugHandler *hotplug_dev,
PCIDevice *pdev = PCI_DEVICE(dev); PCIDevice *pdev = PCI_DEVICE(dev);
int slot = PCI_SLOT(pdev->devfn); int slot = PCI_SLOT(pdev->devfn);
int bsel = acpi_pcihp_get_bsel(pci_get_bus(pdev)); int bsel = acpi_pcihp_get_bsel(pci_get_bus(pdev));
trace_acpi_pci_unplug_request(bsel, slot);
if (bsel < 0) { if (bsel < 0) {
error_setg(errp, "Unsupported bus. Bus doesn't have property '" error_setg(errp, "Unsupported bus. Bus doesn't have property '"
ACPI_PCIHP_PROP_BSEL "' set"); ACPI_PCIHP_PROP_BSEL "' set");
@ -306,23 +306,23 @@ static uint64_t pci_read(void *opaque, hwaddr addr, unsigned int size)
if (!s->legacy_piix) { if (!s->legacy_piix) {
s->acpi_pcihp_pci_status[bsel].up = 0; s->acpi_pcihp_pci_status[bsel].up = 0;
} }
ACPI_PCIHP_DPRINTF("pci_up_read %" PRIu32 "\n", val); trace_acpi_pci_up_read(val);
break; break;
case PCI_DOWN_BASE: case PCI_DOWN_BASE:
val = s->acpi_pcihp_pci_status[bsel].down; val = s->acpi_pcihp_pci_status[bsel].down;
ACPI_PCIHP_DPRINTF("pci_down_read %" PRIu32 "\n", val); trace_acpi_pci_down_read(val);
break; break;
case PCI_EJ_BASE: case PCI_EJ_BASE:
/* No feature defined yet */ /* No feature defined yet */
ACPI_PCIHP_DPRINTF("pci_features_read %" PRIu32 "\n", val); trace_acpi_pci_features_read(val);
break; break;
case PCI_RMV_BASE: case PCI_RMV_BASE:
val = s->acpi_pcihp_pci_status[bsel].hotplug_enable; val = s->acpi_pcihp_pci_status[bsel].hotplug_enable;
ACPI_PCIHP_DPRINTF("pci_rmv_read %" PRIu32 "\n", val); trace_acpi_pci_rmv_read(val);
break; break;
case PCI_SEL_BASE: case PCI_SEL_BASE:
val = s->hotplug_select; val = s->hotplug_select;
ACPI_PCIHP_DPRINTF("pci_sel_read %" PRIu32 "\n", val); trace_acpi_pci_sel_read(val);
default: default:
break; break;
} }
@ -340,13 +340,11 @@ static void pci_write(void *opaque, hwaddr addr, uint64_t data,
break; break;
} }
acpi_pcihp_eject_slot(s, s->hotplug_select, data); acpi_pcihp_eject_slot(s, s->hotplug_select, data);
ACPI_PCIHP_DPRINTF("pciej write %" HWADDR_PRIx " <== %" PRIu64 "\n", trace_acpi_pci_ej_write(addr, data);
addr, data);
break; break;
case PCI_SEL_BASE: case PCI_SEL_BASE:
s->hotplug_select = s->legacy_piix ? ACPI_PCIHP_BSEL_DEFAULT : data; s->hotplug_select = s->legacy_piix ? ACPI_PCIHP_BSEL_DEFAULT : data;
ACPI_PCIHP_DPRINTF("pcisel write %" HWADDR_PRIx " <== %" PRIu64 "\n", trace_acpi_pci_sel_write(addr, data);
addr, data);
default: default:
break; break;
} }

View File

@ -39,14 +39,7 @@
#include "hw/acpi/acpi_dev_interface.h" #include "hw/acpi/acpi_dev_interface.h"
#include "hw/xen/xen.h" #include "hw/xen/xen.h"
#include "qom/cpu.h" #include "qom/cpu.h"
#include "trace.h"
//#define DEBUG
#ifdef DEBUG
# define PIIX4_DPRINTF(format, ...) printf(format, ## __VA_ARGS__)
#else
# define PIIX4_DPRINTF(format, ...) do { } while (0)
#endif
#define GPE_BASE 0xafe0 #define GPE_BASE 0xafe0
#define GPE_LEN 4 #define GPE_LEN 4
@ -583,7 +576,7 @@ static uint64_t gpe_readb(void *opaque, hwaddr addr, unsigned width)
PIIX4PMState *s = opaque; PIIX4PMState *s = opaque;
uint32_t val = acpi_gpe_ioport_readb(&s->ar, addr); uint32_t val = acpi_gpe_ioport_readb(&s->ar, addr);
PIIX4_DPRINTF("gpe read %" HWADDR_PRIx " == %" PRIu32 "\n", addr, val); trace_piix4_gpe_readb(addr, width, val);
return val; return val;
} }
@ -592,10 +585,9 @@ static void gpe_writeb(void *opaque, hwaddr addr, uint64_t val,
{ {
PIIX4PMState *s = opaque; PIIX4PMState *s = opaque;
trace_piix4_gpe_writeb(addr, width, val);
acpi_gpe_ioport_writeb(&s->ar, addr, val); acpi_gpe_ioport_writeb(&s->ar, addr, val);
acpi_update_sci(&s->ar, s->irq); acpi_update_sci(&s->ar, s->irq);
PIIX4_DPRINTF("gpe write %" HWADDR_PRIx " <== %" PRIu64 "\n", addr, val);
} }
static const MemoryRegionOps piix4_gpe_ops = { static const MemoryRegionOps piix4_gpe_ops = {

View File

@ -31,6 +31,22 @@ cpuhp_acpi_ejecting_cpu(uint32_t idx) "0x%"PRIx32
cpuhp_acpi_write_ost_ev(uint32_t slot, uint32_t ev) "idx[0x%"PRIx32"] OST EVENT: 0x%"PRIx32 cpuhp_acpi_write_ost_ev(uint32_t slot, uint32_t ev) "idx[0x%"PRIx32"] OST EVENT: 0x%"PRIx32
cpuhp_acpi_write_ost_status(uint32_t slot, uint32_t st) "idx[0x%"PRIx32"] OST STATUS: 0x%"PRIx32 cpuhp_acpi_write_ost_status(uint32_t slot, uint32_t st) "idx[0x%"PRIx32"] OST STATUS: 0x%"PRIx32
# pcihp.c
acpi_pci_eject_slot(unsigned bsel, unsigned slot) "bsel: %u slot: %u"
acpi_pci_unplug(int bsel, int slot) "bsel: %d slot: %d"
acpi_pci_unplug_request(int bsel, int slot) "bsel: %d slot: %d"
acpi_pci_up_read(uint32_t val) "%" PRIu32
acpi_pci_down_read(uint32_t val) "%" PRIu32
acpi_pci_features_read(uint32_t val) "%" PRIu32
acpi_pci_rmv_read(uint32_t val) "%" PRIu32
acpi_pci_sel_read(uint32_t val) "%" PRIu32
acpi_pci_ej_write(uint64_t addr, uint64_t data) "0x%" PRIx64 " <== %" PRIu64
acpi_pci_sel_write(uint64_t addr, uint64_t data) "0x%" PRIx64 " <== %" PRIu64
# piix4.c
piix4_gpe_readb(uint64_t addr, unsigned width, uint64_t val) "addr: 0x%" PRIx64 " width: %d ==> 0x%" PRIx64
piix4_gpe_writeb(uint64_t addr, unsigned width, uint64_t val) "addr: 0x%" PRIx64 " width: %d <== 0x%" PRIx64
# tco.c # tco.c
tco_timer_reload(int ticks, int msec) "ticks=%d (%d ms)" tco_timer_reload(int ticks, int msec) "ticks=%d (%d ms)"
tco_timer_expired(int timeouts_no, bool strap, bool no_reboot) "timeouts_no=%d no_reboot=%d/%d" tco_timer_expired(int timeouts_no, bool strap, bool no_reboot) "timeouts_no=%d no_reboot=%d/%d"

View File

@ -40,6 +40,7 @@
#include "hw/loader.h" #include "hw/loader.h"
#include "hw/hw.h" #include "hw/hw.h"
#include "hw/acpi/aml-build.h" #include "hw/acpi/aml-build.h"
#include "hw/acpi/pci.h"
#include "hw/pci/pcie_host.h" #include "hw/pci/pcie_host.h"
#include "hw/pci/pci.h" #include "hw/pci/pci.h"
#include "hw/arm/virt.h" #include "hw/arm/virt.h"
@ -546,25 +547,20 @@ build_srat(GArray *table_data, BIOSLinker *linker, VirtMachineState *vms)
} }
static void static void
build_mcfg(GArray *table_data, BIOSLinker *linker, VirtMachineState *vms) build_mcfg(GArray *table_data, BIOSLinker *linker, AcpiMcfgInfo *info)
{ {
AcpiTableMcfg *mcfg; AcpiTableMcfg *mcfg;
const MemMapEntry *memmap = vms->memmap;
int ecam_id = VIRT_ECAM_ID(vms->highmem_ecam);
int len = sizeof(*mcfg) + sizeof(mcfg->allocation[0]); int len = sizeof(*mcfg) + sizeof(mcfg->allocation[0]);
int mcfg_start = table_data->len;
mcfg = acpi_data_push(table_data, len); mcfg = acpi_data_push(table_data, len);
mcfg->allocation[0].address = cpu_to_le64(memmap[ecam_id].base); mcfg->allocation[0].address = cpu_to_le64(info->base);
/* Only a single allocation so no need to play with segments */ /* Only a single allocation so no need to play with segments */
mcfg->allocation[0].pci_segment = cpu_to_le16(0); mcfg->allocation[0].pci_segment = cpu_to_le16(0);
mcfg->allocation[0].start_bus_number = 0; mcfg->allocation[0].start_bus_number = 0;
mcfg->allocation[0].end_bus_number = mcfg->allocation[0].end_bus_number = PCIE_MMCFG_BUS(info->size - 1);
PCIE_MMCFG_BUS(memmap[ecam_id].size - 1);
build_header(linker, table_data, (void *)(table_data->data + mcfg_start), build_header(linker, table_data, (void *)mcfg, "MCFG", len, 1, NULL, NULL);
"MCFG", table_data->len - mcfg_start, 1, NULL, NULL);
} }
/* GTDT */ /* GTDT */
@ -803,7 +799,13 @@ void virt_acpi_build(VirtMachineState *vms, AcpiBuildTables *tables)
build_gtdt(tables_blob, tables->linker, vms); build_gtdt(tables_blob, tables->linker, vms);
acpi_add_table(table_offsets, tables_blob); acpi_add_table(table_offsets, tables_blob);
build_mcfg(tables_blob, tables->linker, vms); {
AcpiMcfgInfo mcfg = {
.base = vms->memmap[VIRT_ECAM_ID(vms->highmem_ecam)].base,
.size = vms->memmap[VIRT_ECAM_ID(vms->highmem_ecam)].size,
};
build_mcfg(tables_blob, tables->linker, &mcfg);
}
acpi_add_table(table_offsets, tables_blob); acpi_add_table(table_offsets, tables_blob);
build_spcr(tables_blob, tables->linker, vms); build_spcr(tables_blob, tables->linker, vms);

View File

@ -103,7 +103,7 @@ const VhostDevConfigOps blk_ops = {
.vhost_dev_config_notifier = vhost_user_blk_handle_config_change, .vhost_dev_config_notifier = vhost_user_blk_handle_config_change,
}; };
static void vhost_user_blk_start(VirtIODevice *vdev) static int vhost_user_blk_start(VirtIODevice *vdev)
{ {
VHostUserBlk *s = VHOST_USER_BLK(vdev); VHostUserBlk *s = VHOST_USER_BLK(vdev);
BusState *qbus = BUS(qdev_get_parent_bus(DEVICE(vdev))); BusState *qbus = BUS(qdev_get_parent_bus(DEVICE(vdev)));
@ -112,13 +112,13 @@ static void vhost_user_blk_start(VirtIODevice *vdev)
if (!k->set_guest_notifiers) { if (!k->set_guest_notifiers) {
error_report("binding does not support guest notifiers"); error_report("binding does not support guest notifiers");
return; return -ENOSYS;
} }
ret = vhost_dev_enable_notifiers(&s->dev, vdev); ret = vhost_dev_enable_notifiers(&s->dev, vdev);
if (ret < 0) { if (ret < 0) {
error_report("Error enabling host notifiers: %d", -ret); error_report("Error enabling host notifiers: %d", -ret);
return; return ret;
} }
ret = k->set_guest_notifiers(qbus->parent, s->dev.nvqs, true); ret = k->set_guest_notifiers(qbus->parent, s->dev.nvqs, true);
@ -157,12 +157,13 @@ static void vhost_user_blk_start(VirtIODevice *vdev)
vhost_virtqueue_mask(&s->dev, vdev, i, false); vhost_virtqueue_mask(&s->dev, vdev, i, false);
} }
return; return ret;
err_guest_notifiers: err_guest_notifiers:
k->set_guest_notifiers(qbus->parent, s->dev.nvqs, false); k->set_guest_notifiers(qbus->parent, s->dev.nvqs, false);
err_host_notifiers: err_host_notifiers:
vhost_dev_disable_notifiers(&s->dev, vdev); vhost_dev_disable_notifiers(&s->dev, vdev);
return ret;
} }
static void vhost_user_blk_stop(VirtIODevice *vdev) static void vhost_user_blk_stop(VirtIODevice *vdev)
@ -190,18 +191,28 @@ static void vhost_user_blk_stop(VirtIODevice *vdev)
static void vhost_user_blk_set_status(VirtIODevice *vdev, uint8_t status) static void vhost_user_blk_set_status(VirtIODevice *vdev, uint8_t status)
{ {
VHostUserBlk *s = VHOST_USER_BLK(vdev); VHostUserBlk *s = VHOST_USER_BLK(vdev);
bool should_start = status & VIRTIO_CONFIG_S_DRIVER_OK; bool should_start = vdev->started;
int ret;
if (!vdev->vm_running) { if (!vdev->vm_running) {
should_start = false; should_start = false;
} }
if (!s->connected) {
return;
}
if (s->dev.started == should_start) { if (s->dev.started == should_start) {
return; return;
} }
if (should_start) { if (should_start) {
vhost_user_blk_start(vdev); ret = vhost_user_blk_start(vdev);
if (ret < 0) {
error_report("vhost-user-blk: vhost start failed: %s",
strerror(-ret));
qemu_chr_fe_disconnect(&s->chardev);
}
} else { } else {
vhost_user_blk_stop(vdev); vhost_user_blk_stop(vdev);
} }
@ -237,10 +248,13 @@ static uint64_t vhost_user_blk_get_features(VirtIODevice *vdev,
static void vhost_user_blk_handle_output(VirtIODevice *vdev, VirtQueue *vq) static void vhost_user_blk_handle_output(VirtIODevice *vdev, VirtQueue *vq)
{ {
VHostUserBlk *s = VHOST_USER_BLK(vdev); VHostUserBlk *s = VHOST_USER_BLK(vdev);
int i; int i, ret;
if (!(virtio_host_has_feature(vdev, VIRTIO_F_VERSION_1) && if (!vdev->start_on_kick) {
!virtio_vdev_has_feature(vdev, VIRTIO_F_VERSION_1))) { return;
}
if (!s->connected) {
return; return;
} }
@ -251,7 +265,13 @@ static void vhost_user_blk_handle_output(VirtIODevice *vdev, VirtQueue *vq)
/* Some guests kick before setting VIRTIO_CONFIG_S_DRIVER_OK so start /* Some guests kick before setting VIRTIO_CONFIG_S_DRIVER_OK so start
* vhost here instead of waiting for .set_status(). * vhost here instead of waiting for .set_status().
*/ */
vhost_user_blk_start(vdev); ret = vhost_user_blk_start(vdev);
if (ret < 0) {
error_report("vhost-user-blk: vhost start failed: %s",
strerror(-ret));
qemu_chr_fe_disconnect(&s->chardev);
return;
}
/* Kick right away to begin processing requests already in vring */ /* Kick right away to begin processing requests already in vring */
for (i = 0; i < s->dev.nvqs; i++) { for (i = 0; i < s->dev.nvqs; i++) {
@ -271,11 +291,103 @@ static void vhost_user_blk_reset(VirtIODevice *vdev)
vhost_dev_free_inflight(s->inflight); vhost_dev_free_inflight(s->inflight);
} }
static int vhost_user_blk_connect(DeviceState *dev)
{
VirtIODevice *vdev = VIRTIO_DEVICE(dev);
VHostUserBlk *s = VHOST_USER_BLK(vdev);
int ret = 0;
if (s->connected) {
return 0;
}
s->connected = true;
s->dev.nvqs = s->num_queues;
s->dev.vqs = s->vqs;
s->dev.vq_index = 0;
s->dev.backend_features = 0;
vhost_dev_set_config_notifier(&s->dev, &blk_ops);
ret = vhost_dev_init(&s->dev, &s->vhost_user, VHOST_BACKEND_TYPE_USER, 0);
if (ret < 0) {
error_report("vhost-user-blk: vhost initialization failed: %s",
strerror(-ret));
return ret;
}
/* restore vhost state */
if (vdev->started) {
ret = vhost_user_blk_start(vdev);
if (ret < 0) {
error_report("vhost-user-blk: vhost start failed: %s",
strerror(-ret));
return ret;
}
}
return 0;
}
static void vhost_user_blk_disconnect(DeviceState *dev)
{
VirtIODevice *vdev = VIRTIO_DEVICE(dev);
VHostUserBlk *s = VHOST_USER_BLK(vdev);
if (!s->connected) {
return;
}
s->connected = false;
if (s->dev.started) {
vhost_user_blk_stop(vdev);
}
vhost_dev_cleanup(&s->dev);
}
static gboolean vhost_user_blk_watch(GIOChannel *chan, GIOCondition cond,
void *opaque)
{
DeviceState *dev = opaque;
VirtIODevice *vdev = VIRTIO_DEVICE(dev);
VHostUserBlk *s = VHOST_USER_BLK(vdev);
qemu_chr_fe_disconnect(&s->chardev);
return true;
}
static void vhost_user_blk_event(void *opaque, int event)
{
DeviceState *dev = opaque;
VirtIODevice *vdev = VIRTIO_DEVICE(dev);
VHostUserBlk *s = VHOST_USER_BLK(vdev);
switch (event) {
case CHR_EVENT_OPENED:
if (vhost_user_blk_connect(dev) < 0) {
qemu_chr_fe_disconnect(&s->chardev);
return;
}
s->watch = qemu_chr_fe_add_watch(&s->chardev, G_IO_HUP,
vhost_user_blk_watch, dev);
break;
case CHR_EVENT_CLOSED:
vhost_user_blk_disconnect(dev);
if (s->watch) {
g_source_remove(s->watch);
s->watch = 0;
}
break;
}
}
static void vhost_user_blk_device_realize(DeviceState *dev, Error **errp) static void vhost_user_blk_device_realize(DeviceState *dev, Error **errp)
{ {
VirtIODevice *vdev = VIRTIO_DEVICE(dev); VirtIODevice *vdev = VIRTIO_DEVICE(dev);
VHostUserBlk *s = VHOST_USER_BLK(vdev); VHostUserBlk *s = VHOST_USER_BLK(vdev);
struct vhost_virtqueue *vqs = NULL; Error *err = NULL;
int i, ret; int i, ret;
if (!s->chardev.chr) { if (!s->chardev.chr) {
@ -306,27 +418,29 @@ static void vhost_user_blk_device_realize(DeviceState *dev, Error **errp)
} }
s->inflight = g_new0(struct vhost_inflight, 1); s->inflight = g_new0(struct vhost_inflight, 1);
s->vqs = g_new(struct vhost_virtqueue, s->num_queues);
s->watch = 0;
s->connected = false;
s->dev.nvqs = s->num_queues; qemu_chr_fe_set_handlers(&s->chardev, NULL, NULL, vhost_user_blk_event,
s->dev.vqs = g_new(struct vhost_virtqueue, s->dev.nvqs); NULL, (void *)dev, NULL, true);
s->dev.vq_index = 0;
s->dev.backend_features = 0;
vqs = s->dev.vqs;
vhost_dev_set_config_notifier(&s->dev, &blk_ops); reconnect:
if (qemu_chr_fe_wait_connected(&s->chardev, &err) < 0) {
ret = vhost_dev_init(&s->dev, &s->vhost_user, VHOST_BACKEND_TYPE_USER, 0); error_report_err(err);
if (ret < 0) {
error_setg(errp, "vhost-user-blk: vhost initialization failed: %s",
strerror(-ret));
goto virtio_err; goto virtio_err;
} }
/* check whether vhost_user_blk_connect() failed or not */
if (!s->connected) {
goto reconnect;
}
ret = vhost_dev_get_config(&s->dev, (uint8_t *)&s->blkcfg, ret = vhost_dev_get_config(&s->dev, (uint8_t *)&s->blkcfg,
sizeof(struct virtio_blk_config)); sizeof(struct virtio_blk_config));
if (ret < 0) { if (ret < 0) {
error_setg(errp, "vhost-user-blk: get block config failed"); error_report("vhost-user-blk: get block config failed");
goto vhost_err; goto reconnect;
} }
if (s->blkcfg.num_queues != s->num_queues) { if (s->blkcfg.num_queues != s->num_queues) {
@ -335,10 +449,8 @@ static void vhost_user_blk_device_realize(DeviceState *dev, Error **errp)
return; return;
vhost_err:
vhost_dev_cleanup(&s->dev);
virtio_err: virtio_err:
g_free(vqs); g_free(s->vqs);
g_free(s->inflight); g_free(s->inflight);
virtio_cleanup(vdev); virtio_cleanup(vdev);
vhost_user_cleanup(&s->vhost_user); vhost_user_cleanup(&s->vhost_user);
@ -348,12 +460,13 @@ static void vhost_user_blk_device_unrealize(DeviceState *dev, Error **errp)
{ {
VirtIODevice *vdev = VIRTIO_DEVICE(dev); VirtIODevice *vdev = VIRTIO_DEVICE(dev);
VHostUserBlk *s = VHOST_USER_BLK(dev); VHostUserBlk *s = VHOST_USER_BLK(dev);
struct vhost_virtqueue *vqs = s->dev.vqs;
vhost_user_blk_set_status(vdev, 0); virtio_set_status(vdev, 0);
qemu_chr_fe_set_handlers(&s->chardev, NULL, NULL, NULL,
NULL, NULL, NULL, false);
vhost_dev_cleanup(&s->dev); vhost_dev_cleanup(&s->dev);
vhost_dev_free_inflight(s->inflight); vhost_dev_free_inflight(s->inflight);
g_free(vqs); g_free(s->vqs);
g_free(s->inflight); g_free(s->inflight);
virtio_cleanup(vdev); virtio_cleanup(vdev);
vhost_user_cleanup(&s->vhost_user); vhost_user_cleanup(&s->vhost_user);

View File

@ -102,9 +102,26 @@ const size_t hw_compat_2_7_len = G_N_ELEMENTS(hw_compat_2_7);
GlobalProperty hw_compat_2_6[] = { GlobalProperty hw_compat_2_6[] = {
{ "virtio-mmio", "format_transport_address", "off" }, { "virtio-mmio", "format_transport_address", "off" },
/* Optional because not all virtio-pci devices support legacy mode */ /*
{ "virtio-pci", "disable-modern", "on", .optional = true }, * don't include devices which are modern-only
{ "virtio-pci", "disable-legacy", "off", .optional = true }, * ie keyboard, mouse, tablet, gpu, vga & crypto
*/
{ "virtio-9p-pci", "disable-modern", "on" },
{ "virtio-9p-pci", "disable-legacy", "off" },
{ "virtio-balloon-pci", "disable-modern", "on" },
{ "virtio-balloon-pci", "disable-legacy", "off" },
{ "virtio-blk-pci", "disable-modern", "on" },
{ "virtio-blk-pci", "disable-legacy", "off" },
{ "virtio-input-host-pci", "disable-modern", "on" },
{ "virtio-input-host-pci", "disable-legacy", "off" },
{ "virtio-net-pci", "disable-modern", "on" },
{ "virtio-net-pci", "disable-legacy", "off" },
{ "virtio-rng-pci", "disable-modern", "on" },
{ "virtio-rng-pci", "disable-legacy", "off" },
{ "virtio-scsi-pci", "disable-modern", "on" },
{ "virtio-scsi-pci", "disable-legacy", "off" },
{ "virtio-serial-pci", "disable-modern", "on" },
{ "virtio-serial-pci", "disable-legacy", "off" },
}; };
const size_t hw_compat_2_6_len = G_N_ELEMENTS(hw_compat_2_6); const size_t hw_compat_2_6_len = G_N_ELEMENTS(hw_compat_2_6);

View File

@ -47,7 +47,9 @@ static void virtio_gpu_pci_realize(VirtIOPCIProxy *vpci_dev, Error **errp)
Error *local_error = NULL; Error *local_error = NULL;
qdev_set_parent_bus(vdev, BUS(&vpci_dev->bus)); qdev_set_parent_bus(vdev, BUS(&vpci_dev->bus));
virtio_pci_force_virtio_1(vpci_dev); if (!virtio_pci_force_virtio_1(vpci_dev, errp)) {
return;
}
object_property_set_bool(OBJECT(vdev), true, "realized", &local_error); object_property_set_bool(OBJECT(vdev), true, "realized", &local_error);
if (local_error) { if (local_error) {

View File

@ -154,7 +154,9 @@ static void virtio_vga_realize(VirtIOPCIProxy *vpci_dev, Error **errp)
/* init virtio bits */ /* init virtio bits */
qdev_set_parent_bus(DEVICE(g), BUS(&vpci_dev->bus)); qdev_set_parent_bus(DEVICE(g), BUS(&vpci_dev->bus));
virtio_pci_force_virtio_1(vpci_dev); if (!virtio_pci_force_virtio_1(vpci_dev, errp)) {
return;
}
object_property_set_bool(OBJECT(g), true, "realized", &err); object_property_set_bool(OBJECT(g), true, "realized", &err);
if (err) { if (err) {
error_propagate(errp, err); error_propagate(errp, err);

View File

@ -59,6 +59,7 @@
#include "hw/i386/x86-iommu.h" #include "hw/i386/x86-iommu.h"
#include "hw/acpi/aml-build.h" #include "hw/acpi/aml-build.h"
#include "hw/acpi/pci.h"
#include "qom/qom-qobject.h" #include "qom/qom-qobject.h"
#include "hw/i386/amd_iommu.h" #include "hw/i386/amd_iommu.h"
@ -87,11 +88,6 @@
/* Default IOAPIC ID */ /* Default IOAPIC ID */
#define ACPI_BUILD_IOAPIC_ID 0x0 #define ACPI_BUILD_IOAPIC_ID 0x0
typedef struct AcpiMcfgInfo {
uint64_t mcfg_base;
uint32_t mcfg_size;
} AcpiMcfgInfo;
typedef struct AcpiPmInfo { typedef struct AcpiPmInfo {
bool s3_disabled; bool s3_disabled;
bool s4_disabled; bool s4_disabled;
@ -2413,29 +2409,16 @@ static void
build_mcfg_q35(GArray *table_data, BIOSLinker *linker, AcpiMcfgInfo *info) build_mcfg_q35(GArray *table_data, BIOSLinker *linker, AcpiMcfgInfo *info)
{ {
AcpiTableMcfg *mcfg; AcpiTableMcfg *mcfg;
const char *sig;
int len = sizeof(*mcfg) + 1 * sizeof(mcfg->allocation[0]); int len = sizeof(*mcfg) + 1 * sizeof(mcfg->allocation[0]);
mcfg = acpi_data_push(table_data, len); mcfg = acpi_data_push(table_data, len);
mcfg->allocation[0].address = cpu_to_le64(info->mcfg_base); mcfg->allocation[0].address = cpu_to_le64(info->base);
/* Only a single allocation so no need to play with segments */ /* Only a single allocation so no need to play with segments */
mcfg->allocation[0].pci_segment = cpu_to_le16(0); mcfg->allocation[0].pci_segment = cpu_to_le16(0);
mcfg->allocation[0].start_bus_number = 0; mcfg->allocation[0].start_bus_number = 0;
mcfg->allocation[0].end_bus_number = PCIE_MMCFG_BUS(info->mcfg_size - 1); mcfg->allocation[0].end_bus_number = PCIE_MMCFG_BUS(info->size - 1);
/* MCFG is used for ECAM which can be enabled or disabled by guest. build_header(linker, table_data, (void *)mcfg, "MCFG", len, 1, NULL, NULL);
* To avoid table size changes (which create migration issues),
* always create the table even if there are no allocations,
* but set the signature to a reserved value in this case.
* ACPI spec requires OSPMs to ignore such tables.
*/
if (info->mcfg_base == PCIE_BASE_ADDR_UNMAPPED) {
/* Reserved signature: ignored by OSPM */
sig = "QEMU";
} else {
sig = "MCFG";
}
build_header(linker, table_data, (void *)mcfg, sig, len, 1, NULL, NULL);
} }
/* /*
@ -2602,12 +2585,15 @@ static bool acpi_get_mcfg(AcpiMcfgInfo *mcfg)
if (!o) { if (!o) {
return false; return false;
} }
mcfg->mcfg_base = qnum_get_uint(qobject_to(QNum, o)); mcfg->base = qnum_get_uint(qobject_to(QNum, o));
qobject_unref(o); qobject_unref(o);
if (mcfg->base == PCIE_BASE_ADDR_UNMAPPED) {
return false;
}
o = object_property_get_qobject(pci_host, PCIE_HOST_MCFG_SIZE, NULL); o = object_property_get_qobject(pci_host, PCIE_HOST_MCFG_SIZE, NULL);
assert(o); assert(o);
mcfg->mcfg_size = qnum_get_uint(qobject_to(QNum, o)); mcfg->size = qnum_get_uint(qobject_to(QNum, o));
qobject_unref(o); qobject_unref(o);
return true; return true;
} }

View File

@ -66,11 +66,6 @@ static int pxb_bus_num(PCIBus *bus)
return pxb->bus_nr; return pxb->bus_nr;
} }
static bool pxb_is_root(PCIBus *bus)
{
return true; /* by definition */
}
static uint16_t pxb_bus_numa_node(PCIBus *bus) static uint16_t pxb_bus_numa_node(PCIBus *bus)
{ {
PXBDev *pxb = convert_to_pxb(bus->parent_dev); PXBDev *pxb = convert_to_pxb(bus->parent_dev);
@ -83,7 +78,6 @@ static void pxb_bus_class_init(ObjectClass *class, void *data)
PCIBusClass *pbc = PCI_BUS_CLASS(class); PCIBusClass *pbc = PCI_BUS_CLASS(class);
pbc->bus_num = pxb_bus_num; pbc->bus_num = pxb_bus_num;
pbc->is_root = pxb_is_root;
pbc->numa_node = pxb_bus_numa_node; pbc->numa_node = pxb_bus_numa_node;
} }

View File

@ -129,14 +129,9 @@ static void pci_bus_unrealize(BusState *qbus, Error **errp)
vmstate_unregister(NULL, &vmstate_pcibus, bus); vmstate_unregister(NULL, &vmstate_pcibus, bus);
} }
static bool pcibus_is_root(PCIBus *bus)
{
return !bus->parent_dev;
}
static int pcibus_num(PCIBus *bus) static int pcibus_num(PCIBus *bus)
{ {
if (pcibus_is_root(bus)) { if (pci_bus_is_root(bus)) {
return 0; /* pci host bridge */ return 0; /* pci host bridge */
} }
return bus->parent_dev->config[PCI_SECONDARY_BUS]; return bus->parent_dev->config[PCI_SECONDARY_BUS];
@ -164,7 +159,6 @@ static void pci_bus_class_init(ObjectClass *klass, void *data)
k->unrealize = pci_bus_unrealize; k->unrealize = pci_bus_unrealize;
k->reset = pcibus_reset; k->reset = pcibus_reset;
pbc->is_root = pcibus_is_root;
pbc->bus_num = pcibus_num; pbc->bus_num = pcibus_num;
pbc->numa_node = pcibus_numa_node; pbc->numa_node = pcibus_numa_node;
pbc->allows_extended_config_space = pcibus_allows_extended_config_space; pbc->allows_extended_config_space = pcibus_allows_extended_config_space;
@ -398,6 +392,7 @@ static void pci_root_bus_init(PCIBus *bus, DeviceState *parent,
bus->slot_reserved_mask = 0x0; bus->slot_reserved_mask = 0x0;
bus->address_space_mem = address_space_mem; bus->address_space_mem = address_space_mem;
bus->address_space_io = address_space_io; bus->address_space_io = address_space_io;
bus->flags |= PCI_BUS_IS_ROOT;
/* host bridge */ /* host bridge */
QLIST_INIT(&bus->child); QLIST_INIT(&bus->child);
@ -415,11 +410,6 @@ bool pci_bus_is_express(PCIBus *bus)
return object_dynamic_cast(OBJECT(bus), TYPE_PCIE_BUS); return object_dynamic_cast(OBJECT(bus), TYPE_PCIE_BUS);
} }
bool pci_bus_is_root(PCIBus *bus)
{
return PCI_BUS_GET_CLASS(bus)->is_root(bus);
}
bool pci_bus_allows_extended_config_space(PCIBus *bus) bool pci_bus_allows_extended_config_space(PCIBus *bus)
{ {
return PCI_BUS_GET_CLASS(bus)->allows_extended_config_space(bus); return PCI_BUS_GET_CLASS(bus)->allows_extended_config_space(bus);

View File

@ -47,11 +47,6 @@ static void pcie_mmcfg_data_write(void *opaque, hwaddr mmcfg_addr,
} }
addr = PCIE_MMCFG_CONFOFFSET(mmcfg_addr); addr = PCIE_MMCFG_CONFOFFSET(mmcfg_addr);
limit = pci_config_size(pci_dev); limit = pci_config_size(pci_dev);
if (limit <= addr) {
/* conventional pci device can be behind pcie-to-pci bridge.
256 <= addr < 4K has no effects. */
return;
}
pci_host_config_write_common(pci_dev, addr, limit, val, len); pci_host_config_write_common(pci_dev, addr, limit, val, len);
} }
@ -70,11 +65,6 @@ static uint64_t pcie_mmcfg_data_read(void *opaque,
} }
addr = PCIE_MMCFG_CONFOFFSET(mmcfg_addr); addr = PCIE_MMCFG_CONFOFFSET(mmcfg_addr);
limit = pci_config_size(pci_dev); limit = pci_config_size(pci_dev);
if (limit <= addr) {
/* conventional pci device can be behind pcie-to-pci bridge.
256 <= addr < 4K has no effects. */
return ~0x0;
}
return pci_host_config_read_common(pci_dev, addr, limit, len); return pci_host_config_read_common(pci_dev, addr, limit, len);
} }

View File

@ -51,7 +51,9 @@ static void virtio_crypto_pci_realize(VirtIOPCIProxy *vpci_dev, Error **errp)
} }
qdev_set_parent_bus(vdev, BUS(&vpci_dev->bus)); qdev_set_parent_bus(vdev, BUS(&vpci_dev->bus));
virtio_pci_force_virtio_1(vpci_dev); if (!virtio_pci_force_virtio_1(vpci_dev, errp)) {
return;
}
object_property_set_bool(OBJECT(vdev), true, "realized", errp); object_property_set_bool(OBJECT(vdev), true, "realized", errp);
object_property_set_link(OBJECT(vcrypto), object_property_set_link(OBJECT(vcrypto),
OBJECT(vcrypto->vdev.conf.cryptodev), "cryptodev", OBJECT(vcrypto->vdev.conf.cryptodev), "cryptodev",

View File

@ -48,7 +48,9 @@ static void virtio_input_pci_realize(VirtIOPCIProxy *vpci_dev, Error **errp)
DeviceState *vdev = DEVICE(&vinput->vdev); DeviceState *vdev = DEVICE(&vinput->vdev);
qdev_set_parent_bus(vdev, BUS(&vpci_dev->bus)); qdev_set_parent_bus(vdev, BUS(&vpci_dev->bus));
virtio_pci_force_virtio_1(vpci_dev); if (!virtio_pci_force_virtio_1(vpci_dev, errp)) {
return;
}
object_property_set_bool(OBJECT(vdev), true, "realized", errp); object_property_set_bool(OBJECT(vdev), true, "realized", errp);
} }

View File

@ -20,6 +20,7 @@
#include "standard-headers/linux/virtio_pci.h" #include "standard-headers/linux/virtio_pci.h"
#include "hw/virtio/virtio.h" #include "hw/virtio/virtio.h"
#include "hw/pci/pci.h" #include "hw/pci/pci.h"
#include "hw/pci/pci_bus.h"
#include "qapi/error.h" #include "qapi/error.h"
#include "qemu/error-report.h" #include "qemu/error-report.h"
#include "hw/pci/msi.h" #include "hw/pci/msi.h"
@ -1721,16 +1722,22 @@ static void virtio_pci_realize(PCIDevice *pci_dev, Error **errp)
/* PCI BAR regions must be powers of 2 */ /* PCI BAR regions must be powers of 2 */
pow2ceil(proxy->notify.offset + proxy->notify.size)); pow2ceil(proxy->notify.offset + proxy->notify.size));
if (proxy->disable_legacy == ON_OFF_AUTO_AUTO) { if ((proxy->disable_legacy == ON_OFF_AUTO_ON) ||
proxy->disable_legacy = pcie_port ? ON_OFF_AUTO_ON : ON_OFF_AUTO_OFF; ((proxy->disable_legacy == ON_OFF_AUTO_AUTO) && pcie_port)) {
} if (proxy->disable_modern) {
error_setg(errp, "device cannot work as neither modern nor "
if (!virtio_pci_modern(proxy) && !virtio_pci_legacy(proxy)) { "legacy mode is enabled");
error_setg(errp, "device cannot work as neither modern nor legacy mode" error_append_hint(errp, "Set either disable-modern or "
" is enabled"); "disable-legacy to off\n");
error_append_hint(errp, "Set either disable-modern or disable-legacy" return;
" to off\n"); }
return; proxy->mode = VIRTIO_PCI_MODE_MODERN;
} else {
if (proxy->disable_modern) {
proxy->mode = VIRTIO_PCI_MODE_LEGACY;
} else {
proxy->mode = VIRTIO_PCI_MODE_TRANSITIONAL;
}
} }
if (pcie_port && pci_is_express(pci_dev)) { if (pcie_port && pci_is_express(pci_dev)) {

View File

@ -15,6 +15,7 @@
#ifndef QEMU_VIRTIO_PCI_H #ifndef QEMU_VIRTIO_PCI_H
#define QEMU_VIRTIO_PCI_H #define QEMU_VIRTIO_PCI_H
#include "qapi/error.h"
#include "hw/pci/msi.h" #include "hw/pci/msi.h"
#include "hw/virtio/virtio-bus.h" #include "hw/virtio/virtio-bus.h"
@ -118,6 +119,12 @@ typedef struct VirtIOPCIQueue {
uint32_t used[2]; uint32_t used[2];
} VirtIOPCIQueue; } VirtIOPCIQueue;
typedef enum {
VIRTIO_PCI_MODE_LEGACY,
VIRTIO_PCI_MODE_TRANSITIONAL,
VIRTIO_PCI_MODE_MODERN,
} VirtIOPCIMode;
struct VirtIOPCIProxy { struct VirtIOPCIProxy {
PCIDevice pci_dev; PCIDevice pci_dev;
MemoryRegion bar; MemoryRegion bar;
@ -142,6 +149,7 @@ struct VirtIOPCIProxy {
bool disable_modern; bool disable_modern;
bool ignore_backend_features; bool ignore_backend_features;
OnOffAuto disable_legacy; OnOffAuto disable_legacy;
VirtIOPCIMode mode;
uint32_t class_code; uint32_t class_code;
uint32_t nvectors; uint32_t nvectors;
uint32_t dfselect; uint32_t dfselect;
@ -156,23 +164,34 @@ struct VirtIOPCIProxy {
static inline bool virtio_pci_modern(VirtIOPCIProxy *proxy) static inline bool virtio_pci_modern(VirtIOPCIProxy *proxy)
{ {
return !proxy->disable_modern; return proxy->mode != VIRTIO_PCI_MODE_LEGACY;
} }
static inline bool virtio_pci_legacy(VirtIOPCIProxy *proxy) static inline bool virtio_pci_legacy(VirtIOPCIProxy *proxy)
{ {
return proxy->disable_legacy == ON_OFF_AUTO_OFF; return proxy->mode != VIRTIO_PCI_MODE_MODERN;
} }
static inline void virtio_pci_force_virtio_1(VirtIOPCIProxy *proxy) static inline bool virtio_pci_force_virtio_1(VirtIOPCIProxy *proxy,
Error **errp)
{ {
proxy->disable_modern = false; if (proxy->disable_legacy == ON_OFF_AUTO_OFF) {
proxy->disable_legacy = ON_OFF_AUTO_ON; error_setg(errp, "Unable to set disable-legacy=off on a virtio-1.0 "
"only device");
return false;
}
if (proxy->disable_modern == true) {
error_setg(errp, "Unable to set disable-modern=on on a virtio-1.0 "
"only device");
return false;
}
proxy->mode = VIRTIO_PCI_MODE_MODERN;
return true;
} }
static inline void virtio_pci_disable_modern(VirtIOPCIProxy *proxy) static inline void virtio_pci_disable_modern(VirtIOPCIProxy *proxy)
{ {
proxy->disable_modern = true; proxy->mode = VIRTIO_PCI_MODE_LEGACY;
} }
/* /*

View File

@ -1162,10 +1162,16 @@ int virtio_set_status(VirtIODevice *vdev, uint8_t val)
} }
} }
} }
vdev->started = val & VIRTIO_CONFIG_S_DRIVER_OK;
if (unlikely(vdev->start_on_kick && vdev->started)) {
vdev->start_on_kick = false;
}
if (k->set_status) { if (k->set_status) {
k->set_status(vdev, val); k->set_status(vdev, val);
} }
vdev->status = val; vdev->status = val;
return 0; return 0;
} }
@ -1208,6 +1214,9 @@ void virtio_reset(void *opaque)
k->reset(vdev); k->reset(vdev);
} }
vdev->start_on_kick = (virtio_host_has_feature(vdev, VIRTIO_F_VERSION_1) &&
!virtio_vdev_has_feature(vdev, VIRTIO_F_VERSION_1));
vdev->started = false;
vdev->broken = false; vdev->broken = false;
vdev->guest_features = 0; vdev->guest_features = 0;
vdev->queue_sel = 0; vdev->queue_sel = 0;
@ -1518,14 +1527,21 @@ void virtio_queue_set_align(VirtIODevice *vdev, int n, int align)
static bool virtio_queue_notify_aio_vq(VirtQueue *vq) static bool virtio_queue_notify_aio_vq(VirtQueue *vq)
{ {
bool ret = false;
if (vq->vring.desc && vq->handle_aio_output) { if (vq->vring.desc && vq->handle_aio_output) {
VirtIODevice *vdev = vq->vdev; VirtIODevice *vdev = vq->vdev;
trace_virtio_queue_notify(vdev, vq - vdev->vq, vq); trace_virtio_queue_notify(vdev, vq - vdev->vq, vq);
return vq->handle_aio_output(vdev, vq); ret = vq->handle_aio_output(vdev, vq);
if (unlikely(vdev->start_on_kick)) {
vdev->started = true;
vdev->start_on_kick = false;
}
} }
return false; return ret;
} }
static void virtio_queue_notify_vq(VirtQueue *vq) static void virtio_queue_notify_vq(VirtQueue *vq)
@ -1539,6 +1555,11 @@ static void virtio_queue_notify_vq(VirtQueue *vq)
trace_virtio_queue_notify(vdev, vq - vdev->vq, vq); trace_virtio_queue_notify(vdev, vq - vdev->vq, vq);
vq->handle_output(vdev, vq); vq->handle_output(vdev, vq);
if (unlikely(vdev->start_on_kick)) {
vdev->started = true;
vdev->start_on_kick = false;
}
} }
} }
@ -1556,6 +1577,11 @@ void virtio_queue_notify(VirtIODevice *vdev, int n)
} else if (vq->handle_output) { } else if (vq->handle_output) {
vq->handle_output(vdev, vq); vq->handle_output(vdev, vq);
} }
if (unlikely(vdev->start_on_kick)) {
vdev->started = true;
vdev->start_on_kick = false;
}
} }
uint16_t virtio_queue_vector(VirtIODevice *vdev, int n) uint16_t virtio_queue_vector(VirtIODevice *vdev, int n)
@ -1770,6 +1796,13 @@ static bool virtio_broken_needed(void *opaque)
return vdev->broken; return vdev->broken;
} }
static bool virtio_started_needed(void *opaque)
{
VirtIODevice *vdev = opaque;
return vdev->started;
}
static const VMStateDescription vmstate_virtqueue = { static const VMStateDescription vmstate_virtqueue = {
.name = "virtqueue_state", .name = "virtqueue_state",
.version_id = 1, .version_id = 1,
@ -1898,6 +1931,17 @@ static const VMStateDescription vmstate_virtio_broken = {
} }
}; };
static const VMStateDescription vmstate_virtio_started = {
.name = "virtio/started",
.version_id = 1,
.minimum_version_id = 1,
.needed = &virtio_started_needed,
.fields = (VMStateField[]) {
VMSTATE_BOOL(started, VirtIODevice),
VMSTATE_END_OF_LIST()
}
};
static const VMStateDescription vmstate_virtio = { static const VMStateDescription vmstate_virtio = {
.name = "virtio", .name = "virtio",
.version_id = 1, .version_id = 1,
@ -1913,6 +1957,7 @@ static const VMStateDescription vmstate_virtio = {
&vmstate_virtio_ringsize, &vmstate_virtio_ringsize,
&vmstate_virtio_broken, &vmstate_virtio_broken,
&vmstate_virtio_extra_state, &vmstate_virtio_extra_state,
&vmstate_virtio_started,
NULL NULL
} }
}; };
@ -2246,7 +2291,7 @@ static void virtio_vmstate_change(void *opaque, int running, RunState state)
VirtIODevice *vdev = opaque; VirtIODevice *vdev = opaque;
BusState *qbus = qdev_get_parent_bus(DEVICE(vdev)); BusState *qbus = qdev_get_parent_bus(DEVICE(vdev));
VirtioBusClass *k = VIRTIO_BUS_GET_CLASS(qbus); VirtioBusClass *k = VIRTIO_BUS_GET_CLASS(qbus);
bool backend_run = running && (vdev->status & VIRTIO_CONFIG_S_DRIVER_OK); bool backend_run = running && vdev->started;
vdev->vm_running = running; vdev->vm_running = running;
if (backend_run) { if (backend_run) {
@ -2286,6 +2331,9 @@ void virtio_init(VirtIODevice *vdev, const char *name,
g_malloc0(sizeof(*vdev->vector_queues) * nvectors); g_malloc0(sizeof(*vdev->vector_queues) * nvectors);
} }
vdev->start_on_kick = (virtio_host_has_feature(vdev, VIRTIO_F_VERSION_1) &&
!virtio_vdev_has_feature(vdev, VIRTIO_F_VERSION_1));
vdev->started = false;
vdev->device_id = device_id; vdev->device_id = device_id;
vdev->status = 0; vdev->status = 0;
atomic_set(&vdev->isr, 0); atomic_set(&vdev->isr, 0);

33
include/hw/acpi/pci.h Normal file
View File

@ -0,0 +1,33 @@
/*
* Support for generating PCI related ACPI tables and passing them to Guests
*
* Copyright (C) 2006 Fabrice Bellard
* Copyright (C) 2008-2010 Kevin O'Connor <kevin@koconnor.net>
* Copyright (C) 2013-2019 Red Hat Inc
* Copyright (C) 2019 Intel Corporation
*
* Author: Wei Yang <richardw.yang@linux.intel.com>
* Author: Michael S. Tsirkin <mst@redhat.com>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
* You should have received a copy of the GNU General Public License along
* with this program; if not, see <http://www.gnu.org/licenses/>.
*/
#ifndef HW_ACPI_PCI_H
#define HW_ACPI_PCI_H
typedef struct AcpiMcfgInfo {
uint64_t base;
uint32_t size;
} AcpiMcfgInfo;
#endif

View File

@ -395,7 +395,6 @@ typedef PCIINTxRoute (*pci_route_irq_fn)(void *opaque, int pin);
#define TYPE_PCIE_BUS "PCIE" #define TYPE_PCIE_BUS "PCIE"
bool pci_bus_is_express(PCIBus *bus); bool pci_bus_is_express(PCIBus *bus);
bool pci_bus_is_root(PCIBus *bus);
bool pci_bus_allows_extended_config_space(PCIBus *bus); bool pci_bus_allows_extended_config_space(PCIBus *bus);
void pci_root_bus_new_inplace(PCIBus *bus, size_t bus_size, DeviceState *parent, void pci_root_bus_new_inplace(PCIBus *bus, size_t bus_size, DeviceState *parent,

View File

@ -15,14 +15,19 @@ typedef struct PCIBusClass {
BusClass parent_class; BusClass parent_class;
/*< public >*/ /*< public >*/
bool (*is_root)(PCIBus *bus);
int (*bus_num)(PCIBus *bus); int (*bus_num)(PCIBus *bus);
uint16_t (*numa_node)(PCIBus *bus); uint16_t (*numa_node)(PCIBus *bus);
bool (*allows_extended_config_space)(PCIBus *bus); bool (*allows_extended_config_space)(PCIBus *bus);
} PCIBusClass; } PCIBusClass;
enum PCIBusFlags {
/* This bus is the root of a PCI domain */
PCI_BUS_IS_ROOT = 0x0001,
};
struct PCIBus { struct PCIBus {
BusState qbus; BusState qbus;
enum PCIBusFlags flags;
PCIIOMMUFunc iommu_fn; PCIIOMMUFunc iommu_fn;
void *iommu_opaque; void *iommu_opaque;
uint8_t devfn_min; uint8_t devfn_min;
@ -47,4 +52,9 @@ struct PCIBus {
Notifier machine_done; Notifier machine_done;
}; };
static inline bool pci_bus_is_root(PCIBus *bus)
{
return !!(bus->flags & PCI_BUS_IS_ROOT);
}
#endif /* QEMU_PCI_BUS_H */ #endif /* QEMU_PCI_BUS_H */

View File

@ -251,8 +251,6 @@ struct PropertyInfo {
/** /**
* GlobalProperty: * GlobalProperty:
* @used: Set to true if property was used when initializing a device. * @used: Set to true if property was used when initializing a device.
* @optional: If set to true, GlobalProperty will be skipped without errors
* if the property doesn't exist.
* *
* An error is fatal for non-hotplugged devices, when the global is applied. * An error is fatal for non-hotplugged devices, when the global is applied.
*/ */
@ -261,7 +259,6 @@ typedef struct GlobalProperty {
const char *property; const char *property;
const char *value; const char *value;
bool used; bool used;
bool optional;
} GlobalProperty; } GlobalProperty;
static inline void static inline void

View File

@ -38,6 +38,9 @@ typedef struct VHostUserBlk {
struct vhost_dev dev; struct vhost_dev dev;
struct vhost_inflight *inflight; struct vhost_inflight *inflight;
VhostUserState vhost_user; VhostUserState vhost_user;
struct vhost_virtqueue *vqs;
guint watch;
bool connected;
} VHostUserBlk; } VHostUserBlk;
#endif #endif

View File

@ -105,6 +105,8 @@ struct VirtIODevice
uint16_t device_id; uint16_t device_id;
bool vm_running; bool vm_running;
bool broken; /* device in invalid state, needs reset */ bool broken; /* device in invalid state, needs reset */
bool started;
bool start_on_kick; /* virtio 1.0 transitional devices support that */
VMChangeStateEntry *vmstate; VMChangeStateEntry *vmstate;
char *bus_name; char *bus_name;
uint8_t device_endian; uint8_t device_endian;

View File

@ -236,7 +236,6 @@ static void chr_closed_bh(void *opaque)
s = DO_UPCAST(NetVhostUserState, nc, ncs[0]); s = DO_UPCAST(NetVhostUserState, nc, ncs[0]);
qmp_set_link(name, false, &err); qmp_set_link(name, false, &err);
vhost_user_stop(queues, ncs);
qemu_chr_fe_set_handlers(&s->chr, NULL, NULL, net_vhost_user_event, qemu_chr_fe_set_handlers(&s->chr, NULL, NULL, net_vhost_user_event,
NULL, opaque, NULL, true); NULL, opaque, NULL, true);

View File

@ -385,9 +385,6 @@ void object_apply_global_props(Object *obj, const GPtrArray *props, Error **errp
if (object_dynamic_cast(obj, p->driver) == NULL) { if (object_dynamic_cast(obj, p->driver) == NULL) {
continue; continue;
} }
if (p->optional && !object_property_find(obj, p->property, NULL)) {
continue;
}
p->used = true; p->used = true;
object_property_parse(obj, p->value, p->property, &err); object_property_parse(obj, p->value, p->property, &err);
if (err != NULL) { if (err != NULL) {

View File

@ -51,19 +51,7 @@ uint32_t acpi_find_rsdp_address(QTestState *qts)
return off; return off;
} }
uint64_t acpi_get_xsdt_address(uint8_t *rsdp_table) void acpi_fetch_rsdp_table(QTestState *qts, uint64_t addr, uint8_t *rsdp_table)
{
uint64_t xsdt_physical_address;
uint8_t revision = rsdp_table[15 /* Revision offset */];
/* We must have revision 2 if we're looking for an XSDT pointer */
g_assert(revision == 2);
memcpy(&xsdt_physical_address, &rsdp_table[24 /* XsdtAddress offset */], 8);
return le64_to_cpu(xsdt_physical_address);
}
void acpi_parse_rsdp_table(QTestState *qts, uint32_t addr, uint8_t *rsdp_table)
{ {
uint8_t revision; uint8_t revision;
@ -91,13 +79,15 @@ void acpi_parse_rsdp_table(QTestState *qts, uint32_t addr, uint8_t *rsdp_table)
* actual one. * actual one.
*/ */
void acpi_fetch_table(QTestState *qts, uint8_t **aml, uint32_t *aml_len, void acpi_fetch_table(QTestState *qts, uint8_t **aml, uint32_t *aml_len,
const uint8_t *addr_ptr, const char *sig, const uint8_t *addr_ptr, int addr_size, const char *sig,
bool verify_checksum) bool verify_checksum)
{ {
uint32_t addr, len; uint32_t len;
uint64_t addr = 0;
memcpy(&addr, addr_ptr , sizeof(addr)); g_assert(addr_size == 4 || addr_size == 8);
addr = le32_to_cpu(addr); memcpy(&addr, addr_ptr , addr_size);
addr = le64_to_cpu(addr);
qtest_memread(qts, addr + 4, &len, 4); /* Length of ACPI table */ qtest_memread(qts, addr + 4, &len, 4); /* Length of ACPI table */
*aml_len = le32_to_cpu(len); *aml_len = le32_to_cpu(len);
*aml = g_malloc0(*aml_len); *aml = g_malloc0(*aml_len);
@ -111,3 +101,47 @@ void acpi_fetch_table(QTestState *qts, uint8_t **aml, uint32_t *aml_len,
g_assert(!acpi_calc_checksum(*aml, *aml_len)); g_assert(!acpi_calc_checksum(*aml, *aml_len));
} }
} }
#define GUID_SIZE 16
static const uint8_t AcpiTestSupportGuid[GUID_SIZE] = {
0xb1, 0xa6, 0x87, 0xab,
0x34, 0x20,
0xa0, 0xbd,
0x71, 0xbd, 0x37, 0x50, 0x07, 0x75, 0x77, 0x85 };
typedef struct {
uint8_t signature_guid[GUID_SIZE];
uint64_t rsdp10;
uint64_t rsdp20;
} __attribute__((packed)) UefiTestSupport;
/* Wait at most 600 seconds (test is slow with TCG and --enable-debug) */
#define TEST_DELAY (1 * G_USEC_PER_SEC / 10)
#define TEST_CYCLES MAX((600 * G_USEC_PER_SEC / TEST_DELAY), 1)
#define MB 0x100000ULL
uint64_t acpi_find_rsdp_address_uefi(QTestState *qts, uint64_t start,
uint64_t size)
{
int i, j;
uint8_t data[GUID_SIZE];
for (i = 0; i < TEST_CYCLES; ++i) {
for (j = 0; j < size / MB; j++) {
/* look for GUID at every 1Mb block */
uint64_t addr = start + j * MB;
qtest_memread(qts, addr, data, sizeof(data));
if (!memcmp(AcpiTestSupportGuid, data, sizeof(data))) {
UefiTestSupport ret;
qtest_memread(qts, addr, &ret, sizeof(ret));
ret.rsdp10 = le64_to_cpu(ret.rsdp10);
ret.rsdp20 = le64_to_cpu(ret.rsdp20);
return ret.rsdp20 ? ret.rsdp20 : ret.rsdp10;
}
}
g_usleep(TEST_DELAY);
}
g_assert_not_reached();
return 0;
}

View File

@ -46,10 +46,11 @@ typedef struct {
uint8_t acpi_calc_checksum(const uint8_t *data, int len); uint8_t acpi_calc_checksum(const uint8_t *data, int len);
uint32_t acpi_find_rsdp_address(QTestState *qts); uint32_t acpi_find_rsdp_address(QTestState *qts);
uint64_t acpi_get_xsdt_address(uint8_t *rsdp_table); uint64_t acpi_find_rsdp_address_uefi(QTestState *qts, uint64_t start,
void acpi_parse_rsdp_table(QTestState *qts, uint32_t addr, uint8_t *rsdp_table); uint64_t size);
void acpi_fetch_rsdp_table(QTestState *qts, uint64_t addr, uint8_t *rsdp_table);
void acpi_fetch_table(QTestState *qts, uint8_t **aml, uint32_t *aml_len, void acpi_fetch_table(QTestState *qts, uint8_t **aml, uint32_t *aml_len,
const uint8_t *addr_ptr, const char *sig, const uint8_t *addr_ptr, int addr_size, const char *sig,
bool verify_checksum); bool verify_checksum);
#endif /* TEST_ACPI_UTILS_H */ #endif /* TEST_ACPI_UTILS_H */

View File

@ -24,9 +24,15 @@
#define ACPI_REBUILD_EXPECTED_AML "TEST_ACPI_REBUILD_AML" #define ACPI_REBUILD_EXPECTED_AML "TEST_ACPI_REBUILD_AML"
typedef struct { typedef struct {
const char *accel;
const char *machine; const char *machine;
const char *variant; const char *variant;
uint32_t rsdp_addr; const char *uefi_fl1;
const char *uefi_fl2;
const char *cd;
const uint64_t ram_start;
const uint64_t scan_len;
uint64_t rsdp_addr;
uint8_t rsdp_table[36 /* ACPI 2.0+ RSDP size */]; uint8_t rsdp_table[36 /* ACPI 2.0+ RSDP size */];
GArray *tables; GArray *tables;
uint32_t smbios_ep_addr; uint32_t smbios_ep_addr;
@ -77,22 +83,13 @@ static void free_test_data(test_data *data)
g_array_free(data->tables, true); g_array_free(data->tables, true);
} }
static void test_acpi_rsdp_address(test_data *data)
{
uint32_t off = acpi_find_rsdp_address(data->qts);
g_assert_cmphex(off, <, 0x100000);
data->rsdp_addr = off;
}
static void test_acpi_rsdp_table(test_data *data) static void test_acpi_rsdp_table(test_data *data)
{ {
uint8_t *rsdp_table = data->rsdp_table, revision; uint8_t *rsdp_table = data->rsdp_table;
uint32_t addr = data->rsdp_addr;
acpi_parse_rsdp_table(data->qts, addr, rsdp_table); acpi_fetch_rsdp_table(data->qts, data->rsdp_addr, rsdp_table);
revision = rsdp_table[15 /* Revision offset */];
switch (revision) { switch (rsdp_table[15 /* Revision offset */]) {
case 0: /* ACPI 1.0 RSDP */ case 0: /* ACPI 1.0 RSDP */
/* With rev 1, checksum is only for the first 20 bytes */ /* With rev 1, checksum is only for the first 20 bytes */
g_assert(!acpi_calc_checksum(rsdp_table, 20)); g_assert(!acpi_calc_checksum(rsdp_table, 20));
@ -107,21 +104,29 @@ static void test_acpi_rsdp_table(test_data *data)
} }
} }
static void test_acpi_rsdt_table(test_data *data) static void test_acpi_rxsdt_table(test_data *data)
{ {
const char *sig = "RSDT";
AcpiSdtTable rsdt = {}; AcpiSdtTable rsdt = {};
int entry_size = 4;
int addr_off = 16 /* RsdtAddress */;
uint8_t *ent; uint8_t *ent;
/* read RSDT table */ if (data->rsdp_table[15 /* Revision offset */] != 0) {
addr_off = 24 /* XsdtAddress */;
entry_size = 8;
sig = "XSDT";
}
/* read [RX]SDT table */
acpi_fetch_table(data->qts, &rsdt.aml, &rsdt.aml_len, acpi_fetch_table(data->qts, &rsdt.aml, &rsdt.aml_len,
&data->rsdp_table[16 /* RsdtAddress */], "RSDT", true); &data->rsdp_table[addr_off], entry_size, sig, true);
/* Load all tables and add to test list directly RSDT referenced tables */ /* Load all tables and add to test list directly RSDT referenced tables */
ACPI_FOREACH_RSDT_ENTRY(rsdt.aml, rsdt.aml_len, ent, 4 /* Entry size */) { ACPI_FOREACH_RSDT_ENTRY(rsdt.aml, rsdt.aml_len, ent, entry_size) {
AcpiSdtTable ssdt_table = {}; AcpiSdtTable ssdt_table = {};
acpi_fetch_table(data->qts, &ssdt_table.aml, &ssdt_table.aml_len, ent, acpi_fetch_table(data->qts, &ssdt_table.aml, &ssdt_table.aml_len, ent,
NULL, true); entry_size, NULL, true);
/* Add table to ASL test tables list */ /* Add table to ASL test tables list */
g_array_append_val(data->tables, ssdt_table); g_array_append_val(data->tables, ssdt_table);
} }
@ -134,16 +139,29 @@ static void test_acpi_fadt_table(test_data *data)
AcpiSdtTable table = g_array_index(data->tables, typeof(table), 0); AcpiSdtTable table = g_array_index(data->tables, typeof(table), 0);
uint8_t *fadt_aml = table.aml; uint8_t *fadt_aml = table.aml;
uint32_t fadt_len = table.aml_len; uint32_t fadt_len = table.aml_len;
uint32_t val;
int dsdt_offset = 40 /* DSDT */;
int dsdt_entry_size = 4;
g_assert(compare_signature(&table, "FACP")); g_assert(compare_signature(&table, "FACP"));
/* Since DSDT/FACS isn't in RSDT, add them to ASL test list manually */ /* Since DSDT/FACS isn't in RSDT, add them to ASL test list manually */
acpi_fetch_table(data->qts, &table.aml, &table.aml_len, memcpy(&val, fadt_aml + 112 /* Flags */, 4);
fadt_aml + 36 /* FIRMWARE_CTRL */, "FACS", false); val = le32_to_cpu(val);
g_array_append_val(data->tables, table); if (!(val & 1UL << 20 /* HW_REDUCED_ACPI */)) {
acpi_fetch_table(data->qts, &table.aml, &table.aml_len,
fadt_aml + 36 /* FIRMWARE_CTRL */, 4, "FACS", false);
g_array_append_val(data->tables, table);
}
memcpy(&val, fadt_aml + dsdt_offset, 4);
val = le32_to_cpu(val);
if (!val) {
dsdt_offset = 140 /* X_DSDT */;
dsdt_entry_size = 8;
}
acpi_fetch_table(data->qts, &table.aml, &table.aml_len, acpi_fetch_table(data->qts, &table.aml, &table.aml_len,
fadt_aml + 40 /* DSDT */, "DSDT", true); fadt_aml + dsdt_offset, dsdt_entry_size, "DSDT", true);
g_array_append_val(data->tables, table); g_array_append_val(data->tables, table);
memset(fadt_aml + 36, 0, 4); /* sanitize FIRMWARE_CTRL ptr */ memset(fadt_aml + 36, 0, 4); /* sanitize FIRMWARE_CTRL ptr */
@ -177,11 +195,14 @@ static void dump_aml_files(test_data *data, bool rebuild)
sdt->aml, ext); sdt->aml, ext);
fd = g_open(aml_file, O_WRONLY|O_TRUNC|O_CREAT, fd = g_open(aml_file, O_WRONLY|O_TRUNC|O_CREAT,
S_IRUSR|S_IWUSR|S_IRGRP|S_IWGRP|S_IROTH); S_IRUSR|S_IWUSR|S_IRGRP|S_IWGRP|S_IROTH);
if (fd < 0) {
perror(aml_file);
}
g_assert(fd >= 0);
} else { } else {
fd = g_file_open_tmp("aml-XXXXXX", &sdt->aml_file, &error); fd = g_file_open_tmp("aml-XXXXXX", &sdt->aml_file, &error);
g_assert_no_error(error); g_assert_no_error(error);
} }
g_assert(fd >= 0);
ret = qemu_write_full(fd, sdt->aml, sdt->aml_len); ret = qemu_write_full(fd, sdt->aml, sdt->aml_len);
g_assert(ret == sdt->aml_len); g_assert(ret == sdt->aml_len);
@ -505,23 +526,44 @@ static void test_smbios_structs(test_data *data)
static void test_acpi_one(const char *params, test_data *data) static void test_acpi_one(const char *params, test_data *data)
{ {
char *args; char *args;
bool use_uefi = data->uefi_fl1 && data->uefi_fl2;
/* Disable kernel irqchip to be able to override apic irq0. */ if (use_uefi) {
args = g_strdup_printf("-machine %s,accel=%s,kernel-irqchip=off " /*
"-net none -display none %s " * TODO: convert '-drive if=pflash' to new syntax (see e33763be7cd3)
"-drive id=hd0,if=none,file=%s,format=raw " * when arm/virt boad starts to support it.
"-device ide-hd,drive=hd0 ", */
data->machine, "kvm:tcg", args = g_strdup_printf("-machine %s,accel=%s -nodefaults -nographic "
params ? params : "", disk); "-drive if=pflash,format=raw,file=%s,readonly "
"-drive if=pflash,format=raw,file=%s,snapshot=on -cdrom %s %s",
data->machine, data->accel ? data->accel : "kvm:tcg",
data->uefi_fl1, data->uefi_fl2, data->cd, params ? params : "");
} else {
/* Disable kernel irqchip to be able to override apic irq0. */
args = g_strdup_printf("-machine %s,accel=%s,kernel-irqchip=off "
"-net none -display none %s "
"-drive id=hd0,if=none,file=%s,format=raw "
"-device ide-hd,drive=hd0 ",
data->machine, data->accel ? data->accel : "kvm:tcg",
params ? params : "", disk);
}
data->qts = qtest_init(args); data->qts = qtest_init(args);
boot_sector_test(data->qts); if (use_uefi) {
g_assert(data->scan_len);
data->rsdp_addr = acpi_find_rsdp_address_uefi(data->qts,
data->ram_start, data->scan_len);
} else {
boot_sector_test(data->qts);
data->rsdp_addr = acpi_find_rsdp_address(data->qts);
g_assert_cmphex(data->rsdp_addr, <, 0x100000);
}
data->tables = g_array_new(false, true, sizeof(AcpiSdtTable)); data->tables = g_array_new(false, true, sizeof(AcpiSdtTable));
test_acpi_rsdp_address(data);
test_acpi_rsdp_table(data); test_acpi_rsdp_table(data);
test_acpi_rsdt_table(data); test_acpi_rxsdt_table(data);
test_acpi_fadt_table(data); test_acpi_fadt_table(data);
if (iasl) { if (iasl) {
@ -532,8 +574,15 @@ static void test_acpi_one(const char *params, test_data *data)
} }
} }
test_smbios_entry_point(data); /*
test_smbios_structs(data); * TODO: make SMBIOS tests work with UEFI firmware,
* Bug on uefi-test-tools to provide entry point:
* https://bugs.launchpad.net/qemu/+bug/1821884
*/
if (!use_uefi) {
test_smbios_entry_point(data);
test_smbios_structs(data);
}
assert(!global_qtest); assert(!global_qtest);
qtest_quit(data->qts); qtest_quit(data->qts);
@ -769,13 +818,14 @@ int main(int argc, char *argv[])
const char *arch = qtest_get_arch(); const char *arch = qtest_get_arch();
int ret; int ret;
ret = boot_sector_init(disk);
if(ret)
return ret;
g_test_init(&argc, &argv, NULL); g_test_init(&argc, &argv, NULL);
if (strcmp(arch, "i386") == 0 || strcmp(arch, "x86_64") == 0) { if (strcmp(arch, "i386") == 0 || strcmp(arch, "x86_64") == 0) {
ret = boot_sector_init(disk);
if (ret) {
return ret;
}
qtest_add_func("acpi/piix4", test_acpi_piix4_tcg); qtest_add_func("acpi/piix4", test_acpi_piix4_tcg);
qtest_add_func("acpi/piix4/bridge", test_acpi_piix4_tcg_bridge); qtest_add_func("acpi/piix4/bridge", test_acpi_piix4_tcg_bridge);
qtest_add_func("acpi/q35", test_acpi_q35_tcg); qtest_add_func("acpi/q35", test_acpi_q35_tcg);

View File

@ -7,21 +7,12 @@
# #
# Authors: # Authors:
# Marcel Apfelbaum <marcel.a@redhat.com> # Marcel Apfelbaum <marcel.a@redhat.com>
# Igor Mammedov <imammedo@redhat.com>
# #
# This work is licensed under the terms of the GNU GPLv2. # This work is licensed under the terms of the GNU GPLv2.
# See the COPYING.LIB file in the top-level directory. # See the COPYING.LIB file in the top-level directory.
qemu= qemu_bins="x86_64-softmmu/qemu-system-x86_64"
if [ -e x86_64-softmmu/qemu-system-x86_64 ]; then
qemu="x86_64-softmmu/qemu-system-x86_64"
elif [ -e i386-softmmu/qemu-system-i386 ]; then
qemu="i386-softmmu/qemu-system-i386"
else
echo "Run 'make' to build the qemu exectutable!"
echo "Run this script from the build directory."
exit 1;
fi
if [ ! -e "tests/bios-tables-test" ]; then if [ ! -e "tests/bios-tables-test" ]; then
echo "Test: bios-tables-test is required! Run make check before this script." echo "Test: bios-tables-test is required! Run make check before this script."
@ -29,6 +20,14 @@ if [ ! -e "tests/bios-tables-test" ]; then
exit 1; exit 1;
fi fi
TEST_ACPI_REBUILD_AML=y QTEST_QEMU_BINARY=$qemu tests/bios-tables-test for qemu in $qemu_bins; do
if [ ! -e $qemu ]; then
echo "Run 'make' to build the following QEMU executables: $qemu_bins"
echo "Also, run this script from the build directory."
exit 1;
fi
TEST_ACPI_REBUILD_AML=y QTEST_QEMU_BINARY=$qemu tests/bios-tables-test
done
echo "The files were rebuilt and can be added to git." echo "The files were rebuilt and can be added to git."

View File

@ -40,14 +40,14 @@ static uint32_t acpi_find_vgia(QTestState *qts)
g_assert_cmphex(rsdp_offset, <, RSDP_ADDR_INVALID); g_assert_cmphex(rsdp_offset, <, RSDP_ADDR_INVALID);
acpi_parse_rsdp_table(qts, rsdp_offset, rsdp_table); acpi_fetch_rsdp_table(qts, rsdp_offset, rsdp_table);
acpi_fetch_table(qts, &rsdt, &rsdt_len, &rsdp_table[16 /* RsdtAddress */], acpi_fetch_table(qts, &rsdt, &rsdt_len, &rsdp_table[16 /* RsdtAddress */],
"RSDT", true); 4, "RSDT", true);
ACPI_FOREACH_RSDT_ENTRY(rsdt, rsdt_len, ent, 4 /* Entry size */) { ACPI_FOREACH_RSDT_ENTRY(rsdt, rsdt_len, ent, 4 /* Entry size */) {
uint8_t *table_aml; uint8_t *table_aml;
acpi_fetch_table(qts, &table_aml, &table_length, ent, NULL, true); acpi_fetch_table(qts, &table_aml, &table_length, ent, 4, NULL, true);
if (!memcmp(table_aml + 16 /* OEM Table ID */, "VMGENID", 7)) { if (!memcmp(table_aml + 16 /* OEM Table ID */, "VMGENID", 7)) {
uint32_t vgia_val; uint32_t vgia_val;
uint8_t *aml = &table_aml[36 /* AML byte-code start */]; uint8_t *aml = &table_aml[36 /* AML byte-code start */];