mirror of https://github.com/xemu-project/xemu.git
memory-device: Support empty memory devices
Let's support empty memory devices -- memory devices that don't have a memory device region in the current configuration. hv-balloon with an optional memdev is the primary use case. Signed-off-by: David Hildenbrand <david@redhat.com> Signed-off-by: Maciej S. Szmigiero <maciej.szmigiero@oracle.com>
This commit is contained in:
parent
d762bf9793
commit
6c1b28e9e4
|
@ -20,6 +20,22 @@
|
||||||
#include "exec/address-spaces.h"
|
#include "exec/address-spaces.h"
|
||||||
#include "trace.h"
|
#include "trace.h"
|
||||||
|
|
||||||
|
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)
|
static gint memory_device_addr_sort(gconstpointer a, gconstpointer b)
|
||||||
{
|
{
|
||||||
const MemoryDeviceState *md_a = MEMORY_DEVICE(a);
|
const MemoryDeviceState *md_a = MEMORY_DEVICE(a);
|
||||||
|
@ -249,6 +265,10 @@ static uint64_t memory_device_get_free_addr(MachineState *ms,
|
||||||
uint64_t next_addr;
|
uint64_t next_addr;
|
||||||
Range tmp;
|
Range tmp;
|
||||||
|
|
||||||
|
if (memory_device_is_empty(md)) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
range_init_nofail(&tmp, mdc->get_addr(md),
|
range_init_nofail(&tmp, mdc->get_addr(md),
|
||||||
memory_device_get_region_size(md, &error_abort));
|
memory_device_get_region_size(md, &error_abort));
|
||||||
|
|
||||||
|
@ -292,6 +312,7 @@ MemoryDeviceInfoList *qmp_memory_device_list(void)
|
||||||
const MemoryDeviceClass *mdc = MEMORY_DEVICE_GET_CLASS(item->data);
|
const MemoryDeviceClass *mdc = MEMORY_DEVICE_GET_CLASS(item->data);
|
||||||
MemoryDeviceInfo *info = g_new0(MemoryDeviceInfo, 1);
|
MemoryDeviceInfo *info = g_new0(MemoryDeviceInfo, 1);
|
||||||
|
|
||||||
|
/* Let's query infotmation even for empty memory devices. */
|
||||||
mdc->fill_device_info(md, info);
|
mdc->fill_device_info(md, info);
|
||||||
|
|
||||||
QAPI_LIST_APPEND(tail, info);
|
QAPI_LIST_APPEND(tail, info);
|
||||||
|
@ -311,7 +332,7 @@ static int memory_device_plugged_size(Object *obj, void *opaque)
|
||||||
const MemoryDeviceState *md = MEMORY_DEVICE(obj);
|
const MemoryDeviceState *md = MEMORY_DEVICE(obj);
|
||||||
const MemoryDeviceClass *mdc = MEMORY_DEVICE_GET_CLASS(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);
|
*size += mdc->get_plugged_size(md, &error_abort);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -337,6 +358,11 @@ void memory_device_pre_plug(MemoryDeviceState *md, MachineState *ms,
|
||||||
uint64_t addr, align = 0;
|
uint64_t addr, align = 0;
|
||||||
MemoryRegion *mr;
|
MemoryRegion *mr;
|
||||||
|
|
||||||
|
/* We support empty memory devices even without device memory. */
|
||||||
|
if (memory_device_is_empty(md)) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
if (!ms->device_memory) {
|
if (!ms->device_memory) {
|
||||||
error_setg(errp, "the configuration is not prepared for memory devices"
|
error_setg(errp, "the configuration is not prepared for memory devices"
|
||||||
" (e.g., for memory hotplug), consider specifying the"
|
" (e.g., for memory hotplug), consider specifying the"
|
||||||
|
@ -380,10 +406,17 @@ out:
|
||||||
void memory_device_plug(MemoryDeviceState *md, MachineState *ms)
|
void memory_device_plug(MemoryDeviceState *md, MachineState *ms)
|
||||||
{
|
{
|
||||||
const MemoryDeviceClass *mdc = MEMORY_DEVICE_GET_CLASS(md);
|
const MemoryDeviceClass *mdc = MEMORY_DEVICE_GET_CLASS(md);
|
||||||
const unsigned int memslots = memory_device_get_memslots(md);
|
unsigned int memslots;
|
||||||
const uint64_t addr = mdc->get_addr(md);
|
uint64_t addr;
|
||||||
MemoryRegion *mr;
|
MemoryRegion *mr;
|
||||||
|
|
||||||
|
if (memory_device_is_empty(md)) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
memslots = memory_device_get_memslots(md);
|
||||||
|
addr = mdc->get_addr(md);
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* We expect that a previous call to memory_device_pre_plug() succeeded, so
|
* We expect that a previous call to memory_device_pre_plug() succeeded, so
|
||||||
* it can't fail at this point.
|
* it can't fail at this point.
|
||||||
|
@ -408,6 +441,10 @@ void memory_device_unplug(MemoryDeviceState *md, MachineState *ms)
|
||||||
const unsigned int memslots = memory_device_get_memslots(md);
|
const unsigned int memslots = memory_device_get_memslots(md);
|
||||||
MemoryRegion *mr;
|
MemoryRegion *mr;
|
||||||
|
|
||||||
|
if (memory_device_is_empty(md)) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* We expect that a previous call to memory_device_pre_plug() succeeded, so
|
* We expect that a previous call to memory_device_pre_plug() succeeded, so
|
||||||
* it can't fail at this point.
|
* 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
|
* address in guest physical memory can either be specified explicitly
|
||||||
* or get assigned automatically.
|
* 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
|
* Conceptually, memory devices only span one memory region. If multiple
|
||||||
* successive memory regions are used, a covering memory region has to
|
* successive memory regions are used, a covering memory region has to
|
||||||
* be provided. Scattered memory regions are not supported for single
|
* 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);
|
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
|
* Called when (un)plugging the memory device, to (un)map the
|
||||||
* memory region in guest physical memory, but also to detect the
|
* memory region in guest physical memory, but also to detect the
|
||||||
|
|
Loading…
Reference in New Issue