virtio,pc: features, cleanups, fixes

Part of ACPI ERST support
 fixes, cleanups
 
 Signed-off-by: Michael S. Tsirkin <mst@redhat.com>
 -----BEGIN PGP SIGNATURE-----
 
 iQFCBAABCAAtFiEEXQn9CHHI+FuUyooNKB8NuNKNVGkFAmH/lpgPHG1zdEByZWRo
 YXQuY29tAAoJECgfDbjSjVRpntwH+LTJ3MIX5tHL2FWR9vfQoIOQms4A2YJb5GFv
 f/wZMQ4Hx/4k3KsicJF4ONJ04cT4IuxtsY9WtUroNcpuh9qy+cMYw61xsd7oa2DB
 k7vInrVaDP1pKmNzK+R1DV4VsbghAZzCh23hKKS8HGOd+DM6PWSozzCSpbQGerNX
 H61bS7lvESLONhHIJdmo5/d4aGEGlt5xs2KzZe/pwl8OU4/WRYK8MgEKOhvAZT7T
 Ups0IDSAOJ5pqzXCLESKFfImNIzak16+lnY9iOMcIFWQVEphMvjkn9jtCu4wvDRe
 500GC8i9Q8X3B/D5Y9TB78mDuiqfQP69zBRfhSjgQeU9+eWCxA==
 =JIT5
 -----END PGP SIGNATURE-----

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

virtio,pc: features, cleanups, fixes

Part of ACPI ERST support
fixes, cleanups

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

# gpg: Signature made Sun 06 Feb 2022 09:36:24 GMT
# gpg:                using RSA key 5D09FD0871C8F85B94CA8A0D281F0DB8D28D5469
# gpg:                issuer "mst@redhat.com"
# 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: (24 commits)
  util/oslib-posix: Fix missing unlock in the error path of os_mem_prealloc()
  ACPI ERST: step 6 of bios-tables-test.c
  ACPI ERST: bios-tables-test testcase
  ACPI ERST: qtest for ERST
  ACPI ERST: create ACPI ERST table for pc/x86 machines
  ACPI ERST: build the ACPI ERST table
  ACPI ERST: support for ACPI ERST feature
  ACPI ERST: header file for ERST
  ACPI ERST: PCI device_id for ERST
  ACPI ERST: bios-tables-test.c steps 1 and 2
  libvhost-user: Map shared RAM with MAP_NORESERVE to support virtio-mem with hugetlb
  libvhost-user: handle removal of identical regions
  libvhost-user: prevent over-running max RAM slots
  libvhost-user: fix VHOST_USER_REM_MEM_REG not closing the fd
  libvhost-user: Simplify VHOST_USER_REM_MEM_REG
  libvhost-user: Add vu_add_mem_reg input validation
  libvhost-user: Add vu_rem_mem_reg input validation
  tests: acpi: test short OEM_ID/OEM_TABLE_ID values in test_oem_fields()
  tests: acpi: update expected blobs
  acpi: fix OEM ID/OEM Table ID padding
  ...

Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
This commit is contained in:
Peter Maydell 2022-02-06 10:46:46 +00:00
commit 0d564a3e32
29 changed files with 1429 additions and 36 deletions

2
configure vendored
View File

