Re: Memory hotplug

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

 



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) { }
+        }
+    }
+
 }

[Index of Archives]     [KVM ARM]     [KVM ia64]     [KVM ppc]     [Virtualization Tools]     [Spice Development]     [Libvirt]     [Libvirt Users]     [Linux USB Devel]     [Linux Audio Users]     [Yosemite Questions]     [Linux Kernel]     [Linux SCSI]     [XFree86]
  Powered by Linux