@@ -45,6 +45,22 @@
*/
#define MEMORY_DEVICES_MEMSLOT_SOFT_LIMIT 256
+static bool memory_device_is_empty(const MemoryDeviceState *md)
+{
+ const MemoryDeviceClass *mdc = MEMORY_DEVICE_GET_CLASS(md);
+ Error *local_err = NULL;
+ MemoryRegion *mr;
+
+ /* dropping const here is fine as we don't touch the memory region */
+ mr = mdc->get_memory_region((MemoryDeviceState *)md, &local_err);
+ if (local_err) {
+ /* Not empty, we'll report errors later when ontaining the MR again. */
+ error_free(local_err);
+ return false;
+ }
+ return !mr;
+}
+
static gint memory_device_addr_sort(gconstpointer a, gconstpointer b)
{
const MemoryDeviceState *md_a = MEMORY_DEVICE(a);
@@ -321,6 +337,10 @@ static uint64_t memory_device_get_free_addr(MachineState *ms,
uint64_t next_addr;
Range tmp;
+ if (memory_device_is_empty(md)) {
+ continue;
+ }
+
range_init_nofail(&tmp, mdc->get_addr(md),
memory_device_get_region_size(md, &error_abort));
@@ -364,6 +384,7 @@ MemoryDeviceInfoList *qmp_memory_device_list(void)
const MemoryDeviceClass *mdc = MEMORY_DEVICE_GET_CLASS(item->data);
MemoryDeviceInfo *info = g_new0(MemoryDeviceInfo, 1);
+ /* Let's query infotmation even for empty memory devices. */
mdc->fill_device_info(md, info);
QAPI_LIST_APPEND(tail, info);
@@ -383,7 +404,7 @@ static int memory_device_plugged_size(Object *obj, void *opaque)
const MemoryDeviceState *md = MEMORY_DEVICE(obj);
const MemoryDeviceClass *mdc = MEMORY_DEVICE_GET_CLASS(obj);
- if (dev->realized) {
+ if (dev->realized && !memory_device_is_empty(md)) {
*size += mdc->get_plugged_size(md, &error_abort);
}
}
@@ -409,6 +430,11 @@ void memory_device_pre_plug(MemoryDeviceState *md, MachineState *ms,
uint64_t addr, align = 0;
MemoryRegion *mr;
+ /* We support empty memory devices even without device memory. */
+ if (memory_device_is_empty(md)) {
+ return;
+ }
+
if (!ms->device_memory) {
error_setg(errp, "the configuration is not prepared for memory devices"
" (e.g., for memory hotplug), consider specifying the"
@@ -452,9 +478,14 @@ out:
void memory_device_plug(MemoryDeviceState *md, MachineState *ms)
{
const MemoryDeviceClass *mdc = MEMORY_DEVICE_GET_CLASS(md);
- const uint64_t addr = mdc->get_addr(md);
+ uint64_t addr;
MemoryRegion *mr;
+ if (memory_device_is_empty(md)) {
+ return;
+ }
+ addr = mdc->get_addr(md);
+
/*
* We expect that a previous call to memory_device_pre_plug() succeeded, so
* it can't fail at this point.
@@ -475,6 +506,10 @@ void memory_device_unplug(MemoryDeviceState *md, MachineState *ms)
const MemoryDeviceClass *mdc = MEMORY_DEVICE_GET_CLASS(md);
MemoryRegion *mr;
+ if (memory_device_is_empty(md)) {
+ return;
+ }
+
/*
* We expect that a previous call to memory_device_pre_plug() succeeded, so
* it can't fail at this point.
@@ -38,6 +38,10 @@ typedef struct MemoryDeviceState MemoryDeviceState;
* address in guest physical memory can either be specified explicitly
* or get assigned automatically.
*
+ * Some memory device might not own a memory region in certain device
+ * configurations. Such devices can logically get (un)plugged, however,
+ * empty memory devices are mostly ignored by the memory device code.
+ *
* Conceptually, memory devices only span one memory region. If multiple
* successive memory regions are used, a covering memory region has to
* be provided. Scattered memory regions are not supported for single
@@ -91,7 +95,8 @@ struct MemoryDeviceClass {
uint64_t (*get_plugged_size)(const MemoryDeviceState *md, Error **errp);
/*
- * Return the memory region of the memory device.
+ * Return the memory region of the memory device. If the device is
+ * completely empty, returns NULL without an error.
*
* Called when (un)plugging the memory device, to (un)map the
* memory region in guest physical memory, but also to detect the