qemu-devel
[Top][All Lists]
Advanced

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

[Qemu-devel] [PATCH v2 5/5] enable cpu hotplug


From: Glauber Costa
Subject: [Qemu-devel] [PATCH v2 5/5] enable cpu hotplug
Date: Fri, 17 Apr 2009 17:00:08 -0400

This patch enable cpu hotplug to happen via acpi events.
Note that all it does is generate acpi messages. It still needs
guest cooperation, in the very way as real hardware.

It is basically what we have in kvm, but in a qemuish style, with
a few improvements.

Signed-off-by: Glauber Costa <address@hidden>
---
 cpu-all.h |    1 +
 exec.c    |   13 +++++++++++
 hw/acpi.c |   67 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
 monitor.c |   21 +++++++++++++++++++
 sysemu.h  |    1 +
 5 files changed, 103 insertions(+), 0 deletions(-)

diff --git a/cpu-all.h b/cpu-all.h
index aaaa70d..a0c97f7 100644
--- a/cpu-all.h
+++ b/cpu-all.h
@@ -745,6 +745,7 @@ int page_check_range(target_ulong start, target_ulong len, 
int flags);
 
 void cpu_exec_init_all(unsigned long tb_size);
 CPUState *cpu_copy(CPUState *env);
+CPUState *qemu_get_cpu(int cpu);
 
 void cpu_dump_state(CPUState *env, FILE *f,
                     int (*cpu_fprintf)(FILE *f, const char *fmt, ...),
diff --git a/exec.c b/exec.c
index 13e43d0..a7ac18f 100644
--- a/exec.c
+++ b/exec.c
@@ -538,6 +538,19 @@ static int cpu_common_load(QEMUFile *f, void *opaque, int 
version_id)
 }
 #endif
 
