virtio, vhost, acpi: features, fixes, tests

ARM ACPI memory hotplug support +
 tests for new arm/virt ACPI tables.
 
 Virtio fs support (no migration).
 A vhost-user reconnect bugfix.
 
 Signed-off-by: Michael S. Tsirkin <mst@redhat.com>
 -----BEGIN PGP SIGNATURE-----
 
 iQEcBAABAgAGBQJdpjPbAAoJECgfDbjSjVRpQqUH/2xyT++y8K17mCI1IILLZd3d
 eOqElEHz78qlEfR2euv63YksZoeHpMO5HiAdwOGGF8CjcaCT4Hl+pPDffTYVXtt+
 VZ88vSSXL49wpMcpvRGR5Isy0eXJzWilTBMu2eu8phN9tX82dlu08Oi4XGAosrBJ
 uZg61DyiGDnSOpoofHhjvXJEaiL0pzkTjf8qAoW3TaVcB9NQKnunMEIDD646JS5z
 AAj4+XBJfUG9cp7/MG+djjVmJDdUpjL5e5uWNWakbgUVqSbHog78RIrBoD6SH7pt
 /6hHHoSM9VX1wWgdTdVdNAQAZVnWs31w4v31d8UfaT15KJEoG47U0gDgmLzXDyo=
 =+xdg
 -----END PGP SIGNATURE-----

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

virtio, vhost, acpi: features, fixes, tests

ARM ACPI memory hotplug support +
tests for new arm/virt ACPI tables.

Virtio fs support (no migration).
A vhost-user reconnect bugfix.

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

# gpg: Signature made Tue 15 Oct 2019 22:02:19 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:
  virtio: add vhost-user-fs-pci device
  virtio: add vhost-user-fs base device
  virtio: Add virtio_fs linux headers
  tests/acpi: add expected tables for arm/virt
  tests: document how to update acpi tables
  tests: Add bios tests to arm/virt
  tests: allow empty expected files
  tests/acpi: add empty files
  tests: Update ACPI tables list for upcoming arm/virt tests
  docs/specs: Add ACPI GED documentation
  hw/arm: Use GED for system_powerdown event
  hw/arm: Factor out powerdown notifier from GPIO
  hw/arm/virt-acpi-build: Add PC-DIMM in SRAT
  hw/arm/virt: Enable device memory cold/hot plug with ACPI boot
  hw/arm/virt: Add memory hotplug framework
  hw/acpi: Add ACPI Generic Event Device Support
  hw/acpi: Do not create memory hotplug method when handler is not defined
  hw/acpi: Make ACPI IO address space configurable
  vhost-user: save features if the char dev is closed

Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
This commit is contained in:
Peter Maydell 2019-10-17 15:30:44 +01:00
commit 39b68bc4f1
39 changed files with 1211 additions and 42 deletions

13
configure vendored
View File

@ -381,6 +381,7 @@ vhost_crypto=""
vhost_scsi=""
vhost_vsock=""
vhost_user=""
vhost_user_fs=""
kvm="no"
hax="no"
hvf="no"
@ -1293,6 +1294,10 @@ for opt do
;;
--enable-vhost-vsock) vhost_vsock="yes"
;;
--disable-vhost-user-fs) vhost_user_fs="no"
;;
--enable-vhost-user-fs) vhost_user_fs="yes"
;;
--disable-opengl) opengl="no"
;;
--enable-opengl) opengl="yes"
@ -2236,6 +2241,10 @@ test "$vhost_crypto" = "" && vhost_crypto=$vhost_user
if test "$vhost_crypto" = "yes" && test "$vhost_user" = "no"; then
error_exit "--enable-vhost-crypto requires --enable-vhost-user"
fi
test "$vhost_user_fs" = "" && vhost_user_fs=$vhost_user
if test "$vhost_user_fs" = "yes" && test "$vhost_user" = "no"; then
error_exit "--enable-vhost-user-fs requires --enable-vhost-user"
fi
# OR the vhost-kernel and vhost-user values for simplicity
if test "$vhost_net" = ""; then
@ -6374,6 +6383,7 @@ echo "vhost-crypto support $vhost_crypto"
echo "vhost-scsi support $vhost_scsi"
echo "vhost-vsock support $vhost_vsock"
echo "vhost-user support $vhost_user"
echo "vhost-user-fs support $vhost_user_fs"
echo "Trace backends $trace_backends"
if have_backend "simple"; then
echo "Trace output file $trace_file-<pid>"
@ -6870,6 +6880,9 @@ fi
if test "$vhost_user" = "yes" ; then
echo "CONFIG_VHOST_USER=y" >> $config_host_mak
fi
if test "$vhost_user_fs" = "yes" ; then
echo "CONFIG_VHOST_USER_FS=y" >> $config_host_mak
fi
if test "$blobs" = "yes" ; then
echo "INSTALL_BLOBS=yes" >> $config_host_mak
fi

View File

@ -0,0 +1,70 @@
==================================================
QEMU and ACPI BIOS Generic Event Device interface
==================================================
The ACPI *Generic Event Device* (GED) is a HW reduced platform
specific device introduced in ACPI v6.1 that handles all platform
events, including the hotplug ones. GED is modelled as a device
in the namespace with a _HID defined to be ACPI0013. This document
describes the interface between QEMU and the ACPI BIOS.
GED allows HW reduced platforms to handle interrupts in ACPI ASL
statements. It follows a very similar approach to the _EVT method
from GPIO events. All interrupts are listed in _CRS and the handler
is written in _EVT method. However, the QEMU implementation uses a
single interrupt for the GED device, relying on an IO memory region
to communicate the type of device affected by the interrupt. This way,
we can support up to 32 events with a unique interrupt.
**Here is an example,**
::
Device (\_SB.GED)
{
Name (_HID, "ACPI0013")
Name (_UID, Zero)
Name (_CRS, ResourceTemplate ()
{
Interrupt (ResourceConsumer, Edge, ActiveHigh, Exclusive, ,, )
{
0x00000029,
}
})
OperationRegion (EREG, SystemMemory, 0x09080000, 0x04)
Field (EREG, DWordAcc, NoLock, WriteAsZeros)
{
ESEL, 32
}
Method (_EVT, 1, Serialized)
{
Local0 = ESEL // ESEL = IO memory region which specifies the
// device type.
If (((Local0 & One) == One))
{
MethodEvent1()
}
If ((Local0 & 0x2) == 0x2)
{
MethodEvent2()
}
...
}
}
GED IO interface (4 byte access)
--------------------------------
**read access:**
::
[0x0-0x3] Event selector bit field (32 bit) set by QEMU.
bits:
0: Memory hotplug event
1: System power down event
2-31: Reserved
**write_access:**
Nothing is expected to be written into GED IO memory

View File

@ -12,3 +12,4 @@ Contents:
ppc-xive
ppc-spapr-xive
acpi_hw_reduced_hotplug

View File

@ -31,3 +31,7 @@ config ACPI_VMGENID
bool
default y
depends on PC
config ACPI_HW_REDUCED
bool
depends on ACPI

View File

@ -6,6 +6,7 @@ common-obj-$(CONFIG_ACPI_MEMORY_HOTPLUG) += memory_hotplug.o
common-obj-$(CONFIG_ACPI_CPU_HOTPLUG) += cpu.o
common-obj-$(CONFIG_ACPI_NVDIMM) += nvdimm.o
common-obj-$(CONFIG_ACPI_VMGENID) += vmgenid.o
common-obj-$(CONFIG_ACPI_HW_REDUCED) += generic_event_device.o
common-obj-$(call lnot,$(CONFIG_ACPI_X86)) += acpi-stub.o
common-obj-y += acpi_interface.o

View File

