#define DEVFN_TO_PHP_SLOT_REG(devfn) (devfn >> 1)
#define PHP_SLOT_REG_TO_DEVFN(reg, hilo) ((reg << 1) | hilo)
+/* ioport to monitor cpu add/remove status */
+#define PROC_BASE 0xaf00
+
typedef struct PCIAcpiState {
PCIDevice dev;
uint16_t pm1_control; /* pm1a_ECNT_BLK */
uint8_t gpe0_sts[ACPI_GPE0_BLK_LEN / 2];
uint8_t gpe0_en[ACPI_GPE0_BLK_LEN / 2];
+ /* CPU bitmap */
+ uint8_t cpus_sts[32];
+
/* SCI IRQ level */
uint8_t sci_asserted;
return 0;
}
+static uint32_t gpe_cpus_readb(void *opaque, uint32_t addr)
+{
+ uint32_t val = 0;
+ GPEState *g = opaque;
+
+ switch (addr) {
+ case PROC_BASE ... PROC_BASE+31:
+ val = g->cpus_sts[addr - PROC_BASE];
+ default:
+ break;
+ }
+
+ return val;
+}
+
+static void gpe_cpus_writeb(void *opaque, uint32_t addr, uint32_t val)
+{
+ GPEState *g = opaque;
+ switch (addr) {
+ case PROC_BASE ... PROC_BASE + 31:
+ /* don't allow to change cpus_sts from inside a guest */
+ break;
+ default:
+ break;
+ }
+}
+
static void gpe_acpi_init(void)
{
GPEState *s = &gpe_state;
memset(s, 0, sizeof(GPEState));
+ int i = 0, cpus = vcpus;
+ char *vcpumap = (char *)&vcpu_avail;
+
+ while (cpus > 0) {
+ s->cpus_sts[i] = vcpumap[i];
+ i++;
+ cpus -= 8;
+ }
+
+ register_ioport_read(PROC_BASE, 32, 1, gpe_cpus_readb, s);
+ register_ioport_write(PROC_BASE, 32, 1, gpe_cpus_writeb, s);
register_ioport_read(ACPI_GPE0_BLK_ADDRESS,
ACPI_GPE0_BLK_LEN / 2,
void i440fx_init_memory_mappings(PCIDevice *d) {
/* our implementation doesn't need this */
}
+
+static void enable_processor(GPEState *g, int cpu)
+{
+ g->gpe0_sts[0] |= 4;
+ g->cpus_sts[cpu/8] |= (1 << (cpu%8));
+}
+
+static void disable_processor(GPEState *g, int cpu)
+{
+ g->gpe0_sts[0] |= 4;
+ g->cpus_sts[cpu/8] &= ~(1 << (cpu%8));
+}
+
+void qemu_cpu_add_remove(int cpu, int state)
+{
+ if ((cpu <=0) || (cpu >= vcpus)) {
+ fprintf(stderr, "vcpu out of range, should be [1~%d]\n", vcpus - 1);
+ return;
+ }
+
+ if (state)
+ enable_processor(&gpe_state, cpu);
+ else
+ disable_processor(&gpe_state, cpu);
+
+ if (gpe_state.gpe0_en[0] & 4) {
+ qemu_set_irq(sci_irq, 1);
+ qemu_set_irq(sci_irq, 0);
+ }
+}
int domid = -1;
int vcpus = 1;
+uint64_t vcpu_avail = 1;
int xc_handle = -1;
term_printf("balloon: actual=%d\n", (int)(actual >> 20));
}
+static void do_cpu_set_nr(int value, const char *status)
+{
+ int state;
+
+ if (!strcmp(status, "online"))
+ state = 1;
+ else if (!strcmp(status, "offline"))
+ state = 0;
+ else {
+ term_printf("invalid status: %s\n", status);
+ return;
+ }
+
+ qemu_cpu_add_remove(value, state);
+}
+
/* Please update qemu-doc.texi when adding or changing commands */
static const term_cmd_t term_cmds[] = {
{ "help|?", "s?", do_help,
"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" },
{ NULL, NULL, },
};
extern int drive_init(struct drive_opt *arg, int snapshot, void *machine);
/* acpi */
+void qemu_cpu_add_remove(int cpu, int state);
void qemu_system_hot_add_init(void);
void qemu_system_device_hot_add(int pcibus, int slot, int state);
QEMU_OPTION_domainname,
QEMU_OPTION_acpi,
QEMU_OPTION_vcpus,
+ QEMU_OPTION_vcpu_avail,
/* Debug/Expert options: */
QEMU_OPTION_serial,
{ "pciemulation", HAS_ARG, QEMU_OPTION_pci_emulation },
{ "vncunused", 0, QEMU_OPTION_vncunused },
{ "vcpus", HAS_ARG, QEMU_OPTION_vcpus },
+ { "vcpu_avail", HAS_ARG, QEMU_OPTION_vcpu_avail },
#if defined(CONFIG_XEN) && !defined(CONFIG_DM)
{ "xen-domid", HAS_ARG, QEMU_OPTION_xen_domid },
{ "xen-create", 0, QEMU_OPTION_xen_create },
vcpus = atoi(optarg);
fprintf(logfile, "qemu: the number of cpus is %d\n", vcpus);
break;
+ case QEMU_OPTION_vcpu_avail:
+ vcpu_avail = atol(optarg);
+ fprintf(logfile, "qemu: the avail cpu bitmap is %lx\n",
+ vcpu_avail);
+ break;
case QEMU_OPTION_acpi:
acpi_enabled = 1;
break;
extern int xc_handle;
extern int xen_pause_requested;
extern int vcpus;
+extern uint64_t vcpu_avail;
#ifdef CONFIG_STUBDOM
#define bdrv_host_device bdrv_raw