Hi Marcelo and guys,
On Wed, Jan 6, 2010 at 11:24 PM, Ryota Ozaki <[email protected]> wrote:
> On Wed, Jan 6, 2010 at 10:59 PM, Marcelo Tosatti <[email protected]> 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) { }
+ }
+ }
+
}