diff options
Diffstat (limited to 'hw/mem/memory-device.c')
-rw-r--r-- | hw/mem/memory-device.c | 103 |
1 files changed, 82 insertions, 21 deletions
diff --git a/hw/mem/memory-device.c b/hw/mem/memory-device.c index 6de4f70bb4..7de1ccd497 100644 --- a/hw/mem/memory-device.c +++ b/hw/mem/memory-device.c @@ -17,6 +17,7 @@ #include "qemu/range.h" #include "hw/virtio/vhost.h" #include "sysemu/kvm.h" +#include "trace.h" static gint memory_device_addr_sort(gconstpointer a, gconstpointer b) { @@ -57,10 +58,9 @@ static int memory_device_used_region_size(Object *obj, void *opaque) if (object_dynamic_cast(obj, TYPE_MEMORY_DEVICE)) { const DeviceState *dev = DEVICE(obj); const MemoryDeviceState *md = MEMORY_DEVICE(obj); - const MemoryDeviceClass *mdc = MEMORY_DEVICE_GET_CLASS(obj); if (dev->realized) { - *size += mdc->get_region_size(md); + *size += memory_device_get_region_size(md, &error_abort); } } @@ -87,16 +87,17 @@ static void memory_device_check_addable(MachineState *ms, uint64_t size, memory_device_used_region_size(OBJECT(ms), &used_region_size); if (used_region_size + size > ms->maxram_size - ms->ram_size) { error_setg(errp, "not enough space, currently 0x%" PRIx64 - " in use of total hot pluggable 0x" RAM_ADDR_FMT, + " in use of total space for memory devices 0x" RAM_ADDR_FMT, used_region_size, ms->maxram_size - ms->ram_size); return; } } -uint64_t memory_device_get_free_addr(MachineState *ms, const uint64_t *hint, - uint64_t align, uint64_t size, - Error **errp) +static uint64_t memory_device_get_free_addr(MachineState *ms, + const uint64_t *hint, + uint64_t align, uint64_t size, + Error **errp) { uint64_t address_space_start, address_space_end; GSList *list = NULL, *item; @@ -120,7 +121,7 @@ uint64_t memory_device_get_free_addr(MachineState *ms, const uint64_t *hint, /* address_space_start indicates the maximum alignment we expect */ if (QEMU_ALIGN_UP(address_space_start, align) != address_space_start) { - error_setg(errp, "the alignment (0%" PRIx64 ") is not supported", + error_setg(errp, "the alignment (0x%" PRIx64 ") is not supported", align); return 0; } @@ -145,11 +146,12 @@ uint64_t memory_device_get_free_addr(MachineState *ms, const uint64_t *hint, if (hint) { new_addr = *hint; if (new_addr < address_space_start) { - error_setg(errp, "can't add memory [0x%" PRIx64 ":0x%" PRIx64 - "] at 0x%" PRIx64, new_addr, size, address_space_start); + error_setg(errp, "can't add memory device [0x%" PRIx64 ":0x%" PRIx64 + "] before 0x%" PRIx64, new_addr, size, + address_space_start); return 0; } else if ((new_addr + size) > address_space_end) { - error_setg(errp, "can't add memory [0x%" PRIx64 ":0x%" PRIx64 + error_setg(errp, "can't add memory device [0x%" PRIx64 ":0x%" PRIx64 "] beyond 0x%" PRIx64, new_addr, size, address_space_end); return 0; @@ -166,15 +168,13 @@ uint64_t memory_device_get_free_addr(MachineState *ms, const uint64_t *hint, uint64_t md_size, md_addr; md_addr = mdc->get_addr(md); - md_size = mdc->get_region_size(md); - if (*errp) { - goto out; - } + md_size = memory_device_get_region_size(md, &error_abort); if (ranges_overlap(md_addr, md_size, new_addr, size)) { if (hint) { const DeviceState *d = DEVICE(md); - error_setg(errp, "address range conflicts with '%s'", d->id); + error_setg(errp, "address range conflicts with memory device" + " id='%s'", d->id ? d->id : "(unnamed)"); goto out; } new_addr = QEMU_ALIGN_UP(md_addr + md_size, align); @@ -232,7 +232,7 @@ static int memory_device_plugged_size(Object *obj, void *opaque) const MemoryDeviceClass *mdc = MEMORY_DEVICE_GET_CLASS(obj); if (dev->realized) { - *size += mdc->get_plugged_size(md); + *size += mdc->get_plugged_size(md, &error_abort); } } @@ -249,22 +249,83 @@ uint64_t get_plugged_memory_size(void) return size; } -void memory_device_plug_region(MachineState *ms, MemoryRegion *mr, - uint64_t addr) +void memory_device_pre_plug(MemoryDeviceState *md, MachineState *ms, + const uint64_t *legacy_align, Error **errp) +{ + const MemoryDeviceClass *mdc = MEMORY_DEVICE_GET_CLASS(md); + Error *local_err = NULL; + uint64_t addr, align; + MemoryRegion *mr; + + mr = mdc->get_memory_region(md, &local_err); + if (local_err) { + goto out; + } + + align = legacy_align ? *legacy_align : memory_region_get_alignment(mr); + addr = mdc->get_addr(md); + addr = memory_device_get_free_addr(ms, !addr ? NULL : &addr, align, + memory_region_size(mr), &local_err); + if (local_err) { + goto out; + } + mdc->set_addr(md, addr, &local_err); + if (!local_err) { + trace_memory_device_pre_plug(DEVICE(md)->id ? DEVICE(md)->id : "", + addr); + } +out: + error_propagate(errp, local_err); +} + +void memory_device_plug(MemoryDeviceState *md, MachineState *ms) { - /* we expect a previous call to memory_device_get_free_addr() */ + const MemoryDeviceClass *mdc = MEMORY_DEVICE_GET_CLASS(md); + const uint64_t addr = mdc->get_addr(md); + MemoryRegion *mr; + + /* + * We expect that a previous call to memory_device_pre_plug() succeeded, so + * it can't fail at this point. + */ + mr = mdc->get_memory_region(md, &error_abort); g_assert(ms->device_memory); memory_region_add_subregion(&ms->device_memory->mr, addr - ms->device_memory->base, mr); + trace_memory_device_plug(DEVICE(md)->id ? DEVICE(md)->id : "", addr); } -void memory_device_unplug_region(MachineState *ms, MemoryRegion *mr) +void memory_device_unplug(MemoryDeviceState *md, MachineState *ms) { - /* we expect a previous call to memory_device_get_free_addr() */ + const MemoryDeviceClass *mdc = MEMORY_DEVICE_GET_CLASS(md); + MemoryRegion *mr; + + /* + * We expect that a previous call to memory_device_pre_plug() succeeded, so + * it can't fail at this point. + */ + mr = mdc->get_memory_region(md, &error_abort); g_assert(ms->device_memory); memory_region_del_subregion(&ms->device_memory->mr, mr); + trace_memory_device_unplug(DEVICE(md)->id ? DEVICE(md)->id : "", + mdc->get_addr(md)); +} + +uint64_t memory_device_get_region_size(const MemoryDeviceState *md, + Error **errp) +{ + const MemoryDeviceClass *mdc = MEMORY_DEVICE_GET_CLASS(md); + MemoryRegion *mr; + + /* dropping const here is fine as we don't touch the memory region */ + mr = mdc->get_memory_region((MemoryDeviceState *)md, errp); + if (!mr) { + return 0; + } + + return memory_region_size(mr); } static const TypeInfo memory_device_info = { |