new file mode 100644
@@ -0,0 +1,195 @@
+/*
+ * MemorySlot device for Memory Hotplug
+ *
+ * Copyright ProfitBricks GmbH 2012
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, see <http://www.gnu.org/licenses/>
+ */
+
+#include "trace.h"
+#include "qdev.h"
+#include "memslot.h"
+#include "../exec-memory.h"
+
+static DeviceState *memslot_hotplug_qdev;
+static memslot_hotplug_fn memslot_hotplug;
+
+static Property memslot_properties[] = {
+ DEFINE_PROP_END_OF_LIST()
+};
+
+void memslot_populate(MemSlotState *s)
+{
+ char buf[32];
+ MemoryRegion *new = NULL;
+
+ sprintf(buf, "memslot%u", s->idx);
+ new = g_malloc(sizeof(MemoryRegion));
+ memory_region_init_ram(new, buf, s->size);
+ vmstate_register_ram_global(new);
+ memory_region_add_subregion(get_system_memory(), s->start, new);
+ s->mr = new;
+ s->populated = 1;
+}
+
+void memslot_depopulate(MemSlotState *s)
+{
+ assert(s);
+ if (s->populated) {
+ vmstate_unregister_ram(s->mr, NULL);
+ memory_region_del_subregion(get_system_memory(), s->mr);
+ memory_region_destroy(s->mr);
+ s->populated = 0;
+ s->mr = NULL;
+ }
+}
+
+MemSlotState *memslot_create(char *id, target_phys_addr_t start, uint64_t size,
+ uint64_t node, uint32_t memslot_idx)
+{
+ DeviceState *dev;
+ MemSlotState *mdev;
+
+ dev = sysbus_create_simple("memslot", -1, NULL);
+ dev->id = id;
+
+ mdev = MEMSLOT(dev);
+ mdev->idx = memslot_idx;
+ mdev->start = start;
+ mdev->size = size;
+ mdev->node = node;
+
+ return mdev;
+}
+
+void memslot_register_hotplug(memslot_hotplug_fn hotplug, DeviceState *qdev)
+{
+ memslot_hotplug_qdev = qdev;
+ memslot_hotplug = hotplug;
+}
+
+static MemSlotState *memslot_find(char *id)
+{
+ DeviceState *qdev;
+ qdev = qdev_find_recursive(sysbus_get_default(), id);
+ if (qdev)
+ return MEMSLOT(qdev);
+ return NULL;
+}
+
+int memslot_do(Monitor *mon, const QDict *qdict)
+{
+ MemSlotState *slot = NULL;
+
+ char *id = (char*) qdict_get_try_str(qdict, "id");
+ if (!id) {
+ fprintf(stderr, "ERROR %s invalid id\n",__FUNCTION__);
+ return 1;
+ }
+
+ slot = memslot_find(id);
+
+ if (!slot) {
+ fprintf(stderr, "%s no slot %s found\n", __FUNCTION__, id);
+ return 1;
+ }
+
+ char *action = (char*) qdict_get_try_str(qdict, "action");
+ if (!action || (strcmp(action, "add") && strcmp(action, "delete"))) {
+ fprintf(stderr, "ERROR %s invalid action\n", __FUNCTION__);
+ return 1;
+ }
+
+ if (!strcmp(action, "add")) {
+ if (slot->populated) {
+ fprintf(stderr, "ERROR %s slot %s already populated\n",
+ __FUNCTION__, id);
+ return 1;
+ }
+ memslot_populate(slot);
+ if (memslot_hotplug)
+ memslot_hotplug(memslot_hotplug_qdev, (SysBusDevice*)slot, 1);
+ }
+ else {
+ if (!slot->populated) {
+ fprintf(stderr, "ERROR %s slot %s is not populated\n",
+ __FUNCTION__, id);
+ return 1;
+ }
+ if (memslot_hotplug)
+ memslot_hotplug(memslot_hotplug_qdev, (SysBusDevice*)slot, 0);
+ }
+ return 0;
+}
+
+MemSlotState *memslot_find_from_idx(uint32_t idx)
+{
+ Error *err = NULL;
+ DeviceState *dev;
+ MemSlotState *slot;
+ char *type;
+ BusState *bus = sysbus_get_default();
+ QTAILQ_FOREACH(dev, &bus->children, sibling) {
+ type = object_property_get_str(OBJECT(dev), "type", &err);
+ if (err) {
+ error_free(err);
+ fprintf(stderr, "error getting device type\n");
+ return NULL;
+ }
+ if (!strcmp(type, "memslot")) {
+ slot = MEMSLOT(dev);
+ if (slot->idx == idx) {
+ fprintf(stderr, "%s found slot with idx %u : %p\n",
+ __FUNCTION__, idx, slot);
+ return slot;
+ }
+ else
+ fprintf(stderr, "%s slot with idx %u != %u\n", __FUNCTION__,
+ slot->idx, idx);
+ }
+ }
+ return NULL;
+}
+
+static int memslot_init(SysBusDevice *s)
+{
+ MemSlotState *slot;
+ slot = MEMSLOT(s);
+ slot->mr = NULL;
+ slot->populated = 0;
+ return 0;
+}
+
+static void memslot_class_init(ObjectClass *klass, void *data)
+{
+ SysBusDeviceClass *sc = SYS_BUS_DEVICE_CLASS(klass);
+ DeviceClass *dc = DEVICE_CLASS(klass);
+
+ dc->props = memslot_properties;
+ sc->init = memslot_init;
+ memslot_hotplug = NULL;
+}
+
+static TypeInfo memslot_info = {
+ .name = "memslot",
+ .parent = TYPE_SYS_BUS_DEVICE,
+ .instance_size = sizeof(MemSlotState),
+ .class_init = memslot_class_init,
+};
+
+static void memslot_register_types(void)
+{
+ type_register_static(&memslot_info);
+}
+
+type_init(memslot_register_types)
new file mode 100644
@@ -0,0 +1,44 @@
+#ifndef QEMU_MEM_H
+#define QEMU_MEM_H
+
+#include "qemu-common.h"
+#include "memory.h"
+#include "sysbus.h"
+
+#define TYPE_MEMSLOT "memslot"
+#define MEMSLOT(obj) \
+ OBJECT_CHECK(MemSlotState, (obj), TYPE_MEMSLOT)
+#define MEMSLOT_CLASS(klass) \
+ OBJECT_CLASS_CHECK(MemSlotClass, (obj), TYPE_MEMSLOT)
+#define MEMSLOT_GET_CLASS(obj) \
+ OBJECT_GET_CLASS(MemSlotClass, (obj), TYPE_MEMSLOT)
+
+typedef struct MemSlotState {
+ SysBusDevice busdev;
+ uint32_t populated; /* 1 means device has been hotplugged. Default is 0. */
+ uint32_t idx; /* index in memory hotplug register/bitmap */
+ uint64_t start; /* starting physical address */
+ uint64_t size;
+ uint32_t node; /* numa node proximity */
+ MemoryRegion *mr; /* MemoryRegion for this slot. !NULL only if populated */
+} MemSlotState;
+
+typedef struct MemSlotClass
+{
+ SysBusDeviceClass parent_class;
+ void (*set)(MemSlotState *s, MemoryRegion *mem);
+} MemSlotClass;
+
+/* mem.c */
+
+typedef int (*memslot_hotplug_fn)(DeviceState *qdev, SysBusDevice *dev, int add);
+
+MemSlotState *memslot_create(char *id, target_phys_addr_t start, uint64_t size,
+ uint64_t node, uint32_t memslot_idx);
+void memslot_populate(MemSlotState *s);
+void memslot_depopulate(MemSlotState *s);
+int memslot_do(Monitor *mon, const QDict *qdict);
+MemSlotState *memslot_find_from_idx(uint32_t idx);
+void memslot_register_hotplug(memslot_hotplug_fn hotplug, DeviceState *qdev);
+
+#endif
Each hotplug-able memory slot is a SysBusDevice. All memslots are initially unpopulated. A hot-add operation for a particular memory slot creates a new MemoryRegion of the given physical address offset, size and node proximity, and attaches it to main system memory as a sub_region. A hot-remove operation detaches and frees the MemoryRegion from system memory. This is an early prototype and lacks proper qdev integration: a separate hotplug mechanism/side-channel is used and main system bus hotplug capability is ignored. Signed-off-by: Vasilis Liaskovitis <vasilis.liaskovitis@profitbricks.com> --- hw/memslot.c | 195 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ hw/memslot.h | 44 +++++++++++++ 2 files changed, 239 insertions(+), 0 deletions(-) create mode 100644 hw/memslot.c create mode 100644 hw/memslot.h