@ -0,0 +1,311 @@
/*
*
* Copyright (c) 2018 Intel Corporation
* Copyright (c) 2019 Huawei Technologies R & D (UK) Ltd
* Written by Samuel Ortiz, Shameer Kolothum
*
* This program is free software; you can redistribute it and/or modify it
* under the terms and conditions of the GNU General Public License,
* version 2 or later, as published by the Free Software Foundation.
*/
#include "qemu/osdep.h"
#include "qapi/error.h"
#include "exec/address-spaces.h"
#include "hw/acpi/acpi.h"
#include "hw/acpi/generic_event_device.h"
#include "hw/irq.h"
#include "hw/mem/pc-dimm.h"
#include "hw/qdev-properties.h"
#include "migration/vmstate.h"
#include "qemu/error-report.h"
static const uint32_t ged_supported_events[] = {
ACPI_GED_MEM_HOTPLUG_EVT,
ACPI_GED_PWR_DOWN_EVT,
};
/*
* The ACPI Generic Event Device (GED) is a hardware-reduced specific
* device[ACPI v6.1 Section 5.6.9] that handles all platform events,
* including the hotplug ones. Platforms need to specify their own
* GED Event bitmap to describe what kind of events they want to support
* through GED. This routine uses a single interrupt for the GED device,
* relying on IO memory region to communicate the type of device
* affected by the interrupt. This way, we can support up to 32 events
* with a unique interrupt.
*/
void build_ged_aml(Aml *table, const char *name, HotplugHandler *hotplug_dev,
uint32_t ged_irq, AmlRegionSpace rs, hwaddr ged_base)
{
AcpiGedState *s = ACPI_GED(hotplug_dev);
Aml *crs = aml_resource_template();
Aml *evt, *field;
Aml *dev = aml_device("%s", name);
Aml *evt_sel = aml_local(0);
Aml *esel = aml_name(AML_GED_EVT_SEL);
/* _CRS interrupt */
aml_append(crs, aml_interrupt(AML_CONSUMER, AML_EDGE, AML_ACTIVE_HIGH,
AML_EXCLUSIVE, &ged_irq, 1));
aml_append(dev, aml_name_decl("_HID", aml_string("ACPI0013")));
aml_append(dev, aml_name_decl("_UID", aml_string(GED_DEVICE)));
aml_append(dev, aml_name_decl("_CRS", crs));
/* Append IO region */
aml_append(dev, aml_operation_region(AML_GED_EVT_REG, rs,
aml_int(ged_base + ACPI_GED_EVT_SEL_OFFSET),
ACPI_GED_EVT_SEL_LEN));
field = aml_field(AML_GED_EVT_REG, AML_DWORD_ACC, AML_NOLOCK,
AML_WRITE_AS_ZEROS);
aml_append(field, aml_named_field(AML_GED_EVT_SEL,
ACPI_GED_EVT_SEL_LEN * BITS_PER_BYTE));
aml_append(dev, field);
/*
* For each GED event we:
* - Add a conditional block for each event, inside a loop.
* - Call a method for each supported GED event type.
*
* The resulting ASL code looks like:
*
* Local0 = ESEL
* If ((Local0 & One) == One)
* {
* MethodEvent0()
* }
*
* If ((Local0 & 0x2) == 0x2)
* {
* MethodEvent1()
* }
* ...
*/
evt = aml_method("_EVT", 1, AML_SERIALIZED);
{
Aml *if_ctx;
uint32_t i;
uint32_t ged_events = ctpop32(s->ged_event_bitmap);
/* Local0 = ESEL */
aml_append(evt, aml_store(esel, evt_sel));
for (i = 0; i < ARRAY_SIZE(ged_supported_events) && ged_events; i++) {
uint32_t event = s->ged_event_bitmap & ged_supported_events[i];
if (!event) {
continue;
}
if_ctx = aml_if(aml_equal(aml_and(evt_sel, aml_int(event), NULL),
aml_int(event)));
switch (event) {
case ACPI_GED_MEM_HOTPLUG_EVT:
aml_append(if_ctx, aml_call0(MEMORY_DEVICES_CONTAINER "."
MEMORY_SLOT_SCAN_METHOD));
break;
case ACPI_GED_PWR_DOWN_EVT:
aml_append(if_ctx,
aml_notify(aml_name(ACPI_POWER_BUTTON_DEVICE),
aml_int(0x80)));
break;
default:
/*
* Please make sure all the events in ged_supported_events[]
* are handled above.
*/
g_assert_not_reached();
}
aml_append(evt, if_ctx);
ged_events--;
}
if (ged_events) {
error_report("Unsupported events specified");
abort();
}
}
/* Append _EVT method */
aml_append(dev, evt);
aml_append(table, dev);
}
/* Memory read by the GED _EVT AML dynamic method */
static uint64_t ged_read(void *opaque, hwaddr addr, unsigned size)
{
uint64_t val = 0;
GEDState *ged_st = opaque;
switch (addr) {
case ACPI_GED_EVT_SEL_OFFSET:
/* Read the selector value and reset it */
val = ged_st->sel;
ged_st->sel = 0;
break;
default:
break;
}
return val;
}
/* Nothing is expected to be written to the GED memory region */
static void ged_write(void *opaque, hwaddr addr, uint64_t data,
unsigned int size)
{
}
static const MemoryRegionOps ged_ops = {
.read = ged_read,
.write = ged_write,
.endianness = DEVICE_LITTLE_ENDIAN,
.valid = {
.min_access_size = 4,
.max_access_size = 4,
},
};
static void acpi_ged_device_plug_cb(HotplugHandler *hotplug_dev,
DeviceState *dev, Error **errp)
{
AcpiGedState *s = ACPI_GED(hotplug_dev);
if (object_dynamic_cast(OBJECT(dev), TYPE_PC_DIMM)) {
acpi_memory_plug_cb(hotplug_dev, &s->memhp_state, dev, errp);
} else {
error_setg(errp, "virt: device plug request for unsupported device"
" type: %s", object_get_typename(OBJECT(dev)));
}
}
static void acpi_ged_send_event(AcpiDeviceIf *adev, AcpiEventStatusBits ev)
{
AcpiGedState *s = ACPI_GED(adev);
GEDState *ged_st = &s->ged_state;
uint32_t sel;
if (ev & ACPI_MEMORY_HOTPLUG_STATUS) {
sel = ACPI_GED_MEM_HOTPLUG_EVT;
} else if (ev & ACPI_POWER_DOWN_STATUS) {
sel = ACPI_GED_PWR_DOWN_EVT;
} else {
/* Unknown event. Return without generating interrupt. */
warn_report("GED: Unsupported event %d. No irq injected", ev);
return;
}
/*
* Set the GED selector field to communicate the event type.
* This will be read by GED aml code to select the appropriate
* event method.
*/
ged_st->sel |= sel;
/* Trigger the event by sending an interrupt to the guest. */
qemu_irq_pulse(s->irq);
}
static Property acpi_ged_properties[] = {
DEFINE_PROP_UINT32("ged-event", AcpiGedState, ged_event_bitmap, 0),
DEFINE_PROP_END_OF_LIST(),
};
static const VMStateDescription vmstate_memhp_state = {
.name = "acpi-ged/memhp",
.version_id = 1,
.minimum_version_id = 1,
.fields = (VMStateField[]) {
VMSTATE_MEMORY_HOTPLUG(memhp_state, AcpiGedState),
VMSTATE_END_OF_LIST()
}
};
static const VMStateDescription vmstate_ged_state = {
.name = "acpi-ged-state",
.version_id = 1,
.minimum_version_id = 1,
.fields = (VMStateField[]) {
VMSTATE_UINT32(sel, GEDState),
VMSTATE_END_OF_LIST()
}
};
static const VMStateDescription vmstate_acpi_ged = {
.name = "acpi-ged",
.version_id = 1,
.minimum_version_id = 1,
.fields = (VMStateField[]) {
VMSTATE_STRUCT(ged_state, AcpiGedState, 1, vmstate_ged_state, GEDState),
VMSTATE_END_OF_LIST(),
},
.subsections = (const VMStateDescription * []) {
&vmstate_memhp_state,
NULL
}
};
static void acpi_ged_initfn(Object *obj)
{
DeviceState *dev = DEVICE(obj);
AcpiGedState *s = ACPI_GED(dev);
SysBusDevice *sbd = SYS_BUS_DEVICE(obj);
GEDState *ged_st = &s->ged_state;
memory_region_init_io(&ged_st->io, obj, &ged_ops, ged_st,
TYPE_ACPI_GED, ACPI_GED_EVT_SEL_LEN);
sysbus_init_mmio(sbd, &ged_st->io);
sysbus_init_irq(sbd, &s->irq);
s->memhp_state.is_enabled = true;
/*
* GED handles memory hotplug event and acpi-mem-hotplug
* memory region gets initialized here. Create an exclusive
* container for memory hotplug IO and expose it as GED sysbus
* MMIO so that boards can map it separately.
*/
memory_region_init(&s->container_memhp, OBJECT(dev), "memhp container",
MEMORY_HOTPLUG_IO_LEN);
sysbus_init_mmio(sbd, &s->container_memhp);
acpi_memory_hotplug_init(&s->container_memhp, OBJECT(dev),
&s->memhp_state, 0);
}
static void acpi_ged_class_init(ObjectClass *class, void *data)
{
DeviceClass *dc = DEVICE_CLASS(class);
HotplugHandlerClass *hc = HOTPLUG_HANDLER_CLASS(class);
AcpiDeviceIfClass *adevc = ACPI_DEVICE_IF_CLASS(class);
dc->desc = "ACPI Generic Event Device";
dc->props = acpi_ged_properties;
dc->vmsd = &vmstate_acpi_ged;
hc->plug = acpi_ged_device_plug_cb;
adevc->send_event = acpi_ged_send_event;
}
static const TypeInfo acpi_ged_info = {
.name = TYPE_ACPI_GED,
.parent = TYPE_SYS_BUS_DEVICE,
.instance_size = sizeof(AcpiGedState),
.instance_init = acpi_ged_initfn,
.class_init = acpi_ged_class_init,
.interfaces = (InterfaceInfo[]) {
{ TYPE_HOTPLUG_HANDLER },
{ TYPE_ACPI_DEVICE_IF },
{ }
}
};
static void acpi_ged_register_types(void)
{
type_register_static(&acpi_ged_info);
}
type_init(acpi_ged_register_types)

