aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--MAINTAINERS18
-rw-r--r--backends/tpm.c11
-rw-r--r--block/qapi.c3
-rw-r--r--block/sheepdog.c1
-rw-r--r--docs/memory-hotplug.txt23
-rw-r--r--docs/qmp/qmp-events.txt22
-rw-r--r--docs/specs/acpi_mem_hotplug.txt58
-rw-r--r--hw/acpi/aml-build.c62
-rw-r--r--hw/acpi/ich9.c19
-rw-r--r--hw/acpi/memory_hotplug.c96
-rw-r--r--hw/acpi/piix4.c17
-rw-r--r--hw/core/qdev.c2
-rw-r--r--hw/i386/acpi-build.c108
-rw-r--r--hw/i386/acpi-dsdt-mem-hotplug.dsl13
-rw-r--r--hw/i386/pc.c62
-rw-r--r--hw/i386/pc_piix.c29
-rw-r--r--hw/i386/pc_q35.c26
-rw-r--r--hw/net/vhost_net.c7
-rw-r--r--hw/net/virtio-net.c9
-rw-r--r--hw/pci/msix.c30
-rw-r--r--hw/pci/pci.c43
-rw-r--r--hw/ppc/spapr.c54
-rw-r--r--hw/s390x/s390-virtio-bus.c13
-rw-r--r--hw/s390x/virtio-ccw.c5
-rw-r--r--hw/scsi/virtio-scsi.c5
-rw-r--r--hw/usb/hcd-xhci.c1
-rw-r--r--hw/virtio/virtio-pci.c51
-rw-r--r--hw/virtio/virtio.c36
-rw-r--r--include/glib-compat.h6
-rw-r--r--include/hw/acpi/acpi-defs.h (renamed from hw/i386/acpi-defs.h)0
-rw-r--r--include/hw/acpi/aml-build.h41
-rw-r--r--include/hw/acpi/memory_hotplug.h12
-rw-r--r--include/hw/acpi/pc-hotplug.h3
-rw-r--r--include/hw/qdev-core.h3
-rw-r--r--include/hw/virtio/virtio-bus.h1
-rw-r--r--include/hw/virtio/virtio-net.h2
-rw-r--r--include/hw/virtio/virtio-scsi.h1
-rw-r--r--include/hw/virtio/virtio.h3
-rw-r--r--include/qapi/qmp/qobject.h13
-rw-r--r--include/sysemu/iothread.h1
-rw-r--r--include/sysemu/tpm_backend_int.h2
-rw-r--r--iothread.c12
-rw-r--r--monitor.c25
-rw-r--r--qapi/block-core.json2
-rw-r--r--qapi/event.json14
-rw-r--r--qjson.c10
-rw-r--r--qobject/Makefile.objs2
-rw-r--r--qobject/json-parser.c2
-rw-r--r--qobject/qjson.c6
-rw-r--r--qobject/qnull.c29
-rwxr-xr-xscripts/qmp/qmp-shell147
-rw-r--r--target-tricore/op_helper.c3
-rw-r--r--target-tricore/translate.c6
-rw-r--r--target-tricore/tricore-opcodes.h2
-rw-r--r--tests/acpi-test-data/pc/DSDTbin2970 -> 3028 bytes
-rw-r--r--tests/acpi-test-data/pc/SSDTbin2475 -> 2486 bytes
-rw-r--r--tests/acpi-test-data/pc/SSDT.bridgebin4334 -> 4345 bytes
-rw-r--r--tests/acpi-test-data/q35/DSDTbin7608 -> 7666 bytes
-rw-r--r--tests/acpi-test-data/q35/SSDTbin680 -> 691 bytes
-rw-r--r--tests/acpi-test-data/q35/SSDT.bridgebin697 -> 708 bytes
-rw-r--r--tests/bios-tables-test.c2
-rw-r--r--tests/check-qjson.c15
-rw-r--r--trace-events4
63 files changed, 878 insertions, 315 deletions
diff --git a/MAINTAINERS b/MAINTAINERS
index 8d14e0ffca..b3552b2c19 100644
--- a/MAINTAINERS
+++ b/MAINTAINERS
@@ -932,20 +932,19 @@ K: srat|SRAT
T: git git://github.com/ehabkost/qemu.git numa
QAPI
-M: Luiz Capitulino <lcapitulino@redhat.com>
+M: Markus Armbruster <armbru@redhat.com>
M: Michael Roth <mdroth@linux.vnet.ibm.com>
-S: Maintained
+S: Supported
F: qapi/
F: tests/qapi-schema/
-T: git git://repo.or.cz/qemu/qmp-unstable.git queue/qmp
+T: git git://repo.or.cz/qemu/armbru.git qapi-next
QAPI Schema
M: Eric Blake <eblake@redhat.com>
-M: Luiz Capitulino <lcapitulino@redhat.com>
M: Markus Armbruster <armbru@redhat.com>
S: Supported
F: qapi-schema.json
-T: git git://repo.or.cz/qemu/qmp-unstable.git queue/qmp
+T: git git://repo.or.cz/qemu/armbru.git qapi-next
QObject
M: Luiz Capitulino <lcapitulino@redhat.com>
@@ -970,13 +969,14 @@ X: qom/cpu.c
F: tests/qom-test.c
QMP
-M: Luiz Capitulino <lcapitulino@redhat.com>
-S: Maintained
+M: Markus Armbruster <armbru@redhat.com>
+S: Supported
F: qmp.c
F: monitor.c
F: qmp-commands.hx
-F: QMP/
-T: git git://repo.or.cz/qemu/qmp-unstable.git queue/qmp
+F: docs/qmp/
+F: scripts/qmp/
+T: git git://repo.or.cz/qemu/armbru.git qapi-next
SLIRP
M: Jan Kiszka <jan.kiszka@siemens.com>
diff --git a/backends/tpm.c b/backends/tpm.c
index 4efe36736e..36c5d46f0a 100644
--- a/backends/tpm.c
+++ b/backends/tpm.c
@@ -165,17 +165,6 @@ void tpm_backend_thread_end(TPMBackendThread *tbt)
}
}
-void tpm_backend_thread_tpm_reset(TPMBackendThread *tbt,
- GFunc func, gpointer user_data)
-{
- if (!tbt->pool) {
- tpm_backend_thread_create(tbt, func, user_data);
- } else {
- g_thread_pool_push(tbt->pool, (gpointer)TPM_BACKEND_CMD_TPM_RESET,
- NULL);
- }
-}
-
static const TypeInfo tpm_backend_info = {
.name = TYPE_TPM_BACKEND,
.parent = TYPE_OBJECT,
diff --git a/block/qapi.c b/block/qapi.c
index 063dd1bc1f..18d2b95f54 100644
--- a/block/qapi.c
+++ b/block/qapi.c
@@ -523,9 +523,6 @@ static void dump_qobject(fprintf_function func_fprintf, void *f,
QDECREF(value);
break;
}
- case QTYPE_NONE:
- break;
- case QTYPE_MAX:
default:
abort();
}
diff --git a/block/sheepdog.c b/block/sheepdog.c
index 2d5f06a390..bd7cbed048 100644
--- a/block/sheepdog.c
+++ b/block/sheepdog.c
@@ -2341,6 +2341,7 @@ static int sd_snapshot_create(BlockDriverState *bs, QEMUSnapshotInfo *sn_info)
if (ret < 0) {
error_report("failed to create inode for snapshot: %s",
error_get_pretty(local_err));
+ error_free(local_err);
goto cleanup;
}
diff --git a/docs/memory-hotplug.txt b/docs/memory-hotplug.txt
index f70571df0c..56bdd0a47b 100644
--- a/docs/memory-hotplug.txt
+++ b/docs/memory-hotplug.txt
@@ -4,9 +4,7 @@ QEMU memory hotplug
This document explains how to use the memory hotplug feature in QEMU,
which is present since v2.1.0.
-Please, note that memory hotunplug is not supported yet. This means
-that you're able to add memory, but you're not able to remove it.
-Also, proper guest support is required for memory hotplug to work.
+Guest support is required for memory hotplug to work.
Basic RAM hotplug
-----------------
@@ -74,3 +72,22 @@ comes from regular RAM, 1GB is a 1GB hugepage page and 256MB is from
-device pc-dimm,id=dimm1,memdev=mem1 \
-object memory-backend-file,id=mem2,size=256M,mem-path=/mnt/hugepages-2MB \
-device pc-dimm,id=dimm2,memdev=mem2
+
+
+RAM hot-unplug
+---------------
+
+In order to be able to hot unplug pc-dimm device, QEMU has to be told the ids
+of pc-dimm device and memory backend object. The ids were assigned when you hot
+plugged memory.
+
+Two monitor commands are used to hot unplug memory:
+
+ - "device_del": deletes a front-end pc-dimm device
+ - "object_del": deletes a memory backend object
+
+For example, assuming that the pc-dimm device with id "dimm1" exists, and its memory
+backend is "mem1", the following commands tries to remove it.
+
+ (qemu) device_del dimm1
+ (qemu) object_del mem1
diff --git a/docs/qmp/qmp-events.txt b/docs/qmp/qmp-events.txt
index b19e490eb5..6dc2cca7de 100644
--- a/docs/qmp/qmp-events.txt
+++ b/docs/qmp/qmp-events.txt
@@ -43,9 +43,10 @@ Data:
- "msg": Informative message (e.g., reason for the corruption)
(json-string)
- "offset": If the corruption resulted from an image access, this
- is the access offset into the image (json-int)
+ is the host's access offset into the image
+ (json-int, optional)
- "size": If the corruption resulted from an image access, this
- is the access size (json-int)
+ is the access size (json-int, optional)
Example:
@@ -231,6 +232,23 @@ Example:
{ "event": "GUEST_PANICKED",
"data": { "action": "pause" } }
+MEM_HOT_UNPLUG_ERROR
+--------------------
+Emitted when memory hot unplug error occurs.
+
+Data:
+
+- "device": device name (json-string)
+- "msg": Informative message (e.g., reason for the error) (json-string)
+
+Example:
+
+{ "event": "MEM_HOT_UNPLUG_ERROR"
+ "data": { "device": "dimm1",
+ "msg": "acpi: device unplug for unsupported device"
+ },
+ "timestamp": { "seconds": 1265044230, "microseconds": 450486 } }
+
NIC_RX_FILTER_CHANGED
---------------------
diff --git a/docs/specs/acpi_mem_hotplug.txt b/docs/specs/acpi_mem_hotplug.txt
index 12909940cc..3df3620ce4 100644
--- a/docs/specs/acpi_mem_hotplug.txt
+++ b/docs/specs/acpi_mem_hotplug.txt
@@ -2,7 +2,7 @@ QEMU<->ACPI BIOS memory hotplug interface
--------------------------------------
ACPI BIOS GPE.3 handler is dedicated for notifying OS about memory hot-add
-events.
+and hot-remove events.
Memory hot-plug interface (IO port 0xa00-0xa17, 1-4 byte access):
---------------------------------------------------------------
@@ -19,7 +19,9 @@ Memory hot-plug interface (IO port 0xa00-0xa17, 1-4 byte access):
1: Device insert event, used to distinguish device for which
no device check event to OSPM was issued.
It's valid only when bit 1 is set.
- 2-7: reserved and should be ignored by OSPM
+ 2: Device remove event, used to distinguish device for which
+ no device eject request to OSPM was issued.
+ 3-7: reserved and should be ignored by OSPM
[0x15-0x17] reserved
write access:
@@ -31,14 +33,62 @@ Memory hot-plug interface (IO port 0xa00-0xa17, 1-4 byte access):
[0xc-0x13] reserved, writes into it are ignored
[0x14] Memory device control fields
bits:
- 0: reserved, OSPM must clear it before writing to register
+ 0: reserved, OSPM must clear it before writing to register.
+ Due to BUG in versions prior 2.4 that field isn't cleared
+ when other fields are written. Keep it reserved and don't
+ try to reuse it.
1: if set to 1 clears device insert event, set by OSPM
after it has emitted device check event for the
selected memory device
- 2-7: reserved, OSPM must clear them before writing to register
+ 2: if set to 1 clears device remove event, set by OSPM
+ after it has emitted device eject request for the
+ selected memory device
+ 3: if set to 1 initiates device eject, set by OSPM when it
+ triggers memory device removal and calls _EJ0 method
+ 4-7: reserved, OSPM must clear them before writing to register
Selecting memory device slot beyond present range has no effect on platform:
- write accesses to memory hot-plug registers not documented above are
ignored
- read accesses to memory hot-plug registers not documented above return
all bits set to 1.
+
+Memory hot remove process diagram:
+----------------------------------
+ +-------------+     +-----------------------+      +------------------+     
+ |  1. QEMU    |     | 2. QEMU               |      |3. QEMU           |     
+ |  device_del +---->+ device unplug request +----->+Send SCI to guest,|     
+ |             |     |         cb            |      |return control to |     
+ +-------------+     +-----------------------+      |management        |     
+                                                    +------------------+     
+                                                                             
+ +---------------------------------------------------------------------+     
+                                                                             
+ +---------------------+              +-------------------------+            
+ | OSPM:               | remove event | OSPM:                   |            
+ | send Eject Request, |              | Scan memory devices     |            
+ | clear remove event  +<-------------+ for event flags         |            
+ |                     |              |                         |            
+ +---------------------+              +-------------------------+            
+           |                                                                 
+           |                                                                 
+ +---------v--------+            +-----------------------+                   
+ | Guest OS:        |  success   | OSPM:                 |                   
+ | process Ejection +----------->+ Execute _EJ0 method,  |                   
+ | request          |            | set eject bit in flags|                   
+ +------------------+            +-----------------------+                   
+           |failure                         |                                
+           v                                v                                
+ +------------------------+      +-----------------------+                   
+ | OSPM:                  |      | QEMU:                 |                   
+ | set OST event & status |      | call device unplug cb |                   
+ | fields                 |      |                       |                   
+ +------------------------+      +-----------------------+                   
+          |                                  |                               
+          v                                  v                               
+ +------------------+              +-------------------+                     
+ |QEMU:             |              |QEMU:              |                     
+ |Send OST QMP event|              |Send device deleted|                     
+ |                  |              |QMP event          |                     
+ +------------------+              |                   |                     
+                                   +-------------------+
diff --git a/hw/acpi/aml-build.c b/hw/acpi/aml-build.c
index d7945f6e2d..77ce00b908 100644
--- a/hw/acpi/aml-build.c
+++ b/hw/acpi/aml-build.c
@@ -26,6 +26,7 @@
#include <string.h>
#include "hw/acpi/aml-build.h"
#include "qemu/bswap.h"
+#include "hw/acpi/bios-linker-loader.h"
static GArray *build_alloc_array(void)
{
@@ -635,9 +636,11 @@ Aml *aml_reserved_field(unsigned length)
}
/* ACPI 1.0b: 16.2.5.2 Named Objects Encoding: DefField */
-Aml *aml_field(const char *name, AmlFieldFlags flags)
+Aml *aml_field(const char *name, AmlAccessType type, AmlUpdateRule rule)
{
Aml *var = aml_bundle(0x81 /* FieldOp */, AML_EXT_PACKAGE);
+ uint8_t flags = rule << 5 | type;
+
build_append_namestring(var->buf, "%s", name);
build_append_byte(var->buf, flags);
return var;
@@ -891,3 +894,60 @@ Aml *aml_qword_memory(AmlDecode dec, AmlMinFixed min_fixed,
dec, addr_gran, addr_min, addr_max,
addr_trans, len, flags);
}
+
+void
+build_header(GArray *linker, GArray *table_data,
+ AcpiTableHeader *h, const char *sig, int len, uint8_t rev)
+{
+ memcpy(&h->signature, sig, 4);
+ h->length = cpu_to_le32(len);
+ h->revision = rev;
+ memcpy(h->oem_id, ACPI_BUILD_APPNAME6, 6);
+ memcpy(h->oem_table_id, ACPI_BUILD_APPNAME4, 4);
+ memcpy(h->oem_table_id + 4, sig, 4);
+ h->oem_revision = cpu_to_le32(1);
+ memcpy(h->asl_compiler_id, ACPI_BUILD_APPNAME4, 4);
+ h->asl_compiler_revision = cpu_to_le32(1);
+ h->checksum = 0;
+ /* Checksum to be filled in by Guest linker */
+ bios_linker_loader_add_checksum(linker, ACPI_BUILD_TABLE_FILE,
+ table_data->data, h, len, &h->checksum);
+}
+
+void *acpi_data_push(GArray *table_data, unsigned size)
+{
+ unsigned off = table_data->len;
+ g_array_set_size(table_data, off + size);
+ return table_data->data + off;
+}
+
+unsigned acpi_data_len(GArray *table)
+{
+#if GLIB_CHECK_VERSION(2, 22, 0)
+ assert(g_array_get_element_size(table) == 1);
+#endif
+ return table->len;
+}
+
+void acpi_add_table(GArray *table_offsets, GArray *table_data)
+{
+ uint32_t offset = cpu_to_le32(table_data->len);
+ g_array_append_val(table_offsets, offset);
+}
+
+void acpi_build_tables_init(AcpiBuildTables *tables)
+{
+ tables->rsdp = g_array_new(false, true /* clear */, 1);
+ tables->table_data = g_array_new(false, true /* clear */, 1);
+ tables->tcpalog = g_array_new(false, true /* clear */, 1);
+ tables->linker = bios_linker_loader_init();
+}
+
+void acpi_build_tables_cleanup(AcpiBuildTables *tables, bool mfre)
+{
+ void *linker_data = bios_linker_loader_cleanup(tables->linker);
+ g_free(linker_data);
+ g_array_free(tables->rsdp, true);
+ g_array_free(tables->table_data, true);
+ g_array_free(tables->tcpalog, mfre);
+}
diff --git a/hw/acpi/ich9.c b/hw/acpi/ich9.c
index 5352e197cb..84e5bb8d39 100644
--- a/hw/acpi/ich9.c
+++ b/hw/acpi/ich9.c
@@ -400,15 +400,26 @@ void ich9_pm_device_plug_cb(ICH9LPCPMRegs *pm, DeviceState *dev, Error **errp)
void ich9_pm_device_unplug_request_cb(ICH9LPCPMRegs *pm, DeviceState *dev,
Error **errp)
{
- error_setg(errp, "acpi: device unplug request for not supported device"
- " type: %s", object_get_typename(OBJECT(dev)));
+ if (pm->acpi_memory_hotplug.is_enabled &&
+ object_dynamic_cast(OBJECT(dev), TYPE_PC_DIMM)) {
+ acpi_memory_unplug_request_cb(&pm->acpi_regs, pm->irq,
+ &pm->acpi_memory_hotplug, dev, errp);
+ } else {
+ error_setg(errp, "acpi: device unplug request for not supported device"
+ " type: %s", object_get_typename(OBJECT(dev)));
+ }
}
void ich9_pm_device_unplug_cb(ICH9LPCPMRegs *pm, DeviceState *dev,
Error **errp)
{
- error_setg(errp, "acpi: device unplug for not supported device"
- " type: %s", object_get_typename(OBJECT(dev)));
+ if (pm->acpi_memory_hotplug.is_enabled &&
+ object_dynamic_cast(OBJECT(dev), TYPE_PC_DIMM)) {
+ acpi_memory_unplug_cb(&pm->acpi_memory_hotplug, dev, errp);
+ } else {
+ error_setg(errp, "acpi: device unplug for not supported device"
+ " type: %s", object_get_typename(OBJECT(dev)));
+ }
}
void ich9_pm_ospm_status(AcpiDeviceIf *adev, ACPIOSTInfoList ***list)
diff --git a/hw/acpi/memory_hotplug.c b/hw/acpi/memory_hotplug.c
index c6580dabb7..34cef1e5c3 100644
--- a/hw/acpi/memory_hotplug.c
+++ b/hw/acpi/memory_hotplug.c
@@ -2,6 +2,7 @@
#include "hw/acpi/pc-hotplug.h"
#include "hw/mem/pc-dimm.h"
#include "hw/boards.h"
+#include "hw/qdev-core.h"
#include "trace.h"
#include "qapi-event.h"
@@ -75,6 +76,7 @@ static uint64_t acpi_memory_hotplug_read(void *opaque, hwaddr addr,
case 0x14: /* pack and return is_* fields */
val |= mdev->is_enabled ? 1 : 0;
val |= mdev->is_inserting ? 2 : 0;
+ val |= mdev->is_removing ? 4 : 0;
trace_mhp_acpi_read_flags(mem_st->selector, val);
break;
default:
@@ -90,6 +92,9 @@ static void acpi_memory_hotplug_write(void *opaque, hwaddr addr, uint64_t data,
MemHotplugState *mem_st = opaque;
MemStatus *mdev;
ACPIOSTInfo *info;
+ DeviceState *dev = NULL;
+ HotplugHandler *hotplug_ctrl = NULL;
+ Error *local_err = NULL;
if (!mem_st->dev_count) {
return;
@@ -127,13 +132,36 @@ static void acpi_memory_hotplug_write(void *opaque, hwaddr addr, uint64_t data,
qapi_event_send_acpi_device_ost(info, &error_abort);
qapi_free_ACPIOSTInfo(info);
break;
- case 0x14:
+ case 0x14: /* set is_* fields */
mdev = &mem_st->devs[mem_st->selector];
if (data & 2) { /* clear insert event */
mdev->is_inserting = false;
trace_mhp_acpi_clear_insert_evt(mem_st->selector);
+ } else if (data & 4) {
+ mdev->is_removing = false;
+ trace_mhp_acpi_clear_remove_evt(mem_st->selector);
+ } else if (data & 8) {
+ if (!mdev->is_enabled) {
+ trace_mhp_acpi_ejecting_invalid_slot(mem_st->selector);
+ break;
+ }
+
+ dev = DEVICE(mdev->dimm);
+ hotplug_ctrl = qdev_get_hotplug_handler(dev);
+ /* call pc-dimm unplug cb */
+ hotplug_handler_unplug(hotplug_ctrl, dev, &local_err);
+ if (local_err) {
+ trace_mhp_acpi_pc_dimm_delete_failed(mem_st->selector);
+ qapi_event_send_mem_unplug_error(dev->id,
+ error_get_pretty(local_err),
+ &error_abort);
+ break;
+ }
+ trace_mhp_acpi_pc_dimm_deleted(mem_st->selector);
}
break;
+ default:
+ break;
}
}
@@ -163,29 +191,51 @@ void acpi_memory_hotplug_init(MemoryRegion *as, Object *owner,
memory_region_add_subregion(as, ACPI_MEMORY_HOTPLUG_BASE, &state->io);
}
-void acpi_memory_plug_cb(ACPIREGS *ar, qemu_irq irq, MemHotplugState *mem_st,
- DeviceState *dev, Error **errp)
+/**
+ * acpi_memory_slot_status:
+ * @mem_st: memory hotplug state
+ * @dev: device
+ * @errp: set in case of an error
+ *
+ * Obtain a single memory slot status.
+ *
+ * This function will be called by memory unplug request cb and unplug cb.
+ */
+static MemStatus *
+acpi_memory_slot_status(MemHotplugState *mem_st,
+ DeviceState *dev, Error **errp)
{
- MemStatus *mdev;
Error *local_err = NULL;
int slot = object_property_get_int(OBJECT(dev), PC_DIMM_SLOT_PROP,
&local_err);
if (local_err) {
error_propagate(errp, local_err);
- return;
+ return NULL;
}
if (slot >= mem_st->dev_count) {
char *dev_path = object_get_canonical_path(OBJECT(dev));
- error_setg(errp, "acpi_memory_plug_cb: "
+ error_setg(errp, "acpi_memory_slot_status: "
"device [%s] returned invalid memory slot[%d]",
dev_path, slot);
g_free(dev_path);
+ return NULL;
+ }
+
+ return &mem_st->devs[slot];
+}
+
+void acpi_memory_plug_cb(ACPIREGS *ar, qemu_irq irq, MemHotplugState *mem_st,
+ DeviceState *dev, Error **errp)
+{
+ MemStatus *mdev;
+
+ mdev = acpi_memory_slot_status(mem_st, dev, errp);
+ if (!mdev) {
return;
}
- mdev = &mem_st->devs[slot];
mdev->dimm = dev;
mdev->is_enabled = true;
mdev->is_inserting = true;
@@ -196,6 +246,38 @@ void acpi_memory_plug_cb(ACPIREGS *ar, qemu_irq irq, MemHotplugState *mem_st,
return;
}
+void acpi_memory_unplug_request_cb(ACPIREGS *ar, qemu_irq irq,
+ MemHotplugState *mem_st,
+ DeviceState *dev, Error **errp)
+{
+ MemStatus *mdev;
+
+ mdev = acpi_memory_slot_status(mem_st, dev, errp);
+ if (!mdev) {
+ return;
+ }
+
+ mdev->is_removing = true;
+
+ /* Do ACPI magic */
+ ar->gpe.sts[0] |= ACPI_MEMORY_HOTPLUG_STATUS;
+ acpi_update_sci(ar, irq);
+}
+
+void acpi_memory_unplug_cb(MemHotplugState *mem_st,
+ DeviceState *dev, Error **errp)
+{
+ MemStatus *mdev;
+
+ mdev = acpi_memory_slot_status(mem_st, dev, errp);
+ if (!mdev) {
+ return;
+ }
+
+ mdev->is_enabled = false;
+ mdev->dimm = NULL;
+}
+
static const VMStateDescription vmstate_memhp_sts = {
.name = "memory hotplug device state",
.version_id = 1,
diff --git a/hw/acpi/piix4.c b/hw/acpi/piix4.c
index d1f11793a0..1b28481bbd 100644
--- a/hw/acpi/piix4.c
+++ b/hw/acpi/piix4.c
@@ -361,7 +361,11 @@ static void piix4_device_unplug_request_cb(HotplugHandler *hotplug_dev,
{
PIIX4PMState *s = PIIX4_PM(hotplug_dev);
- if (object_dynamic_cast(OBJECT(dev), TYPE_PCI_DEVICE)) {
+ if (s->acpi_memory_hotplug.is_enabled &&
+ object_dynamic_cast(OBJECT(dev), TYPE_PC_DIMM)) {
+ acpi_memory_unplug_request_cb(&s->ar, s->irq, &s->acpi_memory_hotplug,
+ dev, errp);
+ } else if (object_dynamic_cast(OBJECT(dev), TYPE_PCI_DEVICE)) {
acpi_pcihp_device_unplug_cb(&s->ar, s->irq, &s->acpi_pci_hotplug, dev,
errp);
} else {
@@ -373,8 +377,15 @@ static void piix4_device_unplug_request_cb(HotplugHandler *hotplug_dev,
static void piix4_device_unplug_cb(HotplugHandler *hotplug_dev,
DeviceState *dev, Error **errp)
{
- error_setg(errp, "acpi: device unplug for not supported device"
- " type: %s", object_get_typename(OBJECT(dev)));
+ PIIX4PMState *s = PIIX4_PM(hotplug_dev);
+
+ if (s->acpi_memory_hotplug.is_enabled &&
+ object_dynamic_cast(OBJECT(dev), TYPE_PC_DIMM)) {
+ acpi_memory_unplug_cb(&s->acpi_memory_hotplug, dev, errp);
+ } else {
+ error_setg(errp, "acpi: device unplug for not supported device"
+ " type: %s", object_get_typename(OBJECT(dev)));
+ }
}
static void piix4_update_bus_hotplug(PCIBus *pci_bus, void *opaque)
diff --git a/hw/core/qdev.c b/hw/core/qdev.c
index 6e6a65d49b..b0f0f84564 100644
--- a/hw/core/qdev.c
+++ b/hw/core/qdev.c
@@ -273,7 +273,7 @@ void qdev_set_legacy_instance_id(DeviceState *dev, int alias_id,
dev->alias_required_for_version = required_for_version;
}
-static HotplugHandler *qdev_get_hotplug_handler(DeviceState *dev)
+HotplugHandler *qdev_get_hotplug_handler(DeviceState *dev)
{
HotplugHandler *hotplug_ctrl = NULL;
diff --git a/hw/i386/acpi-build.c b/hw/i386/acpi-build.c
index a36135705c..73259e729b 100644
--- a/hw/i386/acpi-build.c
+++ b/hw/i386/acpi-build.c
@@ -32,7 +32,7 @@
#include "hw/i386/pc.h"
#include "target-i386/cpu.h"
#include "hw/timer/hpet.h"
-#include "hw/i386/acpi-defs.h"
+#include "hw/acpi/acpi-defs.h"
#include "hw/acpi/acpi.h"
#include "hw/nvram/fw_cfg.h"
#include "hw/acpi/bios-linker-loader.h"
@@ -68,9 +68,6 @@
#define ACPI_BUILD_TABLE_SIZE 0x20000
-/* Reserve RAM space for tables: add another order of magnitude. */
-#define ACPI_BUILD_TABLE_MAX_SIZE 0x200000
-
/* #define DEBUG_ACPI_BUILD */
#ifdef DEBUG_ACPI_BUILD
#define ACPI_BUILD_DPRINTF(fmt, ...) \
@@ -265,51 +262,8 @@ static void acpi_get_pci_info(PcPciInfo *info)
NULL);
}
-#define ACPI_BUILD_APPNAME "Bochs"
-#define ACPI_BUILD_APPNAME6 "BOCHS "
-#define ACPI_BUILD_APPNAME4 "BXPC"
-
-#define ACPI_BUILD_TABLE_FILE "etc/acpi/tables"
-#define ACPI_BUILD_RSDP_FILE "etc/acpi/rsdp"
-#define ACPI_BUILD_TPMLOG_FILE "etc/tpm/log"
-
-static void
-build_header(GArray *linker, GArray *table_data,
- AcpiTableHeader *h, const char *sig, int len, uint8_t rev)
-{
- memcpy(&h->signature, sig, 4);
- h->length = cpu_to_le32(len);
- h->revision = rev;
- memcpy(h->oem_id, ACPI_BUILD_APPNAME6, 6);
- memcpy(h->oem_table_id, ACPI_BUILD_APPNAME4, 4);
- memcpy(h->oem_table_id + 4, sig, 4);
- h->oem_revision = cpu_to_le32(1);
- memcpy(h->asl_compiler_id, ACPI_BUILD_APPNAME4, 4);
- h->asl_compiler_revision = cpu_to_le32(1);
- h->checksum = 0;
- /* Checksum to be filled in by Guest linker */
- bios_linker_loader_add_checksum(linker, ACPI_BUILD_TABLE_FILE,
- table_data->data, h, len, &h->checksum);
-}
-
-/* End here */
#define ACPI_PORT_SMI_CMD 0x00b2 /* TODO: this is APM_CNT_IOPORT */
-static inline void *acpi_data_push(GArray *table_data, unsigned size)
-{
- unsigned off = table_data->len;
- g_array_set_size(table_data, off + size);
- return table_data->data + off;
-}
-
-static unsigned acpi_data_len(GArray *table)
-{
-#if GLIB_CHECK_VERSION(2, 22, 0)
- assert(g_array_get_element_size(table) == 1);
-#endif
- return table->len;
-}
-
static void acpi_align_size(GArray *blob, unsigned align)
{
/* Align size to multiple of given size. This reduces the chance
@@ -318,12 +272,6 @@ static void acpi_align_size(GArray *blob, unsigned align)
g_array_set_size(blob, ROUND_UP(acpi_data_len(blob), align));
}
-static inline void acpi_add_table(GArray *table_offsets, GArray *table_data)
-{
- uint32_t offset = cpu_to_le32(table_data->len);
- g_array_append_val(table_offsets, offset);
-}
-
/* FACS */
static void
build_facs(GArray *table_data, GArray *linker, PcGuestInfo *guest_info)
@@ -796,7 +744,7 @@ build_ssdt(GArray *table_data, GArray *linker,
aml_append(dev, aml_operation_region("PEOR", aml_system_io,
misc->pvpanic_port, 1));
- field = aml_field("PEOR", aml_byte_acc);
+ field = aml_field("PEOR", aml_byte_acc, aml_preserve);
aml_append(field, aml_named_field("PEPT", 8));
aml_append(dev, field);
@@ -813,7 +761,7 @@ build_ssdt(GArray *table_data, GArray *linker,
aml_append(ssdt, scope);
}
- sb_scope = aml_scope("_SB");
+ sb_scope = aml_scope("\\_SB");
{
/* create PCI0.PRES device and its _CRS to reserve CPU hotplug MMIO */
dev = aml_device("PCI0." stringify(CPU_HOTPLUG_RESOURCE_DEVICE));
@@ -833,7 +781,7 @@ build_ssdt(GArray *table_data, GArray *linker,
/* declare CPU hotplug MMIO region and PRS field to access it */
aml_append(sb_scope, aml_operation_region(
"PRST", aml_system_io, pm->cpu_hp_io_base, pm->cpu_hp_io_len));
- field = aml_field("PRST", aml_byte_acc);
+ field = aml_field("PRST", aml_byte_acc, aml_preserve);
aml_append(field, aml_named_field("PRS", 256));
aml_append(sb_scope, field);
@@ -907,7 +855,8 @@ build_ssdt(GArray *table_data, GArray *linker,
pm->mem_hp_io_base, pm->mem_hp_io_len)
);
- field = aml_field(stringify(MEMORY_HOTPLUG_IO_REGION), aml_dword_acc);
+ field = aml_field(stringify(MEMORY_HOTPLUG_IO_REGION), aml_dword_acc,
+ aml_preserve);
aml_append(field, /* read only */
aml_named_field(stringify(MEMORY_SLOT_ADDR_LOW), 32));
aml_append(field, /* read only */
@@ -920,16 +869,24 @@ build_ssdt(GArray *table_data, GArray *linker,
aml_named_field(stringify(MEMORY_SLOT_PROXIMITY), 32));
aml_append(scope, field);
- field = aml_field(stringify(MEMORY_HOTPLUG_IO_REGION), aml_byte_acc);
+ field = aml_field(stringify(MEMORY_HOTPLUG_IO_REGION), aml_byte_acc,
+ aml_write_as_zeros);
aml_append(field, aml_reserved_field(160 /* bits, Offset(20) */));
aml_append(field, /* 1 if enabled, read only */
aml_named_field(stringify(MEMORY_SLOT_ENABLED), 1));
aml_append(field,
/*(read) 1 if has a insert event. (write) 1 to clear event */
aml_named_field(stringify(MEMORY_SLOT_INSERT_EVENT), 1));
+ aml_append(field,
+ /* (read) 1 if has a remove event. (write) 1 to clear event */
+ aml_named_field(stringify(MEMORY_SLOT_REMOVE_EVENT), 1));
+ aml_append(field,
+ /* initiates device eject, write only */
+ aml_named_field(stringify(MEMORY_SLOT_EJECT), 1));
aml_append(scope, field);
- field = aml_field(stringify(MEMORY_HOTPLUG_IO_REGION), aml_dword_acc);
+ field = aml_field(stringify(MEMORY_HOTPLUG_IO_REGION), aml_dword_acc,
+ aml_preserve);
aml_append(field, /* DIMM selector, write only */
aml_named_field(stringify(MEMORY_SLOT_SLECTOR), 32));
aml_append(field, /* _OST event code, write only */
@@ -970,11 +927,17 @@ build_ssdt(GArray *table_data, GArray *linker,
)));
aml_append(dev, method);
+ method = aml_method("_EJ0", 1);
+ s = BASEPATH stringify(MEMORY_SLOT_EJECT_METHOD);
+ aml_append(method, aml_return(aml_call2(
+ s, aml_name("_UID"), aml_arg(0))));
+ aml_append(dev, method);
+
aml_append(sb_scope, dev);
}
/* build Method(MEMORY_SLOT_NOTIFY_METHOD, 2) {
- * If (LEqual(Arg0, 0x00)) {Notify(MP00, Arg1)} ...
+ * If (LEqual(Arg0, 0x00)) {Notify(MP00, Arg1)} ... }
*/
method = aml_method(stringify(MEMORY_SLOT_NOTIFY_METHOD), 2);
for (i = 0; i < nr_mem; i++) {
@@ -1294,31 +1257,6 @@ build_rsdp(GArray *rsdp_table, GArray *linker, unsigned rsdt)
}
typedef
-struct AcpiBuildTables {
- GArray *table_data;
- GArray *rsdp;
- GArray *tcpalog;
- GArray *linker;
-} AcpiBuildTables;
-
-static inline void acpi_build_tables_init(AcpiBuildTables *tables)
-{
- tables->rsdp = g_array_new(false, true /* clear */, 1);
- tables->table_data = g_array_new(false, true /* clear */, 1);
- tables->tcpalog = g_array_new(false, true /* clear */, 1);
- tables->linker = bios_linker_loader_init();
-}
-
-static inline void acpi_build_tables_cleanup(AcpiBuildTables *tables, bool mfre)
-{
- void *linker_data = bios_linker_loader_cleanup(tables->linker);
- g_free(linker_data);
- g_array_free(tables->rsdp, true);
- g_array_free(tables->table_data, true);
- g_array_free(tables->tcpalog, mfre);
-}
-
-typedef
struct AcpiBuildState {
/* Copy of table in RAM (for patching). */
MemoryRegion *table_mr;
diff --git a/hw/i386/acpi-dsdt-mem-hotplug.dsl b/hw/i386/acpi-dsdt-mem-hotplug.dsl
index 1e9ec39274..c2bb6a1602 100644
--- a/hw/i386/acpi-dsdt-mem-hotplug.dsl
+++ b/hw/i386/acpi-dsdt-mem-hotplug.dsl
@@ -29,6 +29,8 @@
External(MEMORY_SLOT_PROXIMITY, FieldUnitObj) // read only
External(MEMORY_SLOT_ENABLED, FieldUnitObj) // 1 if enabled, read only
External(MEMORY_SLOT_INSERT_EVENT, FieldUnitObj) // (read) 1 if has a insert event. (write) 1 to clear event
+ External(MEMORY_SLOT_REMOVE_EVENT, FieldUnitObj) // (read) 1 if has a remove event. (write) 1 to clear event
+ External(MEMORY_SLOT_EJECT, FieldUnitObj) // initiates device eject, write only
External(MEMORY_SLOT_SLECTOR, FieldUnitObj) // DIMM selector, write only
External(MEMORY_SLOT_OST_EVENT, FieldUnitObj) // _OST event code, write only
External(MEMORY_SLOT_OST_STATUS, FieldUnitObj) // _OST status code, write only
@@ -55,8 +57,10 @@
If (LEqual(MEMORY_SLOT_INSERT_EVENT, One)) { // Memory device needs check
MEMORY_SLOT_NOTIFY_METHOD(Local0, 1)
Store(1, MEMORY_SLOT_INSERT_EVENT)
+ } Elseif (LEqual(MEMORY_SLOT_REMOVE_EVENT, One)) { // Ejection request
+ MEMORY_SLOT_NOTIFY_METHOD(Local0, 3)
+ Store(1, MEMORY_SLOT_REMOVE_EVENT)
}
- // TODO: handle memory eject request
Add(Local0, One, Local0) // goto next DIMM
}
Release(MEMORY_SLOT_LOCK)
@@ -156,5 +160,12 @@
Store(Arg2, MEMORY_SLOT_OST_STATUS)
Release(MEMORY_SLOT_LOCK)
}
+
+ Method(MEMORY_SLOT_EJECT_METHOD, 2) {
+ Acquire(MEMORY_SLOT_LOCK, 0xFFFF)
+ Store(ToInteger(Arg0), MEMORY_SLOT_SLECTOR) // select DIMM
+ Store(1, MEMORY_SLOT_EJECT)
+ Release(MEMORY_SLOT_LOCK)
+ }
} // Device()
} // Scope()
diff --git a/hw/i386/pc.c b/hw/i386/pc.c
index a8e6be14e4..769eb25048 100644
--- a/hw/i386/pc.c
+++ b/hw/i386/pc.c
@@ -1677,6 +1677,52 @@ out:
error_propagate(errp, local_err);
}
+static void pc_dimm_unplug_request(HotplugHandler *hotplug_dev,
+ DeviceState *dev, Error **errp)
+{
+ HotplugHandlerClass *hhc;
+ Error *local_err = NULL;
+ PCMachineState *pcms = PC_MACHINE(hotplug_dev);
+
+ if (!pcms->acpi_dev) {
+ error_setg(&local_err,
+ "memory hotplug is not enabled: missing acpi device");
+ goto out;
+ }
+
+ hhc = HOTPLUG_HANDLER_GET_CLASS(pcms->acpi_dev);
+ hhc->unplug_request(HOTPLUG_HANDLER(pcms->acpi_dev), dev, &local_err);
+
+out:
+ error_propagate(errp, local_err);
+}
+
+static void pc_dimm_unplug(HotplugHandler *hotplug_dev,
+ DeviceState *dev, Error **errp)
+{
+ PCMachineState *pcms = PC_MACHINE(hotplug_dev);
+ PCDIMMDevice *dimm = PC_DIMM(dev);
+ PCDIMMDeviceClass *ddc = PC_DIMM_GET_CLASS(dimm);
+ MemoryRegion *mr = ddc->get_memory_region(dimm);
+ HotplugHandlerClass *hhc;
+ Error *local_err = NULL;
+
+ hhc = HOTPLUG_HANDLER_GET_CLASS(pcms->acpi_dev);
+ hhc->unplug(HOTPLUG_HANDLER(pcms->acpi_dev), dev, &local_err);
+
+ if (local_err) {
+ goto out;
+ }
+
+ memory_region_del_subregion(&pcms->hotplug_memory, mr);
+ vmstate_unregister_ram(mr, dev);
+
+ object_unparent(OBJECT(dev));
+
+ out:
+ error_propagate(errp, local_err);
+}
+
static void pc_cpu_plug(HotplugHandler *hotplug_dev,
DeviceState *dev, Error **errp)
{
@@ -1719,15 +1765,23 @@ static void pc_machine_device_plug_cb(HotplugHandler *hotplug_dev,
static void pc_machine_device_unplug_request_cb(HotplugHandler *hotplug_dev,
DeviceState *dev, Error **errp)
{
- error_setg(errp, "acpi: device unplug request for not supported device"
- " type: %s", object_get_typename(OBJECT(dev)));
+ if (object_dynamic_cast(OBJECT(dev), TYPE_PC_DIMM)) {
+ pc_dimm_unplug_request(hotplug_dev, dev, errp);
+ } else {
+ error_setg(errp, "acpi: device unplug request for not supported device"
+ " type: %s", object_get_typename(OBJECT(dev)));
+ }
}
static void pc_machine_device_unplug_cb(HotplugHandler *hotplug_dev,
DeviceState *dev, Error **errp)
{
- error_setg(errp, "acpi: device unplug for not supported device"
- " type: %s", object_get_typename(OBJECT(dev)));
+ if (object_dynamic_cast(OBJECT(dev), TYPE_PC_DIMM)) {
+ pc_dimm_unplug(hotplug_dev, dev, errp);
+ } else {
+ error_setg(errp, "acpi: device unplug for not supported device"
+ " type: %s", object_get_typename(OBJECT(dev)));
+ }
}
static HotplugHandler *pc_get_hotpug_handler(MachineState *machine,
diff --git a/hw/i386/pc_piix.c b/hw/i386/pc_piix.c
index 1fe7bfb29a..212e263404 100644
--- a/hw/i386/pc_piix.c
+++ b/hw/i386/pc_piix.c
@@ -310,8 +310,13 @@ static void pc_init_pci(MachineState *machine)
pc_init1(machine, 1, 1);
}
+static void pc_compat_2_3(MachineState *machine)
+{
+}
+
static void pc_compat_2_2(MachineState *machine)
{
+ pc_compat_2_3(machine);
rsdp_in_ram = false;
x86_cpu_compat_set_features("kvm64", FEAT_1_EDX, 0, CPUID_VME);
x86_cpu_compat_set_features("kvm32", FEAT_1_EDX, 0, CPUID_VME);
@@ -413,6 +418,12 @@ static void pc_compat_1_2(MachineState *machine)
x86_cpu_compat_kvm_no_autoenable(FEAT_KVM, 1 << KVM_FEATURE_PV_EOI);
}
+static void pc_init_pci_2_3(MachineState *machine)
+{
+ pc_compat_2_3(machine);
+ pc_init_pci(machine);
+}
+
static void pc_init_pci_2_2(MachineState *machine)
{
pc_compat_2_2(machine);
@@ -512,19 +523,28 @@ static void pc_xen_hvm_init(MachineState *machine)
.desc = "Standard PC (i440FX + PIIX, 1996)", \
.hot_add_cpu = pc_hot_add_cpu
-#define PC_I440FX_2_3_MACHINE_OPTIONS \
+#define PC_I440FX_2_4_MACHINE_OPTIONS \
PC_I440FX_MACHINE_OPTIONS, \
.default_machine_opts = "firmware=bios-256k.bin", \
.default_display = "std"
-static QEMUMachine pc_i440fx_machine_v2_3 = {
- PC_I440FX_2_3_MACHINE_OPTIONS,
- .name = "pc-i440fx-2.3",
+
+static QEMUMachine pc_i440fx_machine_v2_4 = {
+ PC_I440FX_2_4_MACHINE_OPTIONS,
+ .name = "pc-i440fx-2.4",
.alias = "pc",
.init = pc_init_pci,
.is_default = 1,
};
+#define PC_I440FX_2_3_MACHINE_OPTIONS PC_I440FX_2_4_MACHINE_OPTIONS
+
+static QEMUMachine pc_i440fx_machine_v2_3 = {
+ PC_I440FX_2_3_MACHINE_OPTIONS,
+ .name = "pc-i440fx-2.3",
+ .init = pc_init_pci_2_3,
+};
+
#define PC_I440FX_2_2_MACHINE_OPTIONS PC_I440FX_2_3_MACHINE_OPTIONS
static QEMUMachine pc_i440fx_machine_v2_2 = {
@@ -970,6 +990,7 @@ static QEMUMachine xenfv_machine = {
static void pc_machine_init(void)
{
+ qemu_register_pc_machine(&pc_i440fx_machine_v2_4);
qemu_register_pc_machine(&pc_i440fx_machine_v2_3);
qemu_register_pc_machine(&pc_i440fx_machine_v2_2);
qemu_register_pc_machine(&pc_i440fx_machine_v2_1);
diff --git a/hw/i386/pc_q35.c b/hw/i386/pc_q35.c
index dcc17c074b..e67f2dead7 100644
--- a/hw/i386/pc_q35.c
+++ b/hw/i386/pc_q35.c
@@ -289,8 +289,13 @@ static void pc_q35_init(MachineState *machine)
}
}
+static void pc_compat_2_3(MachineState *machine)
+{
+}
+
static void pc_compat_2_2(MachineState *machine)
{
+ pc_compat_2_3(machine);
rsdp_in_ram = false;
x86_cpu_compat_set_features("kvm64", FEAT_1_EDX, 0, CPUID_VME);
x86_cpu_compat_set_features("kvm32", FEAT_1_EDX, 0, CPUID_VME);
@@ -361,6 +366,12 @@ static void pc_compat_1_4(MachineState *machine)
x86_cpu_compat_set_features("Westmere", FEAT_1_ECX, 0, CPUID_EXT_PCLMULQDQ);
}
+static void pc_q35_init_2_3(MachineState *machine)
+{
+ pc_compat_2_3(machine);
+ pc_q35_init(machine);
+}
+
static void pc_q35_init_2_2(MachineState *machine)
{
pc_compat_2_2(machine);
@@ -410,16 +421,24 @@ static void pc_q35_init_1_4(MachineState *machine)
.hot_add_cpu = pc_hot_add_cpu, \
.units_per_default_bus = 1
-#define PC_Q35_2_3_MACHINE_OPTIONS \
+#define PC_Q35_2_4_MACHINE_OPTIONS \
PC_Q35_MACHINE_OPTIONS, \
.default_machine_opts = "firmware=bios-256k.bin", \
.default_display = "std"
+static QEMUMachine pc_q35_machine_v2_4 = {
+ PC_Q35_2_4_MACHINE_OPTIONS,
+ .name = "pc-q35-2.4",
+ .alias = "q35",
+ .init = pc_q35_init,
+};
+
+#define PC_Q35_2_3_MACHINE_OPTIONS PC_Q35_2_4_MACHINE_OPTIONS
+
static QEMUMachine pc_q35_machine_v2_3 = {
PC_Q35_2_3_MACHINE_OPTIONS,
.name = "pc-q35-2.3",
- .alias = "q35",
- .init = pc_q35_init,
+ .init = pc_q35_init_2_3,
};
#define PC_Q35_2_2_MACHINE_OPTIONS PC_Q35_2_3_MACHINE_OPTIONS
@@ -506,6 +525,7 @@ static QEMUMachine pc_q35_machine_v1_4 = {
static void pc_q35_machine_init(void)
{
+ qemu_register_pc_machine(&pc_q35_machine_v2_4);
qemu_register_pc_machine(&pc_q35_machine_v2_3);
qemu_register_pc_machine(&pc_q35_machine_v2_2);
qemu_register_pc_machine(&pc_q35_machine_v2_1);
diff --git a/hw/net/vhost_net.c b/hw/net/vhost_net.c
index cf23335ba2..47f8b89d51 100644
--- a/hw/net/vhost_net.c
+++ b/hw/net/vhost_net.c
@@ -263,6 +263,13 @@ static void vhost_net_stop_one(struct vhost_net *net,
&file);
assert(r >= 0);
}
+ } else if (net->nc->info->type == NET_CLIENT_OPTIONS_KIND_VHOST_USER) {
+ for (file.index = 0; file.index < net->dev.nvqs; ++file.index) {
+ const VhostOps *vhost_ops = net->dev.vhost_ops;
+ int r = vhost_ops->vhost_call(&net->dev, VHOST_RESET_OWNER,
+ NULL);
+ assert(r >= 0);
+ }
}
if (net->nc->info->poll) {
net->nc->info->poll(net->nc, true);
diff --git a/hw/net/virtio-net.c b/hw/net/virtio-net.c
index 9829ad075b..3af6faf4c8 100644
--- a/hw/net/virtio-net.c
+++ b/hw/net/virtio-net.c
@@ -440,6 +440,9 @@ static uint32_t virtio_net_get_features(VirtIODevice *vdev, uint32_t features)
VirtIONet *n = VIRTIO_NET(vdev);
NetClientState *nc = qemu_get_queue(n->nic);
+ /* Firstly sync all virtio-net possible supported features */
+ features |= n->host_features;
+
virtio_add_feature(&features, VIRTIO_NET_F_MAC);
if (!peer_has_vnet_hdr(n)) {
@@ -1303,7 +1306,7 @@ static void virtio_net_set_multiqueue(VirtIONet *n, int multiqueue)
n->multiqueue = multiqueue;
- for (i = 2; i <= n->max_queues * 2 + 1; i++) {
+ for (i = 2; i < n->max_queues * 2 + 1; i++) {
virtio_del_queue(vdev, i);
}
@@ -1546,7 +1549,7 @@ static void virtio_net_guest_notifier_mask(VirtIODevice *vdev, int idx,
vdev, idx, mask);
}
-void virtio_net_set_config_size(VirtIONet *n, uint32_t host_features)
+static void virtio_net_set_config_size(VirtIONet *n, uint32_t host_features)
{
int i, config_size = 0;
virtio_add_feature(&host_features, VIRTIO_NET_F_MAC);
@@ -1579,6 +1582,7 @@ static void virtio_net_device_realize(DeviceState *dev, Error **errp)
NetClientState *nc;
int i;
+ virtio_net_set_config_size(n, n->host_features);
virtio_init(vdev, "virtio-net", VIRTIO_ID_NET, n->config_size);
n->max_queues = MAX(n->nic_conf.peers.queues, 1);
@@ -1715,6 +1719,7 @@ static void virtio_net_instance_init(Object *obj)
}
static Property virtio_net_properties[] = {
+ DEFINE_VIRTIO_NET_FEATURES(VirtIONet, host_features),
DEFINE_NIC_PROPERTIES(VirtIONet, nic_conf),
DEFINE_PROP_UINT32("x-txtimer", VirtIONet, net_conf.txtimer,
TX_TIMER_INTERVAL),
diff --git a/hw/pci/msix.c b/hw/pci/msix.c
index 031eaabca9..9935f98ae5 100644
--- a/hw/pci/msix.c
+++ b/hw/pci/msix.c
@@ -295,29 +295,37 @@ int msix_init_exclusive_bar(PCIDevice *dev, unsigned short nentries,
{
int ret;
char *name;
+ uint32_t bar_size = 4096;
+ uint32_t bar_pba_offset = bar_size / 2;
+ uint32_t bar_pba_size = (nentries / 8 + 1) * 8;
/*
* Migration compatibility dictates that this remains a 4k
* BAR with the vector table in the lower half and PBA in
- * the upper half. Do not use these elsewhere!
+ * the upper half for nentries which is lower or equal to 128.
+ * No need to care about using more than 65 entries for legacy
+ * machine types who has at most 64 queues.
*/
-#define MSIX_EXCLUSIVE_BAR_SIZE 4096
-#define MSIX_EXCLUSIVE_BAR_TABLE_OFFSET 0
-#define MSIX_EXCLUSIVE_BAR_PBA_OFFSET (MSIX_EXCLUSIVE_BAR_SIZE / 2)
-#define MSIX_EXCLUSIVE_CAP_OFFSET 0
+ if (nentries * PCI_MSIX_ENTRY_SIZE > bar_pba_offset) {
+ bar_pba_offset = nentries * PCI_MSIX_ENTRY_SIZE;
+ }
- if (nentries * PCI_MSIX_ENTRY_SIZE > MSIX_EXCLUSIVE_BAR_PBA_OFFSET) {
- return -EINVAL;
+ if (bar_pba_offset + bar_pba_size > 4096) {
+ bar_size = bar_pba_offset + bar_pba_size;
+ }
+
+ if (bar_size & (bar_size - 1)) {
+ bar_size = 1 << qemu_fls(bar_size);
}
name = g_strdup_printf("%s-msix", dev->name);
- memory_region_init(&dev->msix_exclusive_bar, OBJECT(dev), name, MSIX_EXCLUSIVE_BAR_SIZE);
+ memory_region_init(&dev->msix_exclusive_bar, OBJECT(dev), name, bar_size);
g_free(name);
ret = msix_init(dev, nentries, &dev->msix_exclusive_bar, bar_nr,
- MSIX_EXCLUSIVE_BAR_TABLE_OFFSET, &dev->msix_exclusive_bar,
- bar_nr, MSIX_EXCLUSIVE_BAR_PBA_OFFSET,
- MSIX_EXCLUSIVE_CAP_OFFSET);
+ 0, &dev->msix_exclusive_bar,
+ bar_nr, bar_pba_offset,
+ 0);
if (ret) {
return ret;
}
diff --git a/hw/pci/pci.c b/hw/pci/pci.c
index f5c7a99717..48f19a306d 100644
--- a/hw/pci/pci.c
+++ b/hw/pci/pci.c
@@ -1615,28 +1615,32 @@ static const char * const pci_nic_names[] = {
};
/* Initialize a PCI NIC. */
-static PCIDevice *pci_nic_init(NICInfo *nd, PCIBus *rootbus,
+PCIDevice *pci_nic_init_nofail(NICInfo *nd, PCIBus *rootbus,
const char *default_model,
- const char *default_devaddr,
- Error **errp)
+ const char *default_devaddr)
{
const char *devaddr = nd->devaddr ? nd->devaddr : default_devaddr;
Error *err = NULL;
PCIBus *bus;
- int devfn;
PCIDevice *pci_dev;
DeviceState *dev;
+ int devfn;
int i;
+ if (qemu_show_nic_models(nd->model, pci_nic_models)) {
+ exit(0);
+ }
+
i = qemu_find_nic_model(nd, pci_nic_models, default_model);
- if (i < 0)
- return NULL;
+ if (i < 0) {
+ exit(1);
+ }
bus = pci_get_bus_devfn(&devfn, rootbus, devaddr);
if (!bus) {
error_report("Invalid PCI device address %s for device %s",
devaddr, pci_nic_names[i]);
- return NULL;
+ exit(1);
}
pci_dev = pci_create(bus, devfn, pci_nic_names[i]);
@@ -1645,31 +1649,12 @@ static PCIDevice *pci_nic_init(NICInfo *nd, PCIBus *rootbus,
object_property_set_bool(OBJECT(dev), true, "realized", &err);
if (err) {
- error_propagate(errp, err);
+ error_report_err(err);
object_unparent(OBJECT(dev));
- return NULL;
- }
- return pci_dev;
-}
-
-PCIDevice *pci_nic_init_nofail(NICInfo *nd, PCIBus *rootbus,
- const char *default_model,
- const char *default_devaddr)
-{
- Error *err = NULL;
- PCIDevice *res;
-
- if (qemu_show_nic_models(nd->model, pci_nic_models))
- exit(0);
-
- res = pci_nic_init(nd, rootbus, default_model, default_devaddr, &err);
- if (!res) {
- if (err) {
- error_report_err(err);
- }
exit(1);
}
- return res;
+
+ return pci_dev;
}
PCIDevice *pci_vga_init(PCIBus *bus)
diff --git a/hw/ppc/spapr.c b/hw/ppc/spapr.c
index 644689a6ae..ac261ef050 100644
--- a/hw/ppc/spapr.c
+++ b/hw/ppc/spapr.c
@@ -1825,6 +1825,38 @@ static const TypeInfo spapr_machine_info = {
#define SPAPR_COMPAT_2_1 \
SPAPR_COMPAT_2_2
+static void spapr_compat_2_3(Object *obj)
+{
+}
+
+static void spapr_compat_2_2(Object *obj)
+{
+ spapr_compat_2_3(obj);
+}
+
+static void spapr_compat_2_1(Object *obj)
+{
+ spapr_compat_2_2(obj);
+}
+
+static void spapr_machine_2_3_instance_init(Object *obj)
+{
+ spapr_compat_2_3(obj);
+ spapr_machine_initfn(obj);
+}
+
+static void spapr_machine_2_2_instance_init(Object *obj)
+{
+ spapr_compat_2_2(obj);
+ spapr_machine_initfn(obj);
+}
+
+static void spapr_machine_2_1_instance_init(Object *obj)
+{
+ spapr_compat_2_1(obj);
+ spapr_machine_initfn(obj);
+}
+
static void spapr_machine_2_1_class_init(ObjectClass *oc, void *data)
{
MachineClass *mc = MACHINE_CLASS(oc);
@@ -1843,6 +1875,7 @@ static const TypeInfo spapr_machine_2_1_info = {
.name = TYPE_SPAPR_MACHINE "2.1",
.parent = TYPE_SPAPR_MACHINE,
.class_init = spapr_machine_2_1_class_init,
+ .instance_init = spapr_machine_2_1_instance_init,
};
static void spapr_machine_2_2_class_init(ObjectClass *oc, void *data)
@@ -1862,6 +1895,7 @@ static const TypeInfo spapr_machine_2_2_info = {
.name = TYPE_SPAPR_MACHINE "2.2",
.parent = TYPE_SPAPR_MACHINE,
.class_init = spapr_machine_2_2_class_init,
+ .instance_init = spapr_machine_2_2_instance_init,
};
static void spapr_machine_2_3_class_init(ObjectClass *oc, void *data)
@@ -1870,14 +1904,29 @@ static void spapr_machine_2_3_class_init(ObjectClass *oc, void *data)
mc->name = "pseries-2.3";
mc->desc = "pSeries Logical Partition (PAPR compliant) v2.3";
- mc->alias = "pseries";
- mc->is_default = 1;
}
static const TypeInfo spapr_machine_2_3_info = {
.name = TYPE_SPAPR_MACHINE "2.3",
.parent = TYPE_SPAPR_MACHINE,
.class_init = spapr_machine_2_3_class_init,
+ .instance_init = spapr_machine_2_3_instance_init,
+};
+
+static void spapr_machine_2_4_class_init(ObjectClass *oc, void *data)
+{
+ MachineClass *mc = MACHINE_CLASS(oc);
+
+ mc->name = "pseries-2.4";
+ mc->desc = "pSeries Logical Partition (PAPR compliant) v2.4";
+ mc->alias = "pseries";
+ mc->is_default = 1;
+}
+
+static const TypeInfo spapr_machine_2_4_info = {
+ .name = TYPE_SPAPR_MACHINE "2.4",
+ .parent = TYPE_SPAPR_MACHINE,
+ .class_init = spapr_machine_2_4_class_init,
};
static void spapr_machine_register_types(void)
@@ -1886,6 +1935,7 @@ static void spapr_machine_register_types(void)
type_register_static(&spapr_machine_2_1_info);
type_register_static(&spapr_machine_2_2_info);
type_register_static(&spapr_machine_2_3_info);
+ type_register_static(&spapr_machine_2_4_info);
}
type_init(spapr_machine_register_types)
diff --git a/hw/s390x/s390-virtio-bus.c b/hw/s390x/s390-virtio-bus.c
index 4f69cbbb70..0e35ac970a 100644
--- a/hw/s390x/s390-virtio-bus.c
+++ b/hw/s390x/s390-virtio-bus.c
@@ -155,7 +155,6 @@ static void s390_virtio_net_realize(VirtIOS390Device *s390_dev, Error **errp)
DeviceState *vdev = DEVICE(&dev->vdev);
Error *err = NULL;
- virtio_net_set_config_size(&dev->vdev, s390_dev->host_features);
virtio_net_set_netclient_name(&dev->vdev, qdev->id,
object_get_typename(OBJECT(qdev)));
qdev_set_parent_bus(vdev, BUS(&s390_dev->bus));
@@ -537,18 +536,12 @@ static unsigned virtio_s390_get_features(DeviceState *d)
/**************** S390 Virtio Bus Device Descriptions *******************/
-static Property s390_virtio_net_properties[] = {
- DEFINE_VIRTIO_NET_FEATURES(VirtIOS390Device, host_features),
- DEFINE_PROP_END_OF_LIST(),
-};
-
static void s390_virtio_net_class_init(ObjectClass *klass, void *data)
{
DeviceClass *dc = DEVICE_CLASS(klass);
VirtIOS390DeviceClass *k = VIRTIO_S390_DEVICE_CLASS(klass);
k->realize = s390_virtio_net_realize;
- dc->props = s390_virtio_net_properties;
set_bit(DEVICE_CATEGORY_NETWORK, dc->categories);
}
@@ -657,18 +650,12 @@ static const TypeInfo virtio_s390_device_info = {
.abstract = true,
};
-static Property s390_virtio_scsi_properties[] = {
- DEFINE_VIRTIO_SCSI_FEATURES(VirtIOS390Device, host_features),
- DEFINE_PROP_END_OF_LIST(),
-};
-
static void s390_virtio_scsi_class_init(ObjectClass *klass, void *data)
{
DeviceClass *dc = DEVICE_CLASS(klass);
VirtIOS390DeviceClass *k = VIRTIO_S390_DEVICE_CLASS(klass);
k->realize = s390_virtio_scsi_realize;
- dc->props = s390_virtio_scsi_properties;
set_bit(DEVICE_CATEGORY_STORAGE, dc->categories);
}
diff --git a/hw/s390x/virtio-ccw.c b/hw/s390x/virtio-ccw.c
index 430cc6f017..c96101aa7c 100644
--- a/hw/s390x/virtio-ccw.c
+++ b/hw/s390x/virtio-ccw.c
@@ -281,7 +281,7 @@ static int virtio_ccw_set_vqs(SubchDev *sch, uint64_t addr, uint32_t align,
virtio_queue_set_addr(vdev, index, addr);
if (!addr) {
- virtio_queue_set_vector(vdev, index, 0);
+ virtio_queue_set_vector(vdev, index, VIRTIO_NO_VECTOR);
} else {
/* Fail if we don't have a big enough queue. */
/* TODO: Add interface to handle vring.num changing */
@@ -805,7 +805,6 @@ static void virtio_ccw_net_realize(VirtioCcwDevice *ccw_dev, Error **errp)
DeviceState *vdev = DEVICE(&dev->vdev);
Error *err = NULL;
- virtio_net_set_config_size(&dev->vdev, ccw_dev->host_features[0]);
virtio_net_set_netclient_name(&dev->vdev, qdev->id,
object_get_typename(OBJECT(qdev)));
qdev_set_parent_bus(vdev, BUS(&ccw_dev->bus));
@@ -1441,7 +1440,6 @@ static void virtio_ccw_device_unplugged(DeviceState *d)
static Property virtio_ccw_net_properties[] = {
DEFINE_PROP_STRING("devno", VirtioCcwDevice, bus_id),
- DEFINE_VIRTIO_NET_FEATURES(VirtioCcwDevice, host_features[0]),
DEFINE_PROP_BIT("ioeventfd", VirtioCcwDevice, flags,
VIRTIO_CCW_FLAG_USE_IOEVENTFD_BIT, true),
DEFINE_PROP_END_OF_LIST(),
@@ -1550,7 +1548,6 @@ static const TypeInfo virtio_ccw_balloon = {
static Property virtio_ccw_scsi_properties[] = {
DEFINE_PROP_STRING("devno", VirtioCcwDevice, bus_id),
- DEFINE_VIRTIO_SCSI_FEATURES(VirtioCcwDevice, host_features[0]),
DEFINE_PROP_BIT("ioeventfd", VirtioCcwDevice, flags,
VIRTIO_CCW_FLAG_USE_IOEVENTFD_BIT, true),
DEFINE_PROP_END_OF_LIST(),
diff --git a/hw/scsi/virtio-scsi.c b/hw/scsi/virtio-scsi.c
index c9bea067e1..e242fefa84 100644
--- a/hw/scsi/virtio-scsi.c
+++ b/hw/scsi/virtio-scsi.c
@@ -631,6 +631,10 @@ static void virtio_scsi_set_config(VirtIODevice *vdev,
static uint32_t virtio_scsi_get_features(VirtIODevice *vdev,
uint32_t requested_features)
{
+ VirtIOSCSI *s = VIRTIO_SCSI(vdev);
+
+ /* Firstly sync all virtio-scsi possible supported features */
+ requested_features |= s->host_features;
return requested_features;
}
@@ -945,6 +949,7 @@ static void virtio_scsi_device_unrealize(DeviceState *dev, Error **errp)
static Property virtio_scsi_properties[] = {
DEFINE_VIRTIO_SCSI_PROPERTIES(VirtIOSCSI, parent_obj.conf),
+ DEFINE_VIRTIO_SCSI_FEATURES(VirtIOSCSI, host_features),
DEFINE_PROP_END_OF_LIST(),
};
diff --git a/hw/usb/hcd-xhci.c b/hw/usb/hcd-xhci.c
index 927dc3652f..90a5fbff29 100644
--- a/hw/usb/hcd-xhci.c
+++ b/hw/usb/hcd-xhci.c
@@ -2203,7 +2203,6 @@ static void xhci_kick_ep(XHCIState *xhci, unsigned int slotid,
if (epid == 1) {
if (xhci_fire_ctl_transfer(xhci, xfer) >= 0) {
epctx->next_xfer = (epctx->next_xfer + 1) % TD_QUEUE;
- ep = xfer->packet.ep;
} else {
DPRINTF("xhci: error firing CTL transfer\n");
}
diff --git a/hw/virtio/virtio-pci.c b/hw/virtio/virtio-pci.c
index c7c3f7249b..867c9d17ca 100644
--- a/hw/virtio/virtio-pci.c
+++ b/hw/virtio/virtio-pci.c
@@ -630,28 +630,30 @@ static int virtio_pci_vector_unmask(PCIDevice *dev, unsigned vector,
{
VirtIOPCIProxy *proxy = container_of(dev, VirtIOPCIProxy, pci_dev);
VirtIODevice *vdev = virtio_bus_get_device(&proxy->bus);
- int ret, queue_no;
+ VirtQueue *vq = virtio_vector_first_queue(vdev, vector);
+ int ret, index, unmasked = 0;
- for (queue_no = 0; queue_no < proxy->nvqs_with_notifiers; queue_no++) {
- if (!virtio_queue_get_num(vdev, queue_no)) {
+ while (vq) {
+ index = virtio_get_queue_index(vq);
+ if (!virtio_queue_get_num(vdev, index)) {
break;
}
- if (virtio_queue_vector(vdev, queue_no) != vector) {
- continue;
- }
- ret = virtio_pci_vq_vector_unmask(proxy, queue_no, vector, msg);
+ ret = virtio_pci_vq_vector_unmask(proxy, index, vector, msg);
if (ret < 0) {
goto undo;
}
+ vq = virtio_vector_next_queue(vq);
+ ++unmasked;
}
+
return 0;
undo:
- while (--queue_no >= 0) {
- if (virtio_queue_vector(vdev, queue_no) != vector) {
- continue;
- }
- virtio_pci_vq_vector_mask(proxy, queue_no, vector);
+ vq = virtio_vector_first_queue(vdev, vector);
+ while (vq && --unmasked >= 0) {
+ index = virtio_get_queue_index(vq);
+ virtio_pci_vq_vector_mask(proxy, index, vector);
+ vq = virtio_vector_next_queue(vq);
}
return ret;
}
@@ -660,16 +662,16 @@ static void virtio_pci_vector_mask(PCIDevice *dev, unsigned vector)
{
VirtIOPCIProxy *proxy = container_of(dev, VirtIOPCIProxy, pci_dev);
VirtIODevice *vdev = virtio_bus_get_device(&proxy->bus);
- int queue_no;
+ VirtQueue *vq = virtio_vector_first_queue(vdev, vector);
+ int index;
- for (queue_no = 0; queue_no < proxy->nvqs_with_notifiers; queue_no++) {
- if (!virtio_queue_get_num(vdev, queue_no)) {
+ while (vq) {
+ index = virtio_get_queue_index(vq);
+ if (!virtio_queue_get_num(vdev, index)) {
break;
}
- if (virtio_queue_vector(vdev, queue_no) != vector) {
- continue;
- }
- virtio_pci_vq_vector_mask(proxy, queue_no, vector);
+ virtio_pci_vq_vector_mask(proxy, index, vector);
+ vq = virtio_vector_next_queue(vq);
}
}
@@ -908,6 +910,13 @@ static const TypeInfo virtio_9p_pci_info = {
* virtio-pci: This is the PCIDevice which has a virtio-pci-bus.
*/
+static int virtio_pci_query_nvectors(DeviceState *d)
+{
+ VirtIOPCIProxy *proxy = VIRTIO_PCI(d);
+
+ return proxy->nvectors;
+}
+
/* This is called by virtio-bus just after the device is plugged. */
static void virtio_pci_device_plugged(DeviceState *d)
{
@@ -1078,7 +1087,6 @@ static Property virtio_scsi_pci_properties[] = {
VIRTIO_PCI_FLAG_USE_IOEVENTFD_BIT, true),
DEFINE_PROP_UINT32("vectors", VirtIOPCIProxy, nvectors,
DEV_NVECTORS_UNSPECIFIED),
- DEFINE_VIRTIO_SCSI_FEATURES(VirtIOPCIProxy, host_features),
DEFINE_PROP_END_OF_LIST(),
};
@@ -1360,7 +1368,6 @@ static Property virtio_net_properties[] = {
DEFINE_PROP_BIT("ioeventfd", VirtIOPCIProxy, flags,
VIRTIO_PCI_FLAG_USE_IOEVENTFD_BIT, false),
DEFINE_PROP_UINT32("vectors", VirtIOPCIProxy, nvectors, 3),
- DEFINE_VIRTIO_NET_FEATURES(VirtIOPCIProxy, host_features),
DEFINE_PROP_END_OF_LIST(),
};
@@ -1370,7 +1377,6 @@ static void virtio_net_pci_realize(VirtIOPCIProxy *vpci_dev, Error **errp)
VirtIONetPCI *dev = VIRTIO_NET_PCI(vpci_dev);
DeviceState *vdev = DEVICE(&dev->vdev);
- virtio_net_set_config_size(&dev->vdev, vpci_dev->host_features);
virtio_net_set_netclient_name(&dev->vdev, qdev->id,
object_get_typename(OBJECT(qdev)));
qdev_set_parent_bus(vdev, BUS(&vpci_dev->bus));
@@ -1498,6 +1504,7 @@ static void virtio_pci_bus_class_init(ObjectClass *klass, void *data)
k->vmstate_change = virtio_pci_vmstate_change;
k->device_plugged = virtio_pci_device_plugged;
k->device_unplugged = virtio_pci_device_unplugged;
+ k->query_nvectors = virtio_pci_query_nvectors;
}
static const TypeInfo virtio_pci_bus_info = {
diff --git a/hw/virtio/virtio.c b/hw/virtio/virtio.c
index 17c1260c0d..6985e76b64 100644
--- a/hw/virtio/virtio.c
+++ b/hw/virtio/virtio.c
@@ -89,6 +89,7 @@ struct VirtQueue
VirtIODevice *vdev;
EventNotifier guest_notifier;
EventNotifier host_notifier;
+ QLIST_ENTRY(VirtQueue) node;
};
/* virt queue functions */
@@ -605,7 +606,7 @@ void virtio_reset(void *opaque)
vdev->vq[i].vring.used = 0;
vdev->vq[i].last_avail_idx = 0;
vdev->vq[i].pa = 0;
- vdev->vq[i].vector = VIRTIO_NO_VECTOR;
+ virtio_queue_set_vector(vdev, i, VIRTIO_NO_VECTOR);
vdev->vq[i].signalled_used = 0;
vdev->vq[i].signalled_used_valid = false;
vdev->vq[i].notification = true;
@@ -730,6 +731,16 @@ void virtio_queue_set_num(VirtIODevice *vdev, int n, int num)
virtqueue_init(&vdev->vq[n]);
}
+VirtQueue *virtio_vector_first_queue(VirtIODevice *vdev, uint16_t vector)
+{
+ return QLIST_FIRST(&vdev->vector_queues[vector]);
+}
+
+VirtQueue *virtio_vector_next_queue(VirtQueue *vq)
+{
+ return QLIST_NEXT(vq, node);
+}
+
int virtio_queue_get_num(VirtIODevice *vdev, int n)
{
return vdev->vq[n].vring.num;
@@ -780,8 +791,19 @@ uint16_t virtio_queue_vector(VirtIODevice *vdev, int n)
void virtio_queue_set_vector(VirtIODevice *vdev, int n, uint16_t vector)
{
- if (n < VIRTIO_PCI_QUEUE_MAX)
+ VirtQueue *vq = &vdev->vq[n];
+
+ if (n < VIRTIO_PCI_QUEUE_MAX) {
+ if (vdev->vector_queues &&
+ vdev->vq[n].vector != VIRTIO_NO_VECTOR) {
+ QLIST_REMOVE(vq, node);
+ }
vdev->vq[n].vector = vector;
+ if (vdev->vector_queues &&
+ vector != VIRTIO_NO_VECTOR) {
+ QLIST_INSERT_HEAD(&vdev->vector_queues[vector], vq, node);
+ }
+ }
}
VirtQueue *virtio_add_queue(VirtIODevice *vdev, int queue_size,
@@ -1088,6 +1110,7 @@ void virtio_cleanup(VirtIODevice *vdev)
qemu_del_vm_change_state_handler(vdev->vmstate);
g_free(vdev->config);
g_free(vdev->vq);
+ g_free(vdev->vector_queues);
}
static void virtio_vmstate_change(void *opaque, int running, RunState state)
@@ -1125,7 +1148,16 @@ void virtio_instance_init_common(Object *proxy_obj, void *data,
void virtio_init(VirtIODevice *vdev, const char *name,
uint16_t device_id, size_t config_size)
{
+ BusState *qbus = qdev_get_parent_bus(DEVICE(vdev));
+ VirtioBusClass *k = VIRTIO_BUS_GET_CLASS(qbus);
int i;
+ int nvectors = k->query_nvectors ? k->query_nvectors(qbus->parent) : 0;
+
+ if (nvectors) {
+ vdev->vector_queues =
+ g_malloc0(sizeof(*vdev->vector_queues) * nvectors);
+ }
+
vdev->device_id = device_id;
vdev->status = 0;
vdev->isr = 0;
diff --git a/include/glib-compat.h b/include/glib-compat.h
index 011352b2b6..28d9f15bd3 100644
--- a/include/glib-compat.h
+++ b/include/glib-compat.h
@@ -115,7 +115,7 @@ static inline void g_mutex_init(CompatGMutex *mutex)
static inline void g_mutex_clear(CompatGMutex *mutex)
{
- assert(mutex->once.status != G_ONCE_STATUS_PROGRESS);
+ g_assert(mutex->once.status != G_ONCE_STATUS_PROGRESS);
if (mutex->once.retval) {
g_mutex_free((GMutex *) mutex->once.retval);
}
@@ -155,7 +155,7 @@ static inline void g_cond_init(CompatGCond *cond)
static inline void g_cond_clear(CompatGCond *cond)
{
- assert(cond->once.status != G_ONCE_STATUS_PROGRESS);
+ g_assert(cond->once.status != G_ONCE_STATUS_PROGRESS);
if (cond->once.retval) {
g_cond_free((GCond *) cond->once.retval);
}
@@ -164,7 +164,7 @@ static inline void g_cond_clear(CompatGCond *cond)
static inline void (g_cond_wait)(CompatGCond *cond, CompatGMutex *mutex)
{
- assert(mutex->once.status != G_ONCE_STATUS_PROGRESS);
+ g_assert(mutex->once.status != G_ONCE_STATUS_PROGRESS);
g_once(&cond->once, do_g_cond_new, NULL);
g_cond_wait((GCond *) cond->once.retval, (GMutex *) mutex->once.retval);
}
diff --git a/hw/i386/acpi-defs.h b/include/hw/acpi/acpi-defs.h
index c4468f84e8..c4468f84e8 100644
--- a/hw/i386/acpi-defs.h
+++ b/include/hw/acpi/acpi-defs.h
diff --git a/include/hw/acpi/aml-build.h b/include/hw/acpi/aml-build.h
index 17d3beb5a3..3947201fd1 100644
--- a/include/hw/acpi/aml-build.h
+++ b/include/hw/acpi/aml-build.h
@@ -4,6 +4,18 @@
#include <stdint.h>
#include <glib.h>
#include "qemu/compiler.h"
+#include "hw/acpi/acpi-defs.h"
+
+/* Reserve RAM space for tables: add another order of magnitude. */
+#define ACPI_BUILD_TABLE_MAX_SIZE 0x200000
+
+#define ACPI_BUILD_APPNAME "Bochs"
+#define ACPI_BUILD_APPNAME6 "BOCHS "
+#define ACPI_BUILD_APPNAME4 "BXPC"
+
+#define ACPI_BUILD_TABLE_FILE "etc/acpi/tables"
+#define ACPI_BUILD_RSDP_FILE "etc/acpi/rsdp"
+#define ACPI_BUILD_TPMLOG_FILE "etc/tpm/log"
typedef enum {
AML_NO_OPCODE = 0,/* has only data */
@@ -35,7 +47,13 @@ typedef enum {
aml_dword_acc = 3,
aml_qword_acc = 4,
aml_buffer_acc = 5,
-} AmlFieldFlags;
+} AmlAccessType;
+
+typedef enum {
+ aml_preserve = 0,
+ aml_write_as_ones = 1,
+ aml_write_as_zeros = 2,
+} AmlUpdateRule;
typedef enum {
aml_system_memory = 0x00,
@@ -93,6 +111,14 @@ typedef enum {
aml_ReadWrite = 1,
} AmlReadAndWrite;
+typedef
+struct AcpiBuildTables {
+ GArray *table_data;
+ GArray *rsdp;
+ GArray *tcpalog;
+ GArray *linker;
+} AcpiBuildTables;
+
/**
* init_aml_allocator:
*
@@ -120,7 +146,7 @@ void free_aml_allocator(void);
* Joins Aml elements together and helps to construct AML tables
* Examle of usage:
* Aml *table = aml_def_block("SSDT", ...);
- * Aml *sb = aml_scope("\_SB");
+ * Aml *sb = aml_scope("\\_SB");
* Aml *dev = aml_device("PCI0");
*
* aml_append(dev, aml_name_decl("HID", aml_eisaid("PNP0A03")));
@@ -185,7 +211,16 @@ Aml *aml_if(Aml *predicate);
Aml *aml_package(uint8_t num_elements);
Aml *aml_buffer(void);
Aml *aml_resource_template(void);
-Aml *aml_field(const char *name, AmlFieldFlags flags);
+Aml *aml_field(const char *name, AmlAccessType type, AmlUpdateRule rule);
Aml *aml_varpackage(uint32_t num_elements);
+void
+build_header(GArray *linker, GArray *table_data,
+ AcpiTableHeader *h, const char *sig, int len, uint8_t rev);
+void *acpi_data_push(GArray *table_data, unsigned size);
+unsigned acpi_data_len(GArray *table);
+void acpi_add_table(GArray *table_offsets, GArray *table_data);
+void acpi_build_tables_init(AcpiBuildTables *tables);
+void acpi_build_tables_cleanup(AcpiBuildTables *tables, bool mfre);
+
#endif
diff --git a/include/hw/acpi/memory_hotplug.h b/include/hw/acpi/memory_hotplug.h
index 7bbf8a0064..986223b16c 100644
--- a/include/hw/acpi/memory_hotplug.h
+++ b/include/hw/acpi/memory_hotplug.h
@@ -7,10 +7,17 @@
#define ACPI_MEMORY_HOTPLUG_STATUS 8
+/**
+ * MemStatus:
+ * @is_removing: the memory device in slot has been requested to be ejected.
+ *
+ * This structure stores memory device's status.
+ */
typedef struct MemStatus {
DeviceState *dimm;
bool is_enabled;
bool is_inserting;
+ bool is_removing;
uint32_t ost_event;
uint32_t ost_status;
} MemStatus;
@@ -28,6 +35,11 @@ void acpi_memory_hotplug_init(MemoryRegion *as, Object *owner,
void acpi_memory_plug_cb(ACPIREGS *ar, qemu_irq irq, MemHotplugState *mem_st,
DeviceState *dev, Error **errp);
+void acpi_memory_unplug_request_cb(ACPIREGS *ar, qemu_irq irq,
+ MemHotplugState *mem_st,
+ DeviceState *dev, Error **errp);
+void acpi_memory_unplug_cb(MemHotplugState *mem_st,
+ DeviceState *dev, Error **errp);
extern const VMStateDescription vmstate_memory_hotplug;
#define VMSTATE_MEMORY_HOTPLUG(memhp, state) \
diff --git a/include/hw/acpi/pc-hotplug.h b/include/hw/acpi/pc-hotplug.h
index efa6ed7b7b..0513c1c158 100644
--- a/include/hw/acpi/pc-hotplug.h
+++ b/include/hw/acpi/pc-hotplug.h
@@ -43,6 +43,8 @@
#define MEMORY_SLOT_PROXIMITY MPX
#define MEMORY_SLOT_ENABLED MES
#define MEMORY_SLOT_INSERT_EVENT MINS
+#define MEMORY_SLOT_REMOVE_EVENT MRMV
+#define MEMORY_SLOT_EJECT MEJ
#define MEMORY_SLOT_SLECTOR MSEL
#define MEMORY_SLOT_OST_EVENT MOEV
#define MEMORY_SLOT_OST_STATUS MOSC
@@ -51,6 +53,7 @@
#define MEMORY_SLOT_CRS_METHOD MCRS
#define MEMORY_SLOT_OST_METHOD MOST
#define MEMORY_SLOT_PROXIMITY_METHOD MPXM
+#define MEMORY_SLOT_EJECT_METHOD MEJ0
#define MEMORY_SLOT_NOTIFY_METHOD MTFY
#define MEMORY_SLOT_SCAN_METHOD MSCN
diff --git a/include/hw/qdev-core.h b/include/hw/qdev-core.h
index 4e673f9d29..d4be92fbee 100644
--- a/include/hw/qdev-core.h
+++ b/include/hw/qdev-core.h
@@ -226,7 +226,7 @@ struct Property {
PropertyInfo *info;
int offset;
uint8_t bitnr;
- uint8_t qtype;
+ qtype_code qtype;
int64_t defval;
int arrayoffset;
PropertyInfo *arrayinfo;
@@ -266,6 +266,7 @@ int qdev_init(DeviceState *dev) QEMU_WARN_UNUSED_RESULT;
void qdev_init_nofail(DeviceState *dev);
void qdev_set_legacy_instance_id(DeviceState *dev, int alias_id,
int required_for_version);
+HotplugHandler *qdev_get_hotplug_handler(DeviceState *dev);
void qdev_unplug(DeviceState *dev, Error **errp);
void qdev_simple_device_unplug_cb(HotplugHandler *hotplug_dev,
DeviceState *dev, Error **errp);
diff --git a/include/hw/virtio/virtio-bus.h b/include/hw/virtio/virtio-bus.h
index 0d2e7b49b2..a4588ca4d9 100644
--- a/include/hw/virtio/virtio-bus.h
+++ b/include/hw/virtio/virtio-bus.h
@@ -62,6 +62,7 @@ typedef struct VirtioBusClass {
* This is called by virtio-bus just before the device is unplugged.
*/
void (*device_unplugged)(DeviceState *d);
+ int (*query_nvectors)(DeviceState *d);
/*
* Does the transport have variable vring alignment?
* (ie can it ever call virtio_queue_set_align()?)
diff --git a/include/hw/virtio/virtio-net.h b/include/hw/virtio/virtio-net.h
index 4c2fe83b6b..e0dbb418ad 100644
--- a/include/hw/virtio/virtio-net.h
+++ b/include/hw/virtio/virtio-net.h
@@ -68,6 +68,7 @@ typedef struct VirtIONet {
uint32_t has_vnet_hdr;
size_t host_hdr_len;
size_t guest_hdr_len;
+ uint32_t host_features;
uint8_t has_ufo;
int mergeable_rx_bufs;
uint8_t promisc;
@@ -137,7 +138,6 @@ typedef struct VirtIONet {
DEFINE_PROP_INT32("x-txburst", _state, _field.txburst, TX_BURST), \
DEFINE_PROP_STRING("tx", _state, _field.tx)
-void virtio_net_set_config_size(VirtIONet *n, uint32_t host_features);
void virtio_net_set_netclient_name(VirtIONet *n, const char *name,
const char *type);
diff --git a/include/hw/virtio/virtio-scsi.h b/include/hw/virtio/virtio-scsi.h
index f93b57d3e9..b42e7f1379 100644
--- a/include/hw/virtio/virtio-scsi.h
+++ b/include/hw/virtio/virtio-scsi.h
@@ -98,6 +98,7 @@ typedef struct VirtIOSCSI {
bool dataplane_fenced;
Error *blocker;
Notifier migration_state_notifier;
+ uint32_t host_features;
} VirtIOSCSI;
typedef struct VirtIOSCSIReq {
diff --git a/include/hw/virtio/virtio.h b/include/hw/virtio/virtio.h
index d95f8b6d50..8210cb34f9 100644
--- a/include/hw/virtio/virtio.h
+++ b/include/hw/virtio/virtio.h
@@ -84,6 +84,7 @@ struct VirtIODevice
VMChangeStateEntry *vmstate;
char *bus_name;
uint8_t device_endian;
+ QLIST_HEAD(, VirtQueue) *vector_queues;
};
typedef struct VirtioDeviceClass {
@@ -218,6 +219,8 @@ void virtio_queue_set_host_notifier_fd_handler(VirtQueue *vq, bool assign,
bool set_handler);
void virtio_queue_notify_vq(VirtQueue *vq);
void virtio_irq(VirtQueue *vq);
+VirtQueue *virtio_vector_first_queue(VirtIODevice *vdev, uint16_t vector);
+VirtQueue *virtio_vector_next_queue(VirtQueue *vq);
static inline void virtio_add_feature(uint32_t *features, unsigned int fbit)
{
diff --git a/include/qapi/qmp/qobject.h b/include/qapi/qmp/qobject.h
index d0bbc7c4a6..84b2d9fef5 100644
--- a/include/qapi/qmp/qobject.h
+++ b/include/qapi/qmp/qobject.h
@@ -3,7 +3,7 @@
*
* Based on ideas by Avi Kivity <avi@redhat.com>
*
- * Copyright (C) 2009 Red Hat Inc.
+ * Copyright (C) 2009, 2015 Red Hat Inc.
*
* Authors:
* Luiz Capitulino <lcapitulino@redhat.com>
@@ -36,7 +36,8 @@
#include <assert.h>
typedef enum {
- QTYPE_NONE,
+ QTYPE_NONE, /* sentinel value, no QObject has this type code */
+ QTYPE_QNULL,
QTYPE_QINT,
QTYPE_QSTRING,
QTYPE_QDICT,
@@ -110,4 +111,12 @@ static inline qtype_code qobject_type(const QObject *obj)
return obj->type->code;
}
+extern QObject qnull_;
+
+static inline QObject *qnull(void)
+{
+ qobject_incref(&qnull_);
+ return &qnull_;
+}
+
#endif /* QOBJECT_H */
diff --git a/include/sysemu/iothread.h b/include/sysemu/iothread.h
index 7c01a61d5e..2eefea1cc2 100644
--- a/include/sysemu/iothread.h
+++ b/include/sysemu/iothread.h
@@ -33,7 +33,6 @@ typedef struct {
#define IOTHREAD(obj) \
OBJECT_CHECK(IOThread, obj, TYPE_IOTHREAD)
-IOThread *iothread_find(const char *id);
char *iothread_get_id(IOThread *iothread);
AioContext *iothread_get_aio_context(IOThread *iothread);
diff --git a/include/sysemu/tpm_backend_int.h b/include/sysemu/tpm_backend_int.h
index 05d94d0f5b..40f693a0cc 100644
--- a/include/sysemu/tpm_backend_int.h
+++ b/include/sysemu/tpm_backend_int.h
@@ -32,8 +32,6 @@ void tpm_backend_thread_deliver_request(TPMBackendThread *tbt);
void tpm_backend_thread_create(TPMBackendThread *tbt,
GFunc func, gpointer user_data);
void tpm_backend_thread_end(TPMBackendThread *tbt);
-void tpm_backend_thread_tpm_reset(TPMBackendThread *tbt,
- GFunc func, gpointer user_data);
typedef enum TPMBackendCmd {
TPM_BACKEND_CMD_INIT = 1,
diff --git a/iothread.c b/iothread.c
index a1f91099bc..0416fc4268 100644
--- a/iothread.c
+++ b/iothread.c
@@ -114,18 +114,6 @@ static void iothread_register_types(void)
type_init(iothread_register_types)
-IOThread *iothread_find(const char *id)
-{
- Object *container = container_get(object_get_root(), IOTHREADS_PATH);
- Object *child;
-
- child = object_property_get_link(container, id, NULL);
- if (!child) {
- return NULL;
- }
- return (IOThread *)object_dynamic_cast(child, TYPE_IOTHREAD);
-}
-
char *iothread_get_id(IOThread *iothread)
{
return object_get_canonical_path_component(OBJECT(iothread));
diff --git a/monitor.c b/monitor.c
index 3952d646cd..b2561e1e2d 100644
--- a/monitor.c
+++ b/monitor.c
@@ -4471,11 +4471,12 @@ void set_link_completion(ReadLineState *rs, int nb_args, const char *str)
len = strlen(str);
readline_set_completion_index(rs, len);
if (nb_args == 2) {
- NetClientState *ncs[255];
+ NetClientState *ncs[MAX_QUEUE_NUM];
int count, i;
count = qemu_find_net_clients_except(NULL, ncs,
- NET_CLIENT_OPTIONS_KIND_NONE, 255);
- for (i = 0; i < count; i++) {
+ NET_CLIENT_OPTIONS_KIND_NONE,
+ MAX_QUEUE_NUM);
+ for (i = 0; i < MIN(count, MAX_QUEUE_NUM); i++) {
const char *name = ncs[i]->name;
if (!strncmp(str, name, len)) {
readline_add_completion(rs, name);
@@ -4490,7 +4491,7 @@ void set_link_completion(ReadLineState *rs, int nb_args, const char *str)
void netdev_del_completion(ReadLineState *rs, int nb_args, const char *str)
{
int len, count, i;
- NetClientState *ncs[255];
+ NetClientState *ncs[MAX_QUEUE_NUM];
if (nb_args != 2) {
return;
@@ -4499,8 +4500,8 @@ void netdev_del_completion(ReadLineState *rs, int nb_args, const char *str)
len = strlen(str);
readline_set_completion_index(rs, len);
count = qemu_find_net_clients_except(NULL, ncs, NET_CLIENT_OPTIONS_KIND_NIC,
- 255);
- for (i = 0; i < count; i++) {
+ MAX_QUEUE_NUM);
+ for (i = 0; i < MIN(count, MAX_QUEUE_NUM); i++) {
QemuOpts *opts;
const char *name = ncs[i]->name;
if (strncmp(str, name, len)) {
@@ -4583,15 +4584,16 @@ void host_net_add_completion(ReadLineState *rs, int nb_args, const char *str)
void host_net_remove_completion(ReadLineState *rs, int nb_args, const char *str)
{
- NetClientState *ncs[255];
+ NetClientState *ncs[MAX_QUEUE_NUM];
int count, i, len;
len = strlen(str);
readline_set_completion_index(rs, len);
if (nb_args == 2) {
count = qemu_find_net_clients_except(NULL, ncs,
- NET_CLIENT_OPTIONS_KIND_NONE, 255);
- for (i = 0; i < count; i++) {
+ NET_CLIENT_OPTIONS_KIND_NONE,
+ MAX_QUEUE_NUM);
+ for (i = 0; i < MIN(count, MAX_QUEUE_NUM); i++) {
int id;
char name[16];
@@ -4606,8 +4608,9 @@ void host_net_remove_completion(ReadLineState *rs, int nb_args, const char *str)
return;
} else if (nb_args == 3) {
count = qemu_find_net_clients_except(NULL, ncs,
- NET_CLIENT_OPTIONS_KIND_NIC, 255);
- for (i = 0; i < count; i++) {
+ NET_CLIENT_OPTIONS_KIND_NIC,
+ MAX_QUEUE_NUM);
+ for (i = 0; i < MIN(count, MAX_QUEUE_NUM); i++) {
int id;
const char *name;
diff --git a/qapi/block-core.json b/qapi/block-core.json
index dcf7c04ffa..863ffea0c7 100644
--- a/qapi/block-core.json
+++ b/qapi/block-core.json
@@ -1847,7 +1847,7 @@
# not guaranteed to be stable
#
# @offset: #optional, if the corruption resulted from an image access, this is
-# the access offset into the image
+# the host's access offset into the image
#
# @size: #optional, if the corruption resulted from an image access, this is
# the access size
diff --git a/qapi/event.json b/qapi/event.json
index c51dc491e0..378dda572a 100644
--- a/qapi/event.json
+++ b/qapi/event.json
@@ -330,3 +330,17 @@
##
{ 'event': 'VSERPORT_CHANGE',
'data': { 'id': 'str', 'open': 'bool' } }
+
+##
+# @MEM_UNPLUG_ERROR
+#
+# Emitted when memory hot unplug error occurs.
+#
+# @device: device name
+#
+# @msg: Informative message
+#
+# Since: 2.4
+##
+{ 'event': 'MEM_UNPLUG_ERROR',
+ 'data': { 'device': 'str', 'msg': 'str' } }
diff --git a/qjson.c b/qjson.c
index 0cda2690f5..e478802a46 100644
--- a/qjson.c
+++ b/qjson.c
@@ -24,6 +24,8 @@ struct QJSON {
bool omit_comma;
};
+#define QJSON(obj) OBJECT_CHECK(QJSON, (obj), TYPE_QJSON)
+
static void json_emit_element(QJSON *json, const char *name)
{
/* Check whether we need to print a , before an element */
@@ -87,7 +89,7 @@ const char *qjson_get_str(QJSON *json)
QJSON *qjson_new(void)
{
- QJSON *json = (QJSON *)object_new(TYPE_QJSON);
+ QJSON *json = QJSON(object_new(TYPE_QJSON));
return json;
}
@@ -98,8 +100,7 @@ void qjson_finish(QJSON *json)
static void qjson_initfn(Object *obj)
{
- QJSON *json = (QJSON *)object_dynamic_cast(obj, TYPE_QJSON);
- assert(json);
+ QJSON *json = QJSON(obj);
json->str = qstring_from_str("{ ");
json->omit_comma = true;
@@ -107,9 +108,8 @@ static void qjson_initfn(Object *obj)
static void qjson_finalizefn(Object *obj)
{
- QJSON *json = (QJSON *)object_dynamic_cast(obj, TYPE_QJSON);
+ QJSON *json = QJSON(obj);
- assert(json);
qobject_decref(QOBJECT(json->str));
}
diff --git a/qobject/Makefile.objs b/qobject/Makefile.objs
index c9ff59c6cc..f7595f56fe 100644
--- a/qobject/Makefile.objs
+++ b/qobject/Makefile.objs
@@ -1,3 +1,3 @@
-util-obj-y = qint.o qstring.o qdict.o qlist.o qfloat.o qbool.o
+util-obj-y = qnull.o qint.o qstring.o qdict.o qlist.o qfloat.o qbool.o
util-obj-y += qjson.o json-lexer.o json-streamer.o json-parser.o
util-obj-y += qerror.o
diff --git a/qobject/json-parser.c b/qobject/json-parser.c
index 4288267bd3..717cb8fde7 100644
--- a/qobject/json-parser.c
+++ b/qobject/json-parser.c
@@ -561,6 +561,8 @@ static QObject *parse_keyword(JSONParserContext *ctxt)
ret = QOBJECT(qbool_from_int(true));
} else if (token_is_keyword(token, "false")) {
ret = QOBJECT(qbool_from_int(false));
+ } else if (token_is_keyword(token, "null")) {
+ ret = qnull();
} else {
parse_error(ctxt, token, "invalid keyword `%s'", token_get_value(token));
goto out;
diff --git a/qobject/qjson.c b/qobject/qjson.c
index 12c576d548..846733dafb 100644
--- a/qobject/qjson.c
+++ b/qobject/qjson.c
@@ -127,6 +127,9 @@ static void to_json_list_iter(QObject *obj, void *opaque)
static void to_json(const QObject *obj, QString *str, int pretty, int indent)
{
switch (qobject_type(obj)) {
+ case QTYPE_QNULL:
+ qstring_append(str, "null");
+ break;
case QTYPE_QINT: {
QInt *val = qobject_to_qint(obj);
char buffer[1024];
@@ -260,9 +263,8 @@ static void to_json(const QObject *obj, QString *str, int pretty, int indent)
}
case QTYPE_QERROR:
/* XXX: should QError be emitted? */
- case QTYPE_NONE:
break;
- case QTYPE_MAX:
+ default:
abort();
}
}
diff --git a/qobject/qnull.c b/qobject/qnull.c
new file mode 100644
index 0000000000..9873e266e6
--- /dev/null
+++ b/qobject/qnull.c
@@ -0,0 +1,29 @@
+/*
+ * QNull
+ *
+ * Copyright (C) 2015 Red Hat, Inc.
+ *
+ * Authors:
+ * Markus Armbruster <armbru@redhat.com>
+ *
+ * This work is licensed under the terms of the GNU LGPL, version 2.1
+ * or later. See the COPYING.LIB file in the top-level directory.
+ */
+
+#include "qemu-common.h"
+#include "qapi/qmp/qobject.h"
+
+static void qnull_destroy_obj(QObject *obj)
+{
+ assert(0);
+}
+
+static const QType qnull_type = {
+ .code = QTYPE_QNULL,
+ .destroy = qnull_destroy_obj,
+};
+
+QObject qnull_ = {
+ .type = &qnull_type,
+ .refcnt = 1,
+};
diff --git a/scripts/qmp/qmp-shell b/scripts/qmp/qmp-shell
index e0e848bc30..65280d29d1 100755
--- a/scripts/qmp/qmp-shell
+++ b/scripts/qmp/qmp-shell
@@ -32,6 +32,7 @@
import qmp
import json
+import ast
import readline
import sys
import pprint
@@ -51,6 +52,19 @@ class QMPShellError(Exception):
class QMPShellBadPort(QMPShellError):
pass
+class FuzzyJSON(ast.NodeTransformer):
+ '''This extension of ast.NodeTransformer filters literal "true/false/null"
+ values in an AST and replaces them by proper "True/False/None" values that
+ Python can properly evaluate.'''
+ def visit_Name(self, node):
+ if node.id == 'true':
+ node.id = 'True'
+ if node.id == 'false':
+ node.id = 'False'
+ if node.id == 'null':
+ node.id = 'None'
+ return node
+
# TODO: QMPShell's interface is a bit ugly (eg. _fill_completion() and
# _execute_cmd()). Let's design a better one.
class QMPShell(qmp.QEMUMonitorProtocol):
@@ -59,6 +73,8 @@ class QMPShell(qmp.QEMUMonitorProtocol):
self._greeting = None
self._completer = None
self._pp = pp
+ self._transmode = False
+ self._actions = list()
def __get_address(self, arg):
"""
@@ -88,32 +104,40 @@ class QMPShell(qmp.QEMUMonitorProtocol):
# clearing everything as it doesn't seem to matter
readline.set_completer_delims('')
- def __build_cmd(self, cmdline):
- """
- Build a QMP input object from a user provided command-line in the
- following format:
+ def __parse_value(self, val):
+ try:
+ return int(val)
+ except ValueError:
+ pass
- < command-name > [ arg-name1=arg1 ] ... [ arg-nameN=argN ]
- """
- cmdargs = cmdline.split()
- qmpcmd = { 'execute': cmdargs[0], 'arguments': {} }
- for arg in cmdargs[1:]:
- opt = arg.split('=')
+ if val.lower() == 'true':
+ return True
+ if val.lower() == 'false':
+ return False
+ if val.startswith(('{', '[')):
+ # Try first as pure JSON:
try:
- if(len(opt) > 2):
- opt[1] = '='.join(opt[1:])
- value = int(opt[1])
+ return json.loads(val)
except ValueError:
- if opt[1] == 'true':
- value = True
- elif opt[1] == 'false':
- value = False
- elif opt[1].startswith('{'):
- value = json.loads(opt[1])
- else:
- value = opt[1]
- optpath = opt[0].split('.')
- parent = qmpcmd['arguments']
+ pass
+ # Try once again as FuzzyJSON:
+ try:
+ st = ast.parse(val, mode='eval')
+ return ast.literal_eval(FuzzyJSON().visit(st))
+ except SyntaxError:
+ pass
+ except ValueError:
+ pass
+ return val
+
+ def __cli_expr(self, tokens, parent):
+ for arg in tokens:
+ (key, _, val) = arg.partition('=')
+ if not val:
+ raise QMPShellError("Expected a key=value pair, got '%s'" % arg)
+
+ value = self.__parse_value(val)
+ optpath = key.split('.')
curpath = []
for p in optpath[:-1]:
curpath.append(p)
@@ -126,10 +150,58 @@ class QMPShell(qmp.QEMUMonitorProtocol):
if type(parent[optpath[-1]]) is dict:
raise QMPShellError('Cannot use "%s" as both leaf and non-leaf key' % '.'.join(curpath))
else:
- raise QMPShellError('Cannot set "%s" multiple times' % opt[0])
+ raise QMPShellError('Cannot set "%s" multiple times' % key)
parent[optpath[-1]] = value
+
+ def __build_cmd(self, cmdline):
+ """
+ Build a QMP input object from a user provided command-line in the
+ following format:
+
+ < command-name > [ arg-name1=arg1 ] ... [ arg-nameN=argN ]
+ """
+ cmdargs = cmdline.split()
+
+ # Transactional CLI entry/exit:
+ if cmdargs[0] == 'transaction(':
+ self._transmode = True
+ cmdargs.pop(0)
+ elif cmdargs[0] == ')' and self._transmode:
+ self._transmode = False
+ if len(cmdargs) > 1:
+ raise QMPShellError("Unexpected input after close of Transaction sub-shell")
+ qmpcmd = { 'execute': 'transaction',
+ 'arguments': { 'actions': self._actions } }
+ self._actions = list()
+ return qmpcmd
+
+ # Nothing to process?
+ if not cmdargs:
+ return None
+
+ # Parse and then cache this Transactional Action
+ if self._transmode:
+ finalize = False
+ action = { 'type': cmdargs[0], 'data': {} }
+ if cmdargs[-1] == ')':
+ cmdargs.pop(-1)
+ finalize = True
+ self.__cli_expr(cmdargs[1:], action['data'])
+ self._actions.append(action)
+ return self.__build_cmd(')') if finalize else None
+
+ # Standard command: parse and return it to be executed.
+ qmpcmd = { 'execute': cmdargs[0], 'arguments': {} }
+ self.__cli_expr(cmdargs[1:], qmpcmd['arguments'])
return qmpcmd
+ def _print(self, qmp):
+ jsobj = json.dumps(qmp)
+ if self._pp is not None:
+ self._pp.pprint(jsobj)
+ else:
+ print str(jsobj)
+
def _execute_cmd(self, cmdline):
try:
qmpcmd = self.__build_cmd(cmdline)
@@ -138,15 +210,16 @@ class QMPShell(qmp.QEMUMonitorProtocol):
print 'command format: <command-name> ',
print '[arg-name1=arg1] ... [arg-nameN=argN]'
return True
+ # For transaction mode, we may have just cached the action:
+ if qmpcmd is None:
+ return True
+ if self._verbose:
+ self._print(qmpcmd)
resp = self.cmd_obj(qmpcmd)
if resp is None:
print 'Disconnected'
return False
-
- if self._pp is not None:
- self._pp.pprint(resp)
- else:
- print resp
+ self._print(resp)
return True
def connect(self):
@@ -158,6 +231,11 @@ class QMPShell(qmp.QEMUMonitorProtocol):
version = self._greeting['QMP']['version']['qemu']
print 'Connected to QEMU %d.%d.%d\n' % (version['major'],version['minor'],version['micro'])
+ def get_prompt(self):
+ if self._transmode:
+ return "TRANS> "
+ return "(QEMU) "
+
def read_exec_command(self, prompt):
"""
Read and execute a command.
@@ -177,6 +255,9 @@ class QMPShell(qmp.QEMUMonitorProtocol):
else:
return self._execute_cmd(cmdline)
+ def set_verbosity(self, verbose):
+ self._verbose = verbose
+
class HMPShell(QMPShell):
def __init__(self, address):
QMPShell.__init__(self, address)
@@ -254,7 +335,7 @@ def die(msg):
def fail_cmdline(option=None):
if option:
sys.stderr.write('ERROR: bad command-line option \'%s\'\n' % option)
- sys.stderr.write('qemu-shell [ -p ] [ -H ] < UNIX socket path> | < TCP address:port >\n')
+ sys.stderr.write('qemu-shell [ -v ] [ -p ] [ -H ] < UNIX socket path> | < TCP address:port >\n')
sys.exit(1)
def main():
@@ -262,6 +343,7 @@ def main():
qemu = None
hmp = False
pp = None
+ verbose = False
try:
for arg in sys.argv[1:]:
@@ -273,6 +355,8 @@ def main():
if pp is not None:
fail_cmdline(arg)
pp = pprint.PrettyPrinter(indent=4)
+ elif arg == "-v":
+ verbose = True
else:
if qemu is not None:
fail_cmdline(arg)
@@ -297,7 +381,8 @@ def main():
die('Could not connect to %s' % addr)
qemu.show_banner()
- while qemu.read_exec_command('(QEMU) '):
+ qemu.set_verbosity(verbose)
+ while qemu.read_exec_command(qemu.get_prompt()):
pass
qemu.close()
diff --git a/target-tricore/op_helper.c b/target-tricore/op_helper.c
index 9907e07e22..9919b5b17b 100644
--- a/target-tricore/op_helper.c
+++ b/target-tricore/op_helper.c
@@ -2458,6 +2458,7 @@ void helper_rfe(CPUTriCoreState *env)
if (!cdc_zero(&(env->PSW)) && (env->PSW & MASK_PSW_CDE)) {
/* raise MNG trap */
}
+ env->PC = env->gpr_a[11] & ~0x1;
/* ICR.IE = PCXI.PIE; */
env->ICR = (env->ICR & ~MASK_ICR_IE) + ((env->PCXI & MASK_PCXI_PIE) >> 15);
/* ICR.CCPN = PCXI.PCPN; */
@@ -2581,7 +2582,7 @@ void helper_rslcx(CPUTriCoreState *env)
((env->PCXI & MASK_PCXI_PCXO) << 6);
/* {new_PCXI, A[11], A[10], A[11], D[8], D[9], D[10], D[11], A[12],
A[13], A[14], A[15], D[12], D[13], D[14], D[15]} = M(EA, 16 * word); */
- restore_context_upper(env, ea, &new_PCXI, &env->gpr_a[11]);
+ restore_context_lower(env, ea, &env->gpr_a[11], &new_PCXI);
/* M(EA, word) = FCX; */
cpu_stl_data(env, ea, env->FCX);
/* M(EA, word) = FCX; */
diff --git a/target-tricore/translate.c b/target-tricore/translate.c
index 54a48cd694..663b2a0796 100644
--- a/target-tricore/translate.c
+++ b/target-tricore/translate.c
@@ -3440,7 +3440,7 @@ static void gen_compute_branch(DisasContext *ctx, uint32_t opc, int r1,
break;
case OPCM_32_BRR_LOOP:
if (MASK_OP_BRR_OP2(ctx->opcode) == OPC2_32_BRR_LOOP) {
- gen_loop(ctx, r1, offset * 2);
+ gen_loop(ctx, r2, offset * 2);
} else {
/* OPC2_32_BRR_LOOPU */
gen_goto_tb(ctx, 0, ctx->pc + offset * 2);
@@ -3745,10 +3745,10 @@ static void decode_slr_opc(DisasContext *ctx, int op1)
tcg_gen_addi_tl(cpu_gpr_a[r2], cpu_gpr_a[r2], 2);
break;
case OPC1_16_SLR_LD_W:
- tcg_gen_qemu_ld_tl(cpu_gpr_d[r1], cpu_gpr_a[r2], ctx->mem_idx, MO_LESW);
+ tcg_gen_qemu_ld_tl(cpu_gpr_d[r1], cpu_gpr_a[r2], ctx->mem_idx, MO_LESL);
break;
case OPC1_16_SLR_LD_W_POSTINC:
- tcg_gen_qemu_ld_tl(cpu_gpr_d[r1], cpu_gpr_a[r2], ctx->mem_idx, MO_LESW);
+ tcg_gen_qemu_ld_tl(cpu_gpr_d[r1], cpu_gpr_a[r2], ctx->mem_idx, MO_LESL);
tcg_gen_addi_tl(cpu_gpr_a[r2], cpu_gpr_a[r2], 4);
break;
}
diff --git a/target-tricore/tricore-opcodes.h b/target-tricore/tricore-opcodes.h
index d3a9bc158b..2291f75fd9 100644
--- a/target-tricore/tricore-opcodes.h
+++ b/target-tricore/tricore-opcodes.h
@@ -107,7 +107,7 @@
/* BO Format */
#define MASK_OP_BO_OFF10(op) (MASK_BITS_SHIFT(op, 16, 21) + \
(MASK_BITS_SHIFT(op, 28, 31) << 6))
-#define MASK_OP_BO_OFF10_SEXT(op) (MASK_BITS_SHIFT_SEXT(op, 16, 21) + \
+#define MASK_OP_BO_OFF10_SEXT(op) (MASK_BITS_SHIFT(op, 16, 21) + \
(MASK_BITS_SHIFT_SEXT(op, 28, 31) << 6))
#define MASK_OP_BO_OP2(op) MASK_BITS_SHIFT(op, 22, 27)
#define MASK_OP_BO_S2(op) MASK_BITS_SHIFT(op, 12, 15)
diff --git a/tests/acpi-test-data/pc/DSDT b/tests/acpi-test-data/pc/DSDT
index 1693c3783b..c658203db9 100644
--- a/tests/acpi-test-data/pc/DSDT
+++ b/tests/acpi-test-data/pc/DSDT
Binary files differ
diff --git a/tests/acpi-test-data/pc/SSDT b/tests/acpi-test-data/pc/SSDT
index 59be315237..210d6a71e5 100644
--- a/tests/acpi-test-data/pc/SSDT
+++ b/tests/acpi-test-data/pc/SSDT
Binary files differ
diff --git a/tests/acpi-test-data/pc/SSDT.bridge b/tests/acpi-test-data/pc/SSDT.bridge
index fa6136935c..6e6660b1fb 100644
--- a/tests/acpi-test-data/pc/SSDT.bridge
+++ b/tests/acpi-test-data/pc/SSDT.bridge
Binary files differ
diff --git a/tests/acpi-test-data/q35/DSDT b/tests/acpi-test-data/q35/DSDT
index e9ac11c38f..4723e5954d 100644
--- a/tests/acpi-test-data/q35/DSDT
+++ b/tests/acpi-test-data/q35/DSDT
Binary files differ
diff --git a/tests/acpi-test-data/q35/SSDT b/tests/acpi-test-data/q35/SSDT
index e87f5a35c1..0970c67ddb 100644
--- a/tests/acpi-test-data/q35/SSDT
+++ b/tests/acpi-test-data/q35/SSDT
Binary files differ
diff --git a/tests/acpi-test-data/q35/SSDT.bridge b/tests/acpi-test-data/q35/SSDT.bridge
index b3cac34d70..a778688617 100644
--- a/tests/acpi-test-data/q35/SSDT.bridge
+++ b/tests/acpi-test-data/q35/SSDT.bridge
Binary files differ
diff --git a/tests/bios-tables-test.c b/tests/bios-tables-test.c
index 735ac610be..7e85dc45e3 100644
--- a/tests/bios-tables-test.c
+++ b/tests/bios-tables-test.c
@@ -17,7 +17,7 @@
#include "qemu-common.h"
#include "libqtest.h"
#include "qemu/compiler.h"
-#include "hw/i386/acpi-defs.h"
+#include "hw/acpi/acpi-defs.h"
#include "hw/i386/smbios.h"
#include "qemu/bitmap.h"
diff --git a/tests/check-qjson.c b/tests/check-qjson.c
index 95497a037e..60e5b22a98 100644
--- a/tests/check-qjson.c
+++ b/tests/check-qjson.c
@@ -1,6 +1,6 @@
/*
* Copyright IBM, Corp. 2009
- * Copyright (c) 2013 Red Hat Inc.
+ * Copyright (c) 2013, 2015 Red Hat Inc.
*
* Authors:
* Anthony Liguori <aliguori@us.ibm.com>
@@ -1005,6 +1005,7 @@ static void keyword_literal(void)
{
QObject *obj;
QBool *qbool;
+ QObject *null;
QString *str;
obj = qobject_from_json("true");
@@ -1041,7 +1042,7 @@ static void keyword_literal(void)
g_assert(qbool_get_int(qbool) == 0);
QDECREF(qbool);
-
+
obj = qobject_from_jsonf("%i", true);
g_assert(obj != NULL);
g_assert(qobject_type(obj) == QTYPE_QBOOL);
@@ -1050,6 +1051,16 @@ static void keyword_literal(void)
g_assert(qbool_get_int(qbool) != 0);
QDECREF(qbool);
+
+ obj = qobject_from_json("null");
+ g_assert(obj != NULL);
+ g_assert(qobject_type(obj) == QTYPE_QNULL);
+
+ null = qnull();
+ g_assert(null == obj);
+
+ qobject_decref(obj);
+ qobject_decref(null);
}
typedef struct LiteralQDictEntry LiteralQDictEntry;
diff --git a/trace-events b/trace-events
index 30eba926c4..11387c32b8 100644
--- a/trace-events
+++ b/trace-events
@@ -1562,6 +1562,7 @@ vfio_put_base_device(int fd) "close vdev->fd=%d"
#hw/acpi/memory_hotplug.c
mhp_acpi_invalid_slot_selected(uint32_t slot) "0x%"PRIx32
+mhp_acpi_ejecting_invalid_slot(uint32_t slot) "0x%"PRIx32
mhp_acpi_read_addr_lo(uint32_t slot, uint32_t addr) "slot[0x%"PRIx32"] addr lo: 0x%"PRIx32
mhp_acpi_read_addr_hi(uint32_t slot, uint32_t addr) "slot[0x%"PRIx32"] addr hi: 0x%"PRIx32
mhp_acpi_read_size_lo(uint32_t slot, uint32_t size) "slot[0x%"PRIx32"] size lo: 0x%"PRIx32
@@ -1572,6 +1573,9 @@ mhp_acpi_write_slot(uint32_t slot) "set active slot: 0x%"PRIx32
mhp_acpi_write_ost_ev(uint32_t slot, uint32_t ev) "slot[0x%"PRIx32"] OST EVENT: 0x%"PRIx32
mhp_acpi_write_ost_status(uint32_t slot, uint32_t st) "slot[0x%"PRIx32"] OST STATUS: 0x%"PRIx32
mhp_acpi_clear_insert_evt(uint32_t slot) "slot[0x%"PRIx32"] clear insert event"
+mhp_acpi_clear_remove_evt(uint32_t slot) "slot[0x%"PRIx32"] clear remove event"
+mhp_acpi_pc_dimm_deleted(uint32_t slot) "slot[0x%"PRIx32"] pc-dimm deleted"
+mhp_acpi_pc_dimm_delete_failed(uint32_t slot) "slot[0x%"PRIx32"] pc-dimm delete failed"
# hw/i386/pc.c
mhp_pc_dimm_assigned_slot(int slot) "0x%d"