@samitouri / QOSamiQemu / commits / e83b010836

hw/mem: add sp-mem device for Specific Purpose Memory

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). Signed-off-by: FangSheng Huang <FangSheng.Huang@amd.com> Reviewed-by: Igor Mammedov <imammedo@redhat.com> Reviewed-by: David Hildenbrand (Arm) <david@kernel.org> Reviewed-by: Michael S. Tsirkin <mst@redhat.com> Signed-off-by: Michael S. Tsirkin <mst@redhat.com> Message-ID: <20260623075051.3797975-2-FangSheng.Huang@amd.com>

fanhuang committed Jun 23, 2026 at 15:50 UTC e83b01083631544bec27cbb3a381420b1ac7dc38
4 files changed +147
hw/mem/Kconfig
+4
@@ -16,3 +16,7 @@ config CXL_MEM_DEVICE
16 bool
17 default y if CXL
18 select MEM_DEVICE
19 +
20 +config SP_MEM
21 + bool
22 + select MEM_DEVICE
hw/mem/meson.build
+1
@@ -4,6 +4,7 @@ mem_ss.add(when: 'CONFIG_DIMM', if_true: files('pc-dimm.c'))
4 mem_ss.add(when: 'CONFIG_NPCM7XX', if_true: files('npcm7xx_mc.c'))
5 mem_ss.add(when: 'CONFIG_NVDIMM', if_true: files('nvdimm.c'))
6 mem_ss.add(when: 'CONFIG_CXL_MEM_DEVICE', if_true: files('cxl_type3.c'))
7 +mem_ss.add(when: 'CONFIG_SP_MEM', if_true: files('sp-mem.c'))
8 stub_ss.add(files('cxl_type3_stubs.c'))
9
10 stub_ss.add(files('memory-device-stubs.c'))
hw/mem/sp-mem.c new
+109
@@ -0,0 +1,109 @@
1 +/*
2 + * Specific Purpose Memory (SPM) device
3 + *
4 + * Copyright (c) 2026 Advanced Micro Devices, Inc.
5 + *
6 + * Authors:
7 + * FangSheng Huang <FangSheng.Huang@amd.com>
8 + *
9 + * SPDX-License-Identifier: GPL-2.0-or-later
10 + */
11 +
12 +#include "qemu/osdep.h"
13 +#include "qemu/module.h"
14 +#include "qapi/error.h"
15 +#include "hw/core/qdev-properties.h"
16 +#include "hw/core/qdev.h"
17 +#include "hw/mem/sp-mem.h"
18 +#include "hw/mem/memory-device.h"
19 +#include "system/hostmem.h"
20 +
21 +#define SP_MEM_MEMDEV_PROP "memdev"
22 +#define SP_MEM_NODE_PROP "node"
23 +#define SP_MEM_ADDR_PROP "addr"
24 +
25 +static const Property sp_mem_properties[] = {
26 + DEFINE_PROP_LINK(SP_MEM_MEMDEV_PROP, SpMemDevice, hostmem,
27 + TYPE_MEMORY_BACKEND, HostMemoryBackend *),
28 + DEFINE_PROP_UINT32(SP_MEM_NODE_PROP, SpMemDevice, node, 0),
29 + DEFINE_PROP_UINT64(SP_MEM_ADDR_PROP, SpMemDevice, addr, 0),
30 +};
31 +
32 +static uint64_t sp_mem_get_addr(const MemoryDeviceState *md)
33 +{
34 + return object_property_get_uint(OBJECT(md), SP_MEM_ADDR_PROP,
35 + &error_abort);
36 +}
37 +
38 +static void sp_mem_set_addr(MemoryDeviceState *md, uint64_t addr,
39 + Error **errp)
40 +{
41 + object_property_set_uint(OBJECT(md), SP_MEM_ADDR_PROP, addr, errp);
42 +}
43 +
44 +static MemoryRegion *sp_mem_get_memory_region(MemoryDeviceState *md,
45 + Error **errp)
46 +{
47 + SpMemDevice *spm = SP_MEM(md);
48 +
49 + if (!spm->hostmem) {
50 + error_setg(errp, "'%s' property must be set", SP_MEM_MEMDEV_PROP);
51 + return NULL;
52 + }
53 + return host_memory_backend_get_memory(spm->hostmem);
54 +}
55 +
56 +static void sp_mem_realize(DeviceState *dev, Error **errp)
57 +{
58 + SpMemDevice *spm = SP_MEM(dev);
59 +
60 + if (!spm->hostmem) {
61 + error_setg(errp, "'%s' property is required", SP_MEM_MEMDEV_PROP);
62 + return;
63 + }
64 + if (host_memory_backend_is_mapped(spm->hostmem)) {
65 + error_setg(errp, "memory backend '%s' is already in use",
66 + object_get_canonical_path_component(OBJECT(spm->hostmem)));
67 + return;
68 + }
69 + host_memory_backend_set_mapped(spm->hostmem, true);
70 +}
71 +
72 +static void sp_mem_unrealize(DeviceState *dev)
73 +{
74 + SpMemDevice *spm = SP_MEM(dev);
75 +
76 + host_memory_backend_set_mapped(spm->hostmem, false);
77 +}
78 +
79 +static void sp_mem_class_init(ObjectClass *oc, const void *data)
80 +{
81 + DeviceClass *dc = DEVICE_CLASS(oc);
82 + MemoryDeviceClass *mdc = MEMORY_DEVICE_CLASS(oc);
83 +
84 + dc->desc = "SPM (Specific Purpose Memory) device";
85 + dc->hotpluggable = false;
86 + dc->realize = sp_mem_realize;
87 + dc->unrealize = sp_mem_unrealize;
88 + device_class_set_props(dc, sp_mem_properties);
89 +
90 + mdc->get_addr = sp_mem_get_addr;
91 + mdc->set_addr = sp_mem_set_addr;
92 + mdc->get_memory_region = sp_mem_get_memory_region;
93 + mdc->get_plugged_size = memory_device_get_region_size;
94 +}
95 +
96 +static const TypeInfo sp_mem_types[] = {
97 + {
98 + .name = TYPE_SP_MEM,
99 + .parent = TYPE_DEVICE,
100 + .class_init = sp_mem_class_init,
101 + .instance_size = sizeof(SpMemDevice),
102 + .interfaces = (InterfaceInfo[]) {
103 + { TYPE_MEMORY_DEVICE },
104 + { }
105 + },
106 + },
107 +};
108 +
109 +DEFINE_TYPES(sp_mem_types)
include/hw/mem/sp-mem.h new
+33
@@ -0,0 +1,33 @@
1 +/*
2 + * Specific Purpose Memory (SPM) device
3 + *
4 + * TYPE_MEMORY_DEVICE subclass for boot-time-only memory exposed to the
5 + * guest as an E820 SOFT_RESERVED range with a SRAT memory-affinity entry.
6 + *
7 + * Copyright (c) 2026 Advanced Micro Devices, Inc.
8 + *
9 + * Authors:
10 + * FangSheng Huang <FangSheng.Huang@amd.com>
11 + *
12 + * SPDX-License-Identifier: GPL-2.0-or-later
13 + */
14 +
15 +#ifndef QEMU_SP_MEM_H
16 +#define QEMU_SP_MEM_H
17 +
18 +#include "hw/core/qdev.h"
19 +#include "qom/object.h"
20 +
21 +#define TYPE_SP_MEM "sp-mem"
22 +
23 +OBJECT_DECLARE_SIMPLE_TYPE(SpMemDevice, SP_MEM)
24 +
25 +struct SpMemDevice {
26 + DeviceState parent_obj;
27 +
28 + HostMemoryBackend *hostmem;
29 + uint32_t node;
30 + uint64_t addr;
31 +};
32 +
33 +#endif /* QEMU_SP_MEM_H */