aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorWei Yang <richardw.yang@linux.intel.com>2019-03-01 11:35:48 +0800
committerMichael S. Tsirkin <mst@redhat.com>2019-03-12 22:31:21 -0400
commit9040e6dfa8c3fed87695a3de555d2c775727bb51 (patch)
tree29545b706420f8ab2048a2be270665f31d04564d
parente07fb4b50b629141eb1517002ccfa070dbdc1ea7 (diff)
downloadqemu-9040e6dfa8c3fed87695a3de555d2c775727bb51.zip
qemu-9040e6dfa8c3fed87695a3de555d2c775727bb51.tar.gz
qemu-9040e6dfa8c3fed87695a3de555d2c775727bb51.tar.bz2
i386, acpi: check acpi_memory_hotplug capacity in pre_plug
Currently we do device realization like below: hotplug_handler_pre_plug() dc->realize() hotplug_handler_plug() Before we do device realization and plug, we should allocate necessary resources and check if memory-hotplug-support property is enabled. At the piix4 and ich9, the memory-hotplug-support property is checked at plug stage. This means that device has been realized and mapped into guest address space 'pc_dimm_plug()' by the time acpi plug handler is called, where it might fail and crash QEMU due to reaching g_assert_not_reached() (piix4) or error_abort (ich9). Fix it by checking if memory hotplug is enabled at pre_plug stage where we can gracefully abort hotplug request. Signed-off-by: Wei Yang <richardw.yang@linux.intel.com> CC: Igor Mammedov <imammedo@redhat.com> CC: Eric Blake <eblake@redhat.com> Signed-off-by: Wei Yang <richardw.yang@linux.intel.com> Message-Id: <20190301033548.6691-1-richardw.yang@linux.intel.com> Reviewed-by: Igor Mammedov <imammedo@redhat.com> Reviewed-by: Michael S. Tsirkin <mst@redhat.com> Signed-off-by: Michael S. Tsirkin <mst@redhat.com>
-rw-r--r--hw/acpi/ich9.c15
-rw-r--r--hw/acpi/piix4.c13
-rw-r--r--hw/i386/pc.c2
-rw-r--r--hw/isa/lpc_ich9.c1
-rw-r--r--include/hw/acpi/ich9.h2
5 files changed, 28 insertions, 5 deletions
diff --git a/hw/acpi/ich9.c b/hw/acpi/ich9.c
index c5d8646..e53dfe1 100644
--- a/hw/acpi/ich9.c
+++ b/hw/acpi/ich9.c
@@ -483,13 +483,24 @@ void ich9_pm_add_properties(Object *obj, ICH9LPCPMRegs *pm, Error **errp)
NULL);
}
+void ich9_pm_device_pre_plug_cb(HotplugHandler *hotplug_dev, DeviceState *dev,
+ Error **errp)
+{
+ ICH9LPCState *lpc = ICH9_LPC_DEVICE(hotplug_dev);
+
+ if (object_dynamic_cast(OBJECT(dev), TYPE_PC_DIMM) &&
+ !lpc->pm.acpi_memory_hotplug.is_enabled)
+ error_setg(errp,
+ "memory hotplug is not enabled: %s.memory-hotplug-support "
+ "is not set", object_get_typename(OBJECT(lpc)));
+}
+
void ich9_pm_device_plug_cb(HotplugHandler *hotplug_dev, DeviceState *dev,
Error **errp)
{
ICH9LPCState *lpc = ICH9_LPC_DEVICE(hotplug_dev);
- if (lpc->pm.acpi_memory_hotplug.is_enabled &&
- object_dynamic_cast(OBJECT(dev), TYPE_PC_DIMM)) {
+ if (object_dynamic_cast(OBJECT(dev), TYPE_PC_DIMM)) {
if (object_dynamic_cast(OBJECT(dev), TYPE_NVDIMM)) {
nvdimm_acpi_plug_cb(hotplug_dev, dev);
} else {
diff --git a/hw/acpi/piix4.c b/hw/acpi/piix4.c
index 7b98121..9c079d6 100644
--- a/hw/acpi/piix4.c
+++ b/hw/acpi/piix4.c
@@ -380,9 +380,17 @@ static void piix4_pm_powerdown_req(Notifier *n, void *opaque)
static void piix4_device_pre_plug_cb(HotplugHandler *hotplug_dev,
DeviceState *dev, Error **errp)
{
+ PIIX4PMState *s = PIIX4_PM(hotplug_dev);
+
if (object_dynamic_cast(OBJECT(dev), TYPE_PCI_DEVICE)) {
acpi_pcihp_device_pre_plug_cb(hotplug_dev, dev, errp);
- } else if (!object_dynamic_cast(OBJECT(dev), TYPE_PC_DIMM) &&
+ } else if (object_dynamic_cast(OBJECT(dev), TYPE_PC_DIMM)) {
+ if (!s->acpi_memory_hotplug.is_enabled) {
+ error_setg(errp,
+ "memory hotplug is not enabled: %s.memory-hotplug-support "
+ "is not set", object_get_typename(OBJECT(s)));
+ }
+ } else if (
!object_dynamic_cast(OBJECT(dev), TYPE_CPU)) {
error_setg(errp, "acpi: device pre plug request for not supported"
" device type: %s", object_get_typename(OBJECT(dev)));
@@ -394,8 +402,7 @@ static void piix4_device_plug_cb(HotplugHandler *hotplug_dev,
{
PIIX4PMState *s = PIIX4_PM(hotplug_dev);
- if (s->acpi_memory_hotplug.is_enabled &&
- object_dynamic_cast(OBJECT(dev), TYPE_PC_DIMM)) {
+ if (object_dynamic_cast(OBJECT(dev), TYPE_PC_DIMM)) {
if (object_dynamic_cast(OBJECT(dev), TYPE_NVDIMM)) {
nvdimm_acpi_plug_cb(hotplug_dev, dev);
} else {
diff --git a/hw/i386/pc.c b/hw/i386/pc.c
index 1cdaff5..6077d27 100644
--- a/hw/i386/pc.c
+++ b/hw/i386/pc.c
@@ -2090,6 +2090,8 @@ static void pc_memory_pre_plug(HotplugHandler *hotplug_dev, DeviceState *dev,
return;
}
+ hotplug_handler_pre_plug(pcms->acpi_dev, dev, errp);
+
if (is_nvdimm && !ms->nvdimms_state->is_enabled) {
error_setg(errp, "nvdimm is not enabled: missing 'nvdimm' in '-M'");
return;
diff --git a/hw/isa/lpc_ich9.c b/hw/isa/lpc_ich9.c
index e692b9f..ac44aa5 100644
--- a/hw/isa/lpc_ich9.c
+++ b/hw/isa/lpc_ich9.c
@@ -805,6 +805,7 @@ static void ich9_lpc_class_init(ObjectClass *klass, void *data)
* pc_q35_init()
*/
dc->user_creatable = false;
+ hc->pre_plug = ich9_pm_device_pre_plug_cb;
hc->plug = ich9_pm_device_plug_cb;
hc->unplug_request = ich9_pm_device_unplug_request_cb;
hc->unplug = ich9_pm_device_unplug_cb;
diff --git a/include/hw/acpi/ich9.h b/include/hw/acpi/ich9.h
index 59aeb06..41568d1 100644
--- a/include/hw/acpi/ich9.h
+++ b/include/hw/acpi/ich9.h
@@ -74,6 +74,8 @@ extern const VMStateDescription vmstate_ich9_pm;
void ich9_pm_add_properties(Object *obj, ICH9LPCPMRegs *pm, Error **errp);
+void ich9_pm_device_pre_plug_cb(HotplugHandler *hotplug_dev, DeviceState *dev,
+ Error **errp);
void ich9_pm_device_plug_cb(HotplugHandler *hotplug_dev, DeviceState *dev,
Error **errp);
void ich9_pm_device_unplug_request_cb(HotplugHandler *hotplug_dev,