ACPI memory hotplug
v5 cover ACPI memory hotplug
It's been quite a while since v4 and lots of changes happend in qemu and v4 just can't apply anymore. So this series is basically a rebase. Another purpose is to bring up discussions to make consensus on some questions since v4, see
http://lists.gnu.org/archive/html/qemu-devel/2013-01/msg01219.html
and http://lists.gnu.org/archive/html/qemu-devel/2013-02/msg05332.html
This series works with seabios counterpart.
changes from v4:
- rebased on a recent qemu-git
- based on another series which seperates i440fx refactor from v4.
http://lists.nongnu.org/archive/html/qemu-devel/2013-06/msg03500.html
- hot-unplug patches not included, as suggested by Vasilis, since hot-unplug has some more complications with refcounting memory regions.
- fix some copy-paste errors in qapi-schema.json.
v4: http://lists.gnu.org/archive/html/qemu-devel/2012-12/msg02693.html
Issues:
- hot-remove needs to only unmap the dimm device from guest's view. Freeing the memory should happen when the last user of the device (e.g. virtio-blk) unrefs the device. A testcase is needed for this.
- Live Migration: Ramblocks are migrated before qdev VMStates are migrated. So the DimmDevice is handled diferrently than other devices. Should this be reworked ?( DimmDevice structure currently does not define a VMStateDescription) Live migration works as long as the dimm layout (command line args) are identical at the source and destination qemu command line, and destination takes into account hot-operations that have occured on source. (v3 patch 10/19 created the DimmDevice that corresponds to an unknown incoming ramblock, e.g. for a dimm that was hot-added on source. but has been dropped for the moment).
- A main blocker issue is windows guest functionality. The patchset does not work for windows currently. Testing on win2012 server RC or windows2008 consumer prerelease, when adding a DIMM, there is a BSOD with ACPI_BIOS_ERROR message. After this, the VM keeps rebooting with ACPI_BIOS_ERROR. The windows pnpmem driver obviosuly has a problem with the seabios dimm implementation (or the seabios dimm implementation is not fully ACPI-compliant). If someone can review the seabios patches or has any ideas to debug this, let me know.
- hot-operation notification lists need to be added to migration state.
- If a virtio sg element straddles a ramblock boundary, virtio_map_sg can't handle this and qemu exits with "virtio: Trying to map MMIO memory" assertion. This was discovered with stress testing in a VM with hotplugged DIMMs. The top-most commit in the qemu repo above tries to fix this (803aedf0) but maybe you have a better idea. This problem is critical for hot-add upstreaming and needs to be solved. Review/discussion on the list/irc is necessary.
- q35 was supposed/rumoured to have native acpi hotplug support, but I haven't found it in the spec (and I think other people in the list didn't either). Iiuc the plan is to support paravirtual memory hotplug for both piix4 and q35.
Hu Tao (5):
qapi: make visit_type_size fallback to v->type_int() Implement dimm device abstraction
memory: record below_4g_mem_size, above_4g_mem_size memory controller: initialize dram controller.
pc: Add dimm paravirt SRAT info
Vasilis Liaskovitis (9):
Add SIZE type to qdev properties
qemu-option: export parse_option_number
vl: handle "-device dimm"
acpi_piix4 : Implement memory device hotplug registers acpi_ich9 : Implement memory device hotplug registers Introduce paravirt interface QEMU_CFG_PCI_WINDOW Implement "info memory" and "query-memory"
balloon: update with hotplugged memory Implement dimm-info
default-configs/x86_64-softmmu.mak | 1 + docs/specs/acpi_mem_hotplug.txt | 14 ++ docs/specs/fwcfg.txt | 28 ++++ hmp-commands.hx | 4 + hmp.c | 25 ++++ hmp.h | 2 + hw/Makefile.objs | 1 + hw/acpi/ich9.c | 56 ++++++- hw/acpi/piix4.c | 72 ++++++++- hw/core/qdev-properties.c | 61 ++++++++ hw/i386/pc.c | 74 +++++++-- hw/i386/pc_piix.c | 1 + hw/i386/pc_q35.c | 17 ++- hw/mem-hotplug/Makefile.objs | 1 + hw/mem-hotplug/dimm.c | 298 +++++++++++++++++++++++++++++++++++++ hw/pci-host/piix.c | 13 ++ hw/virtio/virtio-balloon.c | 13 +- include/hw/acpi/ich9.h | 10 ++ include/hw/i386/pc.h | 8 + include/hw/mem-hotplug/dimm.h | 78 ++++++++++ include/hw/nvram/fw_cfg.h | 1 + include/hw/qdev-properties.h | 3 + include/qemu/option.h | 4 + include/sysemu/sysemu.h | 1 + monitor.c | 14 ++ qapi-schema.json | 40 +++++ qapi/qapi-visit-core.c | 6 +- qmp-commands.hx | 22 +++ util/qemu-option.c | 8 +- vl.c | 60 ++++++++ 30 files changed, 907 insertions(+), 29 deletions(-) create mode 100644 docs/specs/acpi_mem_hotplug.txt create mode 100644 docs/specs/fwcfg.txt create mode 100644 hw/mem-hotplug/Makefile.objs create mode 100644 hw/mem-hotplug/dimm.c create mode 100644 include/hw/mem-hotplug/dimm.h
Signature · 1 line
1.8.3.1
PATCH v5 1/14 qapi: make visit_type_size fallback to v->type_int()
In case of v->type_uint64 is NULL, fallback to v->type_int, by calling visit_type_uint64().
--- qapi/qapi-visit-core.c | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-)
qapi/qapi-visit-core.c +5 -1
@@ -239,7 +239,11 @@ void visit_type_int64(Visitor *v, int64_t *obj, const char *name, Error **errp)void visit_type_size (Visitor *v,uint64_t *obj,const char *name,Error **errp) {if (!error_is_set (errp)) { - (v->type_size ? v->type_size : v->type_uint64)(v, obj, name, errp); +if (v->type_size) { + v->type_size (v, obj, name, errp); + }else { +visit_type_uint64 (v, obj, name, errp); + } } }
Signature · 1 line
1.8.3.1
PATCH v5 2/14 Add SIZE type to qdev properties
In reply to Hu TaoFrom: Vasilis Liaskovitis <[email protected]>
This patch adds a 'SIZE' type property to qdev.
It will make dimm description more convenient by allowing sizes to be specified with K,M,G,T prefixes instead of number of bytes e.g.:
-device dimm,id=mem0,size=2G,bus=membus.0
Credits go to Ian Molton for original patch. See:
http://patchwork.ozlabs.org/patch/38835/
--- hw/core/qdev-properties.c | 61 ++++++++++++++++++++++++++++++++++++++++++++ include/hw/qdev-properties.h | 3 +++ include/qemu/option.h | 2 ++ util/qemu-option.c | 4 +-- 4 files changed, 68 insertions(+), 2 deletions(-)
hw/core/qdev-properties.c +61 -0
@@ -1134,3 +1134,64 @@ void qdev_prop_set_globals(DeviceState *dev, Error **errp) class =object_class_get_parent (class); }while (class); } + +/* --- 64bit unsigned int 'size' type --- */ + +static void get_size (Object *obj,Visitor *v,void *opaque, +const char *name,Error **errp) +{ +DeviceState *dev =DEVICE (obj); +Property *prop = opaque; +uint64_t *ptr =qdev_get_prop_ptr (dev, prop); + +visit_type_size (v, ptr, name, errp); +} + +static void set_size (Object *obj,Visitor *v,void *opaque, +const char *name,Error **errp) +{ +DeviceState *dev =DEVICE (obj); +Property *prop = opaque; +uint64_t *ptr =qdev_get_prop_ptr (dev, prop); + +if (dev->realized) { +qdev_prop_set_after_realize (dev, name, errp); +return ; + } + +visit_type_size (v, ptr, name, errp); +} + +static int parse_size (DeviceState *dev,Property *prop,const char *str) +{ +uint64_t *ptr =qdev_get_prop_ptr (dev, prop); +Error *errp =NULL ; + +if (str !=NULL ) { +parse_option_size (prop->name, str, ptr, &errp); + } +assert_no_error (errp); +return 0 ; +} + +static int print_size (DeviceState *dev,Property *prop,char *dest,size_t len) +{ +uint64_t *ptr =qdev_get_prop_ptr (dev, prop); +char suffixes[] = {'T' ,'G' ,'M' ,'K' ,'B' }; +int i =0 ; +uint64_t div; + +for (div = (long int )1 <<40 ; !(*ptr / div) ; div >>=10 ) { + i++; + } + +return snprintf (dest, len,"%0.03f%c" , (double )*ptr / div, suffixes[i]); +} + +PropertyInfo qdev_prop_size = { + .name ="size" , + .parse = parse_size, + .print = print_size, + .get = get_size, + .set = set_size, +};
include/hw/qdev-properties.h +3 -0
@@ -15,6 +15,7 @@ extern PropertyInfo qdev_prop_uint64;extern PropertyInfo qdev_prop_hex8;extern PropertyInfo qdev_prop_hex32;extern PropertyInfo qdev_prop_hex64; +extern PropertyInfo qdev_prop_size;extern PropertyInfo qdev_prop_string;extern PropertyInfo qdev_prop_chr;extern PropertyInfo qdev_prop_ptr;
@@ -116,6 +117,8 @@ extern PropertyInfo qdev_prop_arraylen; DEFINE_PROP_DEFAULT(_n, _s, _f, _d, qdev_prop_hex32, uint32_t)#define DEFINE_PROP_HEX64 (_n, _s, _f, _d) \ DEFINE_PROP_DEFAULT(_n, _s, _f, _d, qdev_prop_hex64, uint64_t) +#define DEFINE_PROP_SIZE (_n, _s, _f, _d) \ + DEFINE_PROP_DEFAULT(_n, _s, _f, _d, qdev_prop_size, uint64_t)#define DEFINE_PROP_PCI_DEVFN (_n, _s, _f, _d) \ DEFINE_PROP_DEFAULT(_n, _s, _f, _d, qdev_prop_pci_devfn, int32_t)
include/qemu/option.h +2 -0
@@ -153,5 +153,7 @@ typedef int (*qemu_opts_loopfunc)(QemuOpts *opts, void *opaque);int qemu_opts_print (QemuOpts *opts,void *dummy);int qemu_opts_foreach (QemuOptsList *list,qemu_opts_loopfunc func,void *opaque,int abort_on_failure); +void parse_option_size (const char *name,const char *value, +uint64_t *ret,Error **errp);#endif
util/qemu-option.c +2 -2
@@ -173,8 +173,8 @@ static void parse_option_number(const char *name, const char *value, } } -static void parse_option_size (const char *name,const char *value, -uint64_t *ret,Error **errp) +void parse_option_size (const char *name,const char *value, +uint64_t *ret,Error **errp) {char *postfix;double sizef;
Signature · 1 line
1.8.3.1
Re: [Qemu-devel] [PATCH v5 02/14] Add SIZE type to qdev properties
Am 26.06.2013 11:13, schrieb Hu Tao:
Quoted 8 lines
From: Vasilis Liaskovitis <[email protected]>
This patch adds a 'SIZE' type property to qdev.
It will make dimm description more convenient by allowing sizes to be specified with K,M,G,T prefixes instead of number of bytes e.g.:
-device dimm,id=mem0,size=2G,bus=membus.0
Quoted 5 lines
Credits go to Ian Molton for original patch. See:
http://patchwork.ozlabs.org/patch/38835/Signed-off-by Vasilis Liaskovitis <[email protected]>Signed-off-by Hu Tao <[email protected]>
If the original patch is not from Vasilis, why is this patch not carrying Ian's Signed-off-by from that patch before Vasilis'? (Then we could drop the Patchwork link.)
Andreas
Signature · 2 lines
SUSE LINUX Products GmbH, Maxfeldstr. 5, 90409 Nürnberg, Germany GF: Jeff Hawn, Jennifer Guild, Felix Imendörffer; HRB 16746 AG Nürnberg
Re: [Qemu-devel] [PATCH v5 02/14] Add SIZE type to qdev properties
Cced: Ian Molton <[email protected]>
Quoted 12 lines · Andreas Färber
Am 26.06.2013 11:13, schrieb Hu Tao:
Quoted 11 lines
From: Vasilis Liaskovitis <[email protected]>
This patch adds a 'SIZE' type property to qdev.
It will make dimm description more convenient by allowing sizes to be specified with K,M,G,T prefixes instead of number of bytes e.g.:
-device dimm,id=mem0,size=2G,bus=membus.0Credits go to Ian Molton for original patch. See:
http://patchwork.ozlabs.org/patch/38835/
Quoted 6 lines
Quoted 2 lines
Signed-off-by Vasilis Liaskovitis <[email protected]>Signed-off-by Hu Tao <[email protected]>If the original patch is not from Vasilis, why is this patch not carrying Ian's Signed-off-by from that patch before Vasilis'? (Then we could drop the Patchwork link.)
I'll update in the next version.
PATCH v5 3/14 qemu-option: export parse_option_number
In reply to Hu TaoFrom: Vasilis Liaskovitis <[email protected]>
--- include/qemu/option.h | 2 ++ util/qemu-option.c | 4 ++-- 2 files changed, 4 insertions(+), 2 deletions(-)
include/qemu/option.h +2 -0
@@ -155,5 +155,7 @@ int qemu_opts_foreach(QemuOptsList *list, qemu_opts_loopfunc func, void *opaque, int abort_on_failure);void parse_option_size (const char *name,const char *value,uint64_t *ret,Error **errp); +void parse_option_number (const char *name,const char *value, +uint64_t *ret,Error **errp);#endif
util/qemu-option.c +2 -2
@@ -155,8 +155,8 @@ static void parse_option_bool(const char *name, const char *value, bool *ret, } } -static void parse_option_number (const char *name,const char *value, -uint64_t *ret,Error **errp) +void parse_option_number (const char *name,const char *value, +uint64_t *ret,Error **errp) {char *postfix;uint64_t number;
Signature · 1 line
1.8.3.1
PATCH v5 4/14 Implement dimm device abstraction
In reply to Hu TaoEach hotplug-able memory slot is a DimmDevice. All DimmDevices are attached to a new bus called DimmBus. This bus is introduced so that we no longer depend on hotplug-capability of main system bus (the main bus does not allow hotplugging). The DimmBus should be attached to a chipset Device (i440fx in case of the pc)
A hot-add operation for a particular dimm:
- creates a new DimmDevice and attaches it to the DimmBus
- 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.
Hotplug operations are done through normal device_add commands. Also add properties to DimmDevice.
TODO/FIXME: Dimm configurations are specified at qemu startup at the command line. Dimms with "populated=off" are actually not created, but their config is saved in the corresponding bus. If user does not specify the correct bus for a dimm device during device_add and there are multiple memory buses in the machine (e.g. right now membus.0 and membus.pv are created in this pachset) the first bus found in the device tree that matches the device type is picked. This bus may be the wrong one, and the dimm config is not retrieved, thus creating a useless dimm device. A solution would be to delete the new dimm if the dimm config was not found (see commented qmp_device_del in dimm_init) but this does not look clean. This design needs to be fixed somehow to avoid similar problems if multiple memory buses are present in the same machine.
--- default-configs/x86_64-softmmu.mak | 1 + hw/Makefile.objs | 1 + hw/mem-hotplug/Makefile.objs | 1 + hw/mem-hotplug/dimm.c | 241 +++++++++++++++++++++++++++++++++++++ include/hw/mem-hotplug/dimm.h | 77 ++++++++++++ 5 files changed, 321 insertions(+) create mode 100644 hw/mem-hotplug/Makefile.objs create mode 100644 hw/mem-hotplug/dimm.c create mode 100644 include/hw/mem-hotplug/dimm.h
default-configs/x86_64-softmmu.mak +1 -0
@@ -46,3 +46,4 @@ CONFIG_APIC=y CONFIG_IOAPIC=y CONFIG_ICC_BUS=y CONFIG_PVPANIC=y +CONFIG_MEM_HOTPLUG=y
hw/Makefile.objs +1 -0
@@ -27,6 +27,7 @@ devices-dirs-$(CONFIG_SOFTMMU) += usb/ devices-dirs-$(CONFIG_VIRTIO) += virtio/ devices-dirs-$(CONFIG_SOFTMMU) += watchdog/ devices-dirs-$(CONFIG_SOFTMMU) += xen/ +devices-dirs-$(CONFIG_MEM_HOTPLUG) += mem-hotplug/ devices-dirs-y += core/ common-obj-y += $(devices-dirs-y) obj-y += $(devices-dirs-y)
hw/mem-hotplug/Makefile.objs new file +1 -0
@@ -0,0 +1 @@ +common-obj-$(CONFIG_MEM_HOTPLUG) += dimm.o
hw/mem-hotplug/dimm.c new file +241 -0
241 lines not on this page · raw message
include/hw/mem-hotplug/dimm.h new file +77 -0
77 lines not on this page · raw message
Signature · 1 line
1.8.3.1
PATCH v5 5/14 vl: handle "-device dimm"
In reply to Hu TaoFrom: Vasilis Liaskovitis <[email protected]>
--- vl.c | 51 +++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 51 insertions(+)
vl.c +51 -0
@@ -170,6 +170,7 @@ int main(int argc, char **argv)#include "ui/qemu-spice.h" #include "qapi/string-input-visitor.h" +#include "hw/mem-hotplug/dimm.h" //#define DEBUG_NET //#define DEBUG_SLIRP
@@ -252,6 +253,7 @@ static QTAILQ_HEAD(, FWBootEntry) fw_boot_order =int nb_numa_nodes;uint64_t node_mem[MAX_NODES ];unsigned long *node_cpumask[MAX_NODES ]; +int nb_hp_dimms;uint8_t qemu_uuid[16 ];
@@ -2338,6 +2340,50 @@ static int chardev_init_func(QemuOpts *opts, void *opaque)return 0 ; } +static int dimmcfg_init_func (QemuOpts *opts,void *opaque) +{ +const char *driver; +const char *id; +uint64_t node, size; +uint32_t populated; +const char *buf, *busbuf; + +/* DimmDevice configuration needs to be known in order to initialize chipset +* with correct memory and pci ranges. But all devices are created after +* chipset / machine initialization. In * order to avoid this problem, we +* parse dimm information earlier into dimmcfg structs. */ + + driver =qemu_opt_get (opts,"driver" ); +if (!strcmp (driver,"dimm" )) { + + id =qemu_opts_id (opts); + buf =qemu_opt_get (opts,"size" ); +parse_option_size ("size" , buf, &size,NULL ); + buf =qemu_opt_get (opts,"node" ); +parse_option_number ("node" , buf, &node,NULL ); + busbuf =qemu_opt_get (opts,"bus" ); + buf =qemu_opt_get (opts,"populated" ); +if (!buf) { + populated =0 ; + }else { + populated =strcmp (buf,"on" ) ?0 :1 ; + } + +dimm_config_create ((char *)id, size, busbuf ? busbuf :"membus.0" , + node, nb_hp_dimms); + +/* if !populated, we just keep the config. The real device +* will be created in the future with a normal device_add +* command. */ +if (!populated) { +qemu_opts_del (opts); + } + nb_hp_dimms++; + } + +return 0 ; +} +#ifdef CONFIG_VIRTFS static int fsdev_init_func (QemuOpts *opts,void *opaque) {
@@ -4260,6 +4306,11 @@ int main(int argc, char **argv, char **envp) }qemu_add_globals (); +/* init generic devices */ +if (qemu_opts_foreach (qemu_find_opts ("device" ), + dimmcfg_init_func,NULL ,1 ) !=0 ) { +exit (1 ); + }qdev_machine_init ();QEMUMachineInitArgs args = { .ram_size = ram_size,
Signature · 1 line
1.8.3.1
Re: [Qemu-devel] [PATCH v5 05/14] vl: handle "-device dimm"
Il 26/06/2013 11:13, Hu Tao ha scritto:
Quoted 60 lines
From: Vasilis Liaskovitis <[email protected]>
Signed-off-by Vasilis Liaskovitis <[email protected]>Signed-off-by Hu Tao <[email protected]>--- vl.c | 51 +++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 51 insertions(+)vl.c +30
-0@@ -170,6 +170,7 @@ int main(int argc, char **argv)#include "ui/qemu-spice.h" #include "qapi/string-input-visitor.h" +#include "hw/mem-hotplug/dimm.h" //#define DEBUG_NET //#define DEBUG_SLIRP @@ -252,6 +253,7 @@ static QTAILQ_HEAD(, FWBootEntry) fw_boot_order =int nb_numa_nodes;uint64_t node_mem[MAX_NODES ];unsigned long *node_cpumask[MAX_NODES ]; +int nb_hp_dimms;uint8_t qemu_uuid[16 ];@@ -2338,6 +2340,50 @@ static int chardev_init_func(QemuOpts *opts, void *opaque)return 0 ; } +static int dimmcfg_init_func (QemuOpts *opts,void *opaque) +{ +const char *driver; +const char *id; +uint64_t node, size; +uint32_t populated; +const char *buf, *busbuf; + +/* DimmDevice configuration needs to be known in order to initialize chipset +* with correct memory and pci ranges. But all devices are created after +* chipset / machine initialization. In * order to avoid this problem, we +* parse dimm information earlier into dimmcfg structs. */ + + driver =qemu_opt_get (opts,"driver" ); +if (!strcmp (driver,"dimm" )) { + + id =qemu_opts_id (opts); + buf =qemu_opt_get (opts,"size" ); +parse_option_size ("size" , buf, &size,NULL ); + buf =qemu_opt_get (opts,"node" ); +parse_option_number ("node" , buf, &node,NULL ); + busbuf =qemu_opt_get (opts,"bus" ); + buf =qemu_opt_get (opts,"populated" ); +if (!buf) { + populated =0 ; + }else { + populated =strcmp (buf,"on" ) ?0 :1 ; + }
vl.c static int chardev_init_func(QemuOpts *opts, void *opaque) · line 2380
Quoted 10 lines
vl.c +10
-0+ +dimm_config_create ((char *)id, size, busbuf ? busbuf :"membus.0" , + node, nb_hp_dimms); + +/* if !populated, we just keep the config. The real device +* will be created in the future with a normal device_add +* command. */ +if (!populated) { +qemu_opts_del (opts); + }
I think you need another option than -device dimm. For example it could be declared together with the NUMA node. This could declare two NUMA nodes, each with 2G of populated and 2G of unpopulated RAM:
-numa node,mem-range=0-2G,mem-range-hotplug=4G-6G \ -numa node,mem-range=2G-4G,mem-range-hotplug=6G-8G
I'm not sure I like the names particularly though. CCing Eduardo, Bandan and Wanlong Gao.
Paolo
Quoted 22 lines
vl.c +11
-0+ nb_hp_dimms++; + } + +return 0 ; +} +#ifdef CONFIG_VIRTFS static int fsdev_init_func (QemuOpts *opts,void *opaque) {@@ -4260,6 +4306,11 @@ int main(int argc, char **argv, char **envp) }qemu_add_globals (); +/* init generic devices */ +if (qemu_opts_foreach (qemu_find_opts ("device" ), + dimmcfg_init_func,NULL ,1 ) !=0 ) { +exit (1 ); + }qdev_machine_init ();QEMUMachineInitArgs args = { .ram_size = ram_size,
Re: [Qemu-devel] [PATCH v5 05/14] vl: handle "-device dimm"
Quoted 76 lines · Paolo Bonzini
Il 26/06/2013 11:13, Hu Tao ha scritto:
Quoted 60 lines
From: Vasilis Liaskovitis <[email protected]>
Signed-off-by Vasilis Liaskovitis <[email protected]>Signed-off-by Hu Tao <[email protected]>--- vl.c | 51 +++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 51 insertions(+)vl.c +30
-0@@ -170,6 +170,7 @@ int main(int argc, char **argv)#include "ui/qemu-spice.h" #include "qapi/string-input-visitor.h" +#include "hw/mem-hotplug/dimm.h" //#define DEBUG_NET //#define DEBUG_SLIRP @@ -252,6 +253,7 @@ static QTAILQ_HEAD(, FWBootEntry) fw_boot_order =int nb_numa_nodes;uint64_t node_mem[MAX_NODES ];unsigned long *node_cpumask[MAX_NODES ]; +int nb_hp_dimms;uint8_t qemu_uuid[16 ];@@ -2338,6 +2340,50 @@ static int chardev_init_func(QemuOpts *opts, void *opaque)return 0 ; } +static int dimmcfg_init_func (QemuOpts *opts,void *opaque) +{ +const char *driver; +const char *id; +uint64_t node, size; +uint32_t populated; +const char *buf, *busbuf; + +/* DimmDevice configuration needs to be known in order to initialize chipset +* with correct memory and pci ranges. But all devices are created after +* chipset / machine initialization. In * order to avoid this problem, we +* parse dimm information earlier into dimmcfg structs. */ + + driver =qemu_opt_get (opts,"driver" ); +if (!strcmp (driver,"dimm" )) { + + id =qemu_opts_id (opts); + buf =qemu_opt_get (opts,"size" ); +parse_option_size ("size" , buf, &size,NULL ); + buf =qemu_opt_get (opts,"node" ); +parse_option_number ("node" , buf, &node,NULL ); + busbuf =qemu_opt_get (opts,"bus" ); + buf =qemu_opt_get (opts,"populated" ); +if (!buf) { + populated =0 ; + }else { + populated =strcmp (buf,"on" ) ?0 :1 ; + }vl.c static int chardev_init_func(QemuOpts *opts, void *opaque) · line 2380
Quoted 10 lines
vl.c +10
-0+ +dimm_config_create ((char *)id, size, busbuf ? busbuf :"membus.0" , + node, nb_hp_dimms); + +/* if !populated, we just keep the config. The real device +* will be created in the future with a normal device_add +* command. */ +if (!populated) { +qemu_opts_del (opts); + }I think you need another option than -device dimm. For example it could be declared together with the NUMA node. This could declare two NUMA nodes, each with 2G of populated and 2G of unpopulated RAM:
Quoted 5 lines
-numa node,mem-range=0-2G,mem-range-hotplug=4G-6G \ -numa node,mem-range=2G-4G,mem-range-hotplug=6G-8GI'm not sure I like the names particularly though. CCing Eduardo, Bandan and Wanlong Gao.
Do we really need to specify the memory range? I suspect that we can
follow current design of normal memory in hot-plug memory. Currently,
we just specify the size of normal memory in each node, and the range
in normal memory is node by node. Then I think we can just specify
the memory size of hot-plug in each node, then the hot-plug memory
range is also node by node, and the whole hot-plug memory block is
just located after the normal memory block. If so, the option can
come like:
-numa node,nodeid=0,mem=2G,cpus=0-1,mem-hotplug=2G,mem-policy=membind,mem-hostnode=0-1,mem-hotplug-policy=interleave,mem-hotplug-hostnode=1 -numa node,nodeid=1,mem=2G,cpus=2-3,mem-hotplug=2G,mem-policy=preferred,mem-hostnode=1,mem-hotplug-policy=membind,mem-hotplug-hostnode=0-1
And each hot-plug memory device size can be assigned through "-device dimm,size=1G", assume that we specify 4 hot-plug memory devices and each 1G, then first two devices as we ranged belong to node0, and other two belong to node1. Then the hot-plug memory will have no effect on current normal memory design.
Thanks,
Wanlong Gao
Quoted 27 lines
Paolo
Quoted 22 lines
vl.c +11
-0+ nb_hp_dimms++; + } + +return 0 ; +} +#ifdef CONFIG_VIRTFS static int fsdev_init_func (QemuOpts *opts,void *opaque) {@@ -4260,6 +4306,11 @@ int main(int argc, char **argv, char **envp) }qemu_add_globals (); +/* init generic devices */ +if (qemu_opts_foreach (qemu_find_opts ("device" ), + dimmcfg_init_func,NULL ,1 ) !=0 ) { +exit (1 ); + }qdev_machine_init ();QEMUMachineInitArgs args = { .ram_size = ram_size,
Re: [Qemu-devel] [PATCH v5 05/14] vl: handle "-device dimm"
Il 27/06/2013 07:08, Wanlong Gao ha scritto:
Quoted 2 lines
Do we really need to specify the memory range? I suspect that we can follow current design of normal memory in hot-plug memory.
I think we can do both. I'm afraid that the configuration of the VM will not be perfectly reproducible without specifying the range, more so if you allow hotplug.
Quoted 9 lines
Currently,
we just specify the size of normal memory in each node, and the range
in normal memory is node by node. Then I think we can just specify
the memory size of hot-plug in each node, then the hot-plug memory
range is also node by node, and the whole hot-plug memory block is
just located after the normal memory block. If so, the option can
come like:
-numa node,nodeid=0,mem=2G,cpus=0-1,mem-hotplug=2G,mem-policy=membind,mem-hostnode=0-1,mem-hotplug-policy=interleave,mem-hotplug-hostnode=1 -numa node,nodeid=1,mem=2G,cpus=2-3,mem-hotplug=2G,mem-policy=preferred,mem-hostnode=1,mem-hotplug-policy=membind,mem-hotplug-hostnode=0-1
I think specifying different policies and bindings for normal and hotplug memory is too much fine-grained. If you really want that, then you would need something like
-numa node,nodeid=0,cpus=0-1 \
-numa mem,nodeid=0,size=2G,policy=membind,hostnode=0-1 \
-numa mem,nodeid=0,size=2G,policy=interleave,hostnode=1,populated=noHmm... this actually doesn't look too bad, and it is much more future-proof. Eduardo, what do you think about it? Should Wanlong redo his patches to support this "-numa mem" syntax? Parsing it should be easy using the QemuOpts visitor, too.
Paolo
Re: [Qemu-devel] [PATCH v5 05/14] vl: handle "-device dimm"
Quoted 22 lines · On Thu, 27 Jun 2013 08:55:25 +0200 Paolo Bonzini <[email protected]> wrote:
Il 27/06/2013 07:08, Wanlong Gao ha scritto:
Quoted 2 lines
Do we really need to specify the memory range? I suspect that we can follow current design of normal memory in hot-plug memory.
I think we can do both. I'm afraid that the configuration of the VM will not be perfectly reproducible without specifying the range, more so if you allow hotplug.
Quoted 9 lines
Currently,
we just specify the size of normal memory in each node, and the range
in normal memory is node by node. Then I think we can just specify
the memory size of hot-plug in each node, then the hot-plug memory
range is also node by node, and the whole hot-plug memory block is
just located after the normal memory block. If so, the option can
come like:
-numa node,nodeid=0,mem=2G,cpus=0-1,mem-hotplug=2G,mem-policy=membind,mem-hostnode=0-1,mem-hotplug-policy=interleave,mem-hotplug-hostnode=1 -numa node,nodeid=1,mem=2G,cpus=2-3,mem-hotplug=2G,mem-policy=preferred,mem-hostnode=1,mem-hotplug-policy=membind,mem-hotplug-hostnode=0-1I think specifying different policies and bindings for normal and hotplug memory is too much fine-grained. If you really want that, then you would need something like
Quoted 8 lines
-numa node,nodeid=0,cpus=0-1 \ -numa mem,nodeid=0,size=2G,policy=membind,hostnode=0-1 \ -numa mem,nodeid=0,size=2G,policy=interleave,hostnode=1,populated=noHmm... this actually doesn't look too bad, and it is much more future-proof. Eduardo, what do you think about it? Should Wanlong redo his patches to support this "-numa mem" syntax? Parsing it should be easy using the QemuOpts visitor, too.
Is hot-plugged memory and its bindings to numa nodes have to be specified at startup?
How about extending -m option to support following syntax:
-m initial_mem[, number_of_hotplug_dimms, max_mem]]
and dynamically forming MEMXX._CRS/_PXM resources on demand instead of creating static resources in SSDT.
without necessity to specify to be hot-plugged DIMMs at startup, hot-plug could become more flexible since arbitrarily sized DIMMs with required NUMA mapping could be specified during hot-plug time, for example:
device_add dimm,id=dimm1,bus=membus.0,size=3G,node=1,...
the only limit would be left is a number of increments(DIMM slots), due to need to pre-generate ACPI memory devices that could supply _CRS/_PXM resources later.
Quoted 3 lines
Paolo
Re: [Qemu-devel] [PATCH v5 05/14] vl: handle "-device dimm"
Quoted 41 lines · Igor Mammedov
Quoted 22 lines · On Thu, 27 Jun 2013 08:55:25 +0200 Paolo Bonzini <[email protected]> wrote:
Il 27/06/2013 07:08, Wanlong Gao ha scritto:
Quoted 2 lines
Do we really need to specify the memory range? I suspect that we can follow current design of normal memory in hot-plug memory.
I think we can do both. I'm afraid that the configuration of the VM will not be perfectly reproducible without specifying the range, more so if you allow hotplug.
Quoted 9 lines
Currently,
we just specify the size of normal memory in each node, and the range
in normal memory is node by node. Then I think we can just specify
the memory size of hot-plug in each node, then the hot-plug memory
range is also node by node, and the whole hot-plug memory block is
just located after the normal memory block. If so, the option can
come like:
-numa node,nodeid=0,mem=2G,cpus=0-1,mem-hotplug=2G,mem-policy=membind,mem-hostnode=0-1,mem-hotplug-policy=interleave,mem-hotplug-hostnode=1 -numa node,nodeid=1,mem=2G,cpus=2-3,mem-hotplug=2G,mem-policy=preferred,mem-hostnode=1,mem-hotplug-policy=membind,mem-hotplug-hostnode=0-1I think specifying different policies and bindings for normal and hotplug memory is too much fine-grained. If you really want that, then you would need something like
Quoted 8 lines
-numa node,nodeid=0,cpus=0-1 \ -numa mem,nodeid=0,size=2G,policy=membind,hostnode=0-1 \ -numa mem,nodeid=0,size=2G,policy=interleave,hostnode=1,populated=noHmm... this actually doesn't look too bad, and it is much more future-proof. Eduardo, what do you think about it? Should Wanlong redo his patches to support this "-numa mem" syntax? Parsing it should be easy using the QemuOpts visitor, too.
Is hot-plugged memory and its bindings to numa nodes have to be specified at startup?
How about extending -m option to support following syntax:
-m initial_mem[,
number_of_hotplug_dimms,max_mem]]
Quoted 8 lines
and dynamically forming MEMXX._CRS/_PXM resources on demand instead of creating static resources in SSDT.
without necessity to specify to be hot-plugged DIMMs at startup, hot-plug could become more flexible since arbitrarily sized DIMMs with required NUMA mapping could be specified during hot-plug time, for example:
device_adddimm,id=dimm1,bus=membus.0,size=3G,node=1,...
Seems impossible as ACPI memory devices' ranges must be specified at startup, but I'll be glad if I'm wrong.
Quoted 10 lines
the only limit would be left is a number of increments(DIMM slots), due to need to pre-generate ACPI memory devices that could supply _CRS/_PXM resources later.
Quoted 3 lines
Paolo
Re: [Qemu-devel] [PATCH v5 05/14] vl: handle "-device dimm"
Il 12/07/2013 04:39, Hu Tao ha scritto:
Quoted 8 lines
Quoted 5 lines
without necessity to specify to be hot-plugged DIMMs at startup, hot-plug could become more flexible since arbitrarily sized DIMMs with required NUMA mapping could be specified during hot-plug time, for example:
device_adddimm,id=dimm1,bus=membus.0,size=3G,node=1,...Seems impossible as ACPI memory devices' ranges must be specified at startup, but I'll be glad if I'm wrong.
Yeah, I also understood the problem to be the SRAT, not the DSDT... Of course you could reserve a single large part of the address range in "-numa mem", and then add one or more DIMMs covering only part of the address range.
Perhaps "populated" could be a size instead of a boolean, to do something like what Igor suggested.
Paolo
Re: [Qemu-devel] [PATCH v5 05/14] vl: handle "-device dimm"
Quoted 7 lines · Paolo Bonzini
Il 12/07/2013 04:39, Hu Tao ha scritto:
Quoted 6 lines
Quoted 5 lines
without necessity to specify to be hot-plugged DIMMs at startup, hot-plug could become more flexible since arbitrarily sized DIMMs with required NUMA mapping could be specified during hot-plug time, for example:
device_adddimm,id=dimm1,bus=membus.0,size=3G,node=1,...
Quoted 7 lines
Quoted 2 lines
Seems impossible as ACPI memory devices' ranges must be specified at startup, but I'll be glad if I'm wrong.
Yeah, I also understood the problem to be the SRAT, not the DSDT... Of course you could reserve a single large part of the address range in "-numa mem", and then add one or more DIMMs covering only part of the address range.
still needs to specify -dimm at startup, right?
Quoted 3 lines
Perhaps "populated" could be a size instead of a boolean, to do something like what Igor suggested.
seems odd that a memory device is partially populated. How can guest OS and firmware cope with that?
Quoted 2 lines
Paolo
Re: [Qemu-devel] [PATCH v5 05/14] vl: handle "-device dimm"
In reply to Paolo BonziniHi,
Quoted 22 lines · Paolo Bonzini
Il 27/06/2013 07:08, Wanlong Gao ha scritto:
Quoted 2 lines
Do we really need to specify the memory range? I suspect that we can follow current design of normal memory in hot-plug memory.
I think we can do both. I'm afraid that the configuration of the VM will not be perfectly reproducible without specifying the range, more so if you allow hotplug.
Quoted 9 lines
Currently,
we just specify the size of normal memory in each node, and the range
in normal memory is node by node. Then I think we can just specify
the memory size of hot-plug in each node, then the hot-plug memory
range is also node by node, and the whole hot-plug memory block is
just located after the normal memory block. If so, the option can
come like:
-numa node,nodeid=0,mem=2G,cpus=0-1,mem-hotplug=2G,mem-policy=membind,mem-hostnode=0-1,mem-hotplug-policy=interleave,mem-hotplug-hostnode=1 -numa node,nodeid=1,mem=2G,cpus=2-3,mem-hotplug=2G,mem-policy=preferred,mem-hostnode=1,mem-hotplug-policy=membind,mem-hotplug-hostnode=0-1I think specifying different policies and bindings for normal and hotplug memory is too much fine-grained. If you really want that, then you would need something like
Quoted 8 lines
-numa node,nodeid=0,cpus=0-1 \ -numa mem,nodeid=0,size=2G,policy=membind,hostnode=0-1 \ -numa mem,nodeid=0,size=2G,policy=interleave,hostnode=1,populated=noHmm... this actually doesn't look too bad, and it is much more future-proof. Eduardo, what do you think about it? Should Wanlong redo his patches to support this "-numa mem" syntax? Parsing it should be easy using the QemuOpts visitor, too.
from what i understand, we are currently favoring this numa option? (I saw it mentioned in Gao's numa patchset series as well)
There is still the question of "how many hotpluggable dimm devices does this memory range describe?". With the dimm device that was clearly defined, but not so with this option. Do we choose a default granularity e.g. 1 GB?
Also, as you mentioned, without specifying the memory range, the VM configuration may be ambiguous. Currently, the VM memory map depends on the order of dimms defined on the command line. So:
"-device dimm,id=dimm0,size=1G,node=0 -device dimm,id=dimm1,size=2G,node=0" and
"-device dimm,id=dimm1,size=2G,node=0 -device dimm,id=dimm1,size=1G,node=0"
assign different memory ranges to the dimms.
On the other hand, iirc memory ranges were discussed with previous maintainers but was rejected: The user/management library may not want to know or simply does not know architectural details of the guest hardware. What happens if the user specifies memory on the PCI-hole? Do we bail out or adjust their arguments? Adjusting ranges might open another can of worms.
In any case, it would be good to get a final consensus on this.
thanks,
- Vasilis
Re: [Qemu-devel] [PATCH v5 05/14] vl: handle "-device dimm"
Il 15/07/2013 19:05, Vasilis Liaskovitis ha scritto:
Quoted 2 lines
from what i understand, we are currently favoring this numa option? (I saw it mentioned in Gao's numa patchset series as well)
The two patchsets have some overlap, so it's good to find a design that fits both.
Quoted 3 lines
There is still the question of "how many hotpluggable dimm devices does this memory range describe?". With the dimm device that was clearly defined, but not so with this option. Do we choose a default granularity e.g. 1 GB?
I think it's the same. One "-numa mem" option = one "-device dimm" option; both define one range. Unused memory ranges may remain if you stumble upon a unusable range such as the PCI window. For example two "-numa mem,size=2G" options would allocate memory from 0 to 2G and from 4 to 6G.
I'm snipping the rest of the email because I hope this covers all your doubts.
Paolo
Re: [Qemu-devel] [PATCH v5 05/14] vl: handle "-device dimm"
Quoted 7 lines · Paolo Bonzini
Il 15/07/2013 19:05, Vasilis Liaskovitis ha scritto:
Quoted 2 lines
from what i understand, we are currently favoring this numa option? (I saw it mentioned in Gao's numa patchset series as well)
The two patchsets have some overlap, so it's good to find a design that fits both.
Quoted 6 lines
Quoted 3 lines
There is still the question of "how many hotpluggable dimm devices does this memory range describe?". With the dimm device that was clearly defined, but not so with this option. Do we choose a default granularity e.g. 1 GB?
I think it's the same. One "-numa mem" option = one "-device dimm" option; both define one range. Unused memory ranges may remain if you
ah ok, I get the proposal now.
Quoted 3 lines
stumble upon a unusable range such as the PCI window. For example two "-numa mem,size=2G" options would allocate memory from 0 to 2G and from 4 to 6G.
ok, that's done already.
thanks,
- Vasilis
Re: [Qemu-devel] [PATCH v5 05/14] vl: handle "-device dimm"
In reply to Paolo BonziniQuoted 11 lines · Paolo Bonzini
Il 15/07/2013 19:05, Vasilis Liaskovitis ha scritto:
Quoted 2 lines
from what i understand, we are currently favoring this numa option? (I saw it mentioned in Gao's numa patchset series as well)
The two patchsets have some overlap, so it's good to find a design that fits both.
Quoted 3 lines
There is still the question of "how many hotpluggable dimm devices does this memory range describe?". With the dimm device that was clearly defined, but not so with this option. Do we choose a default granularity e.g. 1 GB?
Quoted 5 lines
I think it's the same. One "-numa mem" option = one "-device dimm" option; both define one range. Unused memory ranges may remain if you stumble upon a unusable range such as the PCI window. For example two "-numa mem,size=2G" options would allocate memory from 0 to 2G and from 4 to 6G.
So we can drop -dimm if we agree on -numa mem?
Quoted 5 lines
I'm snipping the rest of the email because I hope this covers all your doubts.
Paolo
Re: [Qemu-devel] [PATCH v5 05/14] vl: handle "-device dimm"
Il 16/07/2013 03:27, Hu Tao ha scritto:
Quoted 7 lines
Quoted 5 lines
I think it's the same. One "-numa mem" option = one "-device dimm" option; both define one range. Unused memory ranges may remain if you stumble upon a unusable range such as the PCI window. For example two "-numa mem,size=2G" options would allocate memory from 0 to 2G and from 4 to 6G.
So we can drop -dimm if we agree on -numa mem?
Yes, the point of the "-numa mem" proposal was to avoid the concept of a "partially initialized device" that you had for DIMMs.
BTW, how do you specify which module you are plugging in? I.e., what if I have three 1G ranges at 0, 1G and 2G, and I want to plug the first and the third?
This is especially important with hot-unplug, because then you can have this kind of hole in the address space. If you migrate the VM, you have to reproduce the situation in the destination command line.
Paolo
Re: [Qemu-devel] [PATCH v5 05/14] vl: handle "-device dimm"
Quoted 7 lines · Paolo Bonzini
Il 16/07/2013 03:27, Hu Tao ha scritto:
Quoted 6 lines
Quoted 5 lines
I think it's the same. One "-numa mem" option = one "-device dimm" option; both define one range. Unused memory ranges may remain if you stumble upon a unusable range such as the PCI window. For example two "-numa mem,size=2G" options would allocate memory from 0 to 2G and from 4 to 6G.
Quoted 8 lines
Quoted 1 line
So we can drop -dimm if we agree on -numa mem?
Yes, the point of the "-numa mem" proposal was to avoid the concept of a "partially initialized device" that you had for DIMMs.
BTW, how do you specify which module you are plugging in? I.e., what if I have three 1G ranges at 0, 1G and 2G, and I want to plug the first and the third?
I think an id is still needed to identify ranges, which can be shown to user with `info numa' or similar command, along with the corresponding ranges.
Quoted 7 lines
This is especially important with hot-unplug, because then you can have this kind of hole in the address space. If you migrate the VM, you have to reproduce the situation in the destination command line.
Paolo
Re: [Qemu-devel] [PATCH v5 05/14] vl: handle "-device dimm"
Quoted 13 lines · On Tue, 16 Jul 2013 15:27:19 +0800 Hu Tao <[email protected]> wrote:
Quoted 12 lines · Paolo Bonzini
Il 16/07/2013 03:27, Hu Tao ha scritto:
Quoted 7 lines
Quoted 5 lines
I think it's the same. One "-numa mem" option = one "-device dimm" option; both define one range. Unused memory ranges may remain if you stumble upon a unusable range such as the PCI window. For example two "-numa mem,size=2G" options would allocate memory from 0 to 2G and from 4 to 6G.
So we can drop -dimm if we agree on -numa mem?
Yes, the point of the "-numa mem" proposal was to avoid the concept of a "partially initialized device" that you had for DIMMs.
Quoted 7 lines
Quoted 3 lines
BTW, how do you specify which module you are plugging in? I.e., what if I have three 1G ranges at 0, 1G and 2G, and I want to plug the first and the third?
I think an id is still needed to identify ranges, which can be shown to user with `info numa' or similar command, along with the corresponding ranges.
"info numa" could get actual ranges enumerating present dimms if we would use plain -device for hotplug memory instead of -numa mem hacking.
Quoted 9 lines
Quoted 8 lines
This is especially important with hot-unplug, because then you can have this kind of hole in the address space. If you migrate the VM, you have to reproduce the situation in the destination command line.
Paolo
Re: [Qemu-devel] [PATCH v5 05/14] vl: handle "-device dimm"
In reply to Paolo BonziniQuoted 11 lines · On Tue, 16 Jul 2013 08:19:48 +0200 Paolo Bonzini <[email protected]> wrote:
Il 16/07/2013 03:27, Hu Tao ha scritto:
Quoted 7 lines
Quoted 5 lines
I think it's the same. One "-numa mem" option = one "-device dimm" option; both define one range. Unused memory ranges may remain if you stumble upon a unusable range such as the PCI window. For example two "-numa mem,size=2G" options would allocate memory from 0 to 2G and from 4 to 6G.
So we can drop -dimm if we agree on -numa mem?
Yes, the point of the "-numa mem" proposal was to avoid the concept of a "partially initialized device" that you had for DIMMs.
I've though -numa mem was for mapping initial memory to numa nodes. It seem wrong to use it for representing dimm device and also limiting possible hotplugged regions to specified at startup ranges.
we can leave -numa for initial memory mapping and manage of the mapping of hotpluggable regions with -device dimm,node=X,size=Y.
It that case command line -device dimm will provide a fully initialized dimm device usable at startup (but hot-unplugable) and
(monitor) device_add dimm,,node=X,size=Y
would serve hot-plug case.
That way arbitrary sized dimm could be hot-pluged without specifying them at startup, like it's done on bare-metal.
In addition command line -device would be used in migration case to describe already hot-plugged dimms on target.
Quoted 6 lines
BTW, how do you specify which module you are plugging in? I.e., what if I have three 1G ranges at 0, 1G and 2G, and I want to plug the first and the third?
This is especially important with hot-unplug, because then you can have this kind of hole in the address space. If you migrate the VM, you have to reproduce the situation in the destination command line.
Could we add optional advising 'base-addr' property to replicate exact source configuration on target? some thing like:
-device dimm,node=X,size=Y,base-addr=Z
where mgmt could get actual X,Y,Z inspecting dim device via qom-get. and if base-addr is not set parent of dimm would auto-allocate address where dimm is mapped.
Quoted 3 lines
Paolo
Re: [Qemu-devel] [PATCH v5 05/14] vl: handle "-device dimm"
Il 16/07/2013 12:19, Igor Mammedov ha scritto:
Quoted 10 lines
Quoted 7 lines · On Tue, 16 Jul 2013 08:19:48 +0200 Paolo Bonzini <[email protected]> wrote:
Il 16/07/2013 03:27, Hu Tao ha scritto:
Quoted 6 lines
Quoted 5 lines
I think it's the same. One "-numa mem" option = one "-device dimm" option; both define one range. Unused memory ranges may remain if you stumble upon a unusable range such as the PCI window. For example two "-numa mem,size=2G" options would allocate memory from 0 to 2G and from 4 to 6G.
Quoted 7 lines
Quoted 4 lines
Quoted 1 line
So we can drop -dimm if we agree on -numa mem?
Yes, the point of the "-numa mem" proposal was to avoid the concept of a "partially initialized device" that you had for DIMMs.
I've though -numa mem was for mapping initial memory to numa nodes. It seem wrong to use it for representing dimm device and also limiting possible hotplugged regions to specified at startup ranges.
It's not for DIMM devices, it is for reserving areas of the address space for hot-plugged RAM. DIMM hotplug is done with "device_add dimm" (and you can also use "-numa mem,populated=no,... -device dimm,..." to start a VM with hot-unpluggable memory).
Quoted 10 lines
we can leave -numa for initial memory mapping and manage of the mapping of hotpluggable regions with -device dimm,node=X,size=Y.
It that case command line -device dimm will provide a fully initialized dimm device usable at startup (but hot-unplugable) and
(monitor)device_adddimm,,node=X,size=Y
would serve hot-plug case.That way arbitrary sized dimm could be hot-pluged without specifying them at startup, like it's done on bare-metal.
But the memory ranges need to be specified at startup in the ACPI tables, and that's what "-numa mem" is for.
Quoted 2 lines
In addition command line -device would be used in migration case to describe already hot-plugged dimms on target.
Yep.
Paolo
Re: [Qemu-devel] [PATCH v5 05/14] vl: handle "-device dimm"
Quoted 15 lines · On Tue, 16 Jul 2013 12:31:46 +0200 Paolo Bonzini <[email protected]> wrote:
Il 16/07/2013 12:19, Igor Mammedov ha scritto:
Quoted 14 lines
Quoted 11 lines · On Tue, 16 Jul 2013 08:19:48 +0200 Paolo Bonzini <[email protected]> wrote:
Il 16/07/2013 03:27, Hu Tao ha scritto:
Quoted 7 lines
Quoted 5 lines
I think it's the same. One "-numa mem" option = one "-device dimm" option; both define one range. Unused memory ranges may remain if you stumble upon a unusable range such as the PCI window. For example two "-numa mem,size=2G" options would allocate memory from 0 to 2G and from 4 to 6G.
So we can drop -dimm if we agree on -numa mem?
Yes, the point of the "-numa mem" proposal was to avoid the concept of a "partially initialized device" that you had for DIMMs.
Quoted 8 lines
Quoted 3 lines
I've though -numa mem was for mapping initial memory to numa nodes. It seem wrong to use it for representing dimm device and also limiting possible hotplugged regions to specified at startup ranges.
It's not for DIMM devices, it is for reserving areas of the address space for hot-plugged RAM. DIMM hotplug is done with "
device_adddimm" (and you can also use "-numa mem,populated=no,... -device dimm,..." to start a VM with hot-unpluggable memory).
There isn't a real need to reserve from ACPI pov, memory device in ACPI could provide _PXM() method to return mapping to numa node.
And from my testing linux and windows guest are using it, even if is there is unnecessary mapping in SRAT table overriding SRAT mammping with dynamic one.
It would be better not to use "populated" concept at all. If there is -device dim on cmd line, then it populated and for hotplugged dimm all necessary information could be generated dynamically.
Quoted 8 lines
Quoted 8 lines
we can leave -numa for initial memory mapping and manage of the mapping of hotpluggable regions with -device dimm,node=X,size=Y.
It that case command line -device dimm will provide a fully initialized dimm device usable at startup (but hot-unplugable) and
(monitor)device_adddimm,,node=X,size=Y
would serve hot-plug case.
Quoted 5 lines
Quoted 2 lines
That way arbitrary sized dimm could be hot-pluged without specifying them at startup, like it's done on bare-metal.
But the memory ranges need to be specified at startup in the ACPI tables, and that's what "-numa mem" is for.
not really, there is caveat with windows, which needs a hotplugable SRAT entry that tells it max possible limit (otherwise windows sees new dimm device but refuses to use it saying "server is not configured for hotplug" or something like this), but as far as such entry exists, windows is happily uses dynamic _CRS() and _PXM() if they are below that limit (even if a new range is not in any range defined by SRAT).
And ACPI spec doesn't say that SRAT MUST be populated with hotplug ranges.
It's kind of simplier for bare-metal, where they might do it due to limited supported DIMM capacity by reserving static entries with max supported ranges per DIMM and know in advance DIMM count for platform. But actual _CRS() anyway dynamic since plugged in DIMM could have a smaller capacity then supported max for slot.
To summarize ACPI + windows limitations:
- ACPI needs to pre-allocate memory devices, i.e. number of possible increments OSPM could utilize. It might be possible to overcome limitation be using Load() or LoadTable() in runtime, but I haven't tried it.
- Windows needs to know max supported limit, a fake entry in SRAT from RamSize to max_mem works nicely there (tested with ws2008r2DC and ws2012DC).
That's why I was proposing to extend "-m" option for "slots" number (i.e. nr of memory devices) and 'max_mem' to make Windows happy and cap mgmt tools from going over initially configured limit.
then -device dimm could be used for hotpluggable mem available at startup and device_add fir adding more dimms with user defined sizes to desired nodes at runtime.
Works nice without any need for 'populated=xxx' and predefined ranges.
PS:
I'll be able to post more or less usable RFC that does it on top of mst's ACPI tables in QEMU by the end of this week.
Quoted 7 lines
Quoted 3 lines
In addition command line -device would be used in migration case to describe already hot-plugged dimms on target.
Yep.
Paolo
Re: [Qemu-devel] [PATCH v5 05/14] vl: handle "-device dimm"
Il 16/07/2013 14:00, Igor Mammedov ha scritto:
Quoted 13 lines
Quoted 8 lines
Quoted 8 lines
we can leave -numa for initial memory mapping and manage of the mapping of hotpluggable regions with -device dimm,node=X,size=Y.
It that case command line -device dimm will provide a fully initialized dimm device usable at startup (but hot-unplugable) and
(monitor)device_adddimm,,node=X,size=Y
would serve hot-plug case.Quoted 5 lines
Quoted 2 lines
That way arbitrary sized dimm could be hot-pluged without specifying them at startup, like it's done on bare-metal.
But the memory ranges need to be specified at startup in the ACPI tables, and that's what "-numa mem" is for.
Quoted 8 lines
not really, there is caveat with windows, which needs a hotplugable SRAT entry that tells it max possible limit (otherwise windows sees new dimm device but refuses to use it saying "server is not configured for hotplug" or something like this), but as far as such entry exists, windows is happily uses dynamic
_CRS()and_PXM()if they are below that limit (even if a new range is not in any range defined by SRAT).And ACPI spec doesn't say that SRAT MUST be populated with hotplug ranges.
Right, what is required in ACPI is only pre-allocation of slots.
Quoted 13 lines
It's kind of simplier for bare-metal, where they might do it due to limited supported DIMM capacity by reserving static entries with max supported ranges per DIMM and know in advance DIMM count for platform. But actual
_CRS()anyway dynamic since plugged in DIMM could have a smaller capacity then supported max for slot.To summarize ACPI + windows limitations:
- ACPI needs to pre-allocate memory devices, i.e. number of possible increments OSPM could utilize. It might be possible to overcome limitation be usingLoad()orLoadTable()in runtime, but I haven't tried it.
- Windows needs to know max supported limit, a fake entry in SRAT from RamSize tomax_memworks nicely there (tested with ws2008r2DC and ws2012DC).
Quoted 3 lines
That's why I was proposing to extend "-m" option for "slots" number (i.e. nr of memory devices) and '
max_mem' to make Windows happy and cap mgmt tools from going over initially configured limit.
As far as memory hot-plug is concerned, the "-numa mem" proposal is exactly the same thing that you are proposing, minus the ability to specify many slots in one go. The same "-numa mem" can be used for host node binding as well, but that's not really relevant for memory hot-plug.
In case you want multiple hotpluggable ranges, bonud to different host nodes, It doesn't matter if the SRAT will have one or many fake entries.
Quoted 3 lines
then -device dimm could be used for hotpluggable mem available at startup and
device_addfir adding more dimms with user defined sizes to desired nodes at runtime.
Yes, no disagreement on this.
Quoted 5 lines
Works nice without any need for 'populated=xxx' and predefined ranges.
PS:
I'll be able to post more or less usable RFC that does it on top of mst's ACPI tables in QEMU by the end of this week.
Good!
Paolo
Quoted 8 lines
Quoted 7 lines
Quoted 3 lines
In addition command line -device would be used in migration case to describe already hot-plugged dimms on target.
Yep.
Paolo
PATCH v5 6/14 acpi_piix4 : Implement memory device hotplug registers
In reply to Hu TaoFrom: Vasilis Liaskovitis <[email protected]>
A 32-byte register is used to present up to 256 hotplug-able memory devices to BIOS and OSPM. Hot-add and hot-remove functions trigger an ACPI hotplug event through these. Only reads are allowed from these registers.
An ACPI hot-remove event but needs to wait for OSPM to eject the device. We use a single-byte register to know when OSPM has called the _EJ function for a particular dimm. A write to this byte will depopulate the respective dimm. Only writes are allowed to this byte.
v1->v2:mems_sts address moved from 0xaf20 to 0xaf80 (to accomodate more space for cpu-hotplugging in the future)._EJ array is reduced to a single byte.
Add documentation in docs/specs/acpi_hotplug.txt
v3->v4: Removed hot-remove functions, will be added separately. Updated for memory API.
--- docs/specs/acpi_mem_hotplug.txt | 14 ++++++++ hw/acpi/piix4.c | 72 ++++++++++++++++++++++++++++++++++++++++- 2 files changed, 85 insertions(+), 1 deletion(-) create mode 100644 docs/specs/acpi_mem_hotplug.txt
docs/specs/acpi_mem_hotplug.txt new file +14 -0
@@ -0,0 +1,14 @@ +QEMU<->ACPI BIOS hotplug interface +-------------------------------------- +This document describes the interface between QEMU and the ACPI BIOS for non-PCI +space. For the PCI interface please look at docs/specs/acpi_pci_hotplug.txt + +QEMU<->ACPI BIOS memory hotplug interface +-------------------------------------- + +Memory Dimm status array (IO port 0xaf80-0xaf9f, 1-byte access): +--------------------------------------------------------------- +Dimm hot-plug notification pending. One bit per slot. + +Read by ACPI BIOS GPE.3 handler to notify OS of memory hot-add or hot-remove +events. Read-only.
hw/acpi/piix4.c +71 -1
128 lines not on this page · raw message
Signature · 1 line
1.8.3.1
PATCH v5 7/14 acpi_ich9 : Implement memory device hotplug registers
In reply to Hu TaoFrom: Vasilis Liaskovitis <[email protected]>
This implements acpi dimm hot-add capability for q35 (ich9). The logic is the same as for the pc machine (piix4).
TODO: Fix acpi irq delivery bug. Currently there is a flood of irqs when delivering an acpi interrupt (should be just one). Guest complains as follows:
"irq 9: nobody cared
[...]
Disabling IRQ #9"
where #9 is the acpi irq
--- hw/acpi/ich9.c | 56 ++++++++++++++++++++++++++++++++++++++++++++++++-- include/hw/acpi/ich9.h | 10 +++++++++ 2 files changed, 64 insertions(+), 2 deletions(-)
hw/acpi/ich9.c +54 -2
@@ -33,6 +33,7 @@#include "exec/address-spaces.h" #include "hw/i386/ich9.h" +#include "hw/mem-hotplug/dimm.h" //#define DEBUG
@@ -49,11 +50,14 @@ static void pm_update_sci(ICH9LPCPMRegs *pm) pm1a_sts =acpi_pm1_evt_get_sts (&pm->acpi_regs); - sci_level = (((pm1a_sts & pm->acpi_regs.pm1.evt.en) & + sci_level = ((((pm1a_sts & pm->acpi_regs.pm1.evt.en) & (ACPI_BITMASK_RT_CLOCK_ENABLE |ACPI_BITMASK_POWER_BUTTON_ENABLE |ACPI_BITMASK_GLOBAL_LOCK_ENABLE | -ACPI_BITMASK_TIMER_ENABLE )) !=0 ); +ACPI_BITMASK_TIMER_ENABLE )) !=0 ) || + (((pm->acpi_regs.gpe.sts[0 ] & pm->acpi_regs.gpe.en[0 ]) & + (ICH9_MEM_HOTPLUG_STATUS )) !=0 )); +qemu_set_irq (pm->irq, sci_level);/* schedule a timer interruption if needed */
@@ -202,6 +206,47 @@ static void pm_powerdown_req(Notifier *n, void *opaque)acpi_pm1_evt_power_down (&pm->acpi_regs); } +static uint32_t mem_status_readb (void *opaque,uint32_t addr) +{ +ICH9LPCPMRegs *s = opaque; +uint32_t val =0 ; +MemStatus *g = &s->gpe_mem; +if (addr <ICH9_MEM_LEN ) { + val = (uint32_t ) g->mems_sts[addr]; + } +ICH9_DEBUG ("memhp read %" PRIu32" == %" PRIu32"\n" , addr, val); +return val; +} + +static const MemoryRegionOps ich9_mem_hotplug_ops = { + .old_portio = (MemoryRegionPortio []) { + { + .offset =0 , .len =ICH9_MEM_LEN , .size =1 , + .read = mem_status_readb, + }, +PORTIO_END_OF_LIST () + }, + .endianness =DEVICE_LITTLE_ENDIAN , +}; + +static void enable_mem_device (ICH9LPCState *s,int memdevice) +{ +MemStatus *g = &s->pm.gpe_mem; + s->pm.acpi_regs.gpe.sts[0 ] |=ICH9_MEM_HOTPLUG_STATUS ; + g->mems_sts[memdevice /8 ] |= (1 << (memdevice %8 )); +} + +static int ich9_mem_hotplug (DeviceState *dev,DimmDevice *dimm,int add) +{ +ICH9LPCState *s =ICH9_LPC_DEVICE (dev); + +if (add) { +enable_mem_device (s, dimm->idx); + } +pm_update_sci (&s->pm); +return 0 ; +} +void ich9_pm_init (PCIDevice *lpc_pci,ICH9LPCPMRegs *pm,qemu_irq sci_irq) {
@@ -227,4 +272,11 @@ void ich9_pm_init(PCIDevice *lpc_pci, ICH9LPCPMRegs *pm,qemu_register_reset (pm_reset, pm); pm->powerdown_notifier.notify = pm_powerdown_req;qemu_register_powerdown_notifier (&pm->powerdown_notifier); + +memory_region_init_io (&pm->io_mem, &ich9_mem_hotplug_ops, pm, +"acpi-memory-hotplug0" ,ICH9_MEM_BASE ); +memory_region_add_subregion (get_system_io (),ICH9_MEM_BASE , &pm->io_mem); + +dimm_bus_hotplug (ich9_mem_hotplug, &lpc_pci->qdev); + }
include/hw/acpi/ich9.h +10 -0
@@ -23,6 +23,14 @@#include "hw/acpi/acpi.h" +#define ICH9_MEM_BASE 0xaf80 +#define ICH9_MEM_LEN 32 +#define ICH9_MEM_HOTPLUG_STATUS 8 + +typedef struct MemStatus { +uint8_t mems_sts[ICH9_MEM_LEN ]; +}MemStatus ; + typedef struct ICH9LPCPMRegs { /* * In ich9 spec says that pm1_cnt register is 32bit width and
@@ -34,6 +42,7 @@ typedef struct ICH9LPCPMRegs {MemoryRegion io;MemoryRegion io_gpe;MemoryRegion io_smi; +MemoryRegion io_mem;uint32_t smi_en;uint32_t smi_sts;
@@ -42,6 +51,7 @@ typedef struct ICH9LPCPMRegs {uint32_t pm_io_base;Notifier powerdown_notifier; +MemStatus gpe_mem; } ICH9LPCPMRegs; void ich9_pm_init(PCIDevice *lpc_pci, ICH9LPCPMRegs *pm,
Signature · 1 line
1.8.3.1
PATCH v5 8/14 memory: record below_4g_mem_size, above_4g_mem_size
In reply to Hu Tao--- hw/i386/pc.c | 17 ++++++++--------- include/hw/i386/pc.h | 2 ++ 2 files changed, 10 insertions(+), 9 deletions(-)
hw/i386/pc.c +8 -9
@@ -1288,7 +1288,6 @@ static int memory_controller_init(PCIDevice *dev)MemoryController *m =MEMORY_CONTROLLER (dev);MemoryControllerClass *c =MEMORY_CONTROLLER_GET_CLASS (dev);ram_addr_t ram_size; -hwaddr below_4g_mem_size, above_4g_mem_size;hwaddr pci_hole_start, pci_hole_size;hwaddr pci_hole64_start, pci_hole64_size;int i;
@@ -1296,11 +1295,11 @@ static int memory_controller_init(PCIDevice *dev)g_assert (m->system_memory !=NULL );if (m->ram_size > c->pci_hole_start) { - below_4g_mem_size = c->pci_hole_start; - above_4g_mem_size = m->ram_size - c->pci_hole_start; + m->below_4g_mem_size = c->pci_hole_start; + m->above_4g_mem_size = m->ram_size - c->pci_hole_start; }else { - below_4g_mem_size = m->ram_size; - above_4g_mem_size =0 ; + m->below_4g_mem_size = m->ram_size; + m->above_4g_mem_size =0 ; }/* Allocate RAM. We allocate it as a single memory region and use
@@ -1310,16 +1309,16 @@ static int memory_controller_init(PCIDevice *dev)memory_region_init_ram (&m->ram,"pc.ram" , m->ram_size);vmstate_register_ram_global (&m->ram);memory_region_init_alias (&m->ram_below_4g,"ram-below-4g" , &m->ram, -0 , below_4g_mem_size); +0 , m->below_4g_mem_size);memory_region_add_subregion (m->system_memory,0 , &m->ram_below_4g); -if (above_4g_mem_size >0 ) { +if (m->above_4g_mem_size >0 ) {memory_region_init_alias (&m->ram_above_4g,"ram-above-4g" , &m->ram, - below_4g_mem_size, above_4g_mem_size); + m->below_4g_mem_size, m->above_4g_mem_size);memory_region_add_subregion (m->system_memory, c->pci_hole_end, &m->ram_above_4g); } - pci_hole_start = below_4g_mem_size; + pci_hole_start = m->below_4g_mem_size; pci_hole_size = c->pci_hole_end - pci_hole_start; pci_hole64_start = c->pci_hole_end + m->ram_size - pci_hole_start;
include/hw/i386/pc.h +2 -0
@@ -46,6 +46,8 @@ typedef struct MemoryController {MemoryRegion ram;MemoryRegion ram_below_4g;MemoryRegion ram_above_4g; +hwaddr below_4g_mem_size; +hwaddr above_4g_mem_size; } MemoryController;void mc_update_pam (MemoryController *d);
Signature · 1 line
1.8.3.1
PATCH v5 9/14 memory controller: initialize dram controller.
In reply to Hu Tao--- hw/i386/pc.c | 27 +++++++++++++++++++++++++++ include/hw/i386/pc.h | 5 +++++ 2 files changed, 32 insertions(+)
hw/i386/pc.c +27 -0
@@ -1283,6 +1283,27 @@ void mc_set_smm(int val, void *arg)memory_region_transaction_commit (); } +static hwaddr mc_dimm_offset (DeviceState *dev,uint64_t size) +{ +MemoryController *d =MEMORY_CONTROLLER (dev); +MemoryControllerClass *c =MEMORY_CONTROLLER_GET_CLASS (d); +hwaddr ret; + +if (d->below_4g_mem_size + size <= c->pci_hole_start) { +/* if dimm fits before pci hole, append it normally */ + ret = d->below_4g_mem_size; + d->below_4g_mem_size += size; + }else { +/* otherwise place it above 4GB */ + ret = d->above_4g_mem_size + c->pci_hole_end; + d->above_4g_mem_size += size; + } + + d->ram_size += size; + +return ret; +} +static int memory_controller_init (PCIDevice *dev) {MemoryController *m =MEMORY_CONTROLLER (dev);
@@ -1353,6 +1374,11 @@ static int memory_controller_init(PCIDevice *dev) PAM_EXPAN_SIZE); } + m->dram_channel0 =dimm_bus_create (OBJECT (m),"membus.0" ,8 , + c->dimm_offset); + m->pv_dram_channel =dimm_bus_create (OBJECT (m),"membus.pv" ,0 , + c->dimm_offset); + ram_size = m->ram_size /8 /1024 /1024 ;if (ram_size >255 ) { ram_size =255 ;
@@ -1388,6 +1414,7 @@ static void memory_controller_class_init(ObjectClass *klass, void *data) dc->no_user =1 ; mc->set_smm = mc_set_smm; mc->update = mc_update; + mc->dimm_offset = mc_dimm_offset; }static const TypeInfo memory_controller_type_info = {
include/hw/i386/pc.h +5 -0
@@ -10,6 +10,7 @@#include "hw/i386/ioapic.h" #include "hw/pci/pci.h" #include "hw/pci-host/pam.h" +#include "hw/mem-hotplug/dimm.h" #define TYPE_MEMORY_CONTROLLER "memory controller"#define MEMORY_CONTROLLER (obj) OBJECT_CHECK(MemoryController, (obj), TYPE_DEVICE)
@@ -29,6 +30,7 @@ typedef struct MemoryControllerClass {void (*set_smm)(int val,void *arg);void (*update)(MemoryController *m); +hwaddr (*dimm_offset)(DeviceState *d,uint64_t size); } MemoryControllerClass; typedef struct MemoryController {
@@ -48,6 +50,9 @@ typedef struct MemoryController {MemoryRegion ram_above_4g;hwaddr below_4g_mem_size;hwaddr above_4g_mem_size; + +DimmBus *dram_channel0; +DimmBus *pv_dram_channel; } MemoryController;void mc_update_pam (MemoryController *d);
Signature · 1 line
1.8.3.1
PATCH v5 10/14 pc: Add dimm paravirt SRAT info
In reply to Hu TaoThe numa_fw_cfg paravirt interface is extended to include SRAT information for all hotplug-able dimms. There are 3 words for each hotplug-able memory slot, denoting start address, size and node proximity. The new info is appended after existing numa info, so that the fw_cfg layout does not break. This information is used by Seabios to build hotplug memory device objects at runtime. nb_numa_nodes is set to 1 by default (not 0), so that we always pass srat info to SeaBIOS.
v3->v4: numa_fw_cfg needs to be initalized after memory controller sets up dimm ranges. Make changes for pc_piix and pc_q35 to set numa_fw_cfg after i440fx initialization.
v2->v3: setting nb_numa_nodes to 1 is not needed
v1->v2:
Dimm SRAT info (#dimms) is appended at end of existing numa fw_cfg in order not to break existing layout
Documentation of the new fwcfg layout is included in docs/specs/fwcfg.txt
--- docs/specs/fwcfg.txt | 28 ++++++++++++++++++++++++++++ hw/i386/pc.c | 30 ++++++++++++++++++++++++------ hw/i386/pc_piix.c | 1 + hw/i386/pc_q35.c | 7 +++++-- include/hw/i386/pc.h | 1 + include/sysemu/sysemu.h | 1 + 6 files changed, 60 insertions(+), 8 deletions(-) create mode 100644 docs/specs/fwcfg.txt
docs/specs/fwcfg.txt new file +28 -0
@@ -0,0 +1,28 @@ +QEMU<->BIOS Paravirt Documentation +-------------------------------------- + +This document describes paravirt data structures passed from QEMU to BIOS. + +fw_cfg SRAT paravirt info +-------------------- +The SRAT info passed from QEMU to BIOS has the following layout: + +----------------------------------------------------------------------------------------------- +#nodes | cpu0_pxm | cpu1_pxm | ... | cpulast_pxm | node0_mem | node1_mem | ... | nodelast_mem + +----------------------------------------------------------------------------------------------- +#dimms | dimm0_start | dimm0_sz | dimm0_pxm | ... | dimmlast_start | dimmlast_sz | dimmlast_pxm + +Entry 0 contains the number of numa nodes (nb_numa_nodes). + +Entries 1..max_cpus: The next max_cpus entries describe node proximity for each +one of the vCPUs in the system. + +Entries max_cpus+1..max_cpus+nb_numa_nodes+1: The next nb_numa_nodes entries +describe the memory size for each one of the NUMA nodes in the system. + +Entry max_cpus+nb_numa_nodes+1 contains the number of memory dimms (nb_hp_dimms) + +The last 3 * nb_hp_dimms entries are organized in triplets: Each triplet contains +the physical address offset, size (in bytes), and node proximity for the +respective dimm.
hw/i386/pc.c +24 -6
@@ -55,6 +55,7 @@#include "hw/acpi/acpi.h" #include "hw/cpu/icc_bus.h" #include "hw/boards.h" +#include "hw/mem-hotplug/dimm.h" /* debug PC/ISA interrupts */ //#define DEBUG_IRQ
@@ -606,8 +607,6 @@ static FWCfgState *bochs_bios_init(void)FWCfgState *fw_cfg;uint8_t *smbios_table;size_t smbios_len; -uint64_t *numa_fw_cfg; -int i, j;unsigned int apic_id_limit =pc_apic_id_limit (max_cpus); fw_cfg =fw_cfg_init (BIOS_CFG_IOPORT ,BIOS_CFG_IOPORT +1 ,0 ,0 );
@@ -640,11 +639,25 @@ static FWCfgState *bochs_bios_init(void) &e820_table, sizeof(e820_table));fw_cfg_add_bytes (fw_cfg,FW_CFG_HPET , &hpet_cfg,sizeof (hpet_cfg)); + +return fw_cfg; +} + +void bochs_meminfo_bios_init (void *fw_cfg) +{ +uint64_t *numa_fw_cfg; +uint64_t *hp_dimms_fw_cfg; +int i, j; +unsigned int apic_id_limit =pc_apic_id_limit (max_cpus); +/* allocate memory for the NUMA channel: one (64bit) word for the number * of nodes, one word for each VCPU->node and one word for each node to * hold the amount of memory. +* Finally one word for the number of hotplug memory slots and three words +* for each hotplug memory slot (start address, size and node proximity). */ - numa_fw_cfg =g_new0 (uint64_t,1 + apic_id_limit + nb_numa_nodes); + numa_fw_cfg =g_new0 (uint64_t, +2 + apic_id_limit + nb_numa_nodes +3 * nb_hp_dimms); numa_fw_cfg[0 ] =cpu_to_le64 (nb_numa_nodes);for (i =0 ; i < max_cpus; i++) {unsigned int apic_id =x86_cpu_apic_id_from_index (i);
@@ -659,11 +672,16 @@ static FWCfgState *bochs_bios_init(void)for (i =0 ; i < nb_numa_nodes; i++) { numa_fw_cfg[apic_id_limit +1 + i] =cpu_to_le64 (node_mem[i]); } + + numa_fw_cfg[1 + apic_id_limit + nb_numa_nodes] =cpu_to_le64 (nb_hp_dimms); + + hp_dimms_fw_cfg = numa_fw_cfg +2 + apic_id_limit + nb_numa_nodes; +if (nb_hp_dimms) { +dimm_setup_fwcfg_layout (hp_dimms_fw_cfg); + }fw_cfg_add_bytes (fw_cfg,FW_CFG_NUMA , numa_fw_cfg, - (1 + apic_id_limit + nb_numa_nodes) * + (2 + apic_id_limit + nb_numa_nodes +3 * nb_hp_dimms) *sizeof (*numa_fw_cfg)); - -return fw_cfg; }static long get_file_size (FILE *f)
hw/i386/pc_piix.c +1 -0
@@ -138,6 +138,7 @@ static void pc_init1(MemoryRegion *system_memory,if (!xen_enabled ()) { fw_cfg =pc_memory_init (kernel_filename, kernel_cmdline, initrd_filename, below_4g_mem_size, above_4g_mem_size); +bochs_meminfo_bios_init (fw_cfg); }if (kvm_irqchip_in_kernel ()) {
hw/i386/pc_q35.c +5 -2
@@ -74,6 +74,7 @@ static void pc_q35_init(QEMUMachineInitArgs *args)ICH9LPCState *ich9_lpc;PCIDevice *ahci;DeviceState *icc_bridge; +void *fw_cfg =NULL ; icc_bridge =qdev_create (NULL ,TYPE_ICC_BRIDGE ); object_property_add_child(qdev_get_machine(), "icc-bridge",
@@ -97,8 +98,9 @@ static void pc_q35_init(QEMUMachineInitArgs *args)/* allocate ram and load rom/bios */ if (!xen_enabled ()) { -pc_memory_init (kernel_filename, kernel_cmdline, - initrd_filename, below_4g_mem_size, above_4g_mem_size); + fw_cfg =pc_memory_init (kernel_filename, kernel_cmdline, + initrd_filename, below_4g_mem_size, + above_4g_mem_size); }/* irq lines */
@@ -116,6 +118,7 @@ static void pc_q35_init(QEMUMachineInitArgs *args) q35_host->mch.address_space_io =get_system_io ();/* pci */ qdev_init_nofail (DEVICE (q35_host)); +bochs_meminfo_bios_init (fw_cfg); host_bus = q35_host->host.pci.bus;/* create ISA bus */ lpc = pci_create_simple_multifunction(host_bus, PCI_DEVFN(ICH9_LPC_DEV,
include/hw/i386/pc.h +1 -0
@@ -231,6 +231,7 @@ int pvpanic_init(ISABus *bus);#define E820_UNUSABLE 5int e820_add_entry (uint64_t ,uint64_t ,uint32_t ); +void bochs_meminfo_bios_init (void *fw_cfg);#define PC_COMPAT_1_5 \ {\
include/sysemu/sysemu.h +1 -0
@@ -132,6 +132,7 @@ extern QEMUClock *rtc_clock;extern int nb_numa_nodes;extern uint64_t node_mem[MAX_NODES ];extern unsigned long *node_cpumask[MAX_NODES ]; +extern int nb_hp_dimms;#define MAX_OPTION_ROMS 16 typedef struct QEMUOptionRom {
Signature · 1 line
1.8.3.1
Re: [Qemu-devel] [PATCH v5 10/14] pc: Add dimm paravirt SRAT info
Quoted 14 lines · Hu Tao
The
numa_fw_cfgparavirt interface is extended to include SRAT information for all hotplug-able dimms. There are 3 words for each hotplug-able memory slot, denoting start address, size and node proximity. The new info is appended after existing numa info, so that thefw_cfglayout does not break. This information is used by Seabios to build hotplug memory device objects at runtime.nb_numa_nodesis set to 1 by default (not 0), so that we always pass srat info to SeaBIOS.
v3->v4:numa_fw_cfgneeds to be initalized after memory controller sets up dimm ranges. Make changes forpc_piixandpc_q35to setnuma_fw_cfgafter i440fx initialization.
v2->v3: settingnb_numa_nodesto 1 is not needed
Quoted 7 lines
v1->v2:
Dimm SRAT info (#dimms) is appended at end of existing numafw_cfgin order not to break existing layout
Documentation of the new fwcfg layout is included indocs/specs/fwcfg.txtSigned-off-by Vasilis Liaskovitis <[email protected]>Signed-off-by Hu Tao <[email protected]>
Please do not add any more fwcfg interfaces - generating ACPI in qemu removes the need for it.
So please rebase on top of that work and generate the appropriate ACPI tables directly.
You can find the latest code gnerating ACPI from qemu here:git://git.kernel.org/pub/scm/virt/kvm/mst/qemu.git acpi
This code is work in progress, but once you base on top of that, I can put it on that branch and keep updating if interfaces change.
Quoted 183 lines
--- docs/specs/fwcfg.txt | 28 ++++++++++++++++++++++++++++ hw/i386/pc.c | 30 ++++++++++++++++++++++++------ hw/i386/pc_piix.c | 1 + hw/i386/pc_q35.c | 7 +++++-- include/hw/i386/pc.h | 1 + include/sysemu/sysemu.h | 1 + 6 files changed, 60 insertions(+), 8 deletions(-) create mode 100644 docs/specs/fwcfg.txtdocs/specs/fwcfg.txt new file +28
-0@@ -0,0 +1,28 @@ +QEMU<->BIOS Paravirt Documentation +-------------------------------------- + +This document describes paravirt data structures passed from QEMU to BIOS. + +fw_cfg SRAT paravirt info +-------------------- +The SRAT info passed from QEMU to BIOS has the following layout: + +----------------------------------------------------------------------------------------------- +#nodes | cpu0_pxm | cpu1_pxm | ... | cpulast_pxm | node0_mem | node1_mem | ... | nodelast_mem + +----------------------------------------------------------------------------------------------- +#dimms | dimm0_start | dimm0_sz | dimm0_pxm | ... | dimmlast_start | dimmlast_sz | dimmlast_pxm + +Entry 0 contains the number of numa nodes (nb_numa_nodes). + +Entries 1..max_cpus: The next max_cpus entries describe node proximity for each +one of the vCPUs in the system. + +Entries max_cpus+1..max_cpus+nb_numa_nodes+1: The next nb_numa_nodes entries +describe the memory size for each one of the NUMA nodes in the system. + +Entry max_cpus+nb_numa_nodes+1 contains the number of memory dimms (nb_hp_dimms) + +The last 3 * nb_hp_dimms entries are organized in triplets: Each triplet contains +the physical address offset, size (in bytes), and node proximity for the +respective dimm.hw/i386/pc.c +24
-6@@ -55,6 +55,7 @@#include "hw/acpi/acpi.h" #include "hw/cpu/icc_bus.h" #include "hw/boards.h" +#include "hw/mem-hotplug/dimm.h" /* debug PC/ISA interrupts */ //#define DEBUG_IRQ @@ -606,8 +607,6 @@ static FWCfgState *bochs_bios_init(void)FWCfgState *fw_cfg;uint8_t *smbios_table;size_t smbios_len; -uint64_t *numa_fw_cfg; -int i, j;unsigned int apic_id_limit =pc_apic_id_limit (max_cpus); fw_cfg =fw_cfg_init (BIOS_CFG_IOPORT ,BIOS_CFG_IOPORT +1 ,0 ,0 );@@ -640,11 +639,25 @@ static FWCfgState *bochs_bios_init(void) &e820_table, sizeof(e820_table));fw_cfg_add_bytes (fw_cfg,FW_CFG_HPET , &hpet_cfg,sizeof (hpet_cfg)); + +return fw_cfg; +} + +void bochs_meminfo_bios_init (void *fw_cfg) +{ +uint64_t *numa_fw_cfg; +uint64_t *hp_dimms_fw_cfg; +int i, j; +unsigned int apic_id_limit =pc_apic_id_limit (max_cpus); +/* allocate memory for the NUMA channel: one (64bit) word for the number * of nodes, one word for each VCPU->node and one word for each node to * hold the amount of memory. +* Finally one word for the number of hotplug memory slots and three words +* for each hotplug memory slot (start address, size and node proximity). */ - numa_fw_cfg =g_new0 (uint64_t,1 + apic_id_limit + nb_numa_nodes); + numa_fw_cfg =g_new0 (uint64_t, +2 + apic_id_limit + nb_numa_nodes +3 * nb_hp_dimms); numa_fw_cfg[0 ] =cpu_to_le64 (nb_numa_nodes);for (i =0 ; i < max_cpus; i++) {unsigned int apic_id =x86_cpu_apic_id_from_index (i);@@ -659,11 +672,16 @@ static FWCfgState *bochs_bios_init(void)for (i =0 ; i < nb_numa_nodes; i++) { numa_fw_cfg[apic_id_limit +1 + i] =cpu_to_le64 (node_mem[i]); } + + numa_fw_cfg[1 + apic_id_limit + nb_numa_nodes] =cpu_to_le64 (nb_hp_dimms); + + hp_dimms_fw_cfg = numa_fw_cfg +2 + apic_id_limit + nb_numa_nodes; +if (nb_hp_dimms) { +dimm_setup_fwcfg_layout (hp_dimms_fw_cfg); + }fw_cfg_add_bytes (fw_cfg,FW_CFG_NUMA , numa_fw_cfg, - (1 + apic_id_limit + nb_numa_nodes) * + (2 + apic_id_limit + nb_numa_nodes +3 * nb_hp_dimms) *sizeof (*numa_fw_cfg)); - -return fw_cfg; }static long get_file_size (FILE *f)hw/i386/pc_piix.c +1
-0@@ -138,6 +138,7 @@ static void pc_init1(MemoryRegion *system_memory,if (!xen_enabled ()) { fw_cfg =pc_memory_init (kernel_filename, kernel_cmdline, initrd_filename, below_4g_mem_size, above_4g_mem_size); +bochs_meminfo_bios_init (fw_cfg); }if (kvm_irqchip_in_kernel ()) {hw/i386/pc_q35.c +5
-2@@ -74,6 +74,7 @@ static void pc_q35_init(QEMUMachineInitArgs *args)ICH9LPCState *ich9_lpc;PCIDevice *ahci;DeviceState *icc_bridge; +void *fw_cfg =NULL ; icc_bridge =qdev_create (NULL ,TYPE_ICC_BRIDGE ); object_property_add_child(qdev_get_machine(), "icc-bridge",@@ -97,8 +98,9 @@ static void pc_q35_init(QEMUMachineInitArgs *args)/* allocate ram and load rom/bios */ if (!xen_enabled ()) { -pc_memory_init (kernel_filename, kernel_cmdline, - initrd_filename, below_4g_mem_size, above_4g_mem_size); + fw_cfg =pc_memory_init (kernel_filename, kernel_cmdline, + initrd_filename, below_4g_mem_size, + above_4g_mem_size); }/* irq lines */ @@ -116,6 +118,7 @@ static void pc_q35_init(QEMUMachineInitArgs *args) q35_host->mch.address_space_io =get_system_io ();/* pci */ qdev_init_nofail (DEVICE (q35_host)); +bochs_meminfo_bios_init (fw_cfg); host_bus = q35_host->host.pci.bus;/* create ISA bus */ lpc = pci_create_simple_multifunction(host_bus, PCI_DEVFN(ICH9_LPC_DEV,include/hw/i386/pc.h +1
-0@@ -231,6 +231,7 @@ int pvpanic_init(ISABus *bus);#define E820_UNUSABLE 5int e820_add_entry (uint64_t ,uint64_t ,uint32_t ); +void bochs_meminfo_bios_init (void *fw_cfg);#define PC_COMPAT_1_5 \ {\include/sysemu/sysemu.h +1
-0@@ -132,6 +132,7 @@ extern QEMUClock *rtc_clock;extern int nb_numa_nodes;extern uint64_t node_mem[MAX_NODES ];extern unsigned long *node_cpumask[MAX_NODES ]; +extern int nb_hp_dimms;#define MAX_OPTION_ROMS 16 typedef struct QEMUOptionRom {Signature · 1 line
1.8.3.1
Re: [Qemu-devel] [PATCH v5 10/14] pc: Add dimm paravirt SRAT info
Quoted 23 lines · On Wed, 10 Jul 2013 13:10:03 +0300 "Michael S. Tsirkin" <[email protected]> wrote:
Quoted 14 lines · Hu Tao
The
numa_fw_cfgparavirt interface is extended to include SRAT information for all hotplug-able dimms. There are 3 words for each hotplug-able memory slot, denoting start address, size and node proximity. The new info is appended after existing numa info, so that thefw_cfglayout does not break. This information is used by Seabios to build hotplug memory device objects at runtime.nb_numa_nodesis set to 1 by default (not 0), so that we always pass srat info to SeaBIOS.
v3->v4:numa_fw_cfgneeds to be initalized after memory controller sets up dimm ranges. Make changes forpc_piixandpc_q35to setnuma_fw_cfgafter i440fx initialization.
v2->v3: settingnb_numa_nodesto 1 is not neededQuoted 7 lines
v1->v2:
Dimm SRAT info (#dimms) is appended at end of existing numafw_cfgin order not to break existing layout
Documentation of the new fwcfg layout is included indocs/specs/fwcfg.txtSigned-off-by Vasilis Liaskovitis <[email protected]>Signed-off-by Hu Tao <[email protected]>
Quoted 8 lines
Please do not add any more fwcfg interfaces - generating ACPI in qemu removes the need for it.
So please rebase on top of that work and generate the appropriate ACPI tables directly.
You can find the latest code gnerating ACPI from qemu here:
git://git.kernel.org/pub/scm/virt/kvm/mst/qemu.gitacpi
will it work with upstream Seabios or custom tree is required for it as well?
Quoted 189 lines
This code is work in progress, but once you base on top of that, I can put it on that branch and keep updating if interfaces change.
Quoted 183 lines
--- docs/specs/fwcfg.txt | 28 ++++++++++++++++++++++++++++ hw/i386/pc.c | 30 ++++++++++++++++++++++++------ hw/i386/pc_piix.c | 1 + hw/i386/pc_q35.c | 7 +++++-- include/hw/i386/pc.h | 1 + include/sysemu/sysemu.h | 1 + 6 files changed, 60 insertions(+), 8 deletions(-) create mode 100644 docs/specs/fwcfg.txtdocs/specs/fwcfg.txt new file +28
-0@@ -0,0 +1,28 @@ +QEMU<->BIOS Paravirt Documentation +-------------------------------------- + +This document describes paravirt data structures passed from QEMU to BIOS. + +fw_cfg SRAT paravirt info +-------------------- +The SRAT info passed from QEMU to BIOS has the following layout: + +----------------------------------------------------------------------------------------------- +#nodes | cpu0_pxm | cpu1_pxm | ... | cpulast_pxm | node0_mem | node1_mem | ... | nodelast_mem + +----------------------------------------------------------------------------------------------- +#dimms | dimm0_start | dimm0_sz | dimm0_pxm | ... | dimmlast_start | dimmlast_sz | dimmlast_pxm + +Entry 0 contains the number of numa nodes (nb_numa_nodes). + +Entries 1..max_cpus: The next max_cpus entries describe node proximity for each +one of the vCPUs in the system. + +Entries max_cpus+1..max_cpus+nb_numa_nodes+1: The next nb_numa_nodes entries +describe the memory size for each one of the NUMA nodes in the system. + +Entry max_cpus+nb_numa_nodes+1 contains the number of memory dimms (nb_hp_dimms) + +The last 3 * nb_hp_dimms entries are organized in triplets: Each triplet contains +the physical address offset, size (in bytes), and node proximity for the +respective dimm.hw/i386/pc.c +24
-6@@ -55,6 +55,7 @@#include "hw/acpi/acpi.h" #include "hw/cpu/icc_bus.h" #include "hw/boards.h" +#include "hw/mem-hotplug/dimm.h" /* debug PC/ISA interrupts */ //#define DEBUG_IRQ @@ -606,8 +607,6 @@ static FWCfgState *bochs_bios_init(void)FWCfgState *fw_cfg;uint8_t *smbios_table;size_t smbios_len; -uint64_t *numa_fw_cfg; -int i, j;unsigned int apic_id_limit =pc_apic_id_limit (max_cpus); fw_cfg =fw_cfg_init (BIOS_CFG_IOPORT ,BIOS_CFG_IOPORT +1 ,0 ,0 );@@ -640,11 +639,25 @@ static FWCfgState *bochs_bios_init(void) &e820_table, sizeof(e820_table));fw_cfg_add_bytes (fw_cfg,FW_CFG_HPET , &hpet_cfg,sizeof (hpet_cfg)); + +return fw_cfg; +} + +void bochs_meminfo_bios_init (void *fw_cfg) +{ +uint64_t *numa_fw_cfg; +uint64_t *hp_dimms_fw_cfg; +int i, j; +unsigned int apic_id_limit =pc_apic_id_limit (max_cpus); +/* allocate memory for the NUMA channel: one (64bit) word for the number * of nodes, one word for each VCPU->node and one word for each node to * hold the amount of memory. +* Finally one word for the number of hotplug memory slots and three words +* for each hotplug memory slot (start address, size and node proximity). */ - numa_fw_cfg =g_new0 (uint64_t,1 + apic_id_limit + nb_numa_nodes); + numa_fw_cfg =g_new0 (uint64_t, +2 + apic_id_limit + nb_numa_nodes +3 * nb_hp_dimms); numa_fw_cfg[0 ] =cpu_to_le64 (nb_numa_nodes);for (i =0 ; i < max_cpus; i++) {unsigned int apic_id =x86_cpu_apic_id_from_index (i);@@ -659,11 +672,16 @@ static FWCfgState *bochs_bios_init(void)for (i =0 ; i < nb_numa_nodes; i++) { numa_fw_cfg[apic_id_limit +1 + i] =cpu_to_le64 (node_mem[i]); } + + numa_fw_cfg[1 + apic_id_limit + nb_numa_nodes] =cpu_to_le64 (nb_hp_dimms); + + hp_dimms_fw_cfg = numa_fw_cfg +2 + apic_id_limit + nb_numa_nodes; +if (nb_hp_dimms) { +dimm_setup_fwcfg_layout (hp_dimms_fw_cfg); + }fw_cfg_add_bytes (fw_cfg,FW_CFG_NUMA , numa_fw_cfg, - (1 + apic_id_limit + nb_numa_nodes) * + (2 + apic_id_limit + nb_numa_nodes +3 * nb_hp_dimms) *sizeof (*numa_fw_cfg)); - -return fw_cfg; }static long get_file_size (FILE *f)hw/i386/pc_piix.c +1
-0@@ -138,6 +138,7 @@ static void pc_init1(MemoryRegion *system_memory,if (!xen_enabled ()) { fw_cfg =pc_memory_init (kernel_filename, kernel_cmdline, initrd_filename, below_4g_mem_size, above_4g_mem_size); +bochs_meminfo_bios_init (fw_cfg); }if (kvm_irqchip_in_kernel ()) {hw/i386/pc_q35.c +5
-2@@ -74,6 +74,7 @@ static void pc_q35_init(QEMUMachineInitArgs *args)ICH9LPCState *ich9_lpc;PCIDevice *ahci;DeviceState *icc_bridge; +void *fw_cfg =NULL ; icc_bridge =qdev_create (NULL ,TYPE_ICC_BRIDGE ); object_property_add_child(qdev_get_machine(), "icc-bridge",@@ -97,8 +98,9 @@ static void pc_q35_init(QEMUMachineInitArgs *args)/* allocate ram and load rom/bios */ if (!xen_enabled ()) { -pc_memory_init (kernel_filename, kernel_cmdline, - initrd_filename, below_4g_mem_size, above_4g_mem_size); + fw_cfg =pc_memory_init (kernel_filename, kernel_cmdline, + initrd_filename, below_4g_mem_size, + above_4g_mem_size); }/* irq lines */ @@ -116,6 +118,7 @@ static void pc_q35_init(QEMUMachineInitArgs *args) q35_host->mch.address_space_io =get_system_io ();/* pci */ qdev_init_nofail (DEVICE (q35_host)); +bochs_meminfo_bios_init (fw_cfg); host_bus = q35_host->host.pci.bus;/* create ISA bus */ lpc = pci_create_simple_multifunction(host_bus, PCI_DEVFN(ICH9_LPC_DEV,include/hw/i386/pc.h +1
-0@@ -231,6 +231,7 @@ int pvpanic_init(ISABus *bus);#define E820_UNUSABLE 5int e820_add_entry (uint64_t ,uint64_t ,uint32_t ); +void bochs_meminfo_bios_init (void *fw_cfg);#define PC_COMPAT_1_5 \ {\include/sysemu/sysemu.h +1
-0@@ -132,6 +132,7 @@ extern QEMUClock *rtc_clock;extern int nb_numa_nodes;extern uint64_t node_mem[MAX_NODES ];extern unsigned long *node_cpumask[MAX_NODES ]; +extern int nb_hp_dimms;#define MAX_OPTION_ROMS 16 typedef struct QEMUOptionRom {Signature · 1 line
1.8.3.1
Re: [Qemu-devel] [PATCH v5 10/14] pc: Add dimm paravirt SRAT info
Quoted 29 lines · Igor Mammedov
Quoted 26 lines · On Wed, 10 Jul 2013 13:10:03 +0300 "Michael S. Tsirkin" <[email protected]> wrote:
Quoted 14 lines · Hu Tao
The
numa_fw_cfgparavirt interface is extended to include SRAT information for all hotplug-able dimms. There are 3 words for each hotplug-able memory slot, denoting start address, size and node proximity. The new info is appended after existing numa info, so that thefw_cfglayout does not break. This information is used by Seabios to build hotplug memory device objects at runtime.nb_numa_nodesis set to 1 by default (not 0), so that we always pass srat info to SeaBIOS.
v3->v4:numa_fw_cfgneeds to be initalized after memory controller sets up dimm ranges. Make changes forpc_piixandpc_q35to setnuma_fw_cfgafter i440fx initialization.
v2->v3: settingnb_numa_nodesto 1 is not neededQuoted 7 lines
v1->v2:
Dimm SRAT info (#dimms) is appended at end of existing numafw_cfgin order not to break existing layout
Documentation of the new fwcfg layout is included indocs/specs/fwcfg.txtSigned-off-by Vasilis Liaskovitis <[email protected]>Signed-off-by Hu Tao <[email protected]>Please do not add any more fwcfg interfaces - generating ACPI in qemu removes the need for it.
Quoted 7 lines
Quoted 5 lines
So please rebase on top of that work and generate the appropriate ACPI tables directly.
You can find the latest code gnerating ACPI from qemu here:
git://git.kernel.org/pub/scm/virt/kvm/mst/qemu.gitacpiwill it work with upstream Seabios or custom tree is required for it as well?
Yes.
git://git.kernel.org/pub/scm/virt/kvm/mst/seabios.git acpi
Quoted 189 lines
Quoted 189 lines
This code is work in progress, but once you base on top of that, I can put it on that branch and keep updating if interfaces change.
Quoted 183 lines
--- docs/specs/fwcfg.txt | 28 ++++++++++++++++++++++++++++ hw/i386/pc.c | 30 ++++++++++++++++++++++++------ hw/i386/pc_piix.c | 1 + hw/i386/pc_q35.c | 7 +++++-- include/hw/i386/pc.h | 1 + include/sysemu/sysemu.h | 1 + 6 files changed, 60 insertions(+), 8 deletions(-) create mode 100644 docs/specs/fwcfg.txtdocs/specs/fwcfg.txt new file +28
-0@@ -0,0 +1,28 @@ +QEMU<->BIOS Paravirt Documentation +-------------------------------------- + +This document describes paravirt data structures passed from QEMU to BIOS. + +fw_cfg SRAT paravirt info +-------------------- +The SRAT info passed from QEMU to BIOS has the following layout: + +----------------------------------------------------------------------------------------------- +#nodes | cpu0_pxm | cpu1_pxm | ... | cpulast_pxm | node0_mem | node1_mem | ... | nodelast_mem + +----------------------------------------------------------------------------------------------- +#dimms | dimm0_start | dimm0_sz | dimm0_pxm | ... | dimmlast_start | dimmlast_sz | dimmlast_pxm + +Entry 0 contains the number of numa nodes (nb_numa_nodes). + +Entries 1..max_cpus: The next max_cpus entries describe node proximity for each +one of the vCPUs in the system. + +Entries max_cpus+1..max_cpus+nb_numa_nodes+1: The next nb_numa_nodes entries +describe the memory size for each one of the NUMA nodes in the system. + +Entry max_cpus+nb_numa_nodes+1 contains the number of memory dimms (nb_hp_dimms) + +The last 3 * nb_hp_dimms entries are organized in triplets: Each triplet contains +the physical address offset, size (in bytes), and node proximity for the +respective dimm.hw/i386/pc.c +24
-6@@ -55,6 +55,7 @@#include "hw/acpi/acpi.h" #include "hw/cpu/icc_bus.h" #include "hw/boards.h" +#include "hw/mem-hotplug/dimm.h" /* debug PC/ISA interrupts */ //#define DEBUG_IRQ @@ -606,8 +607,6 @@ static FWCfgState *bochs_bios_init(void)FWCfgState *fw_cfg;uint8_t *smbios_table;size_t smbios_len; -uint64_t *numa_fw_cfg; -int i, j;unsigned int apic_id_limit =pc_apic_id_limit (max_cpus); fw_cfg =fw_cfg_init (BIOS_CFG_IOPORT ,BIOS_CFG_IOPORT +1 ,0 ,0 );@@ -640,11 +639,25 @@ static FWCfgState *bochs_bios_init(void) &e820_table, sizeof(e820_table));fw_cfg_add_bytes (fw_cfg,FW_CFG_HPET , &hpet_cfg,sizeof (hpet_cfg)); + +return fw_cfg; +} + +void bochs_meminfo_bios_init (void *fw_cfg) +{ +uint64_t *numa_fw_cfg; +uint64_t *hp_dimms_fw_cfg; +int i, j; +unsigned int apic_id_limit =pc_apic_id_limit (max_cpus); +/* allocate memory for the NUMA channel: one (64bit) word for the number * of nodes, one word for each VCPU->node and one word for each node to * hold the amount of memory. +* Finally one word for the number of hotplug memory slots and three words +* for each hotplug memory slot (start address, size and node proximity). */ - numa_fw_cfg =g_new0 (uint64_t,1 + apic_id_limit + nb_numa_nodes); + numa_fw_cfg =g_new0 (uint64_t, +2 + apic_id_limit + nb_numa_nodes +3 * nb_hp_dimms); numa_fw_cfg[0 ] =cpu_to_le64 (nb_numa_nodes);for (i =0 ; i < max_cpus; i++) {unsigned int apic_id =x86_cpu_apic_id_from_index (i);@@ -659,11 +672,16 @@ static FWCfgState *bochs_bios_init(void)for (i =0 ; i < nb_numa_nodes; i++) { numa_fw_cfg[apic_id_limit +1 + i] =cpu_to_le64 (node_mem[i]); } + + numa_fw_cfg[1 + apic_id_limit + nb_numa_nodes] =cpu_to_le64 (nb_hp_dimms); + + hp_dimms_fw_cfg = numa_fw_cfg +2 + apic_id_limit + nb_numa_nodes; +if (nb_hp_dimms) { +dimm_setup_fwcfg_layout (hp_dimms_fw_cfg); + }fw_cfg_add_bytes (fw_cfg,FW_CFG_NUMA , numa_fw_cfg, - (1 + apic_id_limit + nb_numa_nodes) * + (2 + apic_id_limit + nb_numa_nodes +3 * nb_hp_dimms) *sizeof (*numa_fw_cfg)); - -return fw_cfg; }static long get_file_size (FILE *f)hw/i386/pc_piix.c +1
-0@@ -138,6 +138,7 @@ static void pc_init1(MemoryRegion *system_memory,if (!xen_enabled ()) { fw_cfg =pc_memory_init (kernel_filename, kernel_cmdline, initrd_filename, below_4g_mem_size, above_4g_mem_size); +bochs_meminfo_bios_init (fw_cfg); }if (kvm_irqchip_in_kernel ()) {hw/i386/pc_q35.c +5
-2@@ -74,6 +74,7 @@ static void pc_q35_init(QEMUMachineInitArgs *args)ICH9LPCState *ich9_lpc;PCIDevice *ahci;DeviceState *icc_bridge; +void *fw_cfg =NULL ; icc_bridge =qdev_create (NULL ,TYPE_ICC_BRIDGE ); object_property_add_child(qdev_get_machine(), "icc-bridge",@@ -97,8 +98,9 @@ static void pc_q35_init(QEMUMachineInitArgs *args)/* allocate ram and load rom/bios */ if (!xen_enabled ()) { -pc_memory_init (kernel_filename, kernel_cmdline, - initrd_filename, below_4g_mem_size, above_4g_mem_size); + fw_cfg =pc_memory_init (kernel_filename, kernel_cmdline, + initrd_filename, below_4g_mem_size, + above_4g_mem_size); }/* irq lines */ @@ -116,6 +118,7 @@ static void pc_q35_init(QEMUMachineInitArgs *args) q35_host->mch.address_space_io =get_system_io ();/* pci */ qdev_init_nofail (DEVICE (q35_host)); +bochs_meminfo_bios_init (fw_cfg); host_bus = q35_host->host.pci.bus;/* create ISA bus */ lpc = pci_create_simple_multifunction(host_bus, PCI_DEVFN(ICH9_LPC_DEV,include/hw/i386/pc.h +1
-0@@ -231,6 +231,7 @@ int pvpanic_init(ISABus *bus);#define E820_UNUSABLE 5int e820_add_entry (uint64_t ,uint64_t ,uint32_t ); +void bochs_meminfo_bios_init (void *fw_cfg);#define PC_COMPAT_1_5 \ {\include/sysemu/sysemu.h +1
-0@@ -132,6 +132,7 @@ extern QEMUClock *rtc_clock;extern int nb_numa_nodes;extern uint64_t node_mem[MAX_NODES ];extern unsigned long *node_cpumask[MAX_NODES ]; +extern int nb_hp_dimms;#define MAX_OPTION_ROMS 16 typedef struct QEMUOptionRom {Signature · 1 line
1.8.3.1
Re: [Qemu-devel] [PATCH v5 10/14] pc: Add dimm paravirt SRAT info
Quoted 33 lines · Michael S. Tsirkin
Quoted 32 lines · Igor Mammedov
Quoted 29 lines · On Wed, 10 Jul 2013 13:10:03 +0300 "Michael S. Tsirkin" <[email protected]> wrote:
Quoted 14 lines · Hu Tao
The
numa_fw_cfgparavirt interface is extended to include SRAT information for all hotplug-able dimms. There are 3 words for each hotplug-able memory slot, denoting start address, size and node proximity. The new info is appended after existing numa info, so that thefw_cfglayout does not break. This information is used by Seabios to build hotplug memory device objects at runtime.nb_numa_nodesis set to 1 by default (not 0), so that we always pass srat info to SeaBIOS.
v3->v4:numa_fw_cfgneeds to be initalized after memory controller sets up dimm ranges. Make changes forpc_piixandpc_q35to setnuma_fw_cfgafter i440fx initialization.
v2->v3: settingnb_numa_nodesto 1 is not neededQuoted 7 lines
v1->v2:
Dimm SRAT info (#dimms) is appended at end of existing numafw_cfgin order not to break existing layout
Documentation of the new fwcfg layout is included indocs/specs/fwcfg.txtSigned-off-by Vasilis Liaskovitis <[email protected]>Signed-off-by Hu Tao <[email protected]>Please do not add any more fwcfg interfaces - generating ACPI in qemu removes the need for it.
So please rebase on top of that work and generate the appropriate ACPI tables directly.
Quoted 8 lines
Quoted 4 lines
Quoted 2 lines
You can find the latest code gnerating ACPI from qemu here:
git://git.kernel.org/pub/scm/virt/kvm/mst/qemu.gitacpiwill it work with upstream Seabios or custom tree is required for it as well?
Yes.
git://git.kernel.org/pub/scm/virt/kvm/mst/seabios.gitacpi
This means I must rebase both qemu and seabios patches on top of your acpi tree. I hope there won't be too much conflicts:)
Re: [Qemu-devel] [PATCH v5 10/14] pc: Add dimm paravirt SRAT info
Quoted 37 lines · Hu Tao
Quoted 36 lines · Michael S. Tsirkin
Quoted 35 lines · Igor Mammedov
Quoted 31 lines · On Wed, 10 Jul 2013 13:10:03 +0300 "Michael S. Tsirkin" <[email protected]> wrote:
Quoted 14 lines · Hu Tao
The
numa_fw_cfgparavirt interface is extended to include SRAT information for all hotplug-able dimms. There are 3 words for each hotplug-able memory slot, denoting start address, size and node proximity. The new info is appended after existing numa info, so that thefw_cfglayout does not break. This information is used by Seabios to build hotplug memory device objects at runtime.nb_numa_nodesis set to 1 by default (not 0), so that we always pass srat info to SeaBIOS.
v3->v4:numa_fw_cfgneeds to be initalized after memory controller sets up dimm ranges. Make changes forpc_piixandpc_q35to setnuma_fw_cfgafter i440fx initialization.
v2->v3: settingnb_numa_nodesto 1 is not neededQuoted 7 lines
v1->v2:
Dimm SRAT info (#dimms) is appended at end of existing numafw_cfgin order not to break existing layout
Documentation of the new fwcfg layout is included indocs/specs/fwcfg.txtSigned-off-by Vasilis Liaskovitis <[email protected]>Signed-off-by Hu Tao <[email protected]>Please do not add any more fwcfg interfaces - generating ACPI in qemu removes the need for it.
So please rebase on top of that work and generate the appropriate ACPI tables directly.
You can find the latest code gnerating ACPI from qemu here:
git://git.kernel.org/pub/scm/virt/kvm/mst/qemu.gitacpi
Quoted 8 lines
Quoted 5 lines
Quoted 1 line
will it work with upstream Seabios or custom tree is required for it as well?
Yes.
git://git.kernel.org/pub/scm/virt/kvm/mst/seabios.gitacpiThis means I must rebase both qemu and seabios patches on top of your acpi tree. I hope there won't be too much conflicts:)
Shouldn't be hard, if there's a problem pls tell me and I'll try to help.
PATCH v5 11/14 Introduce paravirt interface QEMU_CFG_PCI_WINDOW
In reply to Hu TaoFrom: Vasilis Liaskovitis <[email protected]>
Qemu calculates the 32-bit and 64-bit PCI starting offsets based on initial memory and hotplug-able dimms. This info needs to be passed to Seabios for PCI initialization.
--- hw/i386/pc_q35.c | 10 ++++++++++ hw/pci-host/piix.c | 13 +++++++++++++ include/hw/nvram/fw_cfg.h | 1 + 3 files changed, 24 insertions(+)
hw/i386/pc_q35.c +10 -0
@@ -42,6 +42,7 @@#include "hw/ide/ahci.h" #include "hw/usb.h" #include "hw/cpu/icc_bus.h" +#include "hw/nvram/fw_cfg.h" /* ICH9 AHCI has 6 ports */ #define MAX_SATA_PORTS 6
@@ -75,6 +76,7 @@ static void pc_q35_init(QEMUMachineInitArgs *args)PCIDevice *ahci;DeviceState *icc_bridge;void *fw_cfg =NULL ; +uint64_t *pci_window_fw_cfg; icc_bridge =qdev_create (NULL ,TYPE_ICC_BRIDGE ); object_property_add_child(qdev_get_machine(), "icc-bridge",
@@ -119,6 +121,14 @@ static void pc_q35_init(QEMUMachineInitArgs *args)/* pci */ qdev_init_nofail (DEVICE (q35_host));bochs_meminfo_bios_init (fw_cfg); + + pci_window_fw_cfg =g_new0 (uint64_t,2 ); + pci_window_fw_cfg[0 ] =cpu_to_le64 (MCH_HOST_BRIDGE_PCIEXBAR_DEFAULT ); + pci_window_fw_cfg[1 ] =cpu_to_le64 (0x100000000ULL + + q35_host->mch.dev.above_4g_mem_size); +fw_cfg_add_bytes (fw_cfg,FW_CFG_PCI_WINDOW , + (uint8_t *)pci_window_fw_cfg,2 *8 ); + host_bus = q35_host->host.pci.bus;/* create ISA bus */ lpc = pci_create_simple_multifunction(host_bus, PCI_DEVFN(ICH9_LPC_DEV,
hw/pci-host/piix.c +13 -0
@@ -32,6 +32,7 @@#include "hw/xen/xen.h" #include "hw/pci-host/pam.h" #include "sysemu/sysemu.h" +#include "hw/nvram/fw_cfg.h" /* * I440FX chipset data sheet.
@@ -229,6 +230,8 @@ static PCIBus *i440fx_common_init(const char *device_name,PIIX3State *piix3;I440FXPMCState *f;I440FXState *i440fx; +uint64_t *pci_window_fw_cfg; +void *fw_cfg; i440fx =I440FX_DEVICE (object_new (TYPE_I440FX_DEVICE )); s =PCI_HOST_BRIDGE (i440fx);
@@ -266,6 +269,16 @@ static PCIBus *i440fx_common_init(const char *device_name, *piix3_devfn = piix3->dev.devfn; *pci_address_space = &i440fx->pci_address_space; + fw_cfg =fw_cfg_find (); +if (fw_cfg) { + pci_window_fw_cfg =g_new0 (uint64_t,2 ); + pci_window_fw_cfg[0 ] =cpu_to_le64 (f->dev.below_4g_mem_size); + pci_window_fw_cfg[1 ] =cpu_to_le64 (0x100000000ULL + + f->dev.above_4g_mem_size); +fw_cfg_add_bytes (fw_cfg,FW_CFG_PCI_WINDOW , + (uint8_t *)pci_window_fw_cfg,2 *8 ); + } +return s->bus; }
include/hw/nvram/fw_cfg.h +1 -0
@@ -35,6 +35,7 @@#define FW_CFG_SETUP_SIZE 0x17#define FW_CFG_SETUP_DATA 0x18#define FW_CFG_FILE_DIR 0x19 +#define FW_CFG_PCI_WINDOW 0x1a#define FW_CFG_FILE_FIRST 0x20#define FW_CFG_FILE_SLOTS 0x10
Signature · 1 line
1.8.3.1
PATCH v5 12/14 Implement "info memory" and "query-memory"
In reply to Hu TaoFrom: Vasilis Liaskovitis <[email protected]>
Returns total physical memory available to guest in bytes, including hotplugged memory. Note that the number reported here may be different from what the guest sees e.g. if the guest has not logically onlined hotplugged memory.
This functionality is provided independently of a balloon device, since a guest can be using ACPI memory hotplug without using a balloon device.
--- hmp-commands.hx | 2 ++ hmp.c | 8 ++++++++ hmp.h | 1 + hw/mem-hotplug/dimm.c | 14 ++++++++++++++ include/hw/mem-hotplug/dimm.h | 1 + monitor.c | 7 +++++++ qapi-schema.json | 13 +++++++++++++ qmp-commands.hx | 22 ++++++++++++++++++++++ vl.c | 9 +++++++++ 9 files changed, 77 insertions(+)
hmp-commands.hx +2 -0
@@ -1653,6 +1653,8 @@ show device tree show qdev device model list @item info roms show roms +@item info memory-total +show memory-total @item info tpm show the TPM device @end table
hmp.c +8 -0
@@ -675,6 +675,14 @@ void hmp_info_tpm(Monitor *mon, const QDict *qdict)qapi_free_TPMInfoList (info_list); } +void hmp_info_memory (Monitor *mon,const QDict *qdict) +{ +MemoryInfo *mem; + mem =qmp_query_memory (NULL ); +monitor_printf (mon,"MemTotal: %" PRIu64"\n" , mem->total); +qapi_free_MemoryInfo (mem); +} +void hmp_quit (Monitor *mon,const QDict *qdict) {monitor_suspend (mon);
hmp.h +1 -0
@@ -37,6 +37,7 @@ void hmp_info_balloon(Monitor *mon, const QDict *qdict);void hmp_info_pci (Monitor *mon,const QDict *qdict);void hmp_info_block_jobs (Monitor *mon,const QDict *qdict);void hmp_info_tpm (Monitor *mon,const QDict *qdict); +void hmp_info_memory (Monitor *mon,const QDict *qdict);void hmp_quit (Monitor *mon,const QDict *qdict);void hmp_stop (Monitor *mon,const QDict *qdict);void hmp_system_reset (Monitor *mon,const QDict *qdict);
hw/mem-hotplug/dimm.c +14 -0
@@ -185,6 +185,20 @@ void dimm_setup_fwcfg_layout(uint64_t *fw_cfg_slots) } } +uint64_t get_hp_memory_total (void ) +{ +DimmBus *bus; +DimmDevice *slot; +uint64_t info =0 ; + + QLIST_FOREACH(bus, &memory_buses, next) { + QTAILQ_FOREACH(slot, &bus->dimmlist, nextdimm) { + info += slot->size; + } + } +return info; +} +static void dimm_realize (DeviceState *s,Error **errp) {DimmBus *bus =DIMM_BUS (qdev_get_parent_bus (s));
include/hw/mem-hotplug/dimm.h +1 -0
@@ -73,5 +73,6 @@ DimmBus *dimm_bus_create(Object *parent, const char *name, uint32_t max_dimms, dimm_calcoffset_fn pmc_set_offset);void dimm_config_create (char *id,uint64_t size,const char *bus,uint64_t node,uint32_t dimm_idx); +uint64_t get_hp_memory_total (void );#endif
monitor.c +7 -0
@@ -2760,6 +2760,13 @@ static mon_cmd_t info_cmds[] = { .mhandler.cmd = hmp_info_tpm, }, { + .name = "memory", + .args_type = "", + .params = "", + .help = "show memory informations including total memory size", + .mhandler.cmd = hmp_info_memory, + }, + { .name = NULL, }, };
qapi-schema.json +13 -0
@@ -3608,3 +3608,16 @@ '*cpuid-input-ecx': 'int', 'cpuid-register': 'X86CPURegister32', 'features': 'int' } } + +## +# @query-memory: +# +# Returns total memory in bytes, including hotplugged dimms +# +# Returns: int +# +# Since: 1.6 +## +{ 'type': 'MemoryInfo', + 'data': { 'total': 'int' } } +{ 'command': 'query-memory', 'returns': 'MemoryInfo' }
qmp-commands.hx +22 -0
@@ -2997,3 +2997,25 @@ Example: <- { "return": {} } EQMP + + { + .name = "query-memory", + .args_type = "", + .mhandler.cmd_new = qmp_marshal_input_query_memory + }, +SQMP +query-memory +---------- + +Return a json-object with the following information: + +- "total": total memory in bytes, including hotplugged dimms + +Example: + +-> { "execute": "query-memory" } +<- { + "return": { "total": 1073741824 } + } + +EQMP
vl.c +9 -0
@@ -671,6 +671,15 @@ StatusInfo *qmp_query_status(Error **errp)return info; } +MemoryInfo *qmp_query_memory (Error **errp) +{ +MemoryInfo *info =g_malloc0 (sizeof (*info)); + + info->total = ram_size +get_hp_memory_total (); + +return info; +} +/***********************************************************/ /* real time host monotonic timer */
Signature · 1 line
1.8.3.1
Re: [Qemu-devel] [PATCH v5 12/14] Implement "info memory" and "query-memory"
Quoted 15 lines · Hu Tao
From: Vasilis Liaskovitis <[email protected]>
Returns total physical memory available to guest in bytes, including hotplugged memory. Note that the number reported here may be different from what the guest sees e.g. if the guest has not logically onlined hotplugged memory.
This functionality is provided independently of a balloon device, since a guest can be using ACPI memory hotplug without using a balloon device.
Signed-off-by Vasilis Liaskovitis <[email protected]>Signed-off-by Hu Tao <[email protected]>---
+++
b/qapi-schema.json
qapi-schema.json line 3617
Quoted 10 lines
qapi-schema.json +7
-0@@ -3608,3 +3608,16 @@ '*cpuid-input-ecx': 'int', 'cpuid-register': 'X86CPURegister32', 'features': 'int' } } + +## +# @query-memory: +# +# Returns total memory in bytes, including hotplugged dimms +# +# Returns: int
Not true - it returns a struct of useful memory statistics (of which, your initial implementation of the MemoryInfo has only one statistic). This struct is free to grow larger in the future, if we determine other useful things to return.
qapi-schema.json line 3623
Quoted 6 lines
qapi-schema.json +6
-0+# +# Since: 1.6 +## +{ 'type': 'MemoryInfo', + 'data': { 'total': 'int' } } +{ 'command': 'query-memory', 'returns': 'MemoryInfo' }
You've created two items (the 'MemoryInfo' type and the 'query-memory' command), so you should have two pieces of documentation (yes, I know there are pre-existing cases of undocumented types that are declared next to the sole command that uses them, but we should avoid that where possible).
Signature · 2 lines
Eric Blake eblake redhat com +1-919-301-3266 Libvirt virtualization library http://libvirt.org
PATCH v5 13/14 balloon: update with hotplugged memory
In reply to Hu TaoFrom: Vasilis Liaskovitis <[email protected]>
query-balloon and "info balloon" should report total memory available to the guest.
balloon inflate/ deflate can also use all memory available to the guest (initial
+ hotplugged memory)
Ballon driver has been minimaly tested with the patch, please review and test.
Caveat: if the guest does not online hotplugged-memory, it's easy for a balloon inflate command to OOM a guest.
--- hw/virtio/virtio-balloon.c | 13 +++++++++---- 1 file changed, 9 insertions(+), 4 deletions(-)
hw/virtio/virtio-balloon.c +9 -4
@@ -30,6 +30,7 @@#endif #include "hw/virtio/virtio-bus.h" +#include "hw/mem-hotplug/dimm.h" static void balloon_page (void *addr,int deflate) {
@@ -271,10 +272,11 @@ static void virtio_balloon_set_config(VirtIODevice *vdev,VirtIOBalloon *dev =VIRTIO_BALLOON (vdev);struct virtio_balloon_config config;uint32_t oldactual = dev->actual; +uint64_t hotplugged_ram_size =get_hp_memory_total ();memcpy (&config, config_data,8 ); dev->actual =le32_to_cpu (config.actual);if (dev->actual != oldactual) { -qemu_balloon_changed (ram_size - +qemu_balloon_changed (ram_size + hotplugged_ram_size - ((ram_addr_t ) dev->actual <<VIRTIO_BALLOON_PFN_SHIFT )); } }
@@ -290,18 +292,21 @@ static void virtio_balloon_stat(void *opaque, BalloonInfo *info)VirtIOBalloon *dev = opaque; info->actual = ram_size - ((uint64_t ) dev->actual <<VIRTIO_BALLOON_PFN_SHIFT ); + info->actual +=get_hp_memory_total (); }static void virtio_balloon_to_target (void *opaque,ram_addr_t target) {VirtIOBalloon *dev =VIRTIO_BALLOON (opaque);VirtIODevice *vdev =VIRTIO_DEVICE (dev); +uint64_t hotplugged_ram_size =get_hp_memory_total (); -if (target > ram_size) { - target = ram_size; +if (target > ram_size + hotplugged_ram_size) { + target = ram_size + hotplugged_ram_size; }if (target) { - dev->num_pages = (ram_size - target) >>VIRTIO_BALLOON_PFN_SHIFT ; + dev->num_pages = (ram_size + hotplugged_ram_size - target) >> +VIRTIO_BALLOON_PFN_SHIFT ;virtio_notify_config (vdev); } }
Signature · 1 line
1.8.3.1
PATCH v5 14/14 Implement dimm-info
In reply to Hu TaoFrom: Vasilis Liaskovitis <[email protected]>
"query-dimm-info" and "info dimm" will give current state of all dimms in the system e.g.
dimm0: on
dimm1: off
dimm2: off
dimm3: on
etc.
--- hmp-commands.hx | 2 ++ hmp.c | 17 +++++++++++++++++ hmp.h | 1 + hw/mem-hotplug/dimm.c | 43 +++++++++++++++++++++++++++++++++++++++++++ monitor.c | 7 +++++++ qapi-schema.json | 27 +++++++++++++++++++++++++++ 6 files changed, 97 insertions(+)
hmp-commands.hx +2 -0
@@ -1657,6 +1657,8 @@ show roms show memory-total @item info tpm show the TPM device +@item info dimm +show dimm @end table ETEXI
hmp.c +17 -0
@@ -683,6 +683,23 @@ void hmp_info_memory(Monitor *mon, const QDict *qdict)qapi_free_MemoryInfo (mem); } +void hmp_info_dimm (Monitor *mon,const QDict *qdict) +{ +DimmInfoList *info; +DimmInfoList *item; +DimmInfo *dimm; + + info =qmp_query_dimm_info (NULL ); +for (item = info; item; item = item->next) { + dimm = item->value; +monitor_printf (mon,"dimm %s : %s\n" , dimm->dimm, + dimm->state ?"on" :"off" ); + dimm->dimm =NULL ; + } + +qapi_free_DimmInfoList (info); +} +void hmp_quit (Monitor *mon,const QDict *qdict) {monitor_suspend (mon);
hmp.h +1 -0
@@ -38,6 +38,7 @@ void hmp_info_pci(Monitor *mon, const QDict *qdict);void hmp_info_block_jobs (Monitor *mon,const QDict *qdict);void hmp_info_tpm (Monitor *mon,const QDict *qdict);void hmp_info_memory (Monitor *mon,const QDict *qdict); +void hmp_info_dimm (Monitor *mon,const QDict *qdict);void hmp_quit (Monitor *mon,const QDict *qdict);void hmp_stop (Monitor *mon,const QDict *qdict);void hmp_system_reset (Monitor *mon,const QDict *qdict);
hw/mem-hotplug/dimm.c +43 -0
55 lines not on this page · raw message
monitor.c +7 -0
@@ -2753,6 +2753,13 @@ static mon_cmd_t info_cmds[] = { .mhandler.cmd = do_trace_print_events, }, { + .name = "dimm", + .args_type = "", + .params = "", + .help = "show active and non active dimms", + .mhandler.cmd = hmp_info_dimm, + }, + { .name = "tpm", .args_type = "", .params = "",
qapi-schema.json +27 -0
@@ -3621,3 +3621,30 @@ { 'type': 'MemoryInfo', 'data': { 'total': 'int' } } { 'command': 'query-memory', 'returns': 'MemoryInfo' } + +## +# @DimmInfo: +# +# Information about status of dimm device +# +# @dimm: the name of the dimm +# +# @state: 'true' means the dimm device is plugged in, 'false' means +# means the dimm device is plugged out. +# +# Since: 1.6 +# +## +{ 'type': 'DimmInfo', + 'data': {'dimm': 'str', 'state': 'bool'} } + +## +# @query-dimm-info: +# +# Returns the state of dimm devices +# +# Returns: list of @DimmInfo +# +# Since: 1.6 +## +{ 'command': 'query-dimm-info', 'returns': ['DimmInfo'] }
Signature · 1 line
1.8.3.1
Re: [Qemu-devel] [PATCH v5 14/14] Implement dimm-info
Quoted 11 lines · Hu Tao
From: Vasilis Liaskovitis <[email protected]>
"query-dimm-info" and "info dimm" will give current state of all dimms in the system e.g.
+++
b/qapi-schema.jsonqapi-schema.json +0
-0@@ -3621,3 +3621,30 @@ { 'type': 'MemoryInfo', 'data': { 'total': 'int' } } { 'command': 'query-memory', 'returns': 'MemoryInfo' }
qapi-schema.json line 3633
Quoted 10 lines
qapi-schema.json +10
-0+ +## +# @DimmInfo: +# +# Information about status of dimm device +# +# @dimm: the name of the dimm +# +# @state: 'true' means the dimm device is plugged in, 'false' means +# means the dimm device is plugged out.
s/plugged out/unplugged/
Quoted 7 lines
qapi-schema.json +7
-0+# +# Since: 1.6 +# +## +{ 'type': 'DimmInfo', + 'data': {'dimm': 'str', 'state': 'bool'} } +
qapi-schema.json line 3650
Quoted 10 lines
qapi-schema.json +10
-0+## +# @query-dimm-info: +# +# Returns the state of dimm devices +# +# Returns: list of @DimmInfo +# +# Since: 1.6 +## +{ 'command': 'query-dimm-info', 'returns': ['DimmInfo'] }
Looks good from an interface perspective; but missing an example in qmp-commands.hx.
Signature · 2 lines
Eric Blake eblake redhat com +1-919-301-3266 Libvirt virtualization library http://libvirt.org
v5 cover support for ACPI memory hotplug
In reply to Hu TaoThis series adds memory devices and related methods to support ACPI memory hotplug.
This series works with qemu counterpart. See qemu series for a detailed description.
Hu Tao (2):
set psize to 0 when romfile_loadfile failed
acpi: generate hotplug memory devices
Vasilis Liaskovitis (5):
Add ACPI_EXTRACT_DEVICE* macros
Add SSDT memory device support
acpi-dsdt: Implement functions for memory hotplug
q35: Add memory hotplug handler
pci: Use paravirt interface for pcimem_start and pcimem64_start
Makefile | 2 +- src/acpi-dsdt-mem-hotplug.dsl | 57 ++++++++++++++++ src/acpi-dsdt.dsl | 5 +- src/acpi.c | 151 ++++++++++++++++++++++++++++++++++++++++-- src/paravirt.c | 15 +++++ src/paravirt.h | 1 + src/pciinit.c | 9 +++ src/q35-acpi-dsdt.dsl | 6 +- src/romfile.c | 13 ++-- src/ssdt-mem.dsl | 61 +++++++++++++++++ tools/acpi_extract.py | 28 ++++++++ 11 files changed, 333 insertions(+), 15 deletions(-) create mode 100644 src/acpi-dsdt-mem-hotplug.dsl create mode 100644 src/ssdt-mem.dsl
Signature · 1 line
1.8.3.1
PATCH v5 1/7 Add ACPI_EXTRACT_DEVICE* macros
From: Vasilis Liaskovitis <[email protected]>
This allows to extract the beginning, end and name of a Device object.
--- tools/acpi_extract.py | 28 ++++++++++++++++++++++++++++ 1 file changed, 28 insertions(+)
tools/acpi_extract.py +28 -0
@@ -230,6 +230,28 @@ def aml_package_start(offset): offset += 1 return offset + aml_pkglen_bytes(offset) + 1 +def aml_device_start(offset): + #0x5B 0x82 DeviceOp PkgLength NameString ProcID + if ((aml[offset] != 0x5B) or (aml[offset + 1] != 0x82)): + die( "Name offset 0x%x: expected 0x5B 0x83 actual 0x%x 0x%x" % + (offset, aml[offset], aml[offset + 1])); + return offset + +def aml_device_string(offset): + #0x5B 0x82 DeviceOp PkgLength NameString ProcID + start = aml_device_start(offset) + offset += 2 + pkglenbytes = aml_pkglen_bytes(offset) + offset += pkglenbytes + return offset + +def aml_device_end(offset): + start = aml_device_start(offset) + offset += 2 + pkglenbytes = aml_pkglen_bytes(offset) + pkglen = aml_pkglen(offset) + return offset + pkglen + lineno = 0 for line in fileinput.input(): # Strip trailing newline
@@ -322,6 +344,12 @@ for i in range(len(asl)): offset = aml_processor_end(offset) elif (directive == "ACPI_EXTRACT_PKG_START"): offset = aml_package_start(offset) + elif (directive == "ACPI_EXTRACT_DEVICE_START"): + offset = aml_device_start(offset) + elif (directive == "ACPI_EXTRACT_DEVICE_STRING"): + offset = aml_device_string(offset) + elif (directive == "ACPI_EXTRACT_DEVICE_END"): + offset = aml_device_end(offset) else: die("Unsupported directive %s" % directive)
Signature · 1 line
1.8.3.1
PATCH v5 2/7 Add SSDT memory device support
In reply to Hu TaoFrom: Vasilis Liaskovitis <[email protected]>
Define SSDT hotplug-able memory devices in _SB namespace. The dynamically generated SSDT includes per memory device hotplug methods. These methods just call methods defined in the DSDT. Also dynamically generate a MTFY method and a MEON array of the online/available memory devices. ACPI extraction macros are used to place the AML code in variables later used by src/acpi. The design is taken from SSDT cpu generation.
--- Makefile | 2 +- src/ssdt-mem.dsl | 61 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 62 insertions(+), 1 deletion(-) create mode 100644 src/ssdt-mem.dsl
Makefile +1 -1
@@ -223,7 +223,7 @@ $(OUT)%.hex: src/%.dsl ./tools/acpi_extract_preprocess.py ./tools/acpi_extract.p $(Q)$(PYTHON) ./tools/acpi_extract.py $(OUT)$*.lst > $(OUT)$*.off $(Q)cat $(OUT)$*.off > $@ -$(OUT)acpi.o: $(OUT)acpi-dsdt.hex $(OUT)ssdt-proc.hex $(OUT)ssdt-pcihp.hex $(OUT)ssdt-misc.hex $(OUT)q35-acpi-dsdt.hex +$(OUT)acpi.o: $(OUT)acpi-dsdt.hex $(OUT)ssdt-proc.hex $(OUT)ssdt-pcihp.hex $(OUT)ssdt-misc.hex $(OUT)q35-acpi-dsdt.hex $(OUT)ssdt-mem.hex ################ Kconfig rules
src/ssdt-mem.dsl new file +61 -0
61 lines not on this page · raw message
Signature · 1 line
1.8.3.1
PATCH v5 3/7 acpi-dsdt: Implement functions for memory hotplug
In reply to Hu TaoFrom: Vasilis Liaskovitis <[email protected]>
Extend the DSDT to include methods for handling memory hot-add and hot-remove notifications and memory device status requests. These functions are called from the memory device SSDT methods.
--- src/acpi-dsdt-mem-hotplug.dsl | 57 +++++++++++++++++++++++++++++++++++++++++++ src/acpi-dsdt.dsl | 5 +++- 2 files changed, 61 insertions(+), 1 deletion(-) create mode 100644 src/acpi-dsdt-mem-hotplug.dsl
src/acpi-dsdt-mem-hotplug.dsl new file +57 -0
@@ -0,0 +1,57 @@ +/**************************************************************** + * Memory hotplug + ****************************************************************/ + +Scope(\_SB) { + /* Objects filled in by run-time generated SSDT */ + External(MTFY, MethodObj) + External(MEON, PkgObj) + + Method (CMST, 1, NotSerialized) { + // _STA method - return ON status of memdevice + // Local0 = MEON flag for this cpu + Store(DerefOf(Index(MEON, Arg0)), Local0) + If (Local0) { Return(0xF) } Else { Return(0x0) } + } + + /* Memory hotplug notify array */ + OperationRegion(MEST, SystemIO, 0xaf80, 32) + Field (MEST, ByteAcc, NoLock, Preserve) + { + MES, 256 + } + + Method(MESC, 0) { + // Local5 = active memdevice bitmap + Store (MES, Local5) + // Local2 = last read byte from bitmap + Store (Zero, Local2) + // Local0 = memory device iterator + Store (Zero, Local0) + While (LLess(Local0, SizeOf(MEON))) { + // Local1 = MEON flag for this memory device + Store(DerefOf(Index(MEON, Local0)), Local1) + If (And(Local0, 0x07)) { + // Shift down previously read bitmap byte + ShiftRight(Local2, 1, Local2) + } Else { + // Read next byte from memdevice bitmap + Store(DerefOf(Index(Local5, ShiftRight(Local0, 3))), Local2) + } + // Local3 = active state for this memory device + Store(And(Local2, 1), Local3) + + If (LNotEqual(Local1, Local3)) { + // State change - update MEON with new state + Store(Local3, Index(MEON, Local0)) + // Do MEM notify + If (LEqual(Local3, 1)) { + MTFY(Local0, 1) + } + } + Increment(Local0) + } + Return(One) + } + +}
src/acpi-dsdt.dsl +4 -1
@@ -294,6 +294,7 @@ DefinitionBlock ( } #include "acpi-dsdt-cpu-hotplug.dsl" +#include "acpi-dsdt-mem-hotplug.dsl" /****************************************************************
@@ -313,7 +314,9 @@ DefinitionBlock ( // CPU hotplug event \_SB.PRSC() } - Method(_L03) { + Method(_E03) { + // Memory hotplug event + \_SB.MESC() } Method(_L04) { }
Signature · 1 line
1.8.3.1
PATCH v5 4/7 set psize to 0 when romfile_loadfile failed
In reply to Hu Tao--- src/romfile.c | 13 +++++++++---- 1 file changed, 9 insertions(+), 4 deletions(-)
src/romfile.c +9 -4
@@ -51,28 +51,33 @@ romfile_loadfile(const char *name, int *psize) {struct romfile_s *file =romfile_find (name);if (!file) -return NULL ; + goto failed;int filesize = file->size;if (!filesize) -return NULL ; + goto failed;char *data =malloc_tmphigh (filesize+1 );if (!data) {warn_noalloc (); -return NULL ; + goto failed; }dprintf (5 ,"Copying romfile '%s' (len %d)\n" , name, filesize);int ret = file->copy (file, data, filesize);if (ret <0 ) {free (data); -return NULL ; + goto failed; }if (psize) *psize = filesize; data[filesize] ='\0' ;return data; + +failed: +if (psize) + *psize =0 ; +return NULL ; }// Attempt to load an integer from the given file - return 'defval'
Signature · 1 line
1.8.3.1
PATCH v5 5/7 acpi: generate hotplug memory devices
In reply to Hu TaoThe memory device generation is guided by qemu paravirt info. Seabios uses the info to setup SRAT entries for the hotplug-able memory slots, and to generate appropriate memory device objects. One memory device (and corresponding SRAT entry) is generated for each hotplug-able qemu memslot. Currently no SSDT memory device is created for initial system memory.
We only support up to 255 DIMMs for now (PackageOp used for the MEON array can only describe an array of at most 255 elements. VarPackageOp would be needed to support more than 255 devices)
--- src/acpi.c | 151 ++++++++++++++++++++++++++++++++++++++++++++++++++++++--- src/paravirt.c | 8 +++ 2 files changed, 152 insertions(+), 7 deletions(-)
src/acpi.c +144 -7
@@ -15,6 +15,8 @@#include "config.h" // CONFIG_* #include "paravirt.h" // RamSize #include "dev-q35.h" +#include "memmap.h" +#include "paravirt.h" #include "acpi-dsdt.hex"
@@ -250,11 +252,23 @@ encodeLen(u8 *ssdt_ptr, int length, int bytes)#define PCIHP_AML (ssdp_pcihp_aml + *ssdt_pcihp_start)#define PCI_SLOTS 32 +/* 0x5B 0x82 DeviceOp PkgLength NameString DimmID */ +#define MEM_BASE 0xaf80 +#define MEM_AML (ssdm_mem_aml + *ssdt_mem_start) +#define MEM_SIZEOF (*ssdt_mem_end - *ssdt_mem_start) +#define MEM_OFFSET_HEX (*ssdt_mem_name - *ssdt_mem_start + 2) +#define MEM_OFFSET_ID (*ssdt_mem_id - *ssdt_mem_start) +#define MEM_OFFSET_PXM 31 +#define MEM_OFFSET_START 55 +#define MEM_OFFSET_END 63 +#define MEM_OFFSET_SIZE 79 +#define SSDT_SIGNATURE 0x54445353 // SSDT#define SSDT_HEADER_LENGTH 36#include "ssdt-misc.hex" #include "ssdt-pcihp.hex" +#include "ssdt-mem.hex" #define PCI_RMV_BASE 0xae0c
@@ -306,9 +320,100 @@ static void patch_pcihp(int slot, u8 *ssdt_ptr, u32 eject) } } +static void build_memdev (u8 *ssdt_ptr,int i,u64 mem_base,u64 mem_len,u8 node) +{ +memcpy (ssdt_ptr,MEM_AML ,MEM_SIZEOF ); + ssdt_ptr[MEM_OFFSET_HEX ] =getHex (i >>4 ); + ssdt_ptr[MEM_OFFSET_HEX +1 ] =getHex (i); + ssdt_ptr[MEM_OFFSET_ID ] = i; + ssdt_ptr[MEM_OFFSET_PXM ] = node; + *(u64 *)(ssdt_ptr +MEM_OFFSET_START ) =cpu_to_le64 (mem_base); + *(u64 *)(ssdt_ptr +MEM_OFFSET_END ) =cpu_to_le64 (mem_base + mem_len); + *(u64 *)(ssdt_ptr +MEM_OFFSET_SIZE ) =cpu_to_le64 (mem_len); +} + +static u8 *build_memssdt (u8 *ssdt_ptr,int memssdt_len, +u64 *numadimmsmap,int nb_memdevs) +{ +u64 mem_base, mem_len; +u64 *dimm = numadimmsmap; +int node; +int i; + +// build Scope(_SB_) header + *(ssdt_ptr++) =0x10 ;// ScopeOp + ssdt_ptr =encodeLen (ssdt_ptr, memssdt_len,3 ); + *(ssdt_ptr++) ='_' ; + *(ssdt_ptr++) ='S' ; + *(ssdt_ptr++) ='B' ; + *(ssdt_ptr++) ='_' ; + +for (i =0 ; i < nb_memdevs; i++) { + mem_base = *dimm++; + mem_len = *dimm++; + node = *dimm++; +build_memdev (ssdt_ptr, i, mem_base, mem_len, node); + ssdt_ptr +=MEM_SIZEOF ; + } + +// build "Method(MTFY, 2) {If (LEqual(Arg0, 0x00)) {Notify(CM00, Arg1)} ...}" + *(ssdt_ptr++) =0x14 ;// MethodOp + ssdt_ptr =encodeLen (ssdt_ptr,2 +5 +(12 *nb_memdevs),2 ); + *(ssdt_ptr++) ='M' ; + *(ssdt_ptr++) ='T' ; + *(ssdt_ptr++) ='F' ; + *(ssdt_ptr++) ='Y' ; + *(ssdt_ptr++) =0x02 ; +for (i=0 ; i<nb_memdevs; i++) { + *(ssdt_ptr++) =0xA0 ;// IfOp + ssdt_ptr =encodeLen (ssdt_ptr,11 ,1 ); + *(ssdt_ptr++) =0x93 ;// LEqualOp + *(ssdt_ptr++) =0x68 ;// Arg0Op + *(ssdt_ptr++) =0x0A ;// BytePrefix + *(ssdt_ptr++) = i; + *(ssdt_ptr++) =0x86 ;// NotifyOp + *(ssdt_ptr++) ='M' ; + *(ssdt_ptr++) ='P' ; + *(ssdt_ptr++) =getHex (i >>4 ); + *(ssdt_ptr++) =getHex (i); + *(ssdt_ptr++) =0x69 ;// Arg1Op + } + +// build "Name(MEON, Package() { One, One, ..., Zero, Zero, ... })" + *(ssdt_ptr++) =0x08 ;// NameOp + *(ssdt_ptr++) ='M' ; + *(ssdt_ptr++) ='E' ; + *(ssdt_ptr++) ='O' ; + *(ssdt_ptr++) ='N' ; + *(ssdt_ptr++) =0x12 ;// PackageOp + ssdt_ptr =encodeLen (ssdt_ptr,2 +1 +(1 *nb_memdevs),2 ); + *(ssdt_ptr++) = nb_memdevs; + + dimm = numadimmsmap; +u8 memslot_status =0 , enabled; + +for (i =0 ; i < nb_memdevs; i++) { + enabled =0 ; +if (i %8 ==0 ) + memslot_status =inb (MEM_BASE + i/8 ); + enabled = memslot_status &1 ; + mem_base = *dimm++; + mem_len = *dimm++; + dimm++;// node + *(ssdt_ptr++) = enabled ?0x01 :0x00 ; +if (enabled) +add_e820 (mem_base, mem_len,E820_RAM ); + memslot_status = memslot_status >>1 ; + } + +return ssdt_ptr; +} +static void *build_ssdt (void ) { +int nb_memdevs; +u64 *numadimmsmap;int acpi_cpus = MaxCountCPUs >0xff ?0xff : MaxCountCPUs;int length = (sizeof (ssdp_misc_aml)// _S3_ / _S4_ / _S5_ + (1+3+4) // Scope(_SB_)
@@ -318,9 +423,20 @@ build_ssdt(void) + (1 +3 +4 )// Scope(PCI0) + ((PCI_SLOTS -1 ) *PCIHP_SIZEOF )// slots + (1+2+5+(12*(PCI_SLOTS - 1)))); // PCNT -u8 *ssdt =malloc_high (length); + + numadimmsmap =romfile_loadfile ("etc/numa-dimm-map" , &nb_memdevs); + nb_memdevs /=3 *sizeof (u64); + +// for build_memssdt +int memssdt_length = (1 +3 +4 ) + + (nb_memdevs *MEM_SIZEOF ) + + (1 +2 +5 +(12 *nb_memdevs)) + + (6 +2 +1 +(1 *nb_memdevs)); + +u8 *ssdt =malloc_high (length + memssdt_length);if (! ssdt) {warn_noalloc (); +free (numadimmsmap);return NULL ; }u8 *ssdt_ptr = ssdt;
@@ -411,10 +527,13 @@ build_ssdt(void) ssdt_ptr =build_notify (ssdt_ptr,"PCNT" ,1 ,PCI_SLOTS ,"S00_" ,1 ); + ssdt_ptr =build_memssdt (ssdt_ptr, memssdt_length, numadimmsmap, nb_memdevs); +build_header ((void *)ssdt,SSDT_SIGNATURE , ssdt_ptr - ssdt,1 );//hexdump(ssdt, ssdt_ptr - ssdt); +free (numadimmsmap);return ssdt; }
@@ -458,7 +577,7 @@ acpi_build_srat_memory(struct srat_memory_affinity *numamem, numamem->length =sizeof (*numamem);memset (numamem->proximity,0 ,4 ); numamem->proximity[0 ] = node; - numamem->flags =cpu_to_le32 (!!enabled); + numamem->flags =cpu_to_le32 (!!enabled) |cpu_to_le32 (0x2 ); numamem->base_addr =cpu_to_le64 (base); numamem->range_length =cpu_to_le64 (len); }
@@ -466,18 +585,22 @@ acpi_build_srat_memory(struct srat_memory_affinity *numamem,static void *build_srat (void ) { -int numadatasize, numacpusize; +int numadatasize, numacpusize, nb_numa_dimms; +u64 *numadimmsmap;u64 *numadata =romfile_loadfile ("etc/numa-nodes" , &numadatasize);u64 *numacpumap =romfile_loadfile ("etc/numa-cpu-map" , &numacpusize); -if (!numadata || !numacpumap) - goto fail; +int max_cpu = numacpusize /sizeof (u64);int nb_numa_nodes = numadatasize /sizeof (u64); + numadimmsmap =romfile_loadfile ("etc/numa-dimm-map" , &nb_numa_dimms); + + nb_numa_dimms /=3 *sizeof (u64); +struct system_resource_affinity_table *srat;int srat_size =sizeof (*srat) +sizeof (struct srat_processor_affinity ) * max_cpu + -sizeof (struct srat_memory_affinity ) * (nb_numa_nodes +2 ); +sizeof (struct srat_memory_affinity ) * (nb_numa_nodes + nb_numa_dimms +2 ); srat =malloc_high (srat_size);if (!srat) {
@@ -512,6 +635,7 @@ build_srat(void)*/ struct srat_memory_affinity *numamem = (void *)core;int slots =0 ; +int node;u64 mem_len, mem_base, next_base =0 ;acpi_build_srat_memory (numamem,0 ,640 *1024 ,0 ,1 );
@@ -541,7 +665,18 @@ build_srat(void) numamem++; slots++; } -for (; slots < nb_numa_nodes +2 ; slots++) { +if (nb_numa_dimms) { +for (i =1 ; i < nb_numa_dimms +1 ; ++i) { + mem_base = *numadimmsmap++; + mem_len = *numadimmsmap++; + node = *numadimmsmap++; +acpi_build_srat_memory (numamem, mem_base, mem_len, node,1 ); + numamem++; + slots++; + } + } + +for (; slots < nb_numa_nodes + nb_numa_dimms +2 ; slots++) {acpi_build_srat_memory (numamem,0 ,0 ,0 ,0 ); numamem++; }
@@ -550,10 +685,12 @@ build_srat(void)free (numadata);free (numacpumap); +free (numadimmsmap);return srat; fail:free (numadata);free (numacpumap); +free (numadimmsmap);return NULL ; }
src/paravirt.c +8 -0
@@ -240,6 +240,14 @@ qemu_cfg_legacy(void) , sizeof(numacount) + max_cpu*sizeof(u64) , numacount*sizeof(u64)); +u64 dimm_count; +qemu_cfg_select (QEMU_CFG_NUMA ); +qemu_cfg_skip ((1 + max_cpu + numacount) *sizeof (u64)); +qemu_cfg_read (&dimm_count,sizeof (dimm_count)); +qemu_romfile_add ("etc/numa-dimm-map" ,QEMU_CFG_NUMA + , (2 + max_cpu + numacount) *sizeof (u64), + dimm_count *3 *sizeof (u64)); +// e820 data u32 count32;qemu_cfg_read_entry (&count32,QEMU_CFG_E820_TABLE ,sizeof (count32));
Signature · 1 line
1.8.3.1
Re: [Qemu-devel] [PATCH v5 5/7] acpi: generate hotplug memory devices
Quoted 76 lines · On Wed, 26 Jun 2013 17:15:03 +0800 Hu Tao <[email protected]> wrote:
The memory device generation is guided by qemu paravirt info. Seabios uses the info to setup SRAT entries for the hotplug-able memory slots, and to generate appropriate memory device objects. One memory device (and corresponding SRAT entry) is generated for each hotplug-able qemu memslot. Currently no SSDT memory device is created for initial system memory.
We only support up to 255 DIMMs for now (PackageOp used for the MEON array can only describe an array of at most 255 elements. VarPackageOp would be needed to support more than 255 devices)
Signed-off-by Vasilis Liaskovitis <[email protected]>Signed-off-by Hu Tao <[email protected]>--- src/acpi.c | 151 ++++++++++++++++++++++++++++++++++++++++++++++++++++++--- src/paravirt.c | 8 +++ 2 files changed, 152 insertions(+), 7 deletions(-)src/acpi.c +31
-0@@ -15,6 +15,8 @@#include "config.h" // CONFIG_* #include "paravirt.h" // RamSize #include "dev-q35.h" +#include "memmap.h" +#include "paravirt.h" #include "acpi-dsdt.hex" @@ -250,11 +252,23 @@ encodeLen(u8 *ssdt_ptr, int length, int bytes)#define PCIHP_AML (ssdp_pcihp_aml + *ssdt_pcihp_start)#define PCI_SLOTS 32 +/* 0x5B 0x82 DeviceOp PkgLength NameString DimmID */ +#define MEM_BASE 0xaf80 +#define MEM_AML (ssdm_mem_aml + *ssdt_mem_start) +#define MEM_SIZEOF (*ssdt_mem_end - *ssdt_mem_start) +#define MEM_OFFSET_HEX (*ssdt_mem_name - *ssdt_mem_start + 2) +#define MEM_OFFSET_ID (*ssdt_mem_id - *ssdt_mem_start) +#define MEM_OFFSET_PXM 31 +#define MEM_OFFSET_START 55 +#define MEM_OFFSET_END 63 +#define MEM_OFFSET_SIZE 79 +#define SSDT_SIGNATURE 0x54445353 // SSDT#define SSDT_HEADER_LENGTH 36#include "ssdt-misc.hex" #include "ssdt-pcihp.hex" +#include "ssdt-mem.hex" #define PCI_RMV_BASE 0xae0c@@ -306,9 +320,100 @@ static void patch_pcihp(int slot, u8 *ssdt_ptr, u32 eject) } } +static void build_memdev (u8 *ssdt_ptr,int i,u64 mem_base,u64 mem_len,u8 node) +{ +memcpy (ssdt_ptr,MEM_AML ,MEM_SIZEOF ); + ssdt_ptr[MEM_OFFSET_HEX ] =getHex (i >>4 ); + ssdt_ptr[MEM_OFFSET_HEX +1 ] =getHex (i); + ssdt_ptr[MEM_OFFSET_ID ] = i; + ssdt_ptr[MEM_OFFSET_PXM ] = node; + *(u64 *)(ssdt_ptr +MEM_OFFSET_START ) =cpu_to_le64 (mem_base); + *(u64 *)(ssdt_ptr +MEM_OFFSET_END ) =cpu_to_le64 (mem_base + mem_len); + *(u64 *)(ssdt_ptr +MEM_OFFSET_SIZE ) =cpu_to_le64 (mem_len); +} + +static u8 *build_memssdt (u8 *ssdt_ptr,int memssdt_len, +u64 *numadimmsmap,int nb_memdevs) +{ +u64 mem_base, mem_len; +u64 *dimm = numadimmsmap;
src/acpi.c static void patch_pcihp(int slot, u8 *ssdt_ptr, u32 eject) · line 349
Quoted 10 lines
src/acpi.c +10
-0+int node; +int i; + +// build Scope(_SB_) header + *(ssdt_ptr++) =0x10 ;// ScopeOp + ssdt_ptr =encodeLen (ssdt_ptr, memssdt_len,3 ); + *(ssdt_ptr++) ='_' ; + *(ssdt_ptr++) ='S' ; + *(ssdt_ptr++) ='B' ; + *(ssdt_ptr++) ='_' ;
Windows doesn't like much 2 \_SB in one SSDT table, and BSODs.
Just drop it and add stuff to already existing scope or alternatively create a second SSDT table.
Quoted 92 lines
src/acpi.c +75
-1+for (i =0 ; i < nb_memdevs; i++) { + mem_base = *dimm++; + mem_len = *dimm++; + node = *dimm++; +build_memdev (ssdt_ptr, i, mem_base, mem_len, node); + ssdt_ptr +=MEM_SIZEOF ; + } + +// build "Method(MTFY, 2) {If (LEqual(Arg0, 0x00)) {Notify(CM00, Arg1)} ...}" + *(ssdt_ptr++) =0x14 ;// MethodOp + ssdt_ptr =encodeLen (ssdt_ptr,2 +5 +(12 *nb_memdevs),2 ); + *(ssdt_ptr++) ='M' ; + *(ssdt_ptr++) ='T' ; + *(ssdt_ptr++) ='F' ; + *(ssdt_ptr++) ='Y' ; + *(ssdt_ptr++) =0x02 ; +for (i=0 ; i<nb_memdevs; i++) { + *(ssdt_ptr++) =0xA0 ;// IfOp + ssdt_ptr =encodeLen (ssdt_ptr,11 ,1 ); + *(ssdt_ptr++) =0x93 ;// LEqualOp + *(ssdt_ptr++) =0x68 ;// Arg0Op + *(ssdt_ptr++) =0x0A ;// BytePrefix + *(ssdt_ptr++) = i; + *(ssdt_ptr++) =0x86 ;// NotifyOp + *(ssdt_ptr++) ='M' ; + *(ssdt_ptr++) ='P' ; + *(ssdt_ptr++) =getHex (i >>4 ); + *(ssdt_ptr++) =getHex (i); + *(ssdt_ptr++) =0x69 ;// Arg1Op + } + +// build "Name(MEON, Package() { One, One, ..., Zero, Zero, ... })" + *(ssdt_ptr++) =0x08 ;// NameOp + *(ssdt_ptr++) ='M' ; + *(ssdt_ptr++) ='E' ; + *(ssdt_ptr++) ='O' ; + *(ssdt_ptr++) ='N' ; + *(ssdt_ptr++) =0x12 ;// PackageOp + ssdt_ptr =encodeLen (ssdt_ptr,2 +1 +(1 *nb_memdevs),2 ); + *(ssdt_ptr++) = nb_memdevs; + + dimm = numadimmsmap; +u8 memslot_status =0 , enabled; + +for (i =0 ; i < nb_memdevs; i++) { + enabled =0 ; +if (i %8 ==0 ) + memslot_status =inb (MEM_BASE + i/8 ); + enabled = memslot_status &1 ; + mem_base = *dimm++; + mem_len = *dimm++; + dimm++;// node + *(ssdt_ptr++) = enabled ?0x01 :0x00 ; +if (enabled) +add_e820 (mem_base, mem_len,E820_RAM ); + memslot_status = memslot_status >>1 ; + } + +return ssdt_ptr; +} +static void *build_ssdt (void ) { +int nb_memdevs; +u64 *numadimmsmap;int acpi_cpus = MaxCountCPUs >0xff ?0xff : MaxCountCPUs;int length = (sizeof (ssdp_misc_aml)// _S3_ / _S4_ / _S5_ + (1+3+4) // Scope(_SB_)@@ -318,9 +423,20 @@ build_ssdt(void) + (1 +3 +4 )// Scope(PCI0) + ((PCI_SLOTS -1 ) *PCIHP_SIZEOF )// slots + (1+2+5+(12*(PCI_SLOTS - 1)))); // PCNT -u8 *ssdt =malloc_high (length); + + numadimmsmap =romfile_loadfile ("etc/numa-dimm-map" , &nb_memdevs); + nb_memdevs /=3 *sizeof (u64); + +// for build_memssdt +int memssdt_length = (1 +3 +4 ) + + (nb_memdevs *MEM_SIZEOF ) + + (1 +2 +5 +(12 *nb_memdevs)) + + (6 +2 +1 +(1 *nb_memdevs)); + +u8 *ssdt =malloc_high (length + memssdt_length);if (! ssdt) {warn_noalloc (); +free (numadimmsmap);return NULL ; }u8 *ssdt_ptr = ssdt;
src/acpi.c build_ssdt(void) · line 530
Quoted 4 lines
src/acpi.c +1
-0@@ -411,10 +527,13 @@ build_ssdt(void) ssdt_ptr =build_notify (ssdt_ptr,"PCNT" ,1 ,PCI_SLOTS ,"S00_" ,1 ); + ssdt_ptr =build_memssdt (ssdt_ptr, memssdt_length, numadimmsmap, nb_memdevs);
^^^^^^^ name is misleading, since the result of call is not SSDT
Quoted 105 lines
src/acpi.c +26
-6+build_header ((void *)ssdt,SSDT_SIGNATURE , ssdt_ptr - ssdt,1 );//hexdump(ssdt, ssdt_ptr - ssdt); +free (numadimmsmap);return ssdt; }@@ -458,7 +577,7 @@ acpi_build_srat_memory(struct srat_memory_affinity *numamem, numamem->length =sizeof (*numamem);memset (numamem->proximity,0 ,4 ); numamem->proximity[0 ] = node; - numamem->flags =cpu_to_le32 (!!enabled); + numamem->flags =cpu_to_le32 (!!enabled) |cpu_to_le32 (0x2 ); numamem->base_addr =cpu_to_le64 (base); numamem->range_length =cpu_to_le64 (len); }@@ -466,18 +585,22 @@ acpi_build_srat_memory(struct srat_memory_affinity *numamem,static void *build_srat (void ) { -int numadatasize, numacpusize; +int numadatasize, numacpusize, nb_numa_dimms; +u64 *numadimmsmap;u64 *numadata =romfile_loadfile ("etc/numa-nodes" , &numadatasize);u64 *numacpumap =romfile_loadfile ("etc/numa-cpu-map" , &numacpusize); -if (!numadata || !numacpumap) - goto fail; +int max_cpu = numacpusize /sizeof (u64);int nb_numa_nodes = numadatasize /sizeof (u64); + numadimmsmap =romfile_loadfile ("etc/numa-dimm-map" , &nb_numa_dimms); + + nb_numa_dimms /=3 *sizeof (u64); +struct system_resource_affinity_table *srat;int srat_size =sizeof (*srat) +sizeof (struct srat_processor_affinity ) * max_cpu + -sizeof (struct srat_memory_affinity ) * (nb_numa_nodes +2 ); +sizeof (struct srat_memory_affinity ) * (nb_numa_nodes + nb_numa_dimms +2 ); srat =malloc_high (srat_size);if (!srat) {@@ -512,6 +635,7 @@ build_srat(void)*/ struct srat_memory_affinity *numamem = (void *)core;int slots =0 ; +int node;u64 mem_len, mem_base, next_base =0 ;acpi_build_srat_memory (numamem,0 ,640 *1024 ,0 ,1 );@@ -541,7 +665,18 @@ build_srat(void) numamem++; slots++; } -for (; slots < nb_numa_nodes +2 ; slots++) { +if (nb_numa_dimms) { +for (i =1 ; i < nb_numa_dimms +1 ; ++i) { + mem_base = *numadimmsmap++; + mem_len = *numadimmsmap++; + node = *numadimmsmap++; +acpi_build_srat_memory (numamem, mem_base, mem_len, node,1 ); + numamem++; + slots++; + } + } + +for (; slots < nb_numa_nodes + nb_numa_dimms +2 ; slots++) {acpi_build_srat_memory (numamem,0 ,0 ,0 ,0 ); numamem++; }@@ -550,10 +685,12 @@ build_srat(void)free (numadata);free (numacpumap); +free (numadimmsmap);return srat; fail:free (numadata);free (numacpumap); +free (numadimmsmap);return NULL ; }src/paravirt.c +8
-0@@ -240,6 +240,14 @@ qemu_cfg_legacy(void) , sizeof(numacount) + max_cpu*sizeof(u64) , numacount*sizeof(u64)); +u64 dimm_count; +qemu_cfg_select (QEMU_CFG_NUMA ); +qemu_cfg_skip ((1 + max_cpu + numacount) *sizeof (u64)); +qemu_cfg_read (&dimm_count,sizeof (dimm_count)); +qemu_romfile_add ("etc/numa-dimm-map" ,QEMU_CFG_NUMA + , (2 + max_cpu + numacount) *sizeof (u64), + dimm_count *3 *sizeof (u64)); +// e820 data u32 count32;qemu_cfg_read_entry (&count32,QEMU_CFG_E820_TABLE ,sizeof (count32));
PATCH v5 6/7 q35: Add memory hotplug handler
In reply to Hu TaoFrom: Vasilis Liaskovitis <[email protected]>
--- src/q35-acpi-dsdt.dsl | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-)
src/q35-acpi-dsdt.dsl +4 -2
@@ -403,7 +403,7 @@ DefinitionBlock ( } #include "acpi-dsdt-cpu-hotplug.dsl" - +#include "acpi-dsdt-mem-hotplug.dsl" /**************************************************************** * General purpose events
@@ -418,7 +418,9 @@ DefinitionBlock ( // CPU hotplug event \_SB.PRSC() } - Method(_L02) { + Method(_E02) { + // Memory hotplug event + \_SB.MESC() } Method(_L03) { }
Signature · 1 line
1.8.3.1
PATCH v5 7/7 pci: Use paravirt interface for pcimem_start and pcimem64_start
In reply to Hu TaoFrom: Vasilis Liaskovitis <[email protected]>
Initialize the 32-bit and 64-bit pci starting offsets from values passed in by the qemu paravirt interface QEMU_CFG_PCI_WINDOW. Qemu calculates the starting offsets based on initial memory and hotplug-able dimms.
It's possible to avoid the new paravirt interface, and calculate pci ranges from srat entries. But the code changes are ugly, see:
http://lists.gnu.org/archive/html/qemu-devel/2012-09/msg03548.html
--- src/paravirt.c | 7 +++++++ src/paravirt.h | 1 + src/pciinit.c | 9 +++++++++ 3 files changed, 17 insertions(+)
src/paravirt.c +7 -0
@@ -134,6 +134,7 @@ qemu_platform_setup(void)#define QEMU_CFG_BOOT_MENU 0x0e#define QEMU_CFG_MAX_CPUS 0x0f#define QEMU_CFG_FILE_DIR 0x19 +#define QEMU_CFG_PCI_WINDOW 0x1a#define QEMU_CFG_ARCH_LOCAL 0x8000#define QEMU_CFG_ACPI_TABLES (QEMU_CFG_ARCH_LOCAL + 0)#define QEMU_CFG_SMBIOS_ENTRIES (QEMU_CFG_ARCH_LOCAL + 1)
@@ -339,3 +340,9 @@ void qemu_cfg_init(void) , 0, be32_to_cpu(qfile.size)); } } + +void qemu_cfg_get_pci_offsets (u64 *pcimem_start,u64 *pcimem64_start) +{ +qemu_cfg_read_entry (pcimem_start,QEMU_CFG_PCI_WINDOW ,sizeof (u64)); +qemu_cfg_read ((u8 *)(pcimem64_start),sizeof (u64)); +}
src/paravirt.h +1 -0
@@ -27,5 +27,6 @@ static inline int runningOnKVM(void) {void qemu_preinit (void );void qemu_platform_setup (void );void qemu_cfg_init (void ); +void qemu_cfg_get_pci_offsets (u64 *pcimem_start,u64 *pcimem64_start);#endif
src/pciinit.c +9 -0
@@ -805,6 +805,7 @@ static void pci_bios_map_devices(struct pci_bus *busses)void pci_setup (void ) { +u64 pv_pcimem_start, pv_pcimem64_start;if (!CONFIG_QEMU )return ;
@@ -837,6 +838,14 @@ pci_setup(void)pci_bios_init_devices (); +/* if qemu gives us other pci window values, it means there are hotplug-able +* dimms. Adjust accordingly */ +qemu_cfg_get_pci_offsets (&pv_pcimem_start, &pv_pcimem64_start); +if (pv_pcimem_start > pcimem_start) + pcimem_start = pv_pcimem_start; +if (pv_pcimem64_start > pcimem64_start) + pcimem64_start = pv_pcimem64_start; +free (busses);pci_enable_default_vga ();
Signature · 1 line
1.8.3.1
Re: [Qemu-devel] [PATCH v5 7/7] pci: Use paravirt interface for pcimem_start and pcimem64_start
Hi,
2013/6/26 Hu Tao <[email protected]>
Quoted 8 lines
From: Vasilis Liaskovitis <[email protected]>
Initialize the 32-bit and 64-bit pci starting offsets from values passed in by
the qemu paravirt interfaceQEMU_CFG_PCI_WINDOW. Qemu calculates the starting
offsets based on initial memory and hotplug-able dimms.
We should drop this patch and the corresponding seabios patch since Michael Tsirkin's pci-window patches are merged or will be soon.
See
"pc: pass PCI hole ranges to Guests" - already in qemu master "pci: load memory window setup from host" (should go into seabios)
thanks,
- Vasilis
Quoted 78 lines
It's possible to avoid the new paravirt interface, and calculate pci ranges from
srat entries. But the code changes are ugly, see:
http://lists.gnu.org/archive/html/qemu-devel/2012-09/msg03548.htmlSigned-off-by Vasilis Liaskovitis <[email protected]>--- src/paravirt.c | 7 +++++++ src/paravirt.h | 1 + src/pciinit.c | 9 +++++++++ 3 files changed, 17 insertions(+)src/paravirt.c +7
-0@@ -134,6 +134,7 @@ qemu_platform_setup(void)#define QEMU_CFG_BOOT_MENU 0x0e#define QEMU_CFG_MAX_CPUS 0x0f#define QEMU_CFG_FILE_DIR 0x19 +#define QEMU_CFG_PCI_WINDOW 0x1a#define QEMU_CFG_ARCH_LOCAL 0x8000#define QEMU_CFG_ACPI_TABLES (QEMU_CFG_ARCH_LOCAL + 0)#define QEMU_CFG_SMBIOS_ENTRIES (QEMU_CFG_ARCH_LOCAL + 1)@@ -339,3 +340,9 @@ void qemu_cfg_init(void) , 0, be32_to_cpu(qfile.size)); } } + +void qemu_cfg_get_pci_offsets (u64 *pcimem_start,u64 *pcimem64_start) +{ +qemu_cfg_read_entry (pcimem_start,QEMU_CFG_PCI_WINDOW ,sizeof (u64)); +qemu_cfg_read ((u8 *)(pcimem64_start),sizeof (u64)); +}src/paravirt.h +1
-0@@ -27,5 +27,6 @@ static inline int runningOnKVM(void) {void qemu_preinit (void );void qemu_platform_setup (void );void qemu_cfg_init (void ); +void qemu_cfg_get_pci_offsets (u64 *pcimem_start,u64 *pcimem64_start);#endif src/pciinit.c +2
-0@@ -805,6 +805,7 @@ static void pci_bios_map_devices(struct pci_bus *busses)void pci_setup (void ) { +u64 pv_pcimem_start, pv_pcimem64_start;if (!CONFIG_QEMU )return ;@@ -837,6 +838,14 @@ pci_setup(void)pci_bios_init_devices (); +/* if qemu gives us other pci window values, it means there are hotplug-able
src/pciinit.c +7
-1+* dimms. Adjust accordingly */ +qemu_cfg_get_pci_offsets (&pv_pcimem_start, &pv_pcimem64_start); +if (pv_pcimem_start > pcimem_start) + pcimem_start = pv_pcimem_start; +if (pv_pcimem64_start > pcimem64_start) + pcimem64_start = pv_pcimem64_start; +free (busses);pci_enable_default_vga (); --1.8.3.1
Re: [Qemu-devel] [PATCH v5 0/7] support for ACPI memory hotplug
In reply to Hu TaoQuoted 17 lines · Hu Tao
This series adds memory devices and related methods to support ACPI memory hotplug.
This series works with qemu counterpart. See qemu series for a detailed description.
Hu Tao (2):
set psize to 0 whenromfile_loadfilefailed
acpi: generate hotplug memory devicesVasilis Liaskovitis (5):
Add ACPI_EXTRACT_DEVICE* macros
Add SSDT memory device support
acpi-dsdt: Implement functions for memory hotplug
q35: Add memory hotplug handler
pci: Use paravirt interface forpcimem_startandpcimem64_start
Quoted 14 lines
Makefile | 2 +- src/acpi-dsdt-mem-hotplug.dsl | 57 ++++++++++++++++ src/acpi-dsdt.dsl | 5 +- src/acpi.c | 151 ++++++++++++++++++++++++++++++++++++++++-- src/paravirt.c | 15 +++++ src/paravirt.h | 1 + src/pciinit.c | 9 +++ src/q35-acpi-dsdt.dsl | 6 +- src/romfile.c | 13 ++-- src/ssdt-mem.dsl | 61 +++++++++++++++++ tools/acpi_extract.py | 28 ++++++++ 11 files changed, 333 insertions(+), 15 deletions(-) create mode 100644 src/acpi-dsdt-mem-hotplug.dsl create mode 100644 src/ssdt-mem.dsl
We were looking for a new feature to use the acpi tables in qemu. Could you use that instead of adding code to seabios?
You can find the latest bits here:
git://git.kernel.org/pub/scm/virt/kvm/mst/qemu.git acpi
Quoted 3 lines
Signature · 1 line
1.8.3.1
Am 26.06.2013 11:13, schrieb Hu Tao:
Quoted 6 lines
It's been quite a while since v4 and lots of changes happend in qemu and v4 just can't apply anymore. So this series is basically a rebase. Another purpose is to bring up discussions to make consensus on some questions since v4, see
http://lists.gnu.org/archive/html/qemu-devel/2013-01/msg01219.html
and http://lists.gnu.org/archive/html/qemu-devel/2013-02/msg05332.html
[...]
Quoted 7 lines
changes from v4:
- rebased on a recent qemu-git
- based on another series which seperates i440fx refactor from v4.http://lists.nongnu.org/archive/html/qemu-devel/2013-06/msg03500.html- hot-unplug patches not included, as suggested by Vasilis, since hot-unplug has some more complications with refcounting memory regions.
This should hopefully be addressed with yesterday's merge of Paolo's MemoryRegion refactoring.
Andreas
Quoted 3 lines
- fix some copy-paste errors in qapi-schema.json.
v4: http://lists.gnu.org/archive/html/qemu-devel/2012-12/msg02693.html
[snip]
Signature · 2 lines
SUSE LINUX Products GmbH, Maxfeldstr. 5, 90409 Nürnberg, Germany GF: Jeff Hawn, Jennifer Guild, Felix Imendörffer; HRB 16746 AG Nürnberg
Quoted 10 lines · Andreas Färber
Am 26.06.2013 11:13, schrieb Hu Tao:
Quoted 6 lines
It's been quite a while since v4 and lots of changes happend in qemu and v4 just can't apply anymore. So this series is basically a rebase. Another purpose is to bring up discussions to make consensus on some questions since v4, see
http://lists.gnu.org/archive/html/qemu-devel/2013-01/msg01219.html
and http://lists.gnu.org/archive/html/qemu-devel/2013-02/msg05332.html[...]
Quoted 2 lines
changes from v4:
Quoted 8 lines
Quoted 5 lines
- rebased on a recent qemu-git
- based on another series which seperates i440fx refactor from v4.http://lists.nongnu.org/archive/html/qemu-devel/2013-06/msg03500.html- hot-unplug patches not included, as suggested by Vasilis, since hot-unplug has some more complications with refcounting memory regions.
This should hopefully be addressed with yesterday's merge of Paolo's MemoryRegion refactoring.
Thanks for the tip. I'll consider adding hot-unplug patches in v6.
Il 08/07/2013 11:48, Andreas Färber ha scritto:
Quoted 4 lines
Quoted 2 lines
Quoted 2 lines
- hot-unplug patches not included, as suggested by Vasilis, since hot-unplug has some more complications with refcounting memory regions.
This should hopefully be addressed with yesterday's merge of Paolo's MemoryRegion refactoring.
Not entirely because address_space_translate does not yet ref/unref the region, but that's easy enough to add (it is in my rcu branch on github). But the ownership infrastructure is indeed in master now.
Paolo