Hi Marcelo and guys, On Wed, Jan 6, 2010 at 11:24 PM, Ryota Ozaki <ozaki.ryota@xxxxxxxxx> wrote: > On Wed, Jan 6, 2010 at 10:59 PM, Marcelo Tosatti <mtosatti@xxxxxxxxxx> wrote: >> On Wed, Jan 06, 2010 at 10:07:25PM +0900, Ryota Ozaki wrote: [...] >>> I know virtio balloon can changes amount of >>> guest memory online, however, it can change >>> only under initially assigned amount of memory. >>> I want to increase guest memory over the initial >>> amount. >> >> That'd be great. Probably ACPI is the best mechanism >> for memory hotplug. > > Thanks for your advice. I agree with you. > > I'll try to implement it if nobody working on it. I've wrote a piece of initial proof-of-concept code of memory hot-add facility using ACPI. Please find the patches for qemu-kvm and SeaBIOS in the attachment. The code is still pretty immature but works fine in my some restricted environment ;-) The code defines just one Memory Device in RSDT of ACPI in SeaBIOS and the Memory Device has a fixed sized and addressed memory region starting at 512MB upto 1GB. It also adds mem_set qemu command similar to cpu_set to dynamically activate the memory. The hot-add event is notified to OSPM (guest OS) via ACPI general event notification facility of \_GPE0._L03 where pci and cpu hotplug use \_GPE0._L01 and \_GPE0._L02, respectively. Now I'm improving the code to make it more flexible and feasible for real use. Thanks, ozaki-r
diff --git a/hw/acpi.c b/hw/acpi.c index d293127..1f6e3c9 100644 --- a/hw/acpi.c +++ b/hw/acpi.c @@ -795,6 +795,54 @@ void qemu_system_cpu_hot_add(int cpu, int state) qemu_set_irq(pm_state->irq, 0); } } + +// FIXME: must tell which Memory Device is enabled +// to OSPM via \_GPE._L03 +static void enable_memory_device(struct gpe_regs *g, int md) +{ + g->sts |= 8; + //g->cpus_sts[cpu/8] |= (1 << (cpu%8)); +} + +static void disable_memory_device(struct gpe_regs *g, int md) +{ + g->sts |= 8; + //g->cpus_sts[cpu/8] &= ~(1 << (cpu%8)); +} + +static int allocate_memory(int md) +{ + // FIXME: must have each Memory Device objects + target_phys_addr_t start_addr = 0x20000000; + ram_addr_t size = 0x40000000-0x20000000; + ram_addr_t ram_addr; + + ram_addr = qemu_ram_alloc(size); + // Is this correct? + cpu_register_physical_memory(start_addr, size, ram_addr); + + return 1; +} + + +void qemu_system_mem_hot_add(int md, int state) +{ + if (state) { + allocate_memory(md); + // FIXME: need to set _STA enable on the Memory Device + // currently the status is always on ;< + } + + if (state) + enable_memory_device(&gpe, md); + else + disable_memory_device(&gpe, md); + if (gpe.en & 8) { + qemu_set_irq(pm_state->irq, 1); + qemu_set_irq(pm_state->irq, 0); + } +} + #endif static void enable_device(struct pci_status *p, struct gpe_regs *g, int slot) diff --git a/monitor.c b/monitor.c index 6ff6e1f..ac987a6 100644 --- a/monitor.c +++ b/monitor.c @@ -833,6 +833,19 @@ static void do_cpu_set_nr(Monitor *mon, const QDict *qdict) #endif } +static void do_mem_set_nr(Monitor *mon, const QDict *qdict) +{ + int state, value; + const char *status; + + status = qdict_get_str(qdict, "state"); + value = qdict_get_int(qdict, "mem"); + state = 1; +#if defined(TARGET_I386) || defined(TARGET_X86_64) + qemu_system_mem_hot_add(value, state); +#endif +} + static void do_info_jit(Monitor *mon) { dump_exec_info((FILE *)mon, monitor_fprintf); diff --git a/qemu-monitor.hx b/qemu-monitor.hx index 9e3ea3c..d94c6fb 100644 --- a/qemu-monitor.hx +++ b/qemu-monitor.hx @@ -1075,6 +1075,19 @@ STEXI Set CPU @var{cpu} online or offline. ETEXI + { + .name = "mem_set", + .args_type = "mem:i,state:s", + .params = "mem [online|offline]", + .help = "change memory device state", + .mhandler.cmd = do_mem_set_nr, + }, + +STEXI +@item mem_set @var{mem} [online|offline] +Set Memory Device @var{mem} online or offline. +ETEXI + STEXI @end table ETEXI diff --git a/sysemu.h b/sysemu.h index a545a2b..474e1d7 100644 --- a/sysemu.h +++ b/sysemu.h @@ -212,6 +212,7 @@ extern DriveInfo *drive_init(QemuOpts *arg, void *machine, int *fatal_error); /* acpi */ void qemu_system_cpu_hot_add(int cpu, int state); +void qemu_system_mem_hot_add(int cpu, int state); /* device-hotplug */
diff --git a/src/acpi-dsdt.dsl b/src/acpi-dsdt.dsl index cc31112..5211408 100644 --- a/src/acpi-dsdt.dsl +++ b/src/acpi-dsdt.dsl @@ -704,6 +704,7 @@ DefinitionBlock ( Return(0x01) } Method(_L03) { + Notify(\_SB.MEM0, 1) Return(0x01) } Method(_L04) { @@ -744,4 +745,51 @@ DefinitionBlock ( } } + Scope( \_SB){ + + // FIXME: currently support just one fixed Memory Device + Device(MEM0) { + Name(_HID, EISAID("PNP0C80")) + Name(_UID, 0) + + // FIXME: must change the state dynamically + Method (_STA, 0) { + //Store (\_SB.PCI0.PX13.DRSA, Local0) + //And (Local0, 0x80000000, Local0) + //If (LEqual (Local0, 0)) + //{ + // Return (0x00) // not present + //} + //ElseIf (LEqual (Local0, 0)) + //{ + // Return (0x0D) // disabled + //} + //Else + //{ + Return (0x0F) // enabled + //} + } + + Name(_CRS, ResourceTemplate() { + QwordMemory( + ResourceConsumer, + , + MinFixed, // _MINF + MaxFixed, // _MAXF + Cacheable, // _MEM + ReadWrite, // _RW + 0x0FFFFFFF, // _GRA + 0x20000000, // _MIN // from 512M + 0x3FFFFFFF, // _MAX // upto 1024M + 0x00000000, // _TRA + 0x20000000, // _LEN + ) + }) + + // Are these fields needed? + //Method (_SRS, 1) { } + //Method (_DIS, 0) { } + } + } + }