View File

@ -30,12 +30,7 @@
#define MEMORY_SLOT_PROXIMITY_METHOD "MPXM"
#define MEMORY_SLOT_EJECT_METHOD "MEJ0"
#define MEMORY_SLOT_NOTIFY_METHOD "MTFY"
#define MEMORY_SLOT_SCAN_METHOD "MSCN"
#define MEMORY_HOTPLUG_DEVICE "MHPD"
#define MEMORY_HOTPLUG_IO_LEN 24
#define MEMORY_DEVICES_CONTAINER "\\_SB.MHPC"
static uint16_t memhp_io_base;
static ACPIOSTInfo *acpi_memory_device_status(int slot, MemStatus *mdev)
{
@ -210,7 +205,7 @@ static const MemoryRegionOps acpi_memory_hotplug_ops = {
};
void acpi_memory_hotplug_init(MemoryRegion *as, Object *owner,
MemHotplugState *state, uint16_t io_base)
MemHotplugState *state, hwaddr io_base)
{
MachineState *machine = MACHINE(qdev_get_machine());
@ -219,12 +214,10 @@ void acpi_memory_hotplug_init(MemoryRegion *as, Object *owner,
return;
}
assert(!memhp_io_base);
memhp_io_base = io_base;
state->devs = g_malloc0(sizeof(*state->devs) * state->dev_count);
memory_region_init_io(&state->io, owner, &acpi_memory_hotplug_ops, state,
"acpi-mem-hotplug", MEMORY_HOTPLUG_IO_LEN);
memory_region_add_subregion(as, memhp_io_base, &state->io);
memory_region_add_subregion(as, io_base, &state->io);
}
/**
@ -343,7 +336,8 @@ const VMStateDescription vmstate_memory_hotplug = {
void build_memory_hotplug_aml(Aml *table, uint32_t nr_mem,
const char *res_root,
const char *event_handler_method)
const char *event_handler_method,
AmlRegionSpace rs, hwaddr memhp_io_base)
{
int i;
Aml *ifctx;
@ -352,10 +346,6 @@ void build_memory_hotplug_aml(Aml *table, uint32_t nr_mem,
Aml *mem_ctrl_dev;
char *mhp_res_path;
if (!memhp_io_base) {
return;
}
mhp_res_path = g_strdup_printf("%s." MEMORY_HOTPLUG_DEVICE, res_root);
mem_ctrl_dev = aml_device("%s", mhp_res_path);
{
@ -366,14 +356,19 @@ void build_memory_hotplug_aml(Aml *table, uint32_t nr_mem,
aml_name_decl("_UID", aml_string("Memory hotplug resources")));
crs = aml_resource_template();
aml_append(crs,
aml_io(AML_DECODE16, memhp_io_base, memhp_io_base, 0,
MEMORY_HOTPLUG_IO_LEN)
);
if (rs == AML_SYSTEM_IO) {
aml_append(crs,
aml_io(AML_DECODE16, memhp_io_base, memhp_io_base, 0,
MEMORY_HOTPLUG_IO_LEN)
);
} else {
aml_append(crs, aml_memory32_fixed(memhp_io_base,
MEMORY_HOTPLUG_IO_LEN, AML_READ_WRITE));
}
aml_append(mem_ctrl_dev, aml_name_decl("_CRS", crs));
aml_append(mem_ctrl_dev, aml_operation_region(
MEMORY_HOTPLUG_IO_REGION, AML_SYSTEM_IO,
MEMORY_HOTPLUG_IO_REGION, rs,
aml_int(memhp_io_base), MEMORY_HOTPLUG_IO_LEN)
);
@ -717,10 +712,12 @@ void build_memory_hotplug_aml(Aml *table, uint32_t nr_mem,
}
aml_append(table, dev_container);
method = aml_method(event_handler_method, 0, AML_NOTSERIALIZED);
aml_append(method,
aml_call0(MEMORY_DEVICES_CONTAINER "." MEMORY_SLOT_SCAN_METHOD));
aml_append(table, method);
if (event_handler_method) {
method = aml_method(event_handler_method, 0, AML_NOTSERIALIZED);
aml_append(method, aml_call0(MEMORY_DEVICES_CONTAINER "."
MEMORY_SLOT_SCAN_METHOD));
aml_append(table, method);
}
g_free(mhp_res_path);
}

View File

@ -20,6 +20,10 @@ config ARM_VIRT
select SMBIOS
select VIRTIO_MMIO
select ACPI_PCI
select MEM_DEVICE
select DIMM
select ACPI_MEMORY_HOTPLUG
select ACPI_HW_REDUCED
config CHEETAH
bool

View File

@ -39,6 +39,8 @@
#include "hw/acpi/aml-build.h"
#include "hw/acpi/utils.h"
#include "hw/acpi/pci.h"
#include "hw/acpi/memory_hotplug.h"
#include "hw/acpi/generic_event_device.h"
#include "hw/pci/pcie_host.h"
#include "hw/pci/pci.h"
#include "hw/arm/virt.h"
@ -48,7 +50,6 @@
#include "migration/vmstate.h"
#define ARM_SPI_BASE 32
#define ACPI_POWER_BUTTON_DEVICE "PWRB"
static void acpi_dsdt_add_cpus(Aml *scope, int smp_cpus)
{
@ -544,6 +545,14 @@ build_srat(GArray *table_data, BIOSLinker *linker, VirtMachineState *vms)
}
}
if (ms->device_memory) {
numamem = acpi_data_push(table_data, sizeof *numamem);
build_srat_memory(numamem, ms->device_memory->base,
memory_region_size(&ms->device_memory->mr),
ms->numa_state->num_nodes - 1,
MEM_AFFINITY_HOTPLUGGABLE | MEM_AFFINITY_ENABLED);
}
build_header(linker, table_data, (void *)(table_data->data + srat_start),
"SRAT", table_data->len - srat_start, 3, NULL, NULL);
}
@ -708,6 +717,7 @@ static void
build_dsdt(GArray *table_data, BIOSLinker *linker, VirtMachineState *vms)
{
Aml *scope, *dsdt;
MachineState *ms = MACHINE(vms);
const MemMapEntry *memmap = vms->memmap;
const int *irqmap = vms->irqmap;
@ -730,8 +740,27 @@ build_dsdt(GArray *table_data, BIOSLinker *linker, VirtMachineState *vms)
(irqmap[VIRT_MMIO] + ARM_SPI_BASE), NUM_VIRTIO_TRANSPORTS);
acpi_dsdt_add_pci(scope, memmap, (irqmap[VIRT_PCIE] + ARM_SPI_BASE),
vms->highmem, vms->highmem_ecam);
acpi_dsdt_add_gpio(scope, &memmap[VIRT_GPIO],
(irqmap[VIRT_GPIO] + ARM_SPI_BASE));
if (vms->acpi_dev) {
build_ged_aml(scope, "\\_SB."GED_DEVICE,
HOTPLUG_HANDLER(vms->acpi_dev),
irqmap[VIRT_ACPI_GED] + ARM_SPI_BASE, AML_SYSTEM_MEMORY,
memmap[VIRT_ACPI_GED].base);
} else {
acpi_dsdt_add_gpio(scope, &memmap[VIRT_GPIO],
(irqmap[VIRT_GPIO] + ARM_SPI_BASE));
}
if (vms->acpi_dev) {
uint32_t event = object_property_get_uint(OBJECT(vms->acpi_dev),
"ged-event", &error_abort);
if (event & ACPI_GED_MEM_HOTPLUG_EVT) {
build_memory_hotplug_aml(scope, ms->ram_slots, "\\_SB", NULL,
AML_SYSTEM_MEMORY,
memmap[VIRT_PCDIMM_ACPI].base);
}
}
acpi_dsdt_add_power_button(scope);
aml_append(dsdt, scope);

View File

@ -68,6 +68,9 @@
#include "hw/arm/smmuv3.h"
#include "hw/acpi/acpi.h"
#include "target/arm/internals.h"
#include "hw/mem/pc-dimm.h"
#include "hw/mem/nvdimm.h"
#include "hw/acpi/generic_event_device.h"
#define DEFINE_VIRT_MACHINE_LATEST(major, minor, latest) \
static void virt_##major##_##minor##_class_init(ObjectClass *oc, \
@ -138,6 +141,8 @@ static const MemMapEntry base_memmap[] = {
[VIRT_GPIO] = { 0x09030000, 0x00001000 },
[VIRT_SECURE_UART] = { 0x09040000, 0x00001000 },
[VIRT_SMMU] = { 0x09050000, 0x00020000 },
[VIRT_PCDIMM_ACPI] = { 0x09070000, MEMORY_HOTPLUG_IO_LEN },
[VIRT_ACPI_GED] = { 0x09080000, ACPI_GED_EVT_SEL_LEN },
[VIRT_MMIO] = { 0x0a000000, 0x00000200 },
/* ...repeating for a total of NUM_VIRTIO_TRANSPORTS, each of that size */
[VIRT_PLATFORM_BUS] = { 0x0c000000, 0x02000000 },
@ -173,6 +178,7 @@ static const int a15irqmap[] = {
[VIRT_PCIE] = 3, /* ... to 6 */
[VIRT_GPIO] = 7,
[VIRT_SECURE_UART] = 8,
[VIRT_ACPI_GED] = 9,
[VIRT_MMIO] = 16, /* ...to 16 + NUM_VIRTIO_TRANSPORTS - 1 */
[VIRT_GIC_V2M] = 48, /* ...to 48 + NUM_GICV2M_SPIS - 1 */
[VIRT_SMMU] = 74, /* ...to 74 + NUM_SMMU_IRQS - 1 */
@ -525,6 +531,29 @@ static void fdt_add_pmu_nodes(const VirtMachineState *vms)
}
}
static inline DeviceState *create_acpi_ged(VirtMachineState *vms, qemu_irq *pic)
{
DeviceState *dev;
MachineState *ms = MACHINE(vms);
int irq = vms->irqmap[VIRT_ACPI_GED];
uint32_t event = ACPI_GED_PWR_DOWN_EVT;
if (ms->ram_slots) {
event |= ACPI_GED_MEM_HOTPLUG_EVT;
}
dev = qdev_create(NULL, TYPE_ACPI_GED);
qdev_prop_set_uint32(dev, "ged-event", event);
sysbus_mmio_map(SYS_BUS_DEVICE(dev), 0, vms->memmap[VIRT_ACPI_GED].base);
sysbus_mmio_map(SYS_BUS_DEVICE(dev), 1, vms->memmap[VIRT_PCDIMM_ACPI].base);
sysbus_connect_irq(SYS_BUS_DEVICE(dev), 0, pic[irq]);
qdev_init_nofail(dev);
return dev;
}
static void create_its(VirtMachineState *vms, DeviceState *gicdev)
{
const char *itsclass = its_class_name();
@ -764,13 +793,15 @@ static void create_rtc(const VirtMachineState *vms, qemu_irq *pic)
static DeviceState *gpio_key_dev;
static void virt_powerdown_req(Notifier *n, void *opaque)
{
/* use gpio Pin 3 for power button event */
qemu_set_irq(qdev_get_gpio_in(gpio_key_dev, 0), 1);
}
VirtMachineState *s = container_of(n, VirtMachineState, powerdown_notifier);
static Notifier virt_system_powerdown_notifier = {
.notify = virt_powerdown_req
};
if (s->acpi_dev) {
acpi_send_event(s->acpi_dev, ACPI_POWER_DOWN_STATUS);
} else {
/* use gpio Pin 3 for power button event */
qemu_set_irq(qdev_get_gpio_in(gpio_key_dev, 0), 1);
}
}
static void create_gpio(const VirtMachineState *vms, qemu_irq *pic)
{
@ -812,10 +843,6 @@ static void create_gpio(const VirtMachineState *vms, qemu_irq *pic)
KEY_POWER);
qemu_fdt_setprop_cells(vms->fdt, "/gpio-keys/poweroff",
"gpios", phandle, 3, 0);
/* connect powerdown request */
qemu_register_powerdown_notifier(&virt_system_powerdown_notifier);
g_free(nodename);
}
@ -1489,6 +1516,7 @@ static void machvirt_init(MachineState *machine)
MemoryRegion *ram = g_new(MemoryRegion, 1);
bool firmware_loaded;
bool aarch64 = true;
bool has_ged = !vmc->no_ged;
unsigned int smp_cpus = machine->smp.cpus;
unsigned int max_cpus = machine->smp.max_cpus;
@ -1701,7 +1729,15 @@ static void machvirt_init(MachineState *machine)
create_pcie(vms, pic);
create_gpio(vms, pic);
if (has_ged && aarch64 && firmware_loaded && acpi_enabled) {
vms->acpi_dev = create_acpi_ged(vms, pic);
} else {
create_gpio(vms, pic);
}
/* connect powerdown request */
vms->powerdown_notifier.notify = virt_powerdown_req;
qemu_register_powerdown_notifier(&vms->powerdown_notifier);
/* Create mmio transports, so the user can create virtio backends
* (which will be automatically plugged in to the transports). If
@ -1876,6 +1912,52 @@ static const CPUArchIdList *virt_possible_cpu_arch_ids(MachineState *ms)
return ms->possible_cpus;
}
static void virt_memory_pre_plug(HotplugHandler *hotplug_dev, DeviceState *dev,
Error **errp)
{
VirtMachineState *vms = VIRT_MACHINE(hotplug_dev);
const bool is_nvdimm = object_dynamic_cast(OBJECT(dev), TYPE_NVDIMM);
if (is_nvdimm) {
error_setg(errp, "nvdimm is not yet supported");
return;
}
if (!vms->acpi_dev) {
error_setg(errp,
"memory hotplug is not enabled: missing acpi-ged device");
return;
}
pc_dimm_pre_plug(PC_DIMM(dev), MACHINE(hotplug_dev), NULL, errp);
}
static void virt_memory_plug(HotplugHandler *hotplug_dev,
DeviceState *dev, Error **errp)
{
HotplugHandlerClass *hhc;
VirtMachineState *vms = VIRT_MACHINE(hotplug_dev);
Error *local_err = NULL;
pc_dimm_plug(PC_DIMM(dev), MACHINE(vms), &local_err);
if (local_err) {
goto out;
}
hhc = HOTPLUG_HANDLER_GET_CLASS(vms->acpi_dev);
hhc->plug(HOTPLUG_HANDLER(vms->acpi_dev), dev, &error_abort);
out:
error_propagate(errp, local_err);
}
static void virt_machine_device_pre_plug_cb(HotplugHandler *hotplug_dev,
DeviceState *dev, Error **errp)
{
if (object_dynamic_cast(OBJECT(dev), TYPE_PC_DIMM)) {
virt_memory_pre_plug(hotplug_dev, dev, errp);
}
}
static void virt_machine_device_plug_cb(HotplugHandler *hotplug_dev,
DeviceState *dev, Error **errp)
{
@ -1887,12 +1969,23 @@ static void virt_machine_device_plug_cb(HotplugHandler *hotplug_dev,
SYS_BUS_DEVICE(dev));
}
}
if (object_dynamic_cast(OBJECT(dev), TYPE_PC_DIMM)) {
virt_memory_plug(hotplug_dev, dev, errp);
}
}
static void virt_machine_device_unplug_request_cb(HotplugHandler *hotplug_dev,
DeviceState *dev, Error **errp)
{
error_setg(errp, "device unplug request for unsupported device"
" type: %s", object_get_typename(OBJECT(dev)));
}
static HotplugHandler *virt_machine_get_hotplug_handler(MachineState *machine,
DeviceState *dev)
{
if (object_dynamic_cast(OBJECT(dev), TYPE_SYS_BUS_DEVICE)) {
if (object_dynamic_cast(OBJECT(dev), TYPE_SYS_BUS_DEVICE) ||
(object_dynamic_cast(OBJECT(dev), TYPE_PC_DIMM))) {
return HOTPLUG_HANDLER(machine);
}
@ -1956,8 +2049,11 @@ static void virt_machine_class_init(ObjectClass *oc, void *data)
mc->kvm_type = virt_kvm_type;
assert(!mc->get_hotplug_handler);
mc->get_hotplug_handler = virt_machine_get_hotplug_handler;
hc->pre_plug = virt_machine_device_pre_plug_cb;
hc->plug = virt_machine_device_plug_cb;
hc->unplug_request = virt_machine_device_unplug_request_cb;
mc->numa_mem_supported = true;
mc->auto_enable_numa_with_memhp = true;
}
static void virt_instance_init(Object *obj)
@ -2058,8 +2154,12 @@ DEFINE_VIRT_MACHINE_AS_LATEST(4, 2)
static void virt_machine_4_1_options(MachineClass *mc)
{
VirtMachineClass *vmc = VIRT_MACHINE_CLASS(OBJECT_CLASS(mc));
virt_machine_4_2_options(mc);
compat_props_add(mc->compat_props, hw_compat_4_1, hw_compat_4_1_len);
vmc->no_ged = true;
mc->auto_enable_numa_with_memhp = false;
}
DEFINE_VIRT_MACHINE(4, 1)

View File

@ -1888,7 +1888,12 @@ build_dsdt(GArray *table_data, BIOSLinker *linker,
build_cpus_aml(dsdt, machine, opts, pm->cpu_hp_io_base,
"\\_SB.PCI0", "\\_GPE._E02");
}
build_memory_hotplug_aml(dsdt, nr_mem, "\\_SB.PCI0", "\\_GPE._E03");
if (pcms->memhp_io_base && nr_mem) {
build_memory_hotplug_aml(dsdt, nr_mem, "\\_SB.PCI0",
"\\_GPE._E03", AML_SYSTEM_IO,
pcms->memhp_io_base);
}
scope = aml_scope("_GPE");
{

View File

@ -1766,6 +1766,9 @@ void pc_memory_init(PCMachineState *pcms,
/* Init default IOAPIC address space */
pcms->ioapic_as = &address_space_memory;
/* Init ACPI memory hotplug IO base address */
pcms->memhp_io_base = ACPI_MEMORY_HOTPLUG_BASE;
}
/*

View File

@ -11,9 +11,11 @@ common-obj-$(CONFIG_VIRTIO_PCI) += virtio-pci.o
common-obj-$(CONFIG_VIRTIO_MMIO) += virtio-mmio.o
obj-$(CONFIG_VIRTIO_BALLOON) += virtio-balloon.o
obj-$(CONFIG_VIRTIO_CRYPTO) += virtio-crypto.o
obj-$(CONFIG_VHOST_USER_FS) += vhost-user-fs.o
obj-$(call land,$(CONFIG_VIRTIO_CRYPTO),$(CONFIG_VIRTIO_PCI)) += virtio-crypto-pci.o
obj-$(CONFIG_VIRTIO_PMEM) += virtio-pmem.o
common-obj-$(call land,$(CONFIG_VIRTIO_PMEM),$(CONFIG_VIRTIO_PCI)) += virtio-pmem-pci.o
obj-$(call land,$(CONFIG_VHOST_USER_FS),$(CONFIG_VIRTIO_PCI)) += vhost-user-fs-pci.o
obj-$(CONFIG_VHOST_VSOCK) += vhost-vsock.o
ifeq ($(CONFIG_VIRTIO_PCI),y)

View File

@ -0,0 +1,85 @@
/*
* Vhost-user filesystem virtio device PCI glue
*
* Copyright 2018-2019 Red Hat, Inc.
*
* Authors:
* Dr. David Alan Gilbert <dgilbert@redhat.com>
*
* This work is licensed under the terms of the GNU GPL, version 2 or
* (at your option) any later version. See the COPYING file in the
* top-level directory.
*/
#include "qemu/osdep.h"
#include "hw/qdev-properties.h"
#include "hw/virtio/vhost-user-fs.h"
#include "virtio-pci.h"
struct VHostUserFSPCI {
VirtIOPCIProxy parent_obj;
VHostUserFS vdev;
};
typedef struct VHostUserFSPCI VHostUserFSPCI;
#define TYPE_VHOST_USER_FS_PCI "vhost-user-fs-pci-base"
#define VHOST_USER_FS_PCI(obj) \
OBJECT_CHECK(VHostUserFSPCI, (obj), TYPE_VHOST_USER_FS_PCI)
static Property vhost_user_fs_pci_properties[] = {
DEFINE_PROP_UINT32("vectors", VirtIOPCIProxy, nvectors,
DEV_NVECTORS_UNSPECIFIED),
DEFINE_PROP_END_OF_LIST(),
};
static void vhost_user_fs_pci_realize(VirtIOPCIProxy *vpci_dev, Error **errp)
{
VHostUserFSPCI *dev = VHOST_USER_FS_PCI(vpci_dev);
DeviceState *vdev = DEVICE(&dev->vdev);
if (vpci_dev->nvectors == DEV_NVECTORS_UNSPECIFIED) {
vpci_dev->nvectors = dev->vdev.conf.num_request_queues + 1;
}
qdev_set_parent_bus(vdev, BUS(&vpci_dev->bus));
object_property_set_bool(OBJECT(vdev), true, "realized", errp);
}
static void vhost_user_fs_pci_class_init(ObjectClass *klass, void *data)
{
DeviceClass *dc = DEVICE_CLASS(klass);
VirtioPCIClass *k = VIRTIO_PCI_CLASS(klass);
PCIDeviceClass *pcidev_k = PCI_DEVICE_CLASS(klass);
k->realize = vhost_user_fs_pci_realize;
set_bit(DEVICE_CATEGORY_STORAGE, dc->categories);
dc->props = vhost_user_fs_pci_properties;
pcidev_k->vendor_id = PCI_VENDOR_ID_REDHAT_QUMRANET;
pcidev_k->device_id = 0; /* Set by virtio-pci based on virtio id */
pcidev_k->revision = 0x00;
pcidev_k->class_id = PCI_CLASS_STORAGE_OTHER;
}
static void vhost_user_fs_pci_instance_init(Object *obj)
{
VHostUserFSPCI *dev = VHOST_USER_FS_PCI(obj);
virtio_instance_init_common(obj, &dev->vdev, sizeof(dev->vdev),
TYPE_VHOST_USER_FS);
}
static const VirtioPCIDeviceTypeInfo vhost_user_fs_pci_info = {
.base_name = TYPE_VHOST_USER_FS_PCI,
.non_transitional_name = "vhost-user-fs-pci",
.instance_size = sizeof(VHostUserFSPCI),
.instance_init = vhost_user_fs_pci_instance_init,
.class_init = vhost_user_fs_pci_class_init,
};
static void vhost_user_fs_pci_register(void)
{
virtio_pci_types_register(&vhost_user_fs_pci_info);
}
type_init(vhost_user_fs_pci_register);

