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@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;