@ -2768,7 +2768,7 @@ cat > $TMPC << EOF
#include <cpuid.h> #include <cpuid.h>
int main(void) { int main(void) {
unsigned a, b, c, d; unsigned a, b, c, d;
int max = __get_cpuid_max(0, 0); unsigned max = __get_cpuid_max(0, 0);
if (max >= 1) { if (max >= 1) {
__cpuid(1, a, b, c, d); __cpuid(1, a, b, c, d);

View File

@ -10,6 +10,7 @@ config ACPI_X86
select ACPI_HMAT select ACPI_HMAT
select ACPI_PIIX4 select ACPI_PIIX4
select ACPI_PCIHP select ACPI_PCIHP
select ACPI_ERST
config ACPI_X86_ICH config ACPI_X86_ICH
bool bool
@ -60,3 +61,8 @@ config ACPI_HW_REDUCED
select ACPI select ACPI
select ACPI_MEMORY_HOTPLUG select ACPI_MEMORY_HOTPLUG
select ACPI_NVDIMM select ACPI_NVDIMM
config ACPI_ERST
bool
default y
depends on ACPI && PCI

View File

@ -1724,9 +1724,9 @@ void acpi_table_begin(AcpiTable *desc, GArray *array)
build_append_int_noprefix(array, 0, 4); /* Length */ build_append_int_noprefix(array, 0, 4); /* Length */
build_append_int_noprefix(array, desc->rev, 1); /* Revision */ build_append_int_noprefix(array, desc->rev, 1); /* Revision */
build_append_int_noprefix(array, 0, 1); /* Checksum */ build_append_int_noprefix(array, 0, 1); /* Checksum */
build_append_padded_str(array, desc->oem_id, 6, ' '); /* OEMID */ build_append_padded_str(array, desc->oem_id, 6, '\0'); /* OEMID */
/* OEM Table ID */ /* OEM Table ID */
build_append_padded_str(array, desc->oem_table_id, 8, ' '); build_append_padded_str(array, desc->oem_table_id, 8, '\0');
build_append_int_noprefix(array, 1, 4); /* OEM Revision */ build_append_int_noprefix(array, 1, 4); /* OEM Revision */
g_array_append_vals(array, ACPI_BUILD_APPNAME8, 4); /* Creator ID */ g_array_append_vals(array, ACPI_BUILD_APPNAME8, 4); /* Creator ID */
build_append_int_noprefix(array, 1, 4); /* Creator Revision */ build_append_int_noprefix(array, 1, 4); /* Creator Revision */

1051
hw/acpi/erst.c Normal file

File diff suppressed because it is too large Load Diff

View File

@ -22,6 +22,7 @@ acpi_ss.add(when: 'CONFIG_ACPI_PCIHP', if_true: files('pcihp.c'))
acpi_ss.add(when: 'CONFIG_ACPI_PCIHP', if_false: files('acpi-pci-hotplug-stub.c')) acpi_ss.add(when: 'CONFIG_ACPI_PCIHP', if_false: files('acpi-pci-hotplug-stub.c'))
acpi_ss.add(when: 'CONFIG_ACPI_VIOT', if_true: files('viot.c')) acpi_ss.add(when: 'CONFIG_ACPI_VIOT', if_true: files('viot.c'))
acpi_ss.add(when: 'CONFIG_ACPI_X86_ICH', if_true: files('ich9.c', 'tco.c')) acpi_ss.add(when: 'CONFIG_ACPI_X86_ICH', if_true: files('ich9.c', 'tco.c'))
acpi_ss.add(when: 'CONFIG_ACPI_ERST', if_true: files('erst.c'))
acpi_ss.add(when: 'CONFIG_IPMI', if_true: files('ipmi.c'), if_false: files('ipmi-stub.c')) acpi_ss.add(when: 'CONFIG_IPMI', if_true: files('ipmi.c'), if_false: files('ipmi-stub.c'))
acpi_ss.add(when: 'CONFIG_PC', if_false: files('acpi-x86-stub.c')) acpi_ss.add(when: 'CONFIG_PC', if_false: files('acpi-x86-stub.c'))
acpi_ss.add(when: 'CONFIG_TPM', if_true: files('tpm.c')) acpi_ss.add(when: 'CONFIG_TPM', if_true: files('tpm.c'))

View File

@ -55,3 +55,18 @@ piix4_gpe_writeb(uint64_t addr, unsigned width, uint64_t val) "addr: 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"
# erst.c
acpi_erst_reg_write(uint64_t addr, uint64_t val, unsigned size) "addr: 0x%04" PRIx64 " <== 0x%016" PRIx64 " (size: %u)"
acpi_erst_reg_read(uint64_t addr, uint64_t val, unsigned size) " addr: 0x%04" PRIx64 " ==> 0x%016" PRIx64 " (size: %u)"
acpi_erst_mem_write(uint64_t addr, uint64_t val, unsigned size) "addr: 0x%06" PRIx64 " <== 0x%016" PRIx64 " (size: %u)"
acpi_erst_mem_read(uint64_t addr, uint64_t val, unsigned size) " addr: 0x%06" PRIx64 " ==> 0x%016" PRIx64 " (size: %u)"
acpi_erst_pci_bar_0(uint64_t addr) "BAR0: 0x%016" PRIx64
acpi_erst_pci_bar_1(uint64_t addr) "BAR1: 0x%016" PRIx64
acpi_erst_realizefn_in(void)
acpi_erst_realizefn_out(unsigned size) "total nvram size %u bytes"
acpi_erst_reset_in(unsigned record_count) "record_count %u"
acpi_erst_reset_out(unsigned record_count) "record_count %u"
acpi_erst_post_load(void *header, unsigned slot_size) "header: 0x%p slot_size %u"
acpi_erst_class_init_in(void)
acpi_erst_class_init_out(void)

View File

@ -43,6 +43,7 @@
#include "sysemu/tpm.h" #include "sysemu/tpm.h"
#include "hw/acpi/tpm.h" #include "hw/acpi/tpm.h"
#include "hw/acpi/vmgenid.h" #include "hw/acpi/vmgenid.h"
#include "hw/acpi/erst.h"
#include "sysemu/tpm_backend.h" #include "sysemu/tpm_backend.h"
#include "hw/rtc/mc146818rtc_regs.h" #include "hw/rtc/mc146818rtc_regs.h"
#include "migration/vmstate.h" #include "migration/vmstate.h"
@ -74,6 +75,8 @@
#include "hw/acpi/hmat.h" #include "hw/acpi/hmat.h"
#include "hw/acpi/viot.h" #include "hw/acpi/viot.h"
#include CONFIG_DEVICES
/* These are used to size the ACPI tables for -M pc-i440fx-1.7 and /* These are used to size the ACPI tables for -M pc-i440fx-1.7 and
* -M pc-i440fx-2.0. Even if the actual amount of AML generated grows * -M pc-i440fx-2.0. Even if the actual amount of AML generated grows
* a little bit, there should be plenty of free space since the DSDT * a little bit, there should be plenty of free space since the DSDT
@ -2575,6 +2578,18 @@ void acpi_build(AcpiBuildTables *tables, MachineState *machine)
ACPI_DEVICE_IF(x86ms->acpi_dev), x86ms->oem_id, ACPI_DEVICE_IF(x86ms->acpi_dev), x86ms->oem_id,
x86ms->oem_table_id); x86ms->oem_table_id);
#ifdef CONFIG_ACPI_ERST
{
Object *erst_dev;
erst_dev = find_erst_dev();
if (erst_dev) {
acpi_add_table(table_offsets, tables_blob);
build_erst(tables_blob, tables->linker, erst_dev,
x86ms->oem_id, x86ms->oem_table_id);
}
}
#endif
vmgenid_dev = find_vmgenid_dev(); vmgenid_dev = find_vmgenid_dev();
if (vmgenid_dev) { if (vmgenid_dev) {
acpi_add_table(table_offsets, tables_blob); acpi_add_table(table_offsets, tables_blob);

View File

@ -30,6 +30,7 @@
#include "hw/acpi/bios-linker-loader.h" #include "hw/acpi/bios-linker-loader.h"
#include "hw/acpi/generic_event_device.h" #include "hw/acpi/generic_event_device.h"
#include "hw/acpi/utils.h" #include "hw/acpi/utils.h"
#include "hw/acpi/erst.h"
#include "hw/i386/fw_cfg.h" #include "hw/i386/fw_cfg.h"
#include "hw/i386/microvm.h" #include "hw/i386/microvm.h"
#include "hw/pci/pci.h" #include "hw/pci/pci.h"
@ -40,6 +41,8 @@
#include "acpi-common.h" #include "acpi-common.h"
#include "acpi-microvm.h" #include "acpi-microvm.h"
#include CONFIG_DEVICES
static void acpi_dsdt_add_virtio(Aml *scope, static void acpi_dsdt_add_virtio(Aml *scope,
MicrovmMachineState *mms) MicrovmMachineState *mms)
{ {
@ -207,6 +210,18 @@ static void acpi_build_microvm(AcpiBuildTables *tables,
ACPI_DEVICE_IF(x86ms->acpi_dev), x86ms->oem_id, ACPI_DEVICE_IF(x86ms->acpi_dev), x86ms->oem_id,
x86ms->oem_table_id); x86ms->oem_table_id);
#ifdef CONFIG_ACPI_ERST
{
Object *erst_dev;
erst_dev = find_erst_dev();
if (erst_dev) {
acpi_add_table(table_offsets, tables_blob);
build_erst(tables_blob, tables->linker, erst_dev,
x86ms->oem_id, x86ms->oem_table_id);
}
}
#endif
xsdt = tables_blob->len; xsdt = tables_blob->len;
build_xsdt(tables_blob, tables->linker, table_offsets, x86ms->oem_id, build_xsdt(tables_blob, tables->linker, table_offsets, x86ms->oem_id,
x86ms->oem_table_id); x86ms->oem_table_id);

View File

@ -357,10 +357,12 @@ static void pc_compat_1_4_fn(MachineState *machine)
pc_compat_1_5_fn(machine); pc_compat_1_5_fn(machine);
} }
#ifdef CONFIG_ISAPC
static void pc_init_isa(MachineState *machine) static void pc_init_isa(MachineState *machine)
{ {
pc_init1(machine, TYPE_I440FX_PCI_HOST_BRIDGE, TYPE_I440FX_PCI_DEVICE); pc_init1(machine, TYPE_I440FX_PCI_HOST_BRIDGE, TYPE_I440FX_PCI_DEVICE);
} }
#endif
#ifdef CONFIG_XEN #ifdef CONFIG_XEN
static void pc_xen_hvm_init_pci(MachineState *machine) static void pc_xen_hvm_init_pci(MachineState *machine)
@ -916,6 +918,7 @@ void igd_passthrough_isa_bridge_create(PCIBus *bus, uint16_t gpu_dev_id)
pci_config_set_revision(bridge_dev->config, pch_rev_id); pci_config_set_revision(bridge_dev->config, pch_rev_id);
} }
#ifdef CONFIG_ISAPC
static void isapc_machine_options(MachineClass *m) static void isapc_machine_options(MachineClass *m)
{ {
PCMachineClass *pcmc = PC_MACHINE_CLASS(m); PCMachineClass *pcmc = PC_MACHINE_CLASS(m);
@ -935,7 +938,7 @@ static void isapc_machine_options(MachineClass *m)
DEFINE_PC_MACHINE(isapc, "isapc", pc_init_isa, DEFINE_PC_MACHINE(isapc, "isapc", pc_init_isa,
isapc_machine_options); isapc_machine_options);
#endif
#ifdef CONFIG_XEN #ifdef CONFIG_XEN
static void xenfv_4_2_machine_options(MachineClass *m) static void xenfv_4_2_machine_options(MachineClass *m)

24
include/hw/acpi/erst.h Normal file
View File

@ -0,0 +1,24 @@
/*
* ACPI Error Record Serialization Table, ERST, Implementation
*
* ACPI ERST introduced in ACPI 4.0, June 16, 2009.
* ACPI Platform Error Interfaces : Error Serialization
*
* Copyright (c) 2021 Oracle and/or its affiliates.
*
* SPDX-License-Identifier: GPL-2.0-or-later
*/
#ifndef HW_ACPI_ERST_H
#define HW_ACPI_ERST_H
void build_erst(GArray *table_data, BIOSLinker *linker, Object *erst_dev,
const char *oem_id, const char *oem_table_id);
#define TYPE_ACPI_ERST "acpi-erst"
/* returns NULL unless there is exactly one device */
static inline Object *find_erst_dev(void)
{
return object_resolve_path_type("", TYPE_ACPI_ERST, NULL);
}
#endif

View File

@ -108,6 +108,7 @@ extern bool pci_available;
#define PCI_DEVICE_ID_REDHAT_MDPY 0x000f #define PCI_DEVICE_ID_REDHAT_MDPY 0x000f
#define PCI_DEVICE_ID_REDHAT_NVME 0x0010 #define PCI_DEVICE_ID_REDHAT_NVME 0x0010
#define PCI_DEVICE_ID_REDHAT_PVPANIC 0x0011 #define PCI_DEVICE_ID_REDHAT_PVPANIC 0x0011
#define PCI_DEVICE_ID_REDHAT_ACPI_ERST 0x0012
#define PCI_DEVICE_ID_REDHAT_QXL 0x0100 #define PCI_DEVICE_ID_REDHAT_QXL 0x0100
#define FMT_PCIBUS PRIx64 #define FMT_PCIBUS PRIx64

View File

@ -690,6 +690,29 @@ vu_add_mem_reg(VuDev *dev, VhostUserMsg *vmsg) {
VuDevRegion *dev_region = &dev->regions[dev->nregions]; VuDevRegion *dev_region = &dev->regions[dev->nregions];
void *mmap_addr; void *mmap_addr;
if (vmsg->fd_num != 1) {
vmsg_close_fds(vmsg);
vu_panic(dev, "VHOST_USER_ADD_MEM_REG received %d fds - only 1 fd "
"should be sent for this message type", vmsg->fd_num);
return false;
}
if (vmsg->size < VHOST_USER_MEM_REG_SIZE) {
close(vmsg->fds[0]);
vu_panic(dev, "VHOST_USER_ADD_MEM_REG requires a message size of at "
"least %d bytes and only %d bytes were received",
VHOST_USER_MEM_REG_SIZE, vmsg->size);
return false;
}
if (dev->nregions == VHOST_USER_MAX_RAM_SLOTS) {
close(vmsg->fds[0]);
vu_panic(dev, "failing attempt to hot add memory via "
"VHOST_USER_ADD_MEM_REG message because the backend has "
"no free ram slots available");
return false;
}
/* /*
* If we are in postcopy mode and we receive a u64 payload with a 0 value * If we are in postcopy mode and we receive a u64 payload with a 0 value
* we know all the postcopy client bases have been received, and we * we know all the postcopy client bases have been received, and we
@ -728,12 +751,12 @@ vu_add_mem_reg(VuDev *dev, VhostUserMsg *vmsg) {
* accessing it before we userfault. * accessing it before we userfault.
*/ */
mmap_addr = mmap(0, dev_region->size + dev_region->mmap_offset, mmap_addr = mmap(0, dev_region->size + dev_region->mmap_offset,
PROT_NONE, MAP_SHARED, PROT_NONE, MAP_SHARED | MAP_NORESERVE,
vmsg->fds[0], 0); vmsg->fds[0], 0);
} else { } else {
mmap_addr = mmap(0, dev_region->size + dev_region->mmap_offset, mmap_addr = mmap(0, dev_region->size + dev_region->mmap_offset,
PROT_READ | PROT_WRITE, MAP_SHARED, vmsg->fds[0], PROT_READ | PROT_WRITE, MAP_SHARED | MAP_NORESERVE,
0); vmsg->fds[0], 0);
} }
if (mmap_addr == MAP_FAILED) { if (mmap_addr == MAP_FAILED) {
@ -796,10 +819,24 @@ static inline bool reg_equal(VuDevRegion *vudev_reg,
static bool static bool
vu_rem_mem_reg(VuDev *dev, VhostUserMsg *vmsg) { vu_rem_mem_reg(VuDev *dev, VhostUserMsg *vmsg) {
int i, j;
bool found = false;
VuDevRegion shadow_regions[VHOST_USER_MAX_RAM_SLOTS] = {};
VhostUserMemoryRegion m = vmsg->payload.memreg.region, *msg_region = &m; VhostUserMemoryRegion m = vmsg->payload.memreg.region, *msg_region = &m;
int i;
bool found = false;
if (vmsg->fd_num != 1) {
vmsg_close_fds(vmsg);
vu_panic(dev, "VHOST_USER_REM_MEM_REG received %d fds - only 1 fd "
"should be sent for this message type", vmsg->fd_num);
return false;
}
if (vmsg->size < VHOST_USER_MEM_REG_SIZE) {
close(vmsg->fds[0]);
vu_panic(dev, "VHOST_USER_REM_MEM_REG requires a message size of at "
"least %d bytes and only %d bytes were received",
VHOST_USER_MEM_REG_SIZE, vmsg->size);
return false;
}
DPRINT("Removing region:\n"); DPRINT("Removing region:\n");
DPRINT(" guest_phys_addr: 0x%016"PRIx64"\n", DPRINT(" guest_phys_addr: 0x%016"PRIx64"\n",
@ -811,35 +848,40 @@ vu_rem_mem_reg(VuDev *dev, VhostUserMsg *vmsg) {
DPRINT(" mmap_offset 0x%016"PRIx64"\n", DPRINT(" mmap_offset 0x%016"PRIx64"\n",
msg_region->mmap_offset); msg_region->mmap_offset);
for (i = 0, j = 0; i < dev->nregions; i++) { for (i = 0; i < dev->nregions; i++) {
if (!reg_equal(&dev->regions[i], msg_region)) { if (reg_equal(&dev->regions[i], msg_region)) {
shadow_regions[j].gpa = dev->regions[i].gpa;
shadow_regions[j].size = dev->regions[i].size;
shadow_regions[j].qva = dev->regions[i].qva;
shadow_regions[j].mmap_addr = dev->regions[i].mmap_addr;
shadow_regions[j].mmap_offset = dev->regions[i].mmap_offset;
j++;
} else {
found = true;
VuDevRegion *r = &dev->regions[i]; VuDevRegion *r = &dev->regions[i];
void *m = (void *) (uintptr_t) r->mmap_addr; void *m = (void *) (uintptr_t) r->mmap_addr;
if (m) { if (m) {
munmap(m, r->size + r->mmap_offset); munmap(m, r->size + r->mmap_offset);
} }
/*
* Shift all affected entries by 1 to close the hole at index i and
* zero out the last entry.
*/
memmove(dev->regions + i, dev->regions + i + 1,
sizeof(VuDevRegion) * (dev->nregions - i - 1));
memset(dev->regions + dev->nregions - 1, 0, sizeof(VuDevRegion));
DPRINT("Successfully removed a region\n");
dev->nregions--;
i--;
found = true;
/* Continue the search for eventual duplicates. */
} }
} }
if (found) { if (found) {
memcpy(dev->regions, shadow_regions,
sizeof(VuDevRegion) * VHOST_USER_MAX_RAM_SLOTS);
DPRINT("Successfully removed a region\n");
dev->nregions--;
vmsg_set_reply_u64(vmsg, 0); vmsg_set_reply_u64(vmsg, 0);
} else { } else {
vu_panic(dev, "Specified region not found\n"); vu_panic(dev, "Specified region not found\n");
} }
close(vmsg->fds[0]);
return true; return true;
} }
@ -878,7 +920,7 @@ vu_set_mem_table_exec_postcopy(VuDev *dev, VhostUserMsg *vmsg)
* accessing it before we userfault * accessing it before we userfault
*/ */
mmap_addr = mmap(0, dev_region->size + dev_region->mmap_offset, mmap_addr = mmap(0, dev_region->size + dev_region->mmap_offset,
PROT_NONE, MAP_SHARED, PROT_NONE, MAP_SHARED | MAP_NORESERVE,
vmsg->fds[i], 0); vmsg->fds[i], 0);
if (mmap_addr == MAP_FAILED) { if (mmap_addr == MAP_FAILED) {
@ -965,7 +1007,7 @@ vu_set_mem_table_exec(VuDev *dev, VhostUserMsg *vmsg)
* mapped address has to be page aligned, and we use huge * mapped address has to be page aligned, and we use huge
* pages. */ * pages. */
mmap_addr = mmap(0, dev_region->size + dev_region->mmap_offset, mmap_addr = mmap(0, dev_region->size + dev_region->mmap_offset,
PROT_READ | PROT_WRITE, MAP_SHARED, PROT_READ | PROT_WRITE, MAP_SHARED | MAP_NORESERVE,
vmsg->fds[i], 0); vmsg->fds[i], 0);
if (mmap_addr == MAP_FAILED) { if (mmap_addr == MAP_FAILED) {

View File

@ -129,6 +129,8 @@ typedef struct VhostUserMemoryRegion {
uint64_t mmap_offset; uint64_t mmap_offset;
} VhostUserMemoryRegion; } VhostUserMemoryRegion;
#define VHOST_USER_MEM_REG_SIZE (sizeof(VhostUserMemoryRegion))
typedef struct VhostUserMemory { typedef struct VhostUserMemory {
uint32_t nregions; uint32_t nregions;
uint32_t padding; uint32_t padding;

View File

@ -3747,7 +3747,7 @@ static void tcg_target_init(TCGContext *s)
{ {
#ifdef CONFIG_CPUID_H #ifdef CONFIG_CPUID_H
unsigned a, b, c, d, b7 = 0; unsigned a, b, c, d, b7 = 0;
int max = __get_cpuid_max(0, 0); unsigned max = __get_cpuid_max(0, 0);
if (max >= 7) { if (max >= 7) {
/* BMI1 is available on AMD Piledriver and Intel Haswell CPUs. */ /* BMI1 is available on AMD Piledriver and Intel Haswell CPUs. */

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

View File

@ -73,7 +73,8 @@
#define OEM_ID "TEST" #define OEM_ID "TEST"
#define OEM_TABLE_ID "OEM" #define OEM_TABLE_ID "OEM"
#define OEM_TEST_ARGS "-machine x-oem-id="OEM_ID",x-oem-table-id="OEM_TABLE_ID #define OEM_TEST_ARGS "-machine x-oem-id=" OEM_ID ",x-oem-table-id=" \
OEM_TABLE_ID
typedef struct { typedef struct {
bool tcg_only; bool tcg_only;
@ -1446,6 +1447,57 @@ static void test_acpi_piix4_tcg_acpi_hmat(void)
test_acpi_tcg_acpi_hmat(MACHINE_PC); test_acpi_tcg_acpi_hmat(MACHINE_PC);
} }
static void test_acpi_erst(const char *machine)
{
gchar *tmp_path = g_dir_make_tmp("qemu-test-erst.XXXXXX", NULL);
gchar *params;
test_data data;
memset(&data, 0, sizeof(data));
data.machine = machine;
data.variant = ".acpierst";
params = g_strdup_printf(
" -object memory-backend-file,id=erstnvram,"
"mem-path=%s,size=0x10000,share=on"
" -device acpi-erst,memdev=erstnvram", tmp_path);
test_acpi_one(params, &data);
free_test_data(&data);
g_free(params);
g_assert(g_rmdir(tmp_path) == 0);
g_free(tmp_path);
}
static void test_acpi_piix4_acpi_erst(void)
{
test_acpi_erst(MACHINE_PC);
}
static void test_acpi_q35_acpi_erst(void)
{
test_acpi_erst(MACHINE_Q35);
}
static void test_acpi_microvm_acpi_erst(void)
{
gchar *tmp_path = g_dir_make_tmp("qemu-test-erst.XXXXXX", NULL);
gchar *params;
test_data data;
test_acpi_microvm_prepare(&data);
data.variant = ".pcie";
data.tcg_only = true; /* need constant host-phys-bits */
params = g_strdup_printf(" -machine microvm,"
"acpi=on,ioapic2=off,rtc=off,pcie=on"
" -object memory-backend-file,id=erstnvram,"
"mem-path=%s,size=0x10000,share=on"
" -device acpi-erst,memdev=erstnvram", tmp_path);
test_acpi_one(params, &data);
g_free(params);
g_assert(g_rmdir(tmp_path) == 0);
g_free(tmp_path);
free_test_data(&data);
}
static void test_acpi_virt_tcg(void) static void test_acpi_virt_tcg(void)
{ {
test_data data = { test_data data = {
@ -1519,11 +1571,7 @@ static void test_acpi_q35_slic(void)
static void test_oem_fields(test_data *data) static void test_oem_fields(test_data *data)
{ {
int i; int i;
char oem_id[6];
char oem_table_id[8];
strpadcpy(oem_id, sizeof oem_id, OEM_ID, ' ');
strpadcpy(oem_table_id, sizeof oem_table_id, OEM_TABLE_ID, ' ');
for (i = 0; i < data->tables->len; ++i) { for (i = 0; i < data->tables->len; ++i) {
AcpiSdtTable *sdt; AcpiSdtTable *sdt;
@ -1533,8 +1581,8 @@ static void test_oem_fields(test_data *data)
continue; continue;
} }
g_assert(memcmp(sdt->aml + 10, oem_id, 6) == 0); g_assert(strncmp((char *)sdt->aml + 10, OEM_ID, 6) == 0);
g_assert(memcmp(sdt->aml + 16, oem_table_id, 8) == 0); g_assert(strncmp((char *)sdt->aml + 16, OEM_TABLE_ID, 8) == 0);
} }
} }
@ -1675,6 +1723,8 @@ int main(int argc, char *argv[])
qtest_add_func("acpi/q35/dimmpxm", test_acpi_q35_tcg_dimm_pxm); qtest_add_func("acpi/q35/dimmpxm", test_acpi_q35_tcg_dimm_pxm);
qtest_add_func("acpi/piix4/acpihmat", test_acpi_piix4_tcg_acpi_hmat); qtest_add_func("acpi/piix4/acpihmat", test_acpi_piix4_tcg_acpi_hmat);
qtest_add_func("acpi/q35/acpihmat", test_acpi_q35_tcg_acpi_hmat); qtest_add_func("acpi/q35/acpihmat", test_acpi_q35_tcg_acpi_hmat);
qtest_add_func("acpi/piix4/acpierst", test_acpi_piix4_acpi_erst);
qtest_add_func("acpi/q35/acpierst", test_acpi_q35_acpi_erst);
qtest_add_func("acpi/microvm", test_acpi_microvm_tcg); qtest_add_func("acpi/microvm", test_acpi_microvm_tcg);
qtest_add_func("acpi/microvm/usb", test_acpi_microvm_usb_tcg); qtest_add_func("acpi/microvm/usb", test_acpi_microvm_usb_tcg);
qtest_add_func("acpi/microvm/rtc", test_acpi_microvm_rtc_tcg); qtest_add_func("acpi/microvm/rtc", test_acpi_microvm_rtc_tcg);
@ -1684,6 +1734,7 @@ int main(int argc, char *argv[])
qtest_add_func("acpi/q35/ivrs", test_acpi_q35_tcg_ivrs); qtest_add_func("acpi/q35/ivrs", test_acpi_q35_tcg_ivrs);
if (strcmp(arch, "x86_64") == 0) { if (strcmp(arch, "x86_64") == 0) {
qtest_add_func("acpi/microvm/pcie", test_acpi_microvm_pcie_tcg); qtest_add_func("acpi/microvm/pcie", test_acpi_microvm_pcie_tcg);
qtest_add_func("acpi/microvm/acpierst", test_acpi_microvm_acpi_erst);
} }
} }
if (has_kvm) { if (has_kvm) {

View File

@ -138,7 +138,7 @@ static void add_x86_tests(void)
* Unstable CI test under load * Unstable CI test under load
* See https://lists.gnu.org/archive/html/qemu-devel/2019-02/msg05509.html * See https://lists.gnu.org/archive/html/qemu-devel/2019-02/msg05509.html
*/ */
if (g_test_slow()) { if (g_test_slow() && qtest_has_machine("isapc")) {
qtest_add_data_func("cdrom/boot/isapc", "-M isapc " qtest_add_data_func("cdrom/boot/isapc", "-M isapc "
"-drive if=ide,media=cdrom,file=", test_cdboot); "-drive if=ide,media=cdrom,file=", test_cdboot);
} }

164
tests/qtest/erst-test.c Normal file
View File

@ -0,0 +1,164 @@
/*
* QTest testcase for acpi-erst
*
* Copyright (c) 2021 Oracle
*
* This work is licensed under the terms of the GNU GPL, version 2 or later.
* See the COPYING file in the top-level directory.
*/
#include "qemu/osdep.h"
#include <glib/gstdio.h>
#include "libqos/libqos-pc.h"
#include "libqos/libqtest.h"
#include "qemu-common.h"
#include "hw/pci/pci.h"
static void save_fn(QPCIDevice *dev, int devfn, void *data)
{
QPCIDevice **pdev = (QPCIDevice **) data;
*pdev = dev;
}
static QPCIDevice *get_erst_device(QPCIBus *pcibus)
{
QPCIDevice *dev;
dev = NULL;
qpci_device_foreach(pcibus,
PCI_VENDOR_ID_REDHAT,
PCI_DEVICE_ID_REDHAT_ACPI_ERST,
save_fn, &dev);
g_assert(dev != NULL);
return dev;
}
typedef struct _ERSTState {
QOSState *qs;
QPCIBar reg_bar, mem_bar;
uint64_t reg_barsize, mem_barsize;
QPCIDevice *dev;
} ERSTState;
#define ACTION 0
#define VALUE 8
static const char *reg2str(unsigned reg)
{
switch (reg) {
case 0:
return "ACTION";
case 8:
return "VALUE";
default:
return NULL;
}
}
static inline uint32_t in_reg32(ERSTState *s, unsigned reg)
{
const char *name = reg2str(reg);
uint32_t res;
res = qpci_io_readl(s->dev, s->reg_bar, reg);
g_test_message("*%s -> %08x", name, res);
return res;
}
static inline uint64_t in_reg64(ERSTState *s, unsigned reg)
{
const char *name = reg2str(reg);
uint64_t res;
res = qpci_io_readq(s->dev, s->reg_bar, reg);
g_test_message("*%s -> %016llx", name, (unsigned long long)res);
return res;
}
static inline void out_reg32(ERSTState *s, unsigned reg, uint32_t v)
{
const char *name = reg2str(reg);
g_test_message("%08x -> *%s", v, name);
qpci_io_writel(s->dev, s->reg_bar, reg, v);
}
static void cleanup_vm(ERSTState *s)
{
g_free(s->dev);
qtest_shutdown(s->qs);
}
static void setup_vm_cmd(ERSTState *s, const char *cmd)
{
const char *arch = qtest_get_arch();
if (strcmp(arch, "i386") == 0 || strcmp(arch, "x86_64") == 0) {
s->qs = qtest_pc_boot(cmd);
} else {
g_printerr("erst-test tests are only available on x86\n");
exit(EXIT_FAILURE);
}
s->dev = get_erst_device(s->qs->pcibus);
s->reg_bar = qpci_iomap(s->dev, 0, &s->reg_barsize);
g_assert_cmpuint(s->reg_barsize, ==, 16);
s->mem_bar = qpci_iomap(s->dev, 1, &s->mem_barsize);
g_assert_cmpuint(s->mem_barsize, ==, 0x2000);
qpci_device_enable(s->dev);
}
static void test_acpi_erst_basic(void)
{
ERSTState state;
uint64_t log_address_range;
uint64_t log_address_length;
uint32_t log_address_attr;
setup_vm_cmd(&state,
"-object memory-backend-file,"
"mem-path=acpi-erst.XXXXXX,"
"size=64K,"
"share=on,"
"id=nvram "
"-device acpi-erst,"
"memdev=nvram");
out_reg32(&state, ACTION, 0xD);
log_address_range = in_reg64(&state, VALUE);
out_reg32(&state, ACTION, 0xE);
log_address_length = in_reg64(&state, VALUE);
out_reg32(&state, ACTION, 0xF);
log_address_attr = in_reg32(&state, VALUE);
/* Check log_address_range is not 0, ~0 or base */
g_assert_cmpuint(log_address_range, !=, 0ULL);
g_assert_cmpuint(log_address_range, !=, ~0ULL);
g_assert_cmpuint(log_address_range, !=, state.reg_bar.addr);
g_assert_cmpuint(log_address_range, ==, state.mem_bar.addr);
/* Check log_address_length is bar1_size */
g_assert_cmpuint(log_address_length, ==, state.mem_barsize);
/* Check log_address_attr is 0 */
g_assert_cmpuint(log_address_attr, ==, 0);
cleanup_vm(&state);
}
int main(int argc, char **argv)
{
int ret;
g_test_init(&argc, &argv, NULL);
qtest_add_func("/acpi-erst/basic", test_acpi_erst_basic);
ret = g_test_run();
return ret;
}

View File

@ -68,6 +68,7 @@ qtests_i386 = \
(config_all_devices.has_key('CONFIG_RTL8139_PCI') ? ['rtl8139-test'] : []) + \ (config_all_devices.has_key('CONFIG_RTL8139_PCI') ? ['rtl8139-test'] : []) + \
(config_all_devices.has_key('CONFIG_E1000E_PCI_EXPRESS') ? ['fuzz-e1000e-test'] : []) + \ (config_all_devices.has_key('CONFIG_E1000E_PCI_EXPRESS') ? ['fuzz-e1000e-test'] : []) + \
(config_all_devices.has_key('CONFIG_ESP_PCI') ? ['am53c974-test'] : []) + \ (config_all_devices.has_key('CONFIG_ESP_PCI') ? ['am53c974-test'] : []) + \
(config_all_devices.has_key('CONFIG_ACPI_ERST') ? ['erst-test'] : []) + \
(config_all_devices.has_key('CONFIG_VIRTIO_NET') and \ (config_all_devices.has_key('CONFIG_VIRTIO_NET') and \
config_all_devices.has_key('CONFIG_Q35') and \ config_all_devices.has_key('CONFIG_Q35') and \
config_all_devices.has_key('CONFIG_VIRTIO_PCI') and \ config_all_devices.has_key('CONFIG_VIRTIO_PCI') and \
@ -278,6 +279,7 @@ qtests = {
'bios-tables-test': [io, 'boot-sector.c', 'acpi-utils.c', 'tpm-emu.c'], 'bios-tables-test': [io, 'boot-sector.c', 'acpi-utils.c', 'tpm-emu.c'],
'cdrom-test': files('boot-sector.c'), 'cdrom-test': files('boot-sector.c'),
'dbus-vmstate-test': files('migration-helpers.c') + dbus_vmstate1, 'dbus-vmstate-test': files('migration-helpers.c') + dbus_vmstate1,
'erst-test': files('erst-test.c'),
'ivshmem-test': [rt, '../../contrib/ivshmem-server/ivshmem-server.c'], 'ivshmem-test': [rt, '../../contrib/ivshmem-server/ivshmem-server.c'],
'migration-test': files('migration-helpers.c'), 'migration-test': files('migration-helpers.c'),
'pxe-test': files('boot-sector.c'), 'pxe-test': files('boot-sector.c'),

View File

@ -272,7 +272,7 @@ static void init_accel(unsigned cache)
static void __attribute__((constructor)) init_cpuid_cache(void) static void __attribute__((constructor)) init_cpuid_cache(void)
{ {
int max = __get_cpuid_max(0, NULL); unsigned max = __get_cpuid_max(0, NULL);
int a, b, c, d; int a, b, c, d;
unsigned cache = 0; unsigned cache = 0;

View File

@ -683,6 +683,7 @@ void os_mem_prealloc(int fd, char *area, size_t memory, int smp_cpus,
ret = sigaction(SIGBUS, &act, &sigbus_oldact); ret = sigaction(SIGBUS, &act, &sigbus_oldact);
if (ret) { if (ret) {
qemu_mutex_unlock(&sigbus_mutex);
error_setg_errno(errp, errno, error_setg_errno(errp, errno,
"os_mem_prealloc: failed to install signal handler"); "os_mem_prealloc: failed to install signal handler");
return; return;