299
hw/virtio/vhost-user-fs.c Normal file
View File

@ -0,0 +1,299 @@
/*
* Vhost-user filesystem virtio device
*
* Copyright 2018-2019 Red Hat, Inc.
*
* Authors:
* Stefan Hajnoczi <stefanha@redhat.com>
*
* This work is licensed under the terms of the GNU GPL, version 2 or
* (at your option) any later version. See the COPYING file in the
* top-level directory.
*/
#include "qemu/osdep.h"
#include <sys/ioctl.h>
#include "standard-headers/linux/virtio_fs.h"
#include "qapi/error.h"
#include "hw/qdev-properties.h"
#include "hw/virtio/virtio-bus.h"
#include "hw/virtio/virtio-access.h"
#include "qemu/error-report.h"
#include "hw/virtio/vhost-user-fs.h"
#include "monitor/monitor.h"
static void vuf_get_config(VirtIODevice *vdev, uint8_t *config)
{
VHostUserFS *fs = VHOST_USER_FS(vdev);
struct virtio_fs_config fscfg = {};
memcpy((char *)fscfg.tag, fs->conf.tag,
MIN(strlen(fs->conf.tag) + 1, sizeof(fscfg.tag)));
virtio_stl_p(vdev, &fscfg.num_request_queues, fs->conf.num_request_queues);
memcpy(config, &fscfg, sizeof(fscfg));
}
static void vuf_start(VirtIODevice *vdev)
{
VHostUserFS *fs = VHOST_USER_FS(vdev);
BusState *qbus = BUS(qdev_get_parent_bus(DEVICE(vdev)));
VirtioBusClass *k = VIRTIO_BUS_GET_CLASS(qbus);
int ret;
int i;
if (!k->set_guest_notifiers) {
error_report("binding does not support guest notifiers");
return;
}
ret = vhost_dev_enable_notifiers(&fs->vhost_dev, vdev);
if (ret < 0) {
error_report("Error enabling host notifiers: %d", -ret);
return;
}
ret = k->set_guest_notifiers(qbus->parent, fs->vhost_dev.nvqs, true);
if (ret < 0) {
error_report("Error binding guest notifier: %d", -ret);
goto err_host_notifiers;
}
fs->vhost_dev.acked_features = vdev->guest_features;
ret = vhost_dev_start(&fs->vhost_dev, vdev);
if (ret < 0) {
error_report("Error starting vhost: %d", -ret);
goto err_guest_notifiers;
}
/*
* guest_notifier_mask/pending not used yet, so just unmask
* everything here. virtio-pci will do the right thing by
* enabling/disabling irqfd.
*/
for (i = 0; i < fs->vhost_dev.nvqs; i++) {
vhost_virtqueue_mask(&fs->vhost_dev, vdev, i, false);
}
return;
err_guest_notifiers:
k->set_guest_notifiers(qbus->parent, fs->vhost_dev.nvqs, false);
err_host_notifiers:
vhost_dev_disable_notifiers(&fs->vhost_dev, vdev);
}
static void vuf_stop(VirtIODevice *vdev)
{
VHostUserFS *fs = VHOST_USER_FS(vdev);
BusState *qbus = BUS(qdev_get_parent_bus(DEVICE(vdev)));
VirtioBusClass *k = VIRTIO_BUS_GET_CLASS(qbus);
int ret;
if (!k->set_guest_notifiers) {
return;
}
vhost_dev_stop(&fs->vhost_dev, vdev);
ret = k->set_guest_notifiers(qbus->parent, fs->vhost_dev.nvqs, false);
if (ret < 0) {
error_report("vhost guest notifier cleanup failed: %d", ret);
return;
}
vhost_dev_disable_notifiers(&fs->vhost_dev, vdev);
}
static void vuf_set_status(VirtIODevice *vdev, uint8_t status)
{
VHostUserFS *fs = VHOST_USER_FS(vdev);
bool should_start = status & VIRTIO_CONFIG_S_DRIVER_OK;
if (!vdev->vm_running) {
should_start = false;
}
if (fs->vhost_dev.started == should_start) {
return;
}
if (should_start) {
vuf_start(vdev);
} else {
vuf_stop(vdev);
}
}
static uint64_t vuf_get_features(VirtIODevice *vdev,
uint64_t requested_features,
Error **errp)
{
/* No feature bits used yet */
return requested_features;
}
static void vuf_handle_output(VirtIODevice *vdev, VirtQueue *vq)
{
/*
* Not normally called; it's the daemon that handles the queue;
* however virtio's cleanup path can call this.
*/
}
static void vuf_guest_notifier_mask(VirtIODevice *vdev, int idx,
bool mask)
{
VHostUserFS *fs = VHOST_USER_FS(vdev);
vhost_virtqueue_mask(&fs->vhost_dev, vdev, idx, mask);
}
static bool vuf_guest_notifier_pending(VirtIODevice *vdev, int idx)
{
VHostUserFS *fs = VHOST_USER_FS(vdev);
return vhost_virtqueue_pending(&fs->vhost_dev, idx);
}
static void vuf_device_realize(DeviceState *dev, Error **errp)
{
VirtIODevice *vdev = VIRTIO_DEVICE(dev);
VHostUserFS *fs = VHOST_USER_FS(dev);
unsigned int i;
size_t len;
int ret;
if (!fs->conf.chardev.chr) {
error_setg(errp, "missing chardev");
return;
}
if (!fs->conf.tag) {
error_setg(errp, "missing tag property");
return;
}
len = strlen(fs->conf.tag);
if (len == 0) {
error_setg(errp, "tag property cannot be empty");
return;
}
if (len > sizeof_field(struct virtio_fs_config, tag)) {
error_setg(errp, "tag property must be %zu bytes or less",
sizeof_field(struct virtio_fs_config, tag));
return;
}
if (fs->conf.num_request_queues == 0) {
error_setg(errp, "num-request-queues property must be larger than 0");
return;
}
if (!is_power_of_2(fs->conf.queue_size)) {
error_setg(errp, "queue-size property must be a power of 2");
return;
}
if (fs->conf.queue_size > VIRTQUEUE_MAX_SIZE) {
error_setg(errp, "queue-size property must be %u or smaller",
VIRTQUEUE_MAX_SIZE);
return;
}
if (!vhost_user_init(&fs->vhost_user, &fs->conf.chardev, errp)) {
return;
}
virtio_init(vdev, "vhost-user-fs", VIRTIO_ID_FS,
sizeof(struct virtio_fs_config));
/* Hiprio queue */
virtio_add_queue(vdev, fs->conf.queue_size, vuf_handle_output);
/* Request queues */
for (i = 0; i < fs->conf.num_request_queues; i++) {
virtio_add_queue(vdev, fs->conf.queue_size, vuf_handle_output);
}
/* 1 high prio queue, plus the number configured */
fs->vhost_dev.nvqs = 1 + fs->conf.num_request_queues;
fs->vhost_dev.vqs = g_new0(struct vhost_virtqueue, fs->vhost_dev.nvqs);
ret = vhost_dev_init(&fs->vhost_dev, &fs->vhost_user,
VHOST_BACKEND_TYPE_USER, 0);
if (ret < 0) {
error_setg_errno(errp, -ret, "vhost_dev_init failed");
goto err_virtio;
}
return;
err_virtio:
vhost_user_cleanup(&fs->vhost_user);
virtio_cleanup(vdev);
g_free(fs->vhost_dev.vqs);
return;
}
static void vuf_device_unrealize(DeviceState *dev, Error **errp)
{
VirtIODevice *vdev = VIRTIO_DEVICE(dev);
VHostUserFS *fs = VHOST_USER_FS(dev);
/* This will stop vhost backend if appropriate. */
vuf_set_status(vdev, 0);
vhost_dev_cleanup(&fs->vhost_dev);
vhost_user_cleanup(&fs->vhost_user);
virtio_cleanup(vdev);
g_free(fs->vhost_dev.vqs);
fs->vhost_dev.vqs = NULL;
}
static const VMStateDescription vuf_vmstate = {
.name = "vhost-user-fs",
.unmigratable = 1,
};
static Property vuf_properties[] = {
DEFINE_PROP_CHR("chardev", VHostUserFS, conf.chardev),
DEFINE_PROP_STRING("tag", VHostUserFS, conf.tag),
DEFINE_PROP_UINT16("num-request-queues", VHostUserFS,
conf.num_request_queues, 1),
DEFINE_PROP_UINT16("queue-size", VHostUserFS, conf.queue_size, 128),
DEFINE_PROP_STRING("vhostfd", VHostUserFS, conf.vhostfd),
DEFINE_PROP_END_OF_LIST(),
};
static void vuf_class_init(ObjectClass *klass, void *data)
{
DeviceClass *dc = DEVICE_CLASS(klass);
VirtioDeviceClass *vdc = VIRTIO_DEVICE_CLASS(klass);
dc->props = vuf_properties;
dc->vmsd = &vuf_vmstate;
set_bit(DEVICE_CATEGORY_STORAGE, dc->categories);
vdc->realize = vuf_device_realize;
vdc->unrealize = vuf_device_unrealize;
vdc->get_features = vuf_get_features;
vdc->get_config = vuf_get_config;
vdc->set_status = vuf_set_status;
vdc->guest_notifier_mask = vuf_guest_notifier_mask;
vdc->guest_notifier_pending = vuf_guest_notifier_pending;
}
static const TypeInfo vuf_info = {
.name = TYPE_VHOST_USER_FS,
.parent = TYPE_VIRTIO_DEVICE,
.instance_size = sizeof(VHostUserFS),
.class_init = vuf_class_init,
};
static void vuf_register_types(void)
{
type_register_static(&vuf_info);
}
type_init(vuf_register_types)