+CPUState *qemu_get_cpu(int cpu)
+{
+    CPUState *env = first_cpu;
+
+    while (env) {
+        if (env->cpu_index == cpu)
+            break;
+        env = env->next_cpu;
+    }
+
+    return env;
+}
+
 void cpu_exec_init(CPUState *env)
 {
     CPUState **penv;
diff --git a/hw/acpi.c b/hw/acpi.c
index 22fbc4a..0e58dbe 100644
--- a/hw/acpi.c
+++ b/hw/acpi.c
@@ -26,6 +26,7 @@
 #include "kvm.h"
 
 //#define DEBUG
+//#define DEBUG_CPU
 
 /* i82731AB (PIIX4) compatible power management function */
 #define PM_FREQ 3579545
@@ -563,6 +564,7 @@ void qemu_system_powerdown(void)
 #endif
 
 #define GPE_BASE 0xafe0
+#define PROC_BASE 0xaf00
 #define PCI_BASE 0xae00
 #define PCI_EJ_BASE 0xae08
 
@@ -578,6 +580,7 @@ struct pci_status {
 
 static struct gpe_regs gpe;
 static struct pci_status pci0_status;
+static uint8_t cpus_sts[32];
 
 static uint32_t gpe_read_val(uint16_t val, uint32_t addr)
 {
@@ -709,11 +712,43 @@ static void pciej_write(void *opaque, uint32_t addr, 
uint32_t val)
 #endif
 }
 
+static uint32_t cpuhotplug_read(void *opaque, uint32_t addr)
+{
+    if ((addr < PROC_BASE) || (addr > (PROC_BASE + 31))) {
+        /* should never happen, so return a poison */
+        return 0xabcdefab;
+    } else {
+        uint8_t *cpu_status = opaque;
+#if defined(DEBUG_CPU)
+        printf("cpuhotplug read %x == %x\n", addr, cpu_status[addr - 
PROC_BASE]);
+#endif
+        return cpu_status[addr - PROC_BASE];
+    }
+}
+
+static void cpuhotplug_write(void *opaque, uint32_t addr, uint32_t val)
+{
+    /* don't allow to change cpus_sts from inside a guest */
+#if defined(DEBUG_CPU)
+    printf("cpuhotplug write %x <== %d\n", addr, val);
+#endif
+}
+
 void qemu_system_hot_add_init(void)
 {
+    int i = 0, cpus = smp_cpus;
+
+    while (cpus > 0) {
+        cpus_sts[i++] = (cpus < 8) ? (1 << cpus) - 1 : 0xff;
+        cpus -= 8;
+    }
+
     register_ioport_write(GPE_BASE, 4, 1, gpe_writeb, &gpe);
     register_ioport_read(GPE_BASE, 4, 1,  gpe_readb, &gpe);
 
+    register_ioport_write(PROC_BASE, 32, 1, cpuhotplug_write, &cpus_sts);
+    register_ioport_read(PROC_BASE, 32, 1,  cpuhotplug_read, &cpus_sts);
+
     register_ioport_write(PCI_BASE, 8, 4, pcihotplug_write, &pci0_status);
     register_ioport_read(PCI_BASE, 8, 4,  pcihotplug_read, &pci0_status);
 
@@ -733,6 +768,18 @@ static void disable_device(struct pci_status *p, struct 
gpe_regs *g, int slot)
     p->down |= (1 << slot);
 }
 
+static void enable_processor(struct gpe_regs *g, int cpu)
+{
+    g->sts |= 4;
+    cpus_sts[cpu/8] |= (1 << (cpu%8));
+}
+
+static void disable_processor(struct gpe_regs *g, int cpu)
+{
+    g->sts |= 4;
+    cpus_sts[cpu/8] &= ~(1 << (cpu%8));
+}
+
 void qemu_system_device_hot_add(int bus, int slot, int state)
 {
     pci0_status.up = 0;
@@ -747,6 +794,26 @@ void qemu_system_device_hot_add(int bus, int slot, int 
state)
     }
 }
 
+void qemu_system_cpu_hot_add(int cpu, int state)
+{
+    CPUState *env;
+
+    if ((state) && !qemu_get_cpu(cpu)) {
+#ifdef DEBUG_CPU
+        printf("creatng new cpu %d\n", cpu);
+#endif
+        env = pc_new_cpu(cpu, first_cpu->cpu_model_str, 1);
+        enable_processor(&gpe, cpu);
+    } else {
+        disable_processor(&gpe, cpu);
+    }
+
+    if (gpe.en & 4) {
+        qemu_set_irq(pm_state->irq, 1);
+        qemu_set_irq(pm_state->irq, 0);
+    }
+}
+
 struct acpi_table_header
 {
     char signature [4];    /* ACPI signature (4 ASCII characters) */
diff --git a/monitor.c b/monitor.c
index e764b5d..eb55077 100644
--- a/monitor.c
+++ b/monitor.c
@@ -372,6 +372,26 @@ static void do_cpu_set(Monitor *mon, int index)
         monitor_printf(mon, "Invalid CPU index\n");
 }
 
+static void do_cpu_set_nr(Monitor *mon, int value, const char *status)
+{
+    int state;
+
+    if (kvm_enabled() || kqemu_allowed) {
+        monitor_printf(mon, "CPU hotplug not supported\n");
+        return;
+    }
+
+    if (!strcmp(status, "online")) {
+       state = 1;
+    } else if (!strcmp(status, "offline")) {
+       state = 0;
+    } else {
+        monitor_printf(mon, "invalid status: %s\n", status);
+        return;
+    }
+    qemu_system_cpu_hot_add(value, state);
+}
+
 static void do_info_jit(Monitor *mon)
 {
     dump_exec_info((FILE *)mon, monitor_fprintf);
@@ -1739,6 +1759,7 @@ static const mon_cmd_t mon_cmds[] = {
       "target", "request VM to change it's memory allocation (in MB)" },
     { "set_link", "ss", do_set_link,
       "name [up|down]", "change the link status of a network adapter" },
+    { "cpu_set", "is", do_cpu_set_nr, "cpu [online|offline]", "change cpu 
state" },
     { "acl", "sss?i?", do_acl, "<command> <aclname> [<match>] [<index>]\n",
                                "acl show vnc.username\n"
                                "acl policy vnc.username deny\n"
diff --git a/sysemu.h b/sysemu.h
index 3eab34b..b69c6f0 100644
--- a/sysemu.h
+++ b/sysemu.h
@@ -175,6 +175,7 @@ extern int drive_init(struct drive_opt *arg, int snapshot, 
void *machine);
 /* acpi */
 void qemu_system_hot_add_init(void);
 void qemu_system_device_hot_add(int pcibus, int slot, int state);
+void qemu_system_cpu_hot_add(int cpu, int state);
 
 /* device-hotplug */
 
-- 
1.5.6.6





reply via email to

[Prev in Thread] Current Thread [Next in Thread]