diff --git a/src/qemu/qemu_capabilities.c b/src/qemu/qemu_capabilities.c index 7b29a813a6..2ba7956e69 100644 --- a/src/qemu/qemu_capabilities.c +++ b/src/qemu/qemu_capabilities.c @@ -173,7 +173,9 @@ VIR_ENUM_IMPL(qemuCaps, QEMU_CAPS_LAST, "lsi", "virtio-scsi-pci", "iolimits", + "disable-s3", + "disable-s4", /* 105 */ ); struct qemu_feature_flags { @@ -1404,6 +1406,7 @@ qemuCapsExtractDeviceStr(const char *qemu, "-device", "virtio-blk-pci,?", "-device", "virtio-net-pci,?", "-device", "scsi-disk,?", + "-device", "PIIX4_PM,?", NULL); /* qemu -help goes to stdout, but qemu -device ? goes to stderr. */ virCommandSetErrorBuffer(cmd, &output); @@ -1510,6 +1513,10 @@ qemuCapsParseDeviceStr(const char *str, virBitmapPtr flags) if (strstr(str, ".logical_block_size") && strstr(str, ".physical_block_size")) qemuCapsSet(flags, QEMU_CAPS_IOLIMITS); + if (strstr(str, "PIIX4_PM.disable_s3=")) + qemuCapsSet(flags, QEMU_CAPS_DISABLE_S3); + if (strstr(str, "PIIX4_PM.disable_s4=")) + qemuCapsSet(flags, QEMU_CAPS_DISABLE_S4); return 0; } diff --git a/src/qemu/qemu_capabilities.h b/src/qemu/qemu_capabilities.h index b0e41ba49c..a7b3a061c4 100644 --- a/src/qemu/qemu_capabilities.h +++ b/src/qemu/qemu_capabilities.h @@ -139,6 +139,8 @@ enum qemuCapsFlags { QEMU_CAPS_SCSI_LSI = 101, /* -device lsi */ QEMU_CAPS_VIRTIO_SCSI_PCI = 102, /* -device virtio-scsi-pci */ QEMU_CAPS_IOLIMITS = 103, /* -device ...logical_block_size & co */ + QEMU_CAPS_DISABLE_S3 = 104, /* S3 BIOS Advertisement on/off */ + QEMU_CAPS_DISABLE_S4 = 105, /* S4 BIOS Advertisement on/off */ QEMU_CAPS_LAST, /* this must always be the last item */ }; diff --git a/src/qemu/qemu_command.c b/src/qemu/qemu_command.c index 51a225b2a7..e739f34e3f 100644 --- a/src/qemu/qemu_command.c +++ b/src/qemu/qemu_command.c @@ -4790,6 +4790,28 @@ qemuBuildCommandLine(virConnectPtr conn, virCommandAddArg(cmd, "-no-acpi"); } + if (def->pm.s3) { + if (!qemuCapsGet(qemuCaps, QEMU_CAPS_DISABLE_S3)) { + virReportError(VIR_ERR_CONFIG_UNSUPPORTED, + "%s", _("setting ACPI S3 not supported")); + goto error; + } + virCommandAddArg(cmd, "-global"); + virCommandAddArgFormat(cmd, "PIIX4_PM.disable_s3=%d", + def->pm.s3 == VIR_DOMAIN_PM_STATE_DISABLED); + } + + if (def->pm.s4) { + if (!qemuCapsGet(qemuCaps, QEMU_CAPS_DISABLE_S4)) { + virReportError(VIR_ERR_CONFIG_UNSUPPORTED, + "%s", _("setting ACPI S4 not supported")); + goto error; + } + virCommandAddArg(cmd, "-global"); + virCommandAddArgFormat(cmd, "PIIX4_PM.disable_s4=%d", + def->pm.s4 == VIR_DOMAIN_PM_STATE_DISABLED); + } + if (!def->os.bootloader) { /* * We prefer using explicit bootindex=N parameters for predictable @@ -8376,6 +8398,42 @@ virDomainDefPtr qemuParseCommandLine(virCapsPtr caps, *monConfig = chr; } + } else if (STREQ(arg, "-global") && + STRPREFIX(progargv[i + 1], "PIIX4_PM.disable_s3=")) { + /* We want to parse only the known "-global" parameters, + * so the ones that we don't know are still added to the + * namespace */ + WANT_VALUE(); + + val += strlen("PIIX4_PM.disable_s3="); + if (STREQ(val, "0")) + def->pm.s3 = VIR_DOMAIN_PM_STATE_ENABLED; + else if (STREQ(val, "1")) + def->pm.s3 = VIR_DOMAIN_PM_STATE_DISABLED; + else { + virReportError(VIR_ERR_CONFIG_UNSUPPORTED, + _("invalid value for disable_s3 parameter: " + "'%s'"), val); + goto error; + } + + } else if (STREQ(arg, "-global") && + STRPREFIX(progargv[i + 1], "PIIX4_PM.disable_s4=")) { + + WANT_VALUE(); + + val += strlen("PIIX4_PM.disable_s4="); + if (STREQ(val, "0")) + def->pm.s4 = VIR_DOMAIN_PM_STATE_ENABLED; + else if (STREQ(val, "1")) + def->pm.s4 = VIR_DOMAIN_PM_STATE_DISABLED; + else { + virReportError(VIR_ERR_CONFIG_UNSUPPORTED, + _("invalid value for disable_s4 parameter: " + "'%s'"), val); + goto error; + } + } else if (STREQ(arg, "-S")) { /* ignore, always added by libvirt */ } else { diff --git a/src/qemu/qemu_driver.c b/src/qemu/qemu_driver.c index 53d6e5b56e..b12d9bcd24 100644 --- a/src/qemu/qemu_driver.c +++ b/src/qemu/qemu_driver.c @@ -13722,6 +13722,23 @@ qemuDomainPMSuspendForDuration(virDomainPtr dom, goto cleanup; } + if (vm->def->pm.s3 || vm->def->pm.s4) { + if (vm->def->pm.s3 == VIR_DOMAIN_PM_STATE_DISABLED && + (target == VIR_NODE_SUSPEND_TARGET_MEM || + target == VIR_NODE_SUSPEND_TARGET_HYBRID)) { + virReportError(VIR_ERR_INTERNAL_ERROR, "%s", + _("S3 state is disabled for this domain")); + goto cleanup; + } + + if (vm->def->pm.s4 == VIR_DOMAIN_PM_STATE_DISABLED && + target == VIR_NODE_SUSPEND_TARGET_DISK) { + virReportError(VIR_ERR_INTERNAL_ERROR, "%s", + _("S4 state is disabled for this domain")); + goto cleanup; + } + } + if (priv->agentError) { virReportError(VIR_ERR_AGENT_UNRESPONSIVE, "%s", _("QEMU guest agent is not "