View File

@ -13,6 +13,7 @@ typedef enum {
ACPI_MEMORY_HOTPLUG_STATUS = 8,
ACPI_NVDIMM_HOTPLUG_STATUS = 16,
ACPI_VMGENID_CHANGE_STATUS = 32,
ACPI_POWER_DOWN_STATUS = 64,
} AcpiEventStatusBits;
#define TYPE_ACPI_DEVICE_IF "acpi-device-interface"

View File

@ -0,0 +1,103 @@
/*
*
* Copyright (c) 2018 Intel Corporation
* Copyright (c) 2019 Huawei Technologies R & D (UK) Ltd
* Written by Samuel Ortiz, Shameer Kolothum
*
* This program is free software; you can redistribute it and/or modify it
* under the terms and conditions of the GNU General Public License,
* version 2 or later, as published by the Free Software Foundation.
*
* The ACPI Generic Event Device (GED) is a hardware-reduced specific
* device[ACPI v6.1 Section 5.6.9] that handles all platform events,
* including the hotplug ones. Generic Event Device allows platforms
* to handle interrupts in ACPI ASL statements. It follows a very
* similar approach like the _EVT method from GPIO events. All
* interrupts are listed in _CRS and the handler is written in _EVT
* method. Here, we use a single interrupt for the GED device, relying
* on IO memory region to communicate the type of device affected by
* the interrupt. This way, we can support up to 32 events with a
* unique interrupt.
*
* Here is an example.
*
* Device (\_SB.GED)
* {
* Name (_HID, "ACPI0013")
* Name (_UID, Zero)
* Name (_CRS, ResourceTemplate ()
* {
* Interrupt (ResourceConsumer, Edge, ActiveHigh, Exclusive, ,, )
* {
* 0x00000029,
* }
* })
* OperationRegion (EREG, SystemMemory, 0x09080000, 0x04)
* Field (EREG, DWordAcc, NoLock, WriteAsZeros)
* {
* ESEL, 32
* }
*
* Method (_EVT, 1, Serialized) // _EVT: Event
* {
* Local0 = ESEL // ESEL = IO memory region which specifies the
* // device type.
* If (((Local0 & One) == One))
* {
* MethodEvent1()
* }
* If ((Local0 & 0x2) == 0x2)
* {
* MethodEvent2()
* }
* ...
* }
* }
*
*/
#ifndef HW_ACPI_GED_H
#define HW_ACPI_GED_H
#include "hw/sysbus.h"
#include "hw/acpi/memory_hotplug.h"
#define ACPI_POWER_BUTTON_DEVICE "PWRB"
#define TYPE_ACPI_GED "acpi-ged"
#define ACPI_GED(obj) \
OBJECT_CHECK(AcpiGedState, (obj), TYPE_ACPI_GED)
#define ACPI_GED_EVT_SEL_OFFSET 0x0
#define ACPI_GED_EVT_SEL_LEN 0x4
#define GED_DEVICE "GED"
#define AML_GED_EVT_REG "EREG"
#define AML_GED_EVT_SEL "ESEL"
/*
* Platforms need to specify the GED event bitmap
* to describe what kind of events they want to support
* through GED.
*/
#define ACPI_GED_MEM_HOTPLUG_EVT 0x1
#define ACPI_GED_PWR_DOWN_EVT 0x2
typedef struct GEDState {
MemoryRegion io;
uint32_t sel;
} GEDState;
typedef struct AcpiGedState {
SysBusDevice parent_obj;
MemHotplugState memhp_state;
MemoryRegion container_memhp;
GEDState ged_state;
uint32_t ged_event_bitmap;
qemu_irq irq;
} AcpiGedState;
void build_ged_aml(Aml *table, const char* name, HotplugHandler *hotplug_dev,
uint32_t ged_irq, AmlRegionSpace rs, hwaddr ged_base);
#endif

