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)