On Mon, Jul 22, 2024 at 2:32 PM Michal Privoznik <[email protected]>
wrote:

> The aim of pstore device is to provide a bit of NVRAM storage for
> guest kernel to record oops/panic logs just before the it
> crashes. Typical usage includes usage in combination with a
> watchdog so that the logs can be inspected after the watchdog
> rebooted the machine. While Linux kernel (and possibly Windows
> too) support many backends, in QEMU there's just 'acpi-erst'
> device so stick with that for now. The device must be attached to
> a PCI bus and needs two additional values (well, corresponding
> memory-backend-file needs them): size and path. Despite using
> memory-backeng-file this does NOT add any additional RAM to the
>

*memory-backend-file this does....

guest and thus I've decided to expose it as another device type
> instead of memory model.
>
> Signed-off-by: Michal Privoznik <[email protected]>
> ---
>  docs/formatdomain.rst                         |  32 ++++
>  src/ch/ch_domain.c                            |   1 +
>  src/conf/domain_conf.c                        | 153 ++++++++++++++++++
>  src/conf/domain_conf.h                        |  19 +++
>  src/conf/domain_postparse.c                   |   1 +
>  src/conf/domain_validate.c                    |  30 ++++
>  src/conf/schemas/domaincommon.rng             |  25 +++
>  src/conf/virconftypes.h                       |   2 +
>  src/hyperv/hyperv_driver.c                    |   1 +
>  src/libvirt_private.syms                      |   2 +
>  src/libxl/libxl_driver.c                      |   6 +
>  src/lxc/lxc_driver.c                          |   6 +
>  src/qemu/qemu_command.c                       |   1 +
>  src/qemu/qemu_domain.c                        |   3 +
>  src/qemu/qemu_domain_address.c                |  11 ++
>  src/qemu/qemu_driver.c                        |   3 +
>  src/qemu/qemu_hotplug.c                       |   5 +
>  src/qemu/qemu_validate.c                      |  26 +++
>  src/test/test_driver.c                        |   1 +
>  .../pstore-acpi-erst.x86_64-latest.args       |  36 +++++
>  .../pstore-acpi-erst.x86_64-latest.xml        |   1 +
>  tests/qemuxmlconfdata/pstore-acpi-erst.xml    |  53 ++++++
>  tests/qemuxmlconftest.c                       |   1 +
>  23 files changed, 419 insertions(+)
>  create mode 100644
> tests/qemuxmlconfdata/pstore-acpi-erst.x86_64-latest.args
>  create mode 120000
> tests/qemuxmlconfdata/pstore-acpi-erst.x86_64-latest.xml
>  create mode 100644 tests/qemuxmlconfdata/pstore-acpi-erst.xml
>
> diff --git a/docs/formatdomain.rst b/docs/formatdomain.rst
> index 10584dfe83..8b35005c9e 100644
> --- a/docs/formatdomain.rst
> +++ b/docs/formatdomain.rst
> @@ -8659,6 +8659,38 @@ The optional attribute ``backend`` is required if
> the ``type`` is ``qemu``, the
>     ...
>
>
> +Pstore
> +~~~~~~~~~
> +
> +Pstore is an oops/panic logger that writes its logs to a block device and
> +non-block device before the system crashes. Currently only ACPI Error
> Record
> +Serialization Table, ERST, is supported. This feature is designed for
> storing
> +error records in persistent storage for future reference and/or debugging.
> +:since:`Since v10.6.0`
> +
> +::
> +
> +  ...
> +  <pstore backend='acpi-erst'>
> +    <path>/tmp/guest_acpi_esrt</path>
> +    <size unit='KiB'>8</size>
> +    <address type='pci' domain='0x0000' bus='0x02' slot='0x01'
> function='0x0'/>
> +  </pstore>
> +  ...
> +
> +The ``pstore`` element has one mandatory attribute ``backend`` which
> selects
> +desired backend (only ``acpi-erst`` is accepted for now). Then it has the
> +following child elements:
> +
> +``path``
> +  Represents a path in the host that backs the pstore device in the
> guest. It
> +  is mandatory.
> +
> +``size``
> +  Configures the size of the persistent storage available to the guest.
> It is
> +  mandatory.
> +
> +
>  Security label
>  --------------
>
> diff --git a/src/ch/ch_domain.c b/src/ch/ch_domain.c
> index 8e3e205c8c..e1e14554a8 100644
> --- a/src/ch/ch_domain.c
> +++ b/src/ch/ch_domain.c
> @@ -180,6 +180,7 @@ chValidateDomainDeviceDef(const virDomainDeviceDef
> *dev,
>      case VIR_DOMAIN_DEVICE_IOMMU:
>      case VIR_DOMAIN_DEVICE_AUDIO:
>      case VIR_DOMAIN_DEVICE_CRYPTO:
> +    case VIR_DOMAIN_DEVICE_PSTORE:
>          virReportError(VIR_ERR_CONFIG_UNSUPPORTED,
>                         _("Cloud-Hypervisor doesn't support '%1$s'
> device"),
>                         virDomainDeviceTypeToString(dev->type));
> diff --git a/src/conf/domain_conf.c b/src/conf/domain_conf.c
> index 6733857a3a..12ae8a9526 100644
> --- a/src/conf/domain_conf.c
> +++ b/src/conf/domain_conf.c
> @@ -337,6 +337,7 @@ VIR_ENUM_IMPL(virDomainDevice,
>                "vsock",
>                "audio",
>                "crypto",
> +              "pstore",
>  );
>
>  VIR_ENUM_IMPL(virDomainDiskDevice,
> @@ -1513,6 +1514,11 @@ VIR_ENUM_IMPL(virDomainLaunchSecurity,
>                "s390-pv",
>  );
>
> +VIR_ENUM_IMPL(virDomainPstoreBackend,
> +              VIR_DOMAIN_PSTORE_BACKEND_LAST,
> +              "acpi-erst",
> +);
> +
>  typedef enum {
>      VIR_DOMAIN_NET_VHOSTUSER_MODE_NONE,
>      VIR_DOMAIN_NET_VHOSTUSER_MODE_CLIENT,
> @@ -3548,6 +3554,16 @@ void virDomainMemoryDefFree(virDomainMemoryDef *def)
>      g_free(def);
>  }
>
> +void virDomainPstoreDefFree(virDomainPstoreDef *def)
> +{
> +    if (!def)
> +        return;
> +
> +    g_free(def->path);
> +    virDomainDeviceInfoClear(&def->info);
> +    g_free(def);
> +}
> +
>  void virDomainDeviceDefFree(virDomainDeviceDef *def)
>  {
>      if (!def)
> @@ -3632,6 +3648,9 @@ void virDomainDeviceDefFree(virDomainDeviceDef *def)
>      case VIR_DOMAIN_DEVICE_CRYPTO:
>          virDomainCryptoDefFree(def->data.crypto);
>          break;
> +    case VIR_DOMAIN_DEVICE_PSTORE:
> +        virDomainPstoreDefFree(def->data.pstore);
> +        break;
>      case VIR_DOMAIN_DEVICE_LAST:
>      case VIR_DOMAIN_DEVICE_NONE:
>          break;
> @@ -3997,6 +4016,8 @@ void virDomainDefFree(virDomainDef *def)
>
>      virDomainIOMMUDefFree(def->iommu);
>
> +    virDomainPstoreDefFree(def->pstore);
> +
>      g_free(def->idmap.uidmap);
>      g_free(def->idmap.gidmap);
>
> @@ -4554,6 +4575,8 @@ virDomainDeviceGetInfo(const virDomainDeviceDef
> *device)
>          return &device->data.vsock->info;
>      case VIR_DOMAIN_DEVICE_CRYPTO:
>          return &device->data.crypto->info;
> +    case VIR_DOMAIN_DEVICE_PSTORE:
> +        return &device->data.pstore->info;
>
>      /* The following devices do not contain virDomainDeviceInfo */
>      case VIR_DOMAIN_DEVICE_LEASE:
> @@ -4659,6 +4682,9 @@ virDomainDeviceSetData(virDomainDeviceDef *device,
>      case VIR_DOMAIN_DEVICE_CRYPTO:
>          device->data.crypto = devicedata;
>          break;
> +    case VIR_DOMAIN_DEVICE_PSTORE:
> +        device->data.pstore = devicedata;
> +        break;
>      case VIR_DOMAIN_DEVICE_NONE:
>      case VIR_DOMAIN_DEVICE_LAST:
>          break;
> @@ -4877,6 +4903,13 @@ virDomainDeviceInfoIterateFlags(virDomainDef *def,
>              return rc;
>      }
>
> +    device.type = VIR_DOMAIN_DEVICE_PSTORE;
> +    if (def->pstore) {
> +        device.data.pstore = def->pstore;
> +        if ((rc = cb(def, &device, &def->pstore->info, opaque)) != 0)
> +            return rc;
> +    }
> +
>      /* If the flag below is set, make sure @cb can handle @info being
> NULL */
>      if (iteratorFlags & DOMAIN_DEVICE_ITERATE_MISSING_INFO) {
>          device.type = VIR_DOMAIN_DEVICE_GRAPHICS;
> @@ -4936,6 +4969,7 @@ virDomainDeviceInfoIterateFlags(virDomainDef *def,
>      case VIR_DOMAIN_DEVICE_VSOCK:
>      case VIR_DOMAIN_DEVICE_AUDIO:
>      case VIR_DOMAIN_DEVICE_CRYPTO:
> +    case VIR_DOMAIN_DEVICE_PSTORE:
>          break;
>      }
>  #endif
> @@ -14006,6 +14040,40 @@ virDomainCryptoDefParseXML(virDomainXMLOption
> *xmlopt,
>  }
>
>
> +static virDomainPstoreDef *
> +virDomainPstoreDefParseXML(virDomainXMLOption *xmlopt,
> +                           xmlNodePtr node,
> +                           xmlXPathContextPtr ctxt,
> +                           unsigned int flags)
> +{
> +    g_autoptr(virDomainPstoreDef) def = NULL;
> +    VIR_XPATH_NODE_AUTORESTORE(ctxt)
> +
> +        def = g_new0(virDomainPstoreDef, 1);
> +
> +    ctxt->node = node;
> +
> +    if (virXMLPropEnum(node, "backend",
> +                       virDomainPstoreBackendTypeFromString,
> +                       VIR_XML_PROP_REQUIRED,
> +                       &def->backend) < 0) {
> +        return NULL;
> +    }
> +
> +    def->path = virXPathString("string(./path)", ctxt);
> +
> +    if (virDomainParseMemory("./size", "./size/@unit", ctxt,
> +                             &def->size, true, false) < 0) {
> +        return NULL;
> +    }
> +
> +    if (virDomainDeviceInfoParseXML(xmlopt, node, ctxt, &def->info,
> flags) < 0)
> +        return NULL;
> +
> +    return g_steal_pointer(&def);
> +}
> +
> +
>  static int
>  virDomainDeviceDefParseType(const char *typestr,
>                              virDomainDeviceType *type)
> @@ -14185,6 +14253,12 @@ virDomainDeviceDefParse(const char *xmlStr,
>                                                              flags)))
>              return NULL;
>          break;
> +    case VIR_DOMAIN_DEVICE_PSTORE:
> +        if (!(dev->data.pstore = virDomainPstoreDefParseXML(xmlopt, node,
> +                                                            ctxt,
> flags))) {
> +            return NULL;
> +        }
> +        break;
>      case VIR_DOMAIN_DEVICE_NONE:
>      case VIR_DOMAIN_DEVICE_LAST:
>          break;
> @@ -19532,6 +19606,22 @@ virDomainDefParseXML(xmlXPathContextPtr ctxt,
>      }
>      VIR_FREE(nodes);
>
> +    if ((n = virXPathNodeSet("./devices/pstore", ctxt, &nodes)) < 0)
> +        return NULL;
> +
> +    if (n > 1) {
> +        virReportError(VIR_ERR_XML_ERROR, "%s",
> +                       _("only a single pstore device is supported"));
> +        return NULL;
> +    }
> +
> +    if (n > 0) {
> +        if (!(def->pstore = virDomainPstoreDefParseXML(xmlopt, nodes[0],
> +                                                       ctxt, flags)))
> +            return NULL;
> +    }
> +    VIR_FREE(nodes);
> +
>      /* analysis of the user namespace mapping */
>      if ((n = virXPathNodeSet("./idmap/uid", ctxt, &nodes)) < 0)
>          return NULL;
> @@ -21404,6 +21494,33 @@
> virDomainVsockDefCheckABIStability(virDomainVsockDef *src,
>  }
>
>
> +static bool
> +virDomainPstoreDefCheckABIStability(virDomainPstoreDef *src,
> +                                    virDomainPstoreDef *dst)
> +{
> +    if (src->backend != dst->backend) {
> +        virReportError(VIR_ERR_CONFIG_UNSUPPORTED,
> +                       _("Target pstore device backend '%1$s' does not
> match source '%2$s'"),
> +                       virDomainPstoreBackendTypeToString(dst->backend),
> +                       virDomainPstoreBackendTypeToString(src->backend));
> +        return false;
> +    }
> +
> +    if (src->size != dst->size) {
> +        virReportError(VIR_ERR_CONFIG_UNSUPPORTED,
> +                       _("Target pstore size '%1$llu' does not match
> source '%2$llu'"),
> +                       dst->size,
> +                       src->size);
> +        return false;
> +    }
> +
> +    if (!virDomainDeviceInfoCheckABIStability(&src->info, &dst->info))
> +        return false;
> +
> +    return true;
> +}
> +
> +
>  static bool
>  virDomainDefVcpuCheckAbiStability(virDomainDef *src,
>                                    virDomainDef *dst)
> @@ -21863,6 +21980,17 @@ virDomainDefCheckABIStabilityFlags(virDomainDef
> *src,
>          !virDomainVsockDefCheckABIStability(src->vsock, dst->vsock))
>          goto error;
>
> +    if (!!src->pstore != !!dst->pstore) {
> +        virReportError(VIR_ERR_CONFIG_UNSUPPORTED, "%s",
> +                       _("Target domain pstore device count does not
> match source"));
> +        goto error;
> +    }
> +
> +    if (src->pstore &&
> +        !virDomainPstoreDefCheckABIStability(src->pstore, dst->pstore)) {
> +        goto error;
> +    }
> +
>      if (xmlopt && xmlopt->abi.domain &&
>          !xmlopt->abi.domain(src, dst))
>          goto error;
> @@ -21903,6 +22031,7 @@ virDomainDefCheckABIStabilityFlags(virDomainDef
> *src,
>      case VIR_DOMAIN_DEVICE_VSOCK:
>      case VIR_DOMAIN_DEVICE_AUDIO:
>      case VIR_DOMAIN_DEVICE_CRYPTO:
> +    case VIR_DOMAIN_DEVICE_PSTORE:
>          break;
>      }
>  #endif
> @@ -27849,6 +27978,26 @@ virDomainDefFormatFeatures(virBuffer *buf,
>      return 0;
>  }
>
> +static int
> +virDomainPstoreDefFormat(virBuffer *buf,
> +                         virDomainPstoreDef *pstore,
> +                         unsigned int flags)
> +{
> +    g_auto(virBuffer) attrBuf = VIR_BUFFER_INITIALIZER;
> +    g_auto(virBuffer) childBuf = VIR_BUFFER_INIT_CHILD(buf);
> +
> +    virBufferAsprintf(&attrBuf, " backend='%s'",
> +
> virDomainPstoreBackendTypeToString(pstore->backend));
> +
> +    virBufferAsprintf(&childBuf, "<path>%s</path>\n", pstore->path);
> +    virBufferAsprintf(&childBuf, "<size unit='KiB'>%llu</size>\n",
> pstore->size);
> +    virDomainDeviceInfoFormat(&childBuf, &pstore->info, flags);
> +
> +    virXMLFormatElement(buf, "pstore", &attrBuf, &childBuf);
> +    return 0;
> +}
> +
> +
>  int
>  virDomainDefFormatInternal(virDomainDef *def,
>                             virDomainXMLOption *xmlopt,
> @@ -28320,6 +28469,9 @@ virDomainDefFormatInternalSetRootName(virDomainDef
> *def,
>      if (def->vsock)
>          virDomainVsockDefFormat(buf, def->vsock);
>
> +    if (def->pstore)
> +        virDomainPstoreDefFormat(buf, def->pstore, flags);
> +
>      virBufferAdjustIndent(buf, -2);
>      virBufferAddLit(buf, "</devices>\n");
>
> @@ -28479,6 +28631,7 @@ virDomainDeviceIsUSB(virDomainDeviceDef *dev,
>      case VIR_DOMAIN_DEVICE_VSOCK:
>      case VIR_DOMAIN_DEVICE_AUDIO:
>      case VIR_DOMAIN_DEVICE_CRYPTO:
> +    case VIR_DOMAIN_DEVICE_PSTORE:
>      break;
>      }
>
> diff --git a/src/conf/domain_conf.h b/src/conf/domain_conf.h
> index 8283493dfc..546c14e7b0 100644
> --- a/src/conf/domain_conf.h
> +++ b/src/conf/domain_conf.h
> @@ -87,6 +87,7 @@ typedef enum {
>      VIR_DOMAIN_DEVICE_VSOCK,
>      VIR_DOMAIN_DEVICE_AUDIO,
>      VIR_DOMAIN_DEVICE_CRYPTO,
> +    VIR_DOMAIN_DEVICE_PSTORE,
>
>      VIR_DOMAIN_DEVICE_LAST
>  } virDomainDeviceType;
> @@ -120,6 +121,7 @@ struct _virDomainDeviceDef {
>          virDomainVsockDef *vsock;
>          virDomainAudioDef *audio;
>          virDomainCryptoDef *crypto;
> +        virDomainPstoreDef *pstore;
>      } data;
>  };
>
> @@ -2983,6 +2985,19 @@ struct _virDomainVirtioOptions {
>      virTristateSwitch page_per_vq;
>  };
>
> +typedef enum {
> +    VIR_DOMAIN_PSTORE_BACKEND_ACPI_ERST,
> +
> +    VIR_DOMAIN_PSTORE_BACKEND_LAST
> +} virDomainPstoreBackend;
> +
> +struct _virDomainPstoreDef {
> +    virDomainPstoreBackend backend;
> +    unsigned long long size;
> +    char *path;
> +    virDomainDeviceInfo info;
> +};
> +
>
>  #define SCSI_SUPER_WIDE_BUS_MAX_CONT_UNIT 64
>  #define SCSI_WIDE_BUS_MAX_CONT_UNIT 16
> @@ -3159,6 +3174,7 @@ struct _virDomainDef {
>      virDomainRedirFilterDef *redirfilter;
>      virDomainIOMMUDef *iommu;
>      virDomainVsockDef *vsock;
> +    virDomainPstoreDef *pstore;
>
>      void *namespaceData;
>      virXMLNamespace ns;
> @@ -3598,6 +3614,8 @@ void virDomainVsockDefFree(virDomainVsockDef *vsock);
>  G_DEFINE_AUTOPTR_CLEANUP_FUNC(virDomainVsockDef, virDomainVsockDefFree);
>  void virDomainCryptoDefFree(virDomainCryptoDef *def);
>  G_DEFINE_AUTOPTR_CLEANUP_FUNC(virDomainCryptoDef, virDomainCryptoDefFree);
> +void virDomainPstoreDefFree(virDomainPstoreDef *def);
> +G_DEFINE_AUTOPTR_CLEANUP_FUNC(virDomainPstoreDef, virDomainPstoreDefFree);
>  void virDomainNetTeamingInfoFree(virDomainNetTeamingInfo *teaming);
>  G_DEFINE_AUTOPTR_CLEANUP_FUNC(virDomainNetTeamingInfo,
> virDomainNetTeamingInfoFree);
>  void virDomainNetPortForwardFree(virDomainNetPortForward *pf);
> @@ -4268,6 +4286,7 @@ VIR_ENUM_DECL(virDomainCryptoBackend);
>  VIR_ENUM_DECL(virDomainShmemModel);
>  VIR_ENUM_DECL(virDomainShmemRole);
>  VIR_ENUM_DECL(virDomainLaunchSecurity);
> +VIR_ENUM_DECL(virDomainPstoreBackend);
>  /* from libvirt.h */
>  VIR_ENUM_DECL(virDomainState);
>  VIR_ENUM_DECL(virDomainNostateReason);
> diff --git a/src/conf/domain_postparse.c b/src/conf/domain_postparse.c
> index 112795ea65..bf33f29638 100644
> --- a/src/conf/domain_postparse.c
> +++ b/src/conf/domain_postparse.c
> @@ -757,6 +757,7 @@ virDomainDeviceDefPostParseCommon(virDomainDeviceDef
> *dev,
>      case VIR_DOMAIN_DEVICE_IOMMU:
>      case VIR_DOMAIN_DEVICE_AUDIO:
>      case VIR_DOMAIN_DEVICE_CRYPTO:
> +    case VIR_DOMAIN_DEVICE_PSTORE:
>          ret = 0;
>          break;
>
> diff --git a/src/conf/domain_validate.c b/src/conf/domain_validate.c
> index 8209e8fdae..39b8d67928 100644
> --- a/src/conf/domain_validate.c
> +++ b/src/conf/domain_validate.c
> @@ -3022,6 +3022,33 @@ virDomainTPMDevValidate(const virDomainTPMDef *tpm)
>  }
>
>
> +static int
> +virDomainPstoreDefValidate(const virDomainPstoreDef *pstore)
> +{
> +    if (pstore->backend != VIR_DOMAIN_PSTORE_BACKEND_ACPI_ERST) {
> +        virReportError(VIR_ERR_CONFIG_UNSUPPORTED,
> +                       _("unsupported backend for pstore device: %1$s"),
> +
>  virDomainPstoreBackendTypeToString(pstore->backend));
> +        return -1;
> +    }
> +
> +    if (pstore->path == NULL || pstore->path[0] == '\0') {
> +        virReportError(VIR_ERR_XML_ERROR, "%s",
> +                       _("missing path for ACPI ERST pstore device"));
> +        return -1;
> +    }
> +
> +    if (pstore->size < 4 ||
> +        !VIR_IS_POW2(pstore->size)) {
> +        virReportError(VIR_ERR_XML_ERROR, "%s",
> +                       _("invalid size of ACPI ERST pstore device"));
> +        return -1;
> +    }
> +
> +    return 0;
> +}
> +
> +
>  static int
>  virDomainDeviceInfoValidate(const virDomainDeviceDef *dev)
>  {
> @@ -3132,6 +3159,9 @@ virDomainDeviceDefValidateInternal(const
> virDomainDeviceDef *dev,
>      case VIR_DOMAIN_DEVICE_TPM:
>          return virDomainTPMDevValidate(dev->data.tpm);
>
> +    case VIR_DOMAIN_DEVICE_PSTORE:
> +        return virDomainPstoreDefValidate(dev->data.pstore);
> +
>      case VIR_DOMAIN_DEVICE_LEASE:
>      case VIR_DOMAIN_DEVICE_WATCHDOG:
>      case VIR_DOMAIN_DEVICE_HUB:
> diff --git a/src/conf/schemas/domaincommon.rng
> b/src/conf/schemas/domaincommon.rng
> index ab5374d5f0..200009efa5 100644
> --- a/src/conf/schemas/domaincommon.rng
> +++ b/src/conf/schemas/domaincommon.rng
> @@ -6255,6 +6255,28 @@
>      </element>
>    </define>
>
> +  <define name="pstore">
> +    <element name="pstore">
> +      <attribute name="backend">
> +        <value>acpi-erst</value>
> +      </attribute>
> +      <interleave>
> +        <element name="path">
> +          <ref name="absFilePath"/>
> +        </element>
> +        <element name="size">
> +          <ref name="scaledInteger"/>
> +        </element>
> +        <optional>
> +          <ref name="address"/>
> +        </optional>
> +        <optional>
> +          <ref name="alias"/>
> +        </optional>
> +      </interleave>
> +    </element>
> +  </define>
> +
>    <define name="hostdev">
>      <element name="hostdev">
>        <interleave>
> @@ -6724,6 +6746,9 @@
>          <optional>
>            <ref name="vsock"/>
>          </optional>
> +        <optional>
> +          <ref name="pstore"/>
> +        </optional>
>        </interleave>
>      </element>
>    </define>
> diff --git a/src/conf/virconftypes.h b/src/conf/virconftypes.h
> index d8e7c5278c..f18ebcca10 100644
> --- a/src/conf/virconftypes.h
> +++ b/src/conf/virconftypes.h
> @@ -260,6 +260,8 @@ typedef struct _virDomainVsockDef virDomainVsockDef;
>
>  typedef struct _virDomainCryptoDef virDomainCryptoDef;
>
> +typedef struct _virDomainPstoreDef virDomainPstoreDef;
> +
>  typedef struct _virDomainWatchdogDef virDomainWatchdogDef;
>
>  typedef struct _virDomainXMLOption virDomainXMLOption;
> diff --git a/src/hyperv/hyperv_driver.c b/src/hyperv/hyperv_driver.c
> index 7580c6a06c..43ccb9cbd7 100644
> --- a/src/hyperv/hyperv_driver.c
> +++ b/src/hyperv/hyperv_driver.c
> @@ -3133,6 +3133,7 @@ hypervDomainAttachDeviceFlags(virDomainPtr domain,
> const char *xml, unsigned int
>      case VIR_DOMAIN_DEVICE_VSOCK:
>      case VIR_DOMAIN_DEVICE_AUDIO:
>      case VIR_DOMAIN_DEVICE_CRYPTO:
> +    case VIR_DOMAIN_DEVICE_PSTORE:
>          virReportError(VIR_ERR_INTERNAL_ERROR,
>                         _("Attaching devices of type %1$d is not
> implemented"), dev->type);
>          return -1;
> diff --git a/src/libvirt_private.syms b/src/libvirt_private.syms
> index c35366c9e1..d15d6a6a9d 100644
> --- a/src/libvirt_private.syms
> +++ b/src/libvirt_private.syms
> @@ -616,6 +616,8 @@ virDomainPausedReasonTypeToString;
>  virDomainPMSuspendedReasonTypeFromString;
>  virDomainPMSuspendedReasonTypeToString;
>  virDomainProcessCapsFeatureTypeToString;
> +virDomainPstoreBackendTypeFromString;
> +virDomainPstoreBackendTypeToString;
>  virDomainRedirdevBusTypeFromString;
>  virDomainRedirdevBusTypeToString;
>  virDomainRedirdevDefFind;
> diff --git a/src/libxl/libxl_driver.c b/src/libxl/libxl_driver.c
> index 7dcae58413..e72553603d 100644
> --- a/src/libxl/libxl_driver.c
> +++ b/src/libxl/libxl_driver.c
> @@ -3505,6 +3505,7 @@ libxlDomainAttachDeviceLive(libxlDriverPrivate
> *driver,
>          case VIR_DOMAIN_DEVICE_VSOCK:
>          case VIR_DOMAIN_DEVICE_AUDIO:
>          case VIR_DOMAIN_DEVICE_CRYPTO:
> +        case VIR_DOMAIN_DEVICE_PSTORE:
>              virReportError(VIR_ERR_CONFIG_UNSUPPORTED,
>                             _("device type '%1$s' cannot be attached"),
>                             virDomainDeviceTypeToString(dev->type));
> @@ -3613,6 +3614,7 @@ libxlDomainAttachDeviceConfig(virDomainDef *vmdef,
> virDomainDeviceDef *dev)
>          case VIR_DOMAIN_DEVICE_VSOCK:
>          case VIR_DOMAIN_DEVICE_AUDIO:
>          case VIR_DOMAIN_DEVICE_CRYPTO:
> +        case VIR_DOMAIN_DEVICE_PSTORE:
>              virReportError(VIR_ERR_CONFIG_UNSUPPORTED, "%s",
>                             _("persistent attach of device is not
> supported"));
>              return -1;
> @@ -3981,6 +3983,7 @@ libxlDomainDetachDeviceLive(libxlDriverPrivate
> *driver,
>          case VIR_DOMAIN_DEVICE_VSOCK:
>          case VIR_DOMAIN_DEVICE_AUDIO:
>          case VIR_DOMAIN_DEVICE_CRYPTO:
> +        case VIR_DOMAIN_DEVICE_PSTORE:
>              virReportError(VIR_ERR_CONFIG_UNSUPPORTED,
>                             _("device type '%1$s' cannot be detached"),
>                             virDomainDeviceTypeToString(dev->type));
> @@ -4071,6 +4074,7 @@ libxlDomainDetachDeviceConfig(virDomainDef *vmdef,
> virDomainDeviceDef *dev)
>          case VIR_DOMAIN_DEVICE_VSOCK:
>          case VIR_DOMAIN_DEVICE_AUDIO:
>          case VIR_DOMAIN_DEVICE_CRYPTO:
> +        case VIR_DOMAIN_DEVICE_PSTORE:
>              virReportError(VIR_ERR_CONFIG_UNSUPPORTED, "%s",
>                             _("persistent detach of device is not
> supported"));
>              return -1;
> @@ -4133,6 +4137,7 @@ libxlDomainUpdateDeviceLive(virDomainObj *vm,
> virDomainDeviceDef *dev)
>          case VIR_DOMAIN_DEVICE_VSOCK:
>          case VIR_DOMAIN_DEVICE_AUDIO:
>          case VIR_DOMAIN_DEVICE_CRYPTO:
> +        case VIR_DOMAIN_DEVICE_PSTORE:
>              virReportError(VIR_ERR_CONFIG_UNSUPPORTED,
>                             _("device type '%1$s' cannot be updated"),
>                             virDomainDeviceTypeToString(dev->type));
> @@ -4195,6 +4200,7 @@ libxlDomainUpdateDeviceConfig(virDomainDef *vmdef,
> virDomainDeviceDef *dev)
>          case VIR_DOMAIN_DEVICE_VSOCK:
>          case VIR_DOMAIN_DEVICE_AUDIO:
>          case VIR_DOMAIN_DEVICE_CRYPTO:
> +        case VIR_DOMAIN_DEVICE_PSTORE:
>              virReportError(VIR_ERR_CONFIG_UNSUPPORTED, "%s",
>                             _("persistent update of device is not
> supported"));
>              return -1;
> diff --git a/src/lxc/lxc_driver.c b/src/lxc/lxc_driver.c
> index f76d09e8a9..534e257f30 100644
> --- a/src/lxc/lxc_driver.c
> +++ b/src/lxc/lxc_driver.c
> @@ -3056,6 +3056,7 @@ lxcDomainAttachDeviceConfig(virDomainDef *vmdef,
>      case VIR_DOMAIN_DEVICE_VSOCK:
>      case VIR_DOMAIN_DEVICE_AUDIO:
>      case VIR_DOMAIN_DEVICE_CRYPTO:
> +    case VIR_DOMAIN_DEVICE_PSTORE:
>           virReportError(VIR_ERR_CONFIG_UNSUPPORTED, "%s",
>                          _("persistent attach of device is not
> supported"));
>           break;
> @@ -3121,6 +3122,7 @@ lxcDomainUpdateDeviceConfig(virDomainDef *vmdef,
>      case VIR_DOMAIN_DEVICE_VSOCK:
>      case VIR_DOMAIN_DEVICE_AUDIO:
>      case VIR_DOMAIN_DEVICE_CRYPTO:
> +    case VIR_DOMAIN_DEVICE_PSTORE:
>          virReportError(VIR_ERR_CONFIG_UNSUPPORTED, "%s",
>                         _("persistent update of device is not supported"));
>          break;
> @@ -3202,6 +3204,7 @@ lxcDomainDetachDeviceConfig(virDomainDef *vmdef,
>      case VIR_DOMAIN_DEVICE_VSOCK:
>      case VIR_DOMAIN_DEVICE_CRYPTO:
>      case VIR_DOMAIN_DEVICE_AUDIO:
> +    case VIR_DOMAIN_DEVICE_PSTORE:
>          virReportError(VIR_ERR_CONFIG_UNSUPPORTED, "%s",
>                         _("persistent detach of device is not supported"));
>          break;
> @@ -3303,6 +3306,7 @@ lxcDomainAttachDeviceMknodHelper(pid_t pid
> G_GNUC_UNUSED,
>      case VIR_DOMAIN_DEVICE_VSOCK:
>      case VIR_DOMAIN_DEVICE_AUDIO:
>      case VIR_DOMAIN_DEVICE_CRYPTO:
> +    case VIR_DOMAIN_DEVICE_PSTORE:
>          virReportError(VIR_ERR_INTERNAL_ERROR,
>                         _("Unexpected device type %1$d"),
>                         data->def->type);
> @@ -3974,6 +3978,7 @@ lxcDomainAttachDeviceLive(virLXCDriver *driver,
>      case VIR_DOMAIN_DEVICE_VSOCK:
>      case VIR_DOMAIN_DEVICE_AUDIO:
>      case VIR_DOMAIN_DEVICE_CRYPTO:
> +    case VIR_DOMAIN_DEVICE_PSTORE:
>          virReportError(VIR_ERR_CONFIG_UNSUPPORTED,
>                         _("device type '%1$s' cannot be attached"),
>                         virDomainDeviceTypeToString(dev->type));
> @@ -4391,6 +4396,7 @@ lxcDomainDetachDeviceLive(virLXCDriver *driver,
>      case VIR_DOMAIN_DEVICE_VSOCK:
>      case VIR_DOMAIN_DEVICE_AUDIO:
>      case VIR_DOMAIN_DEVICE_CRYPTO:
> +    case VIR_DOMAIN_DEVICE_PSTORE:
>          virReportError(VIR_ERR_CONFIG_UNSUPPORTED,
>                         _("device type '%1$s' cannot be detached"),
>                         virDomainDeviceTypeToString(dev->type));
> diff --git a/src/qemu/qemu_command.c b/src/qemu/qemu_command.c
> index 684de3f701..def124cc27 100644
> --- a/src/qemu/qemu_command.c
> +++ b/src/qemu/qemu_command.c
> @@ -973,6 +973,7 @@ qemuBuildVirtioDevGetConfigDev(const
> virDomainDeviceDef *device,
>          case VIR_DOMAIN_DEVICE_MEMORY:
>          case VIR_DOMAIN_DEVICE_IOMMU:
>          case VIR_DOMAIN_DEVICE_AUDIO:
> +        case VIR_DOMAIN_DEVICE_PSTORE:
>          case VIR_DOMAIN_DEVICE_LAST:
>          default:
>              break;
> diff --git a/src/qemu/qemu_domain.c b/src/qemu/qemu_domain.c
> index 2134b11038..a8d7a1e525 100644
> --- a/src/qemu/qemu_domain.c
> +++ b/src/qemu/qemu_domain.c
> @@ -6358,6 +6358,7 @@ qemuDomainDeviceDefPostParse(virDomainDeviceDef *dev,
>      case VIR_DOMAIN_DEVICE_IOMMU:
>      case VIR_DOMAIN_DEVICE_AUDIO:
>      case VIR_DOMAIN_DEVICE_CRYPTO:
> +    case VIR_DOMAIN_DEVICE_PSTORE:
>          ret = 0;
>          break;
>
> @@ -10360,6 +10361,7 @@
> qemuDomainPrepareChardevSourceOne(virDomainDeviceDef *dev,
>      case VIR_DOMAIN_DEVICE_VSOCK:
>      case VIR_DOMAIN_DEVICE_AUDIO:
>      case VIR_DOMAIN_DEVICE_CRYPTO:
> +    case VIR_DOMAIN_DEVICE_PSTORE:
>          break;
>      }
>
> @@ -12290,6 +12292,7 @@
> qemuDomainDeviceBackendChardevForeachOne(virDomainDeviceDef *dev,
>      case VIR_DOMAIN_DEVICE_VSOCK:
>      case VIR_DOMAIN_DEVICE_AUDIO:
>      case VIR_DOMAIN_DEVICE_CRYPTO:
> +    case VIR_DOMAIN_DEVICE_PSTORE:
>          /* no chardev backend */
>          break;
>      }
> diff --git a/src/qemu/qemu_domain_address.c
> b/src/qemu/qemu_domain_address.c
> index 251f5b7e1a..970ae3949d 100644
> --- a/src/qemu/qemu_domain_address.c
> +++ b/src/qemu/qemu_domain_address.c
> @@ -470,6 +470,7 @@ qemuDomainDeviceSupportZPCI(virDomainDeviceDef *device)
>      case VIR_DOMAIN_DEVICE_VSOCK:
>      case VIR_DOMAIN_DEVICE_AUDIO:
>      case VIR_DOMAIN_DEVICE_CRYPTO:
> +    case VIR_DOMAIN_DEVICE_PSTORE:
>          break;
>
>      case VIR_DOMAIN_DEVICE_NONE:
> @@ -1002,6 +1003,9 @@
> qemuDomainDeviceCalculatePCIConnectFlags(virDomainDeviceDef *dev,
>          }
>          break;
>
> +    case VIR_DOMAIN_DEVICE_PSTORE:
> +        return pciFlags;
> +
>          /* These devices don't ever connect with PCI */
>      case VIR_DOMAIN_DEVICE_NVRAM:
>      case VIR_DOMAIN_DEVICE_TPM:
> @@ -2424,6 +2428,13 @@ qemuDomainAssignDevicePCISlots(virDomainDef *def,
>          }
>      }
>
> +    if (def->pstore &&
> +        virDeviceInfoPCIAddressIsWanted(&def->pstore->info)) {
> +        if (qemuDomainPCIAddressReserveNextAddr(addrs,
> +                                                &def->pstore->info) < 0)
> +            return -1;
> +    }
> +
>      return 0;
>  }
>
> diff --git a/src/qemu/qemu_driver.c b/src/qemu/qemu_driver.c
> index 9f3013e231..e473018ef2 100644
> --- a/src/qemu/qemu_driver.c
> +++ b/src/qemu/qemu_driver.c
> @@ -6863,6 +6863,7 @@ qemuDomainAttachDeviceConfig(virDomainDef *vmdef,
>      case VIR_DOMAIN_DEVICE_PANIC:
>      case VIR_DOMAIN_DEVICE_AUDIO:
>      case VIR_DOMAIN_DEVICE_CRYPTO:
> +    case VIR_DOMAIN_DEVICE_PSTORE:
>      case VIR_DOMAIN_DEVICE_LAST:
>           virReportError(VIR_ERR_OPERATION_UNSUPPORTED,
>                          _("persistent attach of device '%1$s' is not
> supported"),
> @@ -7081,6 +7082,7 @@ qemuDomainDetachDeviceConfig(virDomainDef *vmdef,
>      case VIR_DOMAIN_DEVICE_PANIC:
>      case VIR_DOMAIN_DEVICE_AUDIO:
>      case VIR_DOMAIN_DEVICE_CRYPTO:
> +    case VIR_DOMAIN_DEVICE_PSTORE:
>      case VIR_DOMAIN_DEVICE_LAST:
>          virReportError(VIR_ERR_OPERATION_UNSUPPORTED,
>                         _("persistent detach of device '%1$s' is not
> supported"),
> @@ -7206,6 +7208,7 @@ qemuDomainUpdateDeviceConfig(virDomainDef *vmdef,
>      case VIR_DOMAIN_DEVICE_VSOCK:
>      case VIR_DOMAIN_DEVICE_AUDIO:
>      case VIR_DOMAIN_DEVICE_CRYPTO:
> +    case VIR_DOMAIN_DEVICE_PSTORE:
>      case VIR_DOMAIN_DEVICE_LAST:
>          virReportError(VIR_ERR_OPERATION_UNSUPPORTED,
>                         _("persistent update of device '%1$s' is not
> supported"),
> diff --git a/src/qemu/qemu_hotplug.c b/src/qemu/qemu_hotplug.c
> index 1f4620d833..af4229d507 100644
> --- a/src/qemu/qemu_hotplug.c
> +++ b/src/qemu/qemu_hotplug.c
> @@ -3452,6 +3452,7 @@ qemuDomainAttachDeviceLive(virDomainObj *vm,
>      case VIR_DOMAIN_DEVICE_IOMMU:
>      case VIR_DOMAIN_DEVICE_AUDIO:
>      case VIR_DOMAIN_DEVICE_CRYPTO:
> +    case VIR_DOMAIN_DEVICE_PSTORE:
>      case VIR_DOMAIN_DEVICE_LAST:
>          virReportError(VIR_ERR_OPERATION_UNSUPPORTED,
>                         _("live attach of device '%1$s' is not supported"),
> @@ -5282,6 +5283,7 @@ qemuDomainRemoveAuditDevice(virDomainObj *vm,
>      case VIR_DOMAIN_DEVICE_IOMMU:
>      case VIR_DOMAIN_DEVICE_AUDIO:
>      case VIR_DOMAIN_DEVICE_CRYPTO:
> +    case VIR_DOMAIN_DEVICE_PSTORE:
>      case VIR_DOMAIN_DEVICE_LAST:
>          /* libvirt doesn't yet support detaching these devices */
>          break;
> @@ -5386,6 +5388,7 @@ qemuDomainRemoveDevice(virQEMUDriver *driver,
>      case VIR_DOMAIN_DEVICE_IOMMU:
>      case VIR_DOMAIN_DEVICE_AUDIO:
>      case VIR_DOMAIN_DEVICE_CRYPTO:
> +    case VIR_DOMAIN_DEVICE_PSTORE:
>      case VIR_DOMAIN_DEVICE_LAST:
>          virReportError(VIR_ERR_OPERATION_UNSUPPORTED,
>                         _("don't know how to remove a %1$s device"),
> @@ -6270,6 +6273,7 @@ qemuDomainDetachDeviceLive(virDomainObj *vm,
>      case VIR_DOMAIN_DEVICE_IOMMU:
>      case VIR_DOMAIN_DEVICE_AUDIO:
>      case VIR_DOMAIN_DEVICE_CRYPTO:
> +    case VIR_DOMAIN_DEVICE_PSTORE:
>      case VIR_DOMAIN_DEVICE_LAST:
>          virReportError(VIR_ERR_OPERATION_UNSUPPORTED,
>                         _("live detach of device '%1$s' is not supported"),
> @@ -7259,6 +7263,7 @@ qemuDomainUpdateDeviceLive(virDomainObj *vm,
>      case VIR_DOMAIN_DEVICE_VSOCK:
>      case VIR_DOMAIN_DEVICE_AUDIO:
>      case VIR_DOMAIN_DEVICE_CRYPTO:
> +    case VIR_DOMAIN_DEVICE_PSTORE:
>      case VIR_DOMAIN_DEVICE_LAST:
>          virReportError(VIR_ERR_CONFIG_UNSUPPORTED,
>                         _("live update of device '%1$s' is not supported"),
> diff --git a/src/qemu/qemu_validate.c b/src/qemu/qemu_validate.c
> index 8840306bfd..0e8f0f977f 100644
> --- a/src/qemu/qemu_validate.c
> +++ b/src/qemu/qemu_validate.c
> @@ -4669,6 +4669,29 @@
> qemuValidateDomainDeviceDefCrypto(virDomainCryptoDef *crypto,
>  }
>
>
> +static int
> +qemuValidateDomainDeviceDefPstore(virDomainPstoreDef *pstore,
> +                                  const virDomainDef *def G_GNUC_UNUSED,
> +                                  virQEMUCaps *qemuCaps)
> +{
> +    if (pstore->backend == VIR_DOMAIN_PSTORE_BACKEND_ACPI_ERST &&
> +        !virQEMUCapsGet(qemuCaps, QEMU_CAPS_DEVICE_ACPI_ERST)) {
> +        virReportError(VIR_ERR_CONFIG_UNSUPPORTED, "%s",
> +                       _("acpi-erst backend of pstore device is not
> supported"));
> +        return -1;
> +    }
> +
> +    if (pstore->info.type != VIR_DOMAIN_DEVICE_ADDRESS_TYPE_NONE &&
> +        pstore->info.type != VIR_DOMAIN_DEVICE_ADDRESS_TYPE_PCI) {
> +        virReportError(VIR_ERR_CONFIG_UNSUPPORTED, "%s",
> +                       _("ACPI ERST device must reside on a PCI bus"));
> +        return -1;
> +    }
> +
> +    return 0;
> +}
> +
> +
>  static int
>  qemuSoundCodecTypeToCaps(int type)
>  {
> @@ -5372,6 +5395,9 @@ qemuValidateDomainDeviceDef(const virDomainDeviceDef
> *dev,
>      case VIR_DOMAIN_DEVICE_CRYPTO:
>          return qemuValidateDomainDeviceDefCrypto(dev->data.crypto, def,
> qemuCaps);
>
> +    case VIR_DOMAIN_DEVICE_PSTORE:
> +        return qemuValidateDomainDeviceDefPstore(dev->data.pstore, def,
> qemuCaps);
> +
>      case VIR_DOMAIN_DEVICE_LEASE:
>      case VIR_DOMAIN_DEVICE_PANIC:
>      case VIR_DOMAIN_DEVICE_NONE:
> diff --git a/src/test/test_driver.c b/src/test/test_driver.c
> index df6a86ea44..7cb77f044d 100644
> --- a/src/test/test_driver.c
> +++ b/src/test/test_driver.c
> @@ -10294,6 +10294,7 @@ testDomainUpdateDevice(virDomainDef *vmdef,
>      case VIR_DOMAIN_DEVICE_VSOCK:
>      case VIR_DOMAIN_DEVICE_AUDIO:
>      case VIR_DOMAIN_DEVICE_CRYPTO:
> +    case VIR_DOMAIN_DEVICE_PSTORE:
>      case VIR_DOMAIN_DEVICE_LAST:
>          virReportError(VIR_ERR_OPERATION_UNSUPPORTED,
>                         _("persistent update of device '%1$s' is not
> supported"),
> diff --git a/tests/qemuxmlconfdata/pstore-acpi-erst.x86_64-latest.args
> b/tests/qemuxmlconfdata/pstore-acpi-erst.x86_64-latest.args
> new file mode 100644
> index 0000000000..d7c4708acb
> --- /dev/null
> +++ b/tests/qemuxmlconfdata/pstore-acpi-erst.x86_64-latest.args
> @@ -0,0 +1,36 @@
> +LC_ALL=C \
> +PATH=/bin \
> +HOME=/var/lib/libvirt/qemu/domain--1-guest \
> +USER=test \
> +LOGNAME=test \
> +XDG_DATA_HOME=/var/lib/libvirt/qemu/domain--1-guest/.local/share \
> +XDG_CACHE_HOME=/var/lib/libvirt/qemu/domain--1-guest/.cache \
> +XDG_CONFIG_HOME=/var/lib/libvirt/qemu/domain--1-guest/.config \
> +/usr/bin/qemu-system-x86_64 \
> +-name guest=guest,debug-threads=on \
> +-S \
> +-object
> '{"qom-type":"secret","id":"masterKey0","format":"raw","file":"/var/lib/libvirt/qemu/domain--1-guest/master-key.aes"}'
> \
> +-machine
> pc-q35-9.0,usb=off,dump-guest-core=off,memory-backend=pc.ram,acpi=on \
> +-accel kvm \
> +-cpu qemu64 \
> +-m size=1048576k \
> +-object
> '{"qom-type":"memory-backend-ram","id":"pc.ram","size":1073741824}' \
> +-overcommit mem-lock=off \
> +-smp 1,sockets=1,cores=1,threads=1 \
> +-uuid 63840878-0deb-4095-97e6-fc444d9bc9fa \
> +-display none \
> +-no-user-config \
> +-nodefaults \
> +-chardev socket,id=charmonitor,fd=1729,server=on,wait=off \
> +-mon chardev=charmonitor,id=monitor,mode=control \
> +-rtc base=utc \
> +-no-shutdown \
> +-boot strict=on \
> +-device
> '{"driver":"pcie-root-port","port":8,"chassis":1,"id":"pci.1","bus":"pcie.0","multifunction":true,"addr":"0x1"}'
> \
> +-device
> '{"driver":"pcie-pci-bridge","id":"pci.2","bus":"pci.1","addr":"0x0"}' \
> +-device
> '{"driver":"pcie-root-port","port":9,"chassis":3,"id":"pci.3","bus":"pcie.0","addr":"0x1.0x1"}'
> \
> +-audiodev '{"id":"audio1","driver":"none"}' \
> +-global ICH9-LPC.noreboot=off \
> +-watchdog-action reset \
> +-sandbox
> on,obsolete=deny,elevateprivileges=deny,spawn=deny,resourcecontrol=deny \
> +-msg timestamp=on
> diff --git a/tests/qemuxmlconfdata/pstore-acpi-erst.x86_64-latest.xml
> b/tests/qemuxmlconfdata/pstore-acpi-erst.x86_64-latest.xml
> new file mode 120000
> index 0000000000..11ade68605
> --- /dev/null
> +++ b/tests/qemuxmlconfdata/pstore-acpi-erst.x86_64-latest.xml
> @@ -0,0 +1 @@
> +pstore-acpi-erst.xml
> \ No newline at end of file
> diff --git a/tests/qemuxmlconfdata/pstore-acpi-erst.xml
> b/tests/qemuxmlconfdata/pstore-acpi-erst.xml
> new file mode 100644
> index 0000000000..9b9ba266b2
> --- /dev/null
> +++ b/tests/qemuxmlconfdata/pstore-acpi-erst.xml
> @@ -0,0 +1,53 @@
> +<domain type='kvm'>
> +  <name>guest</name>
> +  <uuid>63840878-0deb-4095-97e6-fc444d9bc9fa</uuid>
> +  <memory unit='KiB'>1048576</memory>
> +  <currentMemory unit='KiB'>1048576</currentMemory>
> +  <vcpu placement='static'>1</vcpu>
> +  <os>
> +    <type arch='x86_64' machine='pc-q35-9.0'>hvm</type>
> +    <boot dev='hd'/>
> +  </os>
> +  <features>
> +    <acpi/>
> +  </features>
> +  <cpu mode='custom' match='exact' check='none'>
> +    <model fallback='forbid'>qemu64</model>
> +  </cpu>
> +  <clock offset='utc'/>
> +  <on_poweroff>destroy</on_poweroff>
> +  <on_reboot>restart</on_reboot>
> +  <on_crash>destroy</on_crash>
> +  <devices>
> +    <emulator>/usr/bin/qemu-system-x86_64</emulator>
> +    <controller type='usb' index='0' model='none'/>
> +    <controller type='sata' index='0'>
> +      <address type='pci' domain='0x0000' bus='0x00' slot='0x1f'
> function='0x2'/>
> +    </controller>
> +    <controller type='pci' index='0' model='pcie-root'/>
> +    <controller type='pci' index='1' model='pcie-root-port'>
> +      <model name='pcie-root-port'/>
> +      <target chassis='1' port='0x8'/>
> +      <address type='pci' domain='0x0000' bus='0x00' slot='0x01'
> function='0x0' multifunction='on'/>
> +    </controller>
> +    <controller type='pci' index='2' model='pcie-to-pci-bridge'>
> +      <model name='pcie-pci-bridge'/>
> +      <address type='pci' domain='0x0000' bus='0x01' slot='0x00'
> function='0x0'/>
> +    </controller>
> +    <controller type='pci' index='3' model='pcie-root-port'>
> +      <model name='pcie-root-port'/>
> +      <target chassis='3' port='0x9'/>
> +      <address type='pci' domain='0x0000' bus='0x00' slot='0x01'
> function='0x1'/>
> +    </controller>
> +    <input type='mouse' bus='ps2'/>
> +    <input type='keyboard' bus='ps2'/>
> +    <audio id='1' type='none'/>
> +    <watchdog model='itco' action='reset'/>
> +    <memballoon model='none'/>
> +    <pstore backend='acpi-erst'>
> +      <path>/tmp/guest_acpi_esrt</path>
> +      <size unit='KiB'>8</size>
> +      <address type='pci' domain='0x0000' bus='0x02' slot='0x01'
> function='0x0'/>
> +    </pstore>
> +  </devices>
> +</domain>
> diff --git a/tests/qemuxmlconftest.c b/tests/qemuxmlconftest.c
> index cc984440ea..68d1127cf4 100644
> --- a/tests/qemuxmlconftest.c
> +++ b/tests/qemuxmlconftest.c
> @@ -2949,6 +2949,7 @@ mymain(void)
>      DO_TEST_CAPS_LATEST("mtp-usb-device")
>      DO_TEST_CAPS_LATEST("net-usb")
>      DO_TEST_CAPS_LATEST("sound-device-virtio")
> +    DO_TEST_CAPS_LATEST("pstore-acpi-erst")
>
>      DO_TEST_CAPS_LATEST_FAILURE("disk-network-iscsi-zero-hosts-invalid")
>      DO_TEST_CAPS_LATEST_PARSE_ERROR("hostdev-scsi-vhost-rawio-invalid")
> --
> 2.44.2
>

Reviewed-by: Kristina Hanicova <[email protected]>

Kristina

Reply via email to