View File

@ -5,6 +5,10 @@
#include "hw/acpi/acpi.h"
#include "hw/acpi/aml-build.h"
#define MEMORY_SLOT_SCAN_METHOD "MSCN"
#define MEMORY_DEVICES_CONTAINER "\\_SB.MHPC"
#define MEMORY_HOTPLUG_IO_LEN 24
/**
* MemStatus:
* @is_removing: the memory device in slot has been requested to be ejected.
@ -29,7 +33,7 @@ typedef struct MemHotplugState {
} MemHotplugState;
void acpi_memory_hotplug_init(MemoryRegion *as, Object *owner,
MemHotplugState *state, uint16_t io_base);
MemHotplugState *state, hwaddr io_base);
void acpi_memory_plug_cb(HotplugHandler *hotplug_dev, MemHotplugState *mem_st,
DeviceState *dev, Error **errp);
@ -48,5 +52,6 @@ void acpi_memory_ospm_status(MemHotplugState *mem_st, ACPIOSTInfoList ***list);
void build_memory_hotplug_aml(Aml *table, uint32_t nr_mem,
const char *res_root,
const char *event_handler_method);
const char *event_handler_method,
AmlRegionSpace rs, hwaddr memhp_io_base);
#endif

View File

@ -77,6 +77,8 @@ enum {
VIRT_GPIO,
VIRT_SECURE_UART,
VIRT_SECURE_MEM,
VIRT_PCDIMM_ACPI,
VIRT_ACPI_GED,
VIRT_LOWMEMMAP_LAST,
};
@ -106,6 +108,7 @@ typedef struct {
bool claim_edge_triggered_timers;
bool smbios_old_sys_ver;
bool no_highmem_ecam;
bool no_ged; /* Machines < 4.2 has no support for ACPI GED device */
} VirtMachineClass;
typedef struct {
@ -133,6 +136,8 @@ typedef struct {
uint32_t iommu_phandle;
int psci_conduit;
hwaddr highest_gpa;
DeviceState *acpi_dev;
Notifier powerdown_notifier;
} VirtMachineState;
#define VIRT_ECAM_ID(high) (high ? VIRT_HIGH_PCIE_ECAM : VIRT_PCIE_ECAM)

View File

@ -70,6 +70,9 @@ struct PCMachineState {
/* Address space used by IOAPIC device. All IOAPIC interrupts
* will be translated to MSI messages in the address space. */
AddressSpace *ioapic_as;
/* ACPI Memory hotplug IO base address */
hwaddr memhp_io_base;
};
#define PC_MACHINE_ACPI_DEVICE_PROP "acpi-device"

View File

@ -0,0 +1,45 @@
/*
* Vhost-user filesystem virtio device
*
* Copyright 2018-2019 Red Hat, Inc.
*
* Authors:
* Stefan Hajnoczi <stefanha@redhat.com>
*
* This work is licensed under the terms of the GNU GPL, version 2 or
* (at your option) any later version. See the COPYING file in the
* top-level directory.
*/
#ifndef _QEMU_VHOST_USER_FS_H
#define _QEMU_VHOST_USER_FS_H
#include "hw/virtio/virtio.h"
#include "hw/virtio/vhost.h"
#include "hw/virtio/vhost-user.h"
#include "chardev/char-fe.h"
#define TYPE_VHOST_USER_FS "vhost-user-fs-device"
#define VHOST_USER_FS(obj) \
OBJECT_CHECK(VHostUserFS, (obj), TYPE_VHOST_USER_FS)
typedef struct {
CharBackend chardev;
char *tag;
uint16_t num_request_queues;
uint16_t queue_size;
char *vhostfd;
} VHostUserFSConf;
typedef struct {
/*< private >*/
VirtIODevice parent;
VHostUserFSConf conf;
struct vhost_virtqueue *vhost_vqs;
struct vhost_dev vhost_dev;
VhostUserState vhost_user;
/*< public >*/
} VHostUserFS;
#endif /* _QEMU_VHOST_USER_FS_H */

View File

@ -235,6 +235,10 @@ static void chr_closed_bh(void *opaque)
s = DO_UPCAST(NetVhostUserState, nc, ncs[0]);
if (s->vhost_net) {
s->acked_features = vhost_net_get_acked_features(s->vhost_net);
}
qmp_set_link(name, false, &err);
qemu_chr_fe_set_handlers(&s->chr, NULL, NULL, net_vhost_user_event,

View File

@ -10,6 +10,33 @@
* See the COPYING file in the top-level directory.
*/
/*
* How to add or update the tests:
* Contributor:
* 1. add empty files for new tables, if any, under tests/data/acpi
* 2. list any changed files in tests/bios-tables-test-allowed-diff.h
* 3. commit the above *before* making changes that affect the tables
* Maintainer:
* After 1-3 above tests will pass but ignore differences with the expected files.
* You will also notice that tests/bios-tables-test-allowed-diff.h lists
* a bunch of files. This is your hint that you need to do the below:
* 4. Run
* make check V=1
* this will produce a bunch of warnings about differences
* beween actual and expected ACPI tables. If you have IASL installed,
* they will also be disassembled so you can look at the disassembled
* output. If not - disassemble them yourself in any way you like.
* Look at the differences - make sure they make sense and match what the
* changes you are merging are supposed to do.
*
* 5. From build directory, run:
* $(SRC_PATH)/tests/data/acpi/rebuild-expected-aml.sh
* 6. Now commit any changes.
* 7. Before doing a pull request, make sure tests/bios-tables-test-allowed-diff.h
* is empty - this will ensure following changes to ACPI tables will
* be noticed.
*/
#include "qemu/osdep.h"
#include <glib/gstdio.h>
#include "qemu-common.h"
@ -334,7 +361,10 @@ try_again:
g_assert(ret);
g_assert_no_error(error);
g_assert(exp_sdt.aml);
g_assert(exp_sdt.aml_len);
if (!exp_sdt.aml_len) {
fprintf(stderr, "Warning! zero length expected file '%s'\n",
aml_file);
}
g_array_append_val(exp_tables, exp_sdt);
}
@ -870,6 +900,53 @@ static void test_acpi_piix4_tcg_dimm_pxm(void)
test_acpi_tcg_dimm_pxm(MACHINE_PC);
}
static void test_acpi_virt_tcg_memhp(void)
{
test_data data = {
.machine = "virt",
.accel = "tcg",
.uefi_fl1 = "pc-bios/edk2-aarch64-code.fd",
.uefi_fl2 = "pc-bios/edk2-arm-vars.fd",
.cd = "tests/data/uefi-boot-images/bios-tables-test.aarch64.iso.qcow2",
.ram_start = 0x40000000ULL,
.scan_len = 256ULL * 1024 * 1024,
};
data.variant = ".memhp";
test_acpi_one(" -cpu cortex-a57"
" -m 256M,slots=3,maxmem=1G"
" -object memory-backend-ram,id=ram0,size=128M"
" -object memory-backend-ram,id=ram1,size=128M"
" -numa node,memdev=ram0 -numa node,memdev=ram1"
" -numa dist,src=0,dst=1,val=21",
&data);
free_test_data(&data);
}
static void test_acpi_virt_tcg_numamem(void)
{
test_data data = {
.machine = "virt",
.accel = "tcg",
.uefi_fl1 = "pc-bios/edk2-aarch64-code.fd",
.uefi_fl2 = "pc-bios/edk2-arm-vars.fd",
.cd = "tests/data/uefi-boot-images/bios-tables-test.aarch64.iso.qcow2",
.ram_start = 0x40000000ULL,
.scan_len = 128ULL * 1024 * 1024,
};
data.variant = ".numamem";
test_acpi_one(" -cpu cortex-a57"
" -object memory-backend-ram,id=ram0,size=128M"
" -numa node,memdev=ram0",
&data);
free_test_data(&data);
}
static void test_acpi_virt_tcg(void)
{
test_data data = {
@ -916,6 +993,8 @@ int main(int argc, char *argv[])
qtest_add_func("acpi/q35/dimmpxm", test_acpi_q35_tcg_dimm_pxm);
} else if (strcmp(arch, "aarch64") == 0) {
qtest_add_func("acpi/virt", test_acpi_virt_tcg);
qtest_add_func("acpi/virt/numamem", test_acpi_virt_tcg_numamem);
qtest_add_func("acpi/virt/memhp", test_acpi_virt_tcg_memhp);
}
ret = g_test_run();
boot_sector_cleanup(disk);

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.

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.