From: Igor Mammedov <imammedo@redhat.com>
To: fanhuang <FangSheng.Huang@amd.com>
Cc: <qemu-devel@nongnu.org>, <david@kernel.org>, <gourry@gourry.net>,
<philmd@mailo.com>, <Zhigang.Luo@amd.com>, <Lianjie.Shi@amd.com>,
Peter Xu <peterx@redhat.com>
Subject: Re: [PATCH v12 1/4] hw/mem: add sp-mem device for Specific Purpose Memory
Date: Wed, 17 Jun 2026 11:16:52 +0200 [thread overview]
Message-ID: <20260617111652.1bb4d2d4@imammedo> (raw)
In-Reply-To: <20260616090808.3047939-2-FangSheng.Huang@amd.com>
On Tue, 16 Jun 2026 17:08:05 +0800
fanhuang <FangSheng.Huang@amd.com> wrote:
> Introduce a TYPE_MEMORY_DEVICE subclass `sp-mem` for boot-time
> SOFT_RESERVED memory exposed to the guest with a per-device NUMA
> proximity domain.
>
> The device targets accelerator memory (HBM and similar) that the
> firmware hands to the guest OS as SOFT_RESERVED memory, so a driver
> in the guest -- rather than the kernel's general allocator -- owns
> the range.
>
> Usage:
>
> -object memory-backend-ram,id=spm0,size=$SIZE
> -numa node,nodeid=$N
> -device sp-mem,id=dev0,memdev=spm0,node=$N[,addr=$GPA]
>
> The device is boot-time only (no hotplug).
Modulo nitpicking/patch splitting and a migration question LGTM
>
> Signed-off-by: FangSheng Huang <FangSheng.Huang@amd.com>
> ---
> qapi/machine.json | 43 +++++++++++-
> include/hw/mem/sp-mem.h | 33 +++++++++
> hw/core/machine-hmp-cmds.c | 11 +++
> hw/mem/sp-mem.c | 136 +++++++++++++++++++++++++++++++++++++
> hw/mem/Kconfig | 4 ++
> hw/mem/meson.build | 1 +
> 6 files changed, 226 insertions(+), 2 deletions(-)
> create mode 100644 include/hw/mem/sp-mem.h
> create mode 100644 hw/mem/sp-mem.c
>
> diff --git a/qapi/machine.json b/qapi/machine.json
> index 685e4e29b8..777cfc81e1 100644
> --- a/qapi/machine.json
> +++ b/qapi/machine.json
> @@ -1413,6 +1413,32 @@
> }
> }
>
> +##
> +# @SpMemDeviceInfo:
> +#
> +# sp-mem device state information
> +#
> +# @id: device's ID
> +#
> +# @addr: physical address, where device is mapped
> +#
> +# @size: size of memory that the device provides
> +#
> +# @node: NUMA proximity domain to which the device is assigned
> +#
> +# @memdev: memory backend linked with device
> +#
> +# Since: 11.1
> +##
> +{ 'struct': 'SpMemDeviceInfo',
> + 'data': { '*id': 'str',
> + 'addr': 'size',
> + 'size': 'size',
> + 'node': 'int',
> + 'memdev': 'str'
> + }
> +}
> +
> ##
> # @MemoryDeviceInfoKind:
> #
> @@ -1426,11 +1452,13 @@
> #
> # @hv-balloon: since 8.2.
> #
> +# @sp-mem: since 11.1.
> +#
> # Since: 2.1
> ##
> { 'enum': 'MemoryDeviceInfoKind',
> 'data': [ 'dimm', 'nvdimm', 'virtio-pmem', 'virtio-mem', 'sgx-epc',
> - 'hv-balloon' ] }
> + 'hv-balloon', 'sp-mem' ] }
>
> ##
> # @PCDIMMDeviceInfoWrapper:
> @@ -1482,6 +1510,16 @@
> { 'struct': 'HvBalloonDeviceInfoWrapper',
> 'data': { 'data': 'HvBalloonDeviceInfo' } }
>
> +##
> +# @SpMemDeviceInfoWrapper:
> +#
> +# @data: sp-mem device state information
> +#
> +# Since: 11.1
> +##
> +{ 'struct': 'SpMemDeviceInfoWrapper',
> + 'data': { 'data': 'SpMemDeviceInfo' } }
> +
> ##
> # @MemoryDeviceInfo:
> #
> @@ -1499,7 +1537,8 @@
> 'virtio-pmem': 'VirtioPMEMDeviceInfoWrapper',
> 'virtio-mem': 'VirtioMEMDeviceInfoWrapper',
> 'sgx-epc': 'SgxEPCDeviceInfoWrapper',
> - 'hv-balloon': 'HvBalloonDeviceInfoWrapper'
> + 'hv-balloon': 'HvBalloonDeviceInfoWrapper',
> + 'sp-mem': 'SpMemDeviceInfoWrapper'
> }
> }
>
> diff --git a/include/hw/mem/sp-mem.h b/include/hw/mem/sp-mem.h
> new file mode 100644
> index 0000000000..a8951b49e6
> --- /dev/null
> +++ b/include/hw/mem/sp-mem.h
> @@ -0,0 +1,33 @@
> +/*
> + * Specific Purpose Memory (SPM) device
> + *
> + * TYPE_MEMORY_DEVICE subclass for boot-time-only memory exposed to the
> + * guest as an E820 SOFT_RESERVED range with a SRAT memory-affinity entry.
> + *
> + * Copyright (c) 2026 Advanced Micro Devices, Inc.
> + *
> + * Authors:
> + * FangSheng Huang <FangSheng.Huang@amd.com>
> + *
> + * SPDX-License-Identifier: GPL-2.0-or-later
> + */
> +
> +#ifndef QEMU_SP_MEM_H
> +#define QEMU_SP_MEM_H
> +
> +#include "hw/core/qdev.h"
> +#include "qom/object.h"
> +
> +#define TYPE_SP_MEM "sp-mem"
> +
> +OBJECT_DECLARE_SIMPLE_TYPE(SpMemDevice, SP_MEM)
> +
> +struct SpMemDevice {
> + DeviceState parent_obj;
> +
> + HostMemoryBackend *hostmem;
> + uint32_t node;
> + uint64_t addr;
> +};
> +
> +#endif /* QEMU_SP_MEM_H */
> diff --git a/hw/core/machine-hmp-cmds.c b/hw/core/machine-hmp-cmds.c
> index 46846f741a..686304bafa 100644
> --- a/hw/core/machine-hmp-cmds.c
> +++ b/hw/core/machine-hmp-cmds.c
> @@ -279,6 +279,7 @@ void hmp_info_memory_devices(Monitor *mon, const QDict *qdict)
> PCDIMMDeviceInfo *di;
> SgxEPCDeviceInfo *se;
> HvBalloonDeviceInfo *hi;
> + SpMemDeviceInfo *spmi;
>
> for (info = info_list; info; info = info->next) {
> value = info->value;
> @@ -350,6 +351,16 @@ void hmp_info_memory_devices(Monitor *mon, const QDict *qdict)
> monitor_printf(mon, " memdev: %s\n", hi->memdev);
> }
> break;
> + case MEMORY_DEVICE_INFO_KIND_SP_MEM:
> + spmi = value->u.sp_mem.data;
> + monitor_printf(mon, "Memory device [%s]: \"%s\"\n",
> + MemoryDeviceInfoKind_str(value->type),
> + spmi->id ? spmi->id : "");
> + monitor_printf(mon, " addr: 0x%" PRIx64 "\n", spmi->addr);
> + monitor_printf(mon, " node: %" PRId64 "\n", spmi->node);
> + monitor_printf(mon, " size: %" PRIu64 "\n", spmi->size);
> + monitor_printf(mon, " memdev: %s\n", spmi->memdev);
> + break;
> default:
> g_assert_not_reached();
> }
hmp could be a separate patch.
> diff --git a/hw/mem/sp-mem.c b/hw/mem/sp-mem.c
> new file mode 100644
> index 0000000000..3b46cabc46
> --- /dev/null
> +++ b/hw/mem/sp-mem.c
> @@ -0,0 +1,136 @@
> +/*
> + * Specific Purpose Memory (SPM) device
> + *
> + * Copyright (c) 2026 Advanced Micro Devices, Inc.
> + *
> + * Authors:
> + * FangSheng Huang <FangSheng.Huang@amd.com>
> + *
> + * SPDX-License-Identifier: GPL-2.0-or-later
> + */
> +
> +#include "qemu/osdep.h"
> +#include "qemu/module.h"
> +#include "qapi/error.h"
> +#include "hw/core/qdev-properties.h"
> +#include "hw/core/qdev.h"
> +#include "hw/mem/sp-mem.h"
> +#include "hw/mem/memory-device.h"
> +#include "migration/vmstate.h"
> +#include "system/hostmem.h"
> +
> +#define SP_MEM_MEMDEV_PROP "memdev"
> +#define SP_MEM_NODE_PROP "node"
> +#define SP_MEM_ADDR_PROP "addr"
> +
> +static const Property sp_mem_properties[] = {
> + DEFINE_PROP_LINK(SP_MEM_MEMDEV_PROP, SpMemDevice, hostmem,
> + TYPE_MEMORY_BACKEND, HostMemoryBackend *),
> + DEFINE_PROP_UINT32(SP_MEM_NODE_PROP, SpMemDevice, node, 0),
> + DEFINE_PROP_UINT64(SP_MEM_ADDR_PROP, SpMemDevice, addr, 0),
> +};
> +
> +static uint64_t sp_mem_get_addr(const MemoryDeviceState *md)
> +{
> + return object_property_get_uint(OBJECT(md), SP_MEM_ADDR_PROP,
> + &error_abort);
> +}
> +
> +static void sp_mem_set_addr(MemoryDeviceState *md, uint64_t addr,
> + Error **errp)
> +{
> + object_property_set_uint(OBJECT(md), SP_MEM_ADDR_PROP, addr, errp);
> +}
> +
> +static MemoryRegion *sp_mem_get_memory_region(MemoryDeviceState *md,
> + Error **errp)
> +{
> + SpMemDevice *spm = SP_MEM(md);
> +
> + if (!spm->hostmem) {
> + error_setg(errp, "'%s' property must be set", SP_MEM_MEMDEV_PROP);
> + return NULL;
> + }
> + return host_memory_backend_get_memory(spm->hostmem);
> +}
> +
> +static void sp_mem_fill_device_info(const MemoryDeviceState *md,
> + MemoryDeviceInfo *info)
> +{
> + SpMemDeviceInfo *di = g_new0(SpMemDeviceInfo, 1);
> + SpMemDevice *spm = SP_MEM(md);
> + DeviceState *dev = DEVICE(md);
> +
> + di->id = dev->id ? g_strdup(dev->id) : NULL;
> + di->addr = spm->addr;
> + di->size = memory_region_size(
> + host_memory_backend_get_memory(spm->hostmem));
> + di->node = spm->node;
> + di->memdev = object_get_canonical_path(OBJECT(spm->hostmem));
> +
> + info->u.sp_mem.data = di;
> + info->type = MEMORY_DEVICE_INFO_KIND_SP_MEM;
> +}
if missing this doesn't break anything, I'd bundle it together with hmp patch
> +
> +static void sp_mem_realize(DeviceState *dev, Error **errp)
> +{
> + SpMemDevice *spm = SP_MEM(dev);
> +
> + if (!spm->hostmem) {
> + error_setg(errp, "'%s' property is required", SP_MEM_MEMDEV_PROP);
> + return;
> + }
> + if (host_memory_backend_is_mapped(spm->hostmem)) {
> + error_setg(errp, "memory backend '%s' is already in use",
> + object_get_canonical_path_component(OBJECT(spm->hostmem)));
> + return;
> + }
> + host_memory_backend_set_mapped(spm->hostmem, true);
> +}
> +
> +static void sp_mem_unrealize(DeviceState *dev)
> +{
> + SpMemDevice *spm = SP_MEM(dev);
> +
> + host_memory_backend_set_mapped(spm->hostmem, false);
> +}
> +
> +static const VMStateDescription vmstate_sp_mem = {
> + .name = TYPE_SP_MEM,
> + /* boot-time only; no plug/unplug state to migrate */
> + .unmigratable = 1,
this is explicit migration blocker, isn't it?
are we sure about setting it un-migratable, if yes/no than why?
I don't see how plug/unplug is involved here,
but I'd speculate that we would want to migrate memory content itself.
CCing Peter,
for a look from migration pov
> +};
> +
> +static void sp_mem_class_init(ObjectClass *oc, const void *data)
> +{
> + DeviceClass *dc = DEVICE_CLASS(oc);
> + MemoryDeviceClass *mdc = MEMORY_DEVICE_CLASS(oc);
> +
> + dc->desc = "SPM (Specific Purpose Memory) device";
> + dc->hotpluggable = false;
> + dc->realize = sp_mem_realize;
> + dc->unrealize = sp_mem_unrealize;
> + dc->vmsd = &vmstate_sp_mem;
> + device_class_set_props(dc, sp_mem_properties);
> +
> + mdc->get_addr = sp_mem_get_addr;
> + mdc->set_addr = sp_mem_set_addr;
> + mdc->get_memory_region = sp_mem_get_memory_region;
> + mdc->get_plugged_size = memory_device_get_region_size;
> + mdc->fill_device_info = sp_mem_fill_device_info;
> +}
> +
> +static const TypeInfo sp_mem_types[] = {
> + {
> + .name = TYPE_SP_MEM,
> + .parent = TYPE_DEVICE,
> + .class_init = sp_mem_class_init,
> + .instance_size = sizeof(SpMemDevice),
> + .interfaces = (InterfaceInfo[]) {
> + { TYPE_MEMORY_DEVICE },
> + { }
> + },
> + },
> +};
> +
> +DEFINE_TYPES(sp_mem_types)
> diff --git a/hw/mem/Kconfig b/hw/mem/Kconfig
> index 73c5ae8ad9..39ddb36710 100644
> --- a/hw/mem/Kconfig
> +++ b/hw/mem/Kconfig
> @@ -16,3 +16,7 @@ config CXL_MEM_DEVICE
> bool
> default y if CXL
> select MEM_DEVICE
> +
> +config SP_MEM
> + bool
> + select MEM_DEVICE
> diff --git a/hw/mem/meson.build b/hw/mem/meson.build
> index 8c2beeb7d4..f410d75475 100644
> --- a/hw/mem/meson.build
> +++ b/hw/mem/meson.build
> @@ -4,6 +4,7 @@ mem_ss.add(when: 'CONFIG_DIMM', if_true: files('pc-dimm.c'))
> mem_ss.add(when: 'CONFIG_NPCM7XX', if_true: files('npcm7xx_mc.c'))
> mem_ss.add(when: 'CONFIG_NVDIMM', if_true: files('nvdimm.c'))
> mem_ss.add(when: 'CONFIG_CXL_MEM_DEVICE', if_true: files('cxl_type3.c'))
> +mem_ss.add(when: 'CONFIG_SP_MEM', if_true: files('sp-mem.c'))
> stub_ss.add(files('cxl_type3_stubs.c'))
>
> stub_ss.add(files('memory-device-stubs.c'))
next prev parent reply other threads:[~2026-06-17 9:17 UTC|newest]
Thread overview: 10+ messages / expand[flat|nested] mbox.gz Atom feed top
2026-06-16 9:08 [PATCH v12 0/4] hw/mem: add sp-mem device for Specific Purpose Memory fanhuang
2026-06-16 9:08 ` [PATCH v12 1/4] " fanhuang
2026-06-17 9:16 ` Igor Mammedov [this message]
2026-06-17 10:00 ` Huang, FangSheng (Jerry)
2026-06-16 9:08 ` [PATCH v12 2/4] i386/acpi-build: partition device_memory SRAT umbrella for sp-mem fanhuang
2026-06-17 11:04 ` Igor Mammedov
2026-06-16 9:08 ` [PATCH v12 3/4] hw/i386: hook sp-mem into the pc machine plug path fanhuang
2026-06-17 11:14 ` Igor Mammedov
2026-06-16 9:08 ` [PATCH v12 4/4] MAINTAINERS: cover sp-mem under Memory devices, add R: tag fanhuang
2026-06-17 11:19 ` [PATCH v12 0/4] hw/mem: add sp-mem device for Specific Purpose Memory Igor Mammedov
Reply instructions:
You may reply publicly to this message via plain-text email
using any one of the following methods:
* Save the following mbox file, import it into your mail client,
and reply-to-all from there: mbox
Avoid top-posting and favor interleaved quoting:
https://en.wikipedia.org/wiki/Posting_style#Interleaved_style
* Reply using the --to, --cc, and --in-reply-to
switches of git-send-email(1):
git send-email \
--in-reply-to=20260617111652.1bb4d2d4@imammedo \
--to=imammedo@redhat.com \
--cc=FangSheng.Huang@amd.com \
--cc=Lianjie.Shi@amd.com \
--cc=Zhigang.Luo@amd.com \
--cc=david@kernel.org \
--cc=gourry@gourry.net \
--cc=peterx@redhat.com \
--cc=philmd@mailo.com \
--cc=qemu-devel@nongnu.org \
/path/to/YOUR_REPLY
https://kernel.org/pub/software/scm/git/docs/git-send-email.html
* If your mail client supports setting the In-Reply-To header
via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line
before the message body.
This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.