Implement -memslot qemu-kvm command line option to define hotplug-able memory
slots.
Syntax: "-memslot id=name,start=addr,size=sz,node=nodeid"
e.g. "-memslot id=hot1,start=4294967296,size=1073741824,node=0"
will define a 1G memory slot starting at physical address 4G, belonging to numa
node 0. Defining no node will automatically add a memslot to node 0.
Also implement a new hmp monitor command for hot-add and hot-remove of memory slots
Syntax: "memslot slotname action"
where action is add/delete and slotname is the qdev-id of the memory slot.
Signed-off-by: Vasilis Liaskovitis <vasilis.liaskovitis(a)profitbricks.com>
---
Makefile.objs | 2 +-
hmp-commands.hx | 15 +++++++++++++++
monitor.c | 8 ++++++++
monitor.h | 1 +
qemu-config.c | 25 +++++++++++++++++++++++++
qemu-options.hx | 8 ++++++++
sysemu.h | 1 +
vl.c | 40 ++++++++++++++++++++++++++++++++++++++++
8 files changed, 99 insertions(+), 1 deletions(-)
diff --git a/Makefile.objs b/Makefile.objs
index 5c3bcda..98ce865 100644
--- a/Makefile.objs
+++ b/Makefile.objs
@@ -240,7 +240,7 @@ hw-obj-$(CONFIG_USB_OHCI) += usb/hcd-ohci.o
hw-obj-$(CONFIG_USB_EHCI) += usb/hcd-ehci.o
hw-obj-$(CONFIG_USB_XHCI) += usb/hcd-xhci.o
hw-obj-$(CONFIG_FDC) += fdc.o
-hw-obj-$(CONFIG_ACPI) += acpi.o acpi_piix4.o
+hw-obj-$(CONFIG_ACPI) += acpi.o acpi_piix4.o memslot.o
hw-obj-$(CONFIG_APM) += pm_smbus.o apm.o
hw-obj-$(CONFIG_DMA) += dma.o
hw-obj-$(CONFIG_I82374) += i82374.o
diff --git a/hmp-commands.hx b/hmp-commands.hx
index a6f5a84..cadf4ca 100644
--- a/hmp-commands.hx
+++ b/hmp-commands.hx
@@ -618,6 +618,21 @@ Add device.
ETEXI
{
+ .name = "memslot",
+ .args_type = "id:s,action:s",
+ .params = "id,action",
+ .help = "add memslot device",
+ .user_print = monitor_user_noop,
+ .mhandler.cmd_new = do_memslot_add,
+ },
+
+STEXI
+@item memslot_add @var{config}
+@findex memslot_add
+
+Add memslot.
+ETEXI
+ {
.name = "device_del",
.args_type = "id:s",
.params = "device",
diff --git a/monitor.c b/monitor.c
index 8946a10..f672186 100644
--- a/monitor.c
+++ b/monitor.c
@@ -30,6 +30,7 @@
#include "hw/pci.h"
#include "hw/watchdog.h"
#include "hw/loader.h"
+#include "hw/memslot.h"
#include "gdbstub.h"
#include "net.h"
#include "net/slirp.h"
@@ -4675,3 +4676,10 @@ int monitor_read_block_device_key(Monitor *mon, const char *device,
return monitor_read_bdrv_key_start(mon, bs, completion_cb, opaque);
}
+
+int do_memslot_add(Monitor *mon, const QDict *qdict, QObject **ret_data)
+{
+#if defined(TARGET_I386) || defined(TARGET_X86_64)
+ return memslot_do(mon, qdict);
+#endif
+}
diff --git a/monitor.h b/monitor.h
index 0d49800..1e14a63 100644
--- a/monitor.h
+++ b/monitor.h
@@ -80,5 +80,6 @@ int monitor_read_password(Monitor *mon, ReadLineFunc *readline_func,
int qmp_qom_set(Monitor *mon, const QDict *qdict, QObject **ret);
int qmp_qom_get(Monitor *mon, const QDict *qdict, QObject **ret);
+int do_memslot_add(Monitor *mon, const QDict *qdict, QObject **ret_data);
#endif /* !MONITOR_H */
diff --git a/qemu-config.c b/qemu-config.c
index be84a03..1f26187 100644
--- a/qemu-config.c
+++ b/qemu-config.c
@@ -613,6 +613,30 @@ QemuOptsList qemu_boot_opts = {
},
};
+static QemuOptsList qemu_memslot_opts = {
+ .name = "memslot",
+ .head = QTAILQ_HEAD_INITIALIZER(qemu_memslot_opts.head),
+ .desc = {
+ {
+ .name = "id",
+ .type = QEMU_OPT_STRING,
+ },{
+ .name = "start",
+ .type = QEMU_OPT_SIZE,
+ .help = "physical address start for this memslot",
+ },{
+ .name = "size",
+ .type = QEMU_OPT_SIZE,
+ .help = "memory size for this memslot",
+ },{
+ .name = "node",
+ .type = QEMU_OPT_NUMBER,
+ .help = "NUMA node number (i.e. proximity) for this memslot",
+ },
+ { /* end of list */ }
+ },
+};
+
static QemuOptsList *vm_config_groups[32] = {
&qemu_drive_opts,
&qemu_chardev_opts,
@@ -628,6 +652,7 @@ static QemuOptsList *vm_config_groups[32] = {
&qemu_machine_opts,
&qemu_boot_opts,
&qemu_iscsi_opts,
+ &qemu_memslot_opts,
NULL,
};
diff --git a/qemu-options.hx b/qemu-options.hx
index a169792..aff0546 100644
--- a/qemu-options.hx
+++ b/qemu-options.hx
@@ -2728,3 +2728,11 @@ HXCOMM This is the last statement. Insert new options before this line!
STEXI
@end table
ETEXI
+
+DEF("memslot", HAS_ARG, QEMU_OPTION_memslot,
+ "-memslot start=num,size=num,id=name\n"
+ "specify unpopulated memory slot",
+ QEMU_ARCH_ALL)
+
+
+
diff --git a/sysemu.h b/sysemu.h
index bc2c788..7247099 100644
--- a/sysemu.h
+++ b/sysemu.h
@@ -136,6 +136,7 @@ extern QEMUClock *rtc_clock;
extern int nb_numa_nodes;
extern uint64_t node_mem[MAX_NODES];
extern uint64_t node_cpumask[MAX_NODES];
+extern int nb_hp_memslots;
#define MAX_OPTION_ROMS 16
typedef struct QEMUOptionRom {
diff --git a/vl.c b/vl.c
index 50df453..85ac0f9 100644
--- a/vl.c
+++ b/vl.c
@@ -126,6 +126,7 @@ int main(int argc, char **argv)
#include "hw/xen.h"
#include "hw/qdev.h"
#include "hw/loader.h"
+#include "hw/memslot.h"
#include "bt-host.h"
#include "net.h"
#include "net/slirp.h"
@@ -247,6 +248,7 @@ QTAILQ_HEAD(, FWBootEntry) fw_boot_order = QTAILQ_HEAD_INITIALIZER(fw_boot_order
int nb_numa_nodes;
uint64_t node_mem[MAX_NODES];
uint64_t node_cpumask[MAX_NODES];
+int nb_hp_memslots;
uint8_t qemu_uuid[16];
@@ -512,6 +514,36 @@ static void configure_rtc_date_offset(const char *startdate, int legacy)
}
}
+static void configure_memslot(QemuOpts *opts)
+{
+ const char *value, *id;
+ uint64_t start, size, node;
+
+ id = qemu_opts_id(opts);
+ value = qemu_opt_get(opts, "start");
+ if (!value) {
+ fprintf(stderr, "qemu: invalid start address for memslot '%s'\n", id);
+ exit(1);
+ }
+ start = atoll(value);
+ value = qemu_opt_get(opts, "size");
+ if (!value) {
+ fprintf(stderr, "qemu: invalid size for memslot '%s'\n", id);
+ exit(1);
+ }
+ size = atoi(value);
+ value = qemu_opt_get(opts, "node");
+ if (!value) {
+ fprintf(stderr, "qemu: no node proximity defined for memslot '%s'\n", id);
+ node = 0;
+ }
+ else node = atoi(value);
+ fprintf(stderr, "qemu: memslot %s start %lu size %lu node %lu \n", id,
+ start, size, node);
+ memslot_create((char*)id, start, size, node, nb_hp_memslots);
+ nb_hp_memslots++;
+}
+
static void configure_rtc(QemuOpts *opts)
{
const char *value;
@@ -2330,6 +2362,7 @@ int main(int argc, char **argv, char **envp)
nb_numa_nodes = 0;
nb_nics = 0;
+ nb_hp_memslots = 0;
autostart= 1;
@@ -2521,6 +2554,13 @@ int main(int argc, char **argv, char **envp)
case QEMU_OPTION_kernel:
qemu_opts_set(qemu_find_opts("machine"), 0, "kernel", optarg);
break;
+ case QEMU_OPTION_memslot:
+ opts = qemu_opts_parse(qemu_find_opts("memslot"), optarg, 0);
+ if (!opts) {
+ exit(1);
+ }
+ configure_memslot(opts);
+ break;
case QEMU_OPTION_initrd:
qemu_opts_set(qemu_find_opts("machine"), 0, "initrd", optarg);
break;
--
1.7.9