On 6/17/2026 5:16 PM, Igor Mammedov wrote:
On Tue, 16 Jun 2026 17:08:05 +0800 fanhuang <[email protected]> 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+ 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.+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
Will split the introspection bits (fill_device_info + the HMP printer) into their own patch in the next respin.
+ +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
You're right that the "plug/unplug" wording is off. The device carries no per-device migration state, so with a normal RAM backend it would migrate like pc-dimm. I'd originally marked it unmigratable out of caution, being unsure whether the backend could be migrated -- but on reflection that's a property of the backend, not of sp-mem: a backend that can't be migrated can express that itself, independently of this device. So dropping the flag and letting sp-mem migrate like pc-dimm, leaving any restriction to the backend, looks like the more flexible choice. Peter, does that match your view, or is there a reason to keep a gate at the device? Best regards, FangSheng Huang (Jerry)
