Merge remote-tracking branch 'afaerber/qom-cpu' into staging

# By Igor Mammedov (21) and others
# Via Andreas Färber
* afaerber/qom-cpu: (29 commits)
  Drop redundant resume_all_vcpus() from main()
  cpus: Fix pausing TCG CPUs while in vCPU thread
  target-i386: Replace cpuid_*features fields with a feature word array
  target-i386: Break CPUID feature definition lines
  target-i386/kvm.c: Code formatting changes
  target-i386: Group together level, xlevel, xlevel2 fields
  pc: Implement QEMUMachine::hot_add_cpu hook
  QMP: Add cpu-add command
  Add hot_add_cpu hook to QEMUMachine
  target-i386: Move APIC to ICC bus
  target-i386: Attach ICC bus to CPU on its creation
  target-i386: Introduce ICC bus/device/bridge
  cpu: Move cpu_write_elfXX_note() functions to CPUState
  kvmvapic: Make dependency on sysbus.h explicit
  target-i386: Replace MSI_SPACE_SIZE with APIC_SPACE_SIZE
  target-i386: Do not allow to set apic-id once CPU is realized
  target-i386: Introduce apic-id CPU property
  target-i386: Introduce feat2prop() for CPU properties
  acpi_piix4: Add infrastructure to send CPU hot-plug GPE to guest
  cpu: Add helper cpu_exists(), to check if CPU with specified id exists
  ...
This commit is contained in:
Anthony Liguori 2013-05-02 10:57:01 -05:00
commit 8ca27ce2e1
52 changed files with 1162 additions and 327 deletions

View File

@ -644,6 +644,12 @@ F: qom/cpu.c
F: include/qemu/cpu.h
F: target-i386/cpu.c
ICC Bus
M: Igor Mammedov <imammedo@redhat.com>
S: Supported
F: include/hw/cpu/icc_bus.h
F: hw/cpu/icc_bus.c
Device Tree
M: Peter Crosthwaite <peter.crosthwaite@petalogix.com>
M: Alexander Graf <agraf@suse.de>

View File

@ -60,6 +60,12 @@ all: $(PROGS) stap
# Dummy command so that make thinks it has done something
@true
CONFIG_NO_PCI = $(if $(subst n,,$(CONFIG_PCI)),n,y)
CONFIG_NO_KVM = $(if $(subst n,,$(CONFIG_KVM)),n,y)
CONFIG_NO_XEN = $(if $(subst n,,$(CONFIG_XEN)),n,y)
CONFIG_NO_GET_MEMORY_MAPPING = $(if $(subst n,,$(CONFIG_HAVE_GET_MEMORY_MAPPING)),n,y)
CONFIG_NO_CORE_DUMP = $(if $(subst n,,$(CONFIG_HAVE_CORE_DUMP)),n,y)
#########################################################
# cpu emulator library
obj-y = exec.o translate-all.o cpu-exec.o
@ -70,6 +76,7 @@ obj-y += fpu/softfloat.o
obj-y += target-$(TARGET_BASE_ARCH)/
obj-y += disas.o
obj-$(CONFIG_GDBSTUB_XML) += gdbstub-xml.o
obj-$(CONFIG_NO_KVM) += kvm-stub.o
#########################################################
# Linux user emulator target
@ -98,18 +105,11 @@ endif #CONFIG_BSD_USER
#########################################################
# System emulator target
ifdef CONFIG_SOFTMMU
CONFIG_NO_PCI = $(if $(subst n,,$(CONFIG_PCI)),n,y)
CONFIG_NO_KVM = $(if $(subst n,,$(CONFIG_KVM)),n,y)
CONFIG_NO_XEN = $(if $(subst n,,$(CONFIG_XEN)),n,y)
CONFIG_NO_GET_MEMORY_MAPPING = $(if $(subst n,,$(CONFIG_HAVE_GET_MEMORY_MAPPING)),n,y)
CONFIG_NO_CORE_DUMP = $(if $(subst n,,$(CONFIG_HAVE_CORE_DUMP)),n,y)
obj-y += arch_init.o cpus.o monitor.o gdbstub.o balloon.o ioport.o
obj-y += qtest.o
obj-y += hw/
obj-$(CONFIG_FDT) += device_tree.o
obj-$(CONFIG_KVM) += kvm-all.o
obj-$(CONFIG_NO_KVM) += kvm-stub.o
obj-y += memory.o savevm.o cputlb.o
obj-$(CONFIG_HAVE_GET_MEMORY_MAPPING) += memory_mapping.o
obj-$(CONFIG_HAVE_CORE_DUMP) += dump.o

View File

@ -110,7 +110,7 @@ static const char *get_elf_platform(void)
static uint32_t get_elf_hwcap(void)
{
return thread_env->cpuid_features;
return thread_env->features[FEAT_1_EDX];
}
#ifdef TARGET_X86_64

View File

@ -1004,13 +1004,13 @@ int main(int argc, char **argv)
env->cr[0] = CR0_PG_MASK | CR0_WP_MASK | CR0_PE_MASK;
env->hflags |= HF_PE_MASK;
if (env->cpuid_features & CPUID_SSE) {
if (env->features[FEAT_1_EDX] & CPUID_SSE) {
env->cr[4] |= CR4_OSFXSR_MASK;
env->hflags |= HF_OSFXSR_MASK;
}
#ifndef TARGET_ABI32
/* enable 64 bit mode if possible */
if (!(env->cpuid_ext2_features & CPUID_EXT2_LM)) {
if (!(env->features[FEAT_8000_0001_EDX] & CPUID_EXT2_LM)) {
fprintf(stderr, "The selected x86 CPU does not support 64 bit mode\n");
exit(1);
}

27
cpus.c
View File

@ -812,6 +812,12 @@ static void *qemu_dummy_cpu_thread_fn(void *arg)
static void tcg_exec_all(void);
static void tcg_signal_cpu_creation(CPUState *cpu, void *data)
{
cpu->thread_id = qemu_get_thread_id();
cpu->created = true;
}
static void *qemu_tcg_cpu_thread_fn(void *arg)
{
CPUState *cpu = arg;
@ -820,13 +826,8 @@ static void *qemu_tcg_cpu_thread_fn(void *arg)
qemu_tcg_init_cpu_signals();
qemu_thread_get_self(cpu->thread);
/* signal CPU creation */
qemu_mutex_lock(&qemu_global_mutex);
for (env = first_cpu; env != NULL; env = env->next_cpu) {
cpu = ENV_GET_CPU(env);
cpu->thread_id = qemu_get_thread_id();
cpu->created = true;
}
qemu_for_each_cpu(tcg_signal_cpu_creation, NULL);
qemu_cond_signal(&qemu_cpu_cond);
/* wait for initial kick-off after machine start */
@ -973,9 +974,10 @@ void pause_all_vcpus(void)
if (qemu_in_vcpu_thread()) {
cpu_stop_current();
if (!kvm_enabled()) {
penv = first_cpu;
while (penv) {
CPUState *pcpu = ENV_GET_CPU(penv);
pcpu->stop = 0;
pcpu->stop = false;
pcpu->stopped = true;
penv = penv->next_cpu;
}
@ -993,6 +995,13 @@ void pause_all_vcpus(void)
}
}
void cpu_resume(CPUState *cpu)
{
cpu->stop = false;
cpu->stopped = false;
qemu_cpu_kick(cpu);
}
void resume_all_vcpus(void)
{
CPUArchState *penv = first_cpu;
@ -1000,9 +1009,7 @@ void resume_all_vcpus(void)
qemu_clock_enable(vm_clock, true);
while (penv) {
CPUState *pcpu = ENV_GET_CPU(penv);
pcpu->stop = false;
pcpu->stopped = false;
qemu_cpu_kick(pcpu);
cpu_resume(pcpu);
penv = penv->next_cpu;
}
}

View File

@ -44,4 +44,5 @@ CONFIG_LPC_ICH9=y
CONFIG_PCI_Q35=y
CONFIG_APIC=y
CONFIG_IOAPIC=y
CONFIG_ICC_BUS=y
CONFIG_PVPANIC=y

View File

@ -44,4 +44,5 @@ CONFIG_LPC_ICH9=y
CONFIG_PCI_Q35=y
CONFIG_APIC=y
CONFIG_IOAPIC=y
CONFIG_ICC_BUS=y
CONFIG_PVPANIC=y

View File

@ -0,0 +1,22 @@
QEMU<->ACPI BIOS CPU hotplug interface
--------------------------------------
QEMU supports CPU hotplug via ACPI. This document
describes the interface between QEMU and the ACPI BIOS.
ACPI GPE block (IO ports 0xafe0-0xafe3, byte access):
-----------------------------------------
Generic ACPI GPE block. Bit 2 (GPE.2) used to notify CPU
hot-add/remove event to ACPI BIOS, via SCI interrupt.
CPU present bitmap (IO port 0xaf00-0xae1f, 1-byte access):
---------------------------------------------------------------
One bit per CPU. Bit position reflects corresponding CPU APIC ID.
Read-only.
CPU hot-add/remove notification:
-----------------------------------------------------
QEMU sets/clears corresponding CPU bit on hot-add/remove event.
CPU present map read by ACPI BIOS GPE.2 handler to notify OS of CPU
hot-(un)plug events.

View File

@ -24,34 +24,6 @@ void qmp_dump_guest_memory(bool paging, const char *file, bool has_begin,
error_set(errp, QERR_UNSUPPORTED);
}
int cpu_write_elf64_note(write_core_dump_function f,
CPUArchState *env, int cpuid,
void *opaque)
{
return -1;
}
int cpu_write_elf32_note(write_core_dump_function f,
CPUArchState *env, int cpuid,
void *opaque)
{
return -1;
}
int cpu_write_elf64_qemunote(write_core_dump_function f,
CPUArchState *env,
void *opaque)
{
return -1;
}
int cpu_write_elf32_qemunote(write_core_dump_function f,
CPUArchState *env,
void *opaque)
{
return -1;
}
int cpu_get_dump_info(ArchDumpInfo *info)
{
return -1;

8
dump.c
View File

@ -282,7 +282,7 @@ static int write_elf64_notes(DumpState *s)
for (env = first_cpu; env != NULL; env = env->next_cpu) {
cpu = ENV_GET_CPU(env);
id = cpu_index(cpu);
ret = cpu_write_elf64_note(fd_write_vmcore, env, id, s);
ret = cpu_write_elf64_note(fd_write_vmcore, cpu, id, s);
if (ret < 0) {
dump_error(s, "dump: failed to write elf notes.\n");
return -1;
@ -290,7 +290,7 @@ static int write_elf64_notes(DumpState *s)
}
for (env = first_cpu; env != NULL; env = env->next_cpu) {
ret = cpu_write_elf64_qemunote(fd_write_vmcore, env, s);
ret = cpu_write_elf64_qemunote(fd_write_vmcore, cpu, s);
if (ret < 0) {
dump_error(s, "dump: failed to write CPU status.\n");
return -1;
@ -334,7 +334,7 @@ static int write_elf32_notes(DumpState *s)
for (env = first_cpu; env != NULL; env = env->next_cpu) {
cpu = ENV_GET_CPU(env);
id = cpu_index(cpu);
ret = cpu_write_elf32_note(fd_write_vmcore, env, id, s);
ret = cpu_write_elf32_note(fd_write_vmcore, cpu, id, s);
if (ret < 0) {
dump_error(s, "dump: failed to write elf notes.\n");
return -1;
@ -342,7 +342,7 @@ static int write_elf32_notes(DumpState *s)
}
for (env = first_cpu; env != NULL; env = env->next_cpu) {
ret = cpu_write_elf32_qemunote(fd_write_vmcore, env, s);
ret = cpu_write_elf32_qemunote(fd_write_vmcore, cpu, s);
if (ret < 0) {
dump_error(s, "dump: failed to write CPU status.\n");
return -1;

10
exec.c
View File

@ -265,6 +265,16 @@ CPUState *qemu_get_cpu(int index)
return env ? cpu : NULL;
}
void qemu_for_each_cpu(void (*func)(CPUState *cpu, void *data), void *data)
{
CPUArchState *env = first_cpu;
while (env) {
func(ENV_GET_CPU(env), data);
env = env->next_cpu;
}
}
void cpu_exec_init(CPUArchState *env)
{
CPUState *cpu = ENV_GET_CPU(env);

View File

@ -48,19 +48,28 @@
#define PCI_EJ_BASE 0xae08
#define PCI_RMV_BASE 0xae0c
#define PIIX4_PROC_BASE 0xaf00
#define PIIX4_PROC_LEN 32
#define PIIX4_PCI_HOTPLUG_STATUS 2
#define PIIX4_CPU_HOTPLUG_STATUS 4
struct pci_status {
uint32_t up; /* deprecated, maintained for migration compatibility */
uint32_t down;
};
typedef struct CPUStatus {
uint8_t sts[PIIX4_PROC_LEN];
} CPUStatus;
typedef struct PIIX4PMState {
PCIDevice dev;
MemoryRegion io;
MemoryRegion io_gpe;
MemoryRegion io_pci;
MemoryRegion io_cpu;
ACPIREGS ar;
APMState apm;
@ -82,6 +91,9 @@ typedef struct PIIX4PMState {
uint8_t disable_s3;
uint8_t disable_s4;
uint8_t s4_val;
CPUStatus gpe_cpu;
Notifier cpu_added_notifier;
} PIIX4PMState;
static void piix4_acpi_system_hot_add_init(MemoryRegion *parent,
@ -100,8 +112,8 @@ static void pm_update_sci(PIIX4PMState *s)
ACPI_BITMASK_POWER_BUTTON_ENABLE |
ACPI_BITMASK_GLOBAL_LOCK_ENABLE |
ACPI_BITMASK_TIMER_ENABLE)) != 0) ||
(((s->ar.gpe.sts[0] & s->ar.gpe.en[0])
& PIIX4_PCI_HOTPLUG_STATUS) != 0);
(((s->ar.gpe.sts[0] & s->ar.gpe.en[0]) &
(PIIX4_PCI_HOTPLUG_STATUS | PIIX4_CPU_HOTPLUG_STATUS)) != 0);
qemu_set_irq(s->irq, sci_level);
/* schedule a timer interruption if needed */
@ -585,6 +597,73 @@ static const MemoryRegionOps piix4_pci_ops = {
},
};
static uint64_t cpu_status_read(void *opaque, hwaddr addr, unsigned int size)
{
PIIX4PMState *s = opaque;
CPUStatus *cpus = &s->gpe_cpu;
uint64_t val = cpus->sts[addr];
return val;
}
static void cpu_status_write(void *opaque, hwaddr addr, uint64_t data,
unsigned int size)
{
/* TODO: implement VCPU removal on guest signal that CPU can be removed */
}
static const MemoryRegionOps cpu_hotplug_ops = {
.read = cpu_status_read,
.write = cpu_status_write,
.endianness = DEVICE_LITTLE_ENDIAN,
.valid = {
.min_access_size = 1,
.max_access_size = 1,
},
};
typedef enum {
PLUG,
UNPLUG,
} HotplugEventType;
static void piix4_cpu_hotplug_req(PIIX4PMState *s, CPUState *cpu,
HotplugEventType action)
{
CPUStatus *g = &s->gpe_cpu;
ACPIGPE *gpe = &s->ar.gpe;
CPUClass *k = CPU_GET_CLASS(cpu);
int64_t cpu_id;
assert(s != NULL);
*gpe->sts = *gpe->sts | PIIX4_CPU_HOTPLUG_STATUS;
cpu_id = k->get_arch_id(CPU(cpu));
if (action == PLUG) {
g->sts[cpu_id / 8] |= (1 << (cpu_id % 8));
} else {
g->sts[cpu_id / 8] &= ~(1 << (cpu_id % 8));
}
pm_update_sci(s);
}
static void piix4_cpu_added_req(Notifier *n, void *opaque)
{
PIIX4PMState *s = container_of(n, PIIX4PMState, cpu_added_notifier);
piix4_cpu_hotplug_req(s, CPU(opaque), PLUG);
}
static void piix4_init_cpu_status(CPUState *cpu, void *data)
{
CPUStatus *g = (CPUStatus *)data;
CPUClass *k = CPU_GET_CLASS(cpu);
int64_t id = k->get_arch_id(cpu);
g_assert((id / 8) < PIIX4_PROC_LEN);
g->sts[id / 8] |= (1 << (id % 8));
}
static int piix4_device_hotplug(DeviceState *qdev, PCIDevice *dev,
PCIHotplugState state);
@ -600,6 +679,13 @@ static void piix4_acpi_system_hot_add_init(MemoryRegion *parent,
memory_region_add_subregion(parent, PCI_HOTPLUG_ADDR,
&s->io_pci);
pci_bus_hotplug(bus, piix4_device_hotplug, &s->dev.qdev);
qemu_for_each_cpu(piix4_init_cpu_status, &s->gpe_cpu);
memory_region_init_io(&s->io_cpu, &cpu_hotplug_ops, s, "apci-cpu-hotplug",
PIIX4_PROC_LEN);
memory_region_add_subregion(parent, PIIX4_PROC_BASE, &s->io_cpu);
s->cpu_added_notifier.notify = piix4_cpu_added_req;
qemu_register_cpu_added_notifier(&s->cpu_added_notifier);
}
static void enable_device(PIIX4PMState *s, int slot)

View File

@ -1,4 +1,5 @@
obj-$(CONFIG_ARM11MPCORE) += arm11mpcore.o
obj-$(CONFIG_ARM9MPCORE) += a9mpcore.o
obj-$(CONFIG_ARM15MPCORE) += a15mpcore.o
obj-$(CONFIG_ICC_BUS) += icc_bus.o

119
hw/cpu/icc_bus.c Normal file
View File

@ -0,0 +1,119 @@
/* icc_bus.c
* emulate x86 ICC (Interrupt Controller Communications) bus
*
* Copyright (c) 2013 Red Hat, Inc
*
* Authors:
* Igor Mammedov <imammedo@redhat.com>
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2 of the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, see <http://www.gnu.org/licenses/>
*/
#include "hw/cpu/icc_bus.h"
#include "hw/sysbus.h"
/* icc-bridge implementation */
static void icc_bus_init(Object *obj)
{
BusState *b = BUS(obj);
b->allow_hotplug = true;
}
static const TypeInfo icc_bus_info = {
.name = TYPE_ICC_BUS,
.parent = TYPE_BUS,
.instance_size = sizeof(ICCBus),
.instance_init = icc_bus_init,
};
/* icc-device implementation */
static void icc_device_realize(DeviceState *dev, Error **errp)
{
ICCDevice *id = ICC_DEVICE(dev);
ICCDeviceClass *idc = ICC_DEVICE_GET_CLASS(id);
if (idc->init) {
if (idc->init(id) < 0) {
error_setg(errp, "%s initialization failed.",
object_get_typename(OBJECT(dev)));
}
}
}
static void icc_device_class_init(ObjectClass *oc, void *data)
{
DeviceClass *dc = DEVICE_CLASS(oc);
dc->realize = icc_device_realize;
dc->bus_type = TYPE_ICC_BUS;
}
static const TypeInfo icc_device_info = {
.name = TYPE_ICC_DEVICE,
.parent = TYPE_DEVICE,
.abstract = true,
.instance_size = sizeof(ICCDevice),
.class_size = sizeof(ICCDeviceClass),
.class_init = icc_device_class_init,
};
/* icc-bridge implementation */
typedef struct ICCBridgeState {
/*< private >*/
SysBusDevice parent_obj;
/*< public >*/
ICCBus icc_bus;
MemoryRegion apic_container;
} ICCBridgeState;
#define ICC_BRIGDE(obj) OBJECT_CHECK(ICCBridgeState, (obj), TYPE_ICC_BRIDGE)
static void icc_bridge_init(Object *obj)
{
ICCBridgeState *s = ICC_BRIGDE(obj);
SysBusDevice *sb = SYS_BUS_DEVICE(obj);
qbus_create_inplace(&s->icc_bus, TYPE_ICC_BUS, DEVICE(s), "icc");
/* Do not change order of registering regions,
* APIC must be first registered region, board maps it by 0 index
*/
memory_region_init(&s->apic_container, "icc-apic-container",
APIC_SPACE_SIZE);
sysbus_init_mmio(sb, &s->apic_container);
s->icc_bus.apic_address_space = &s->apic_container;
}
static const TypeInfo icc_bridge_info = {
.name = TYPE_ICC_BRIDGE,
.parent = TYPE_SYS_BUS_DEVICE,
.instance_init = icc_bridge_init,
.instance_size = sizeof(ICCBridgeState),
};
static void icc_bus_register_types(void)
{
type_register_static(&icc_bus_info);
type_register_static(&icc_device_info);
type_register_static(&icc_bridge_info);
}
type_init(icc_bus_register_types)

View File

@ -174,7 +174,7 @@ static const MemoryRegionOps kvm_apic_io_ops = {
static void kvm_apic_init(APICCommonState *s)
{
memory_region_init_io(&s->io_memory, &kvm_apic_io_ops, s, "kvm-apic-msi",
MSI_SPACE_SIZE);
APIC_SPACE_SIZE);
if (kvm_has_gsi_routing()) {
msi_supported = true;

View File

@ -129,7 +129,7 @@ static const TypeInfo kvmclock_info = {
void kvmclock_create(void)
{
if (kvm_enabled() &&
first_cpu->cpuid_kvm_features & ((1ULL << KVM_FEATURE_CLOCKSOURCE) |
first_cpu->features[FEAT_KVM] & ((1ULL << KVM_FEATURE_CLOCKSOURCE) |
(1ULL << KVM_FEATURE_CLOCKSOURCE2))) {
sysbus_create_simple("kvmclock", -1, NULL);
}

View File

@ -12,6 +12,7 @@
#include "sysemu/cpus.h"
#include "sysemu/kvm.h"
#include "hw/i386/apic_internal.h"
#include "hw/sysbus.h"
#define VAPIC_IO_PORT 0x7e

View File

@ -53,6 +53,8 @@
#include "qemu/bitmap.h"
#include "qemu/config-file.h"
#include "hw/acpi/acpi.h"
#include "hw/cpu/icc_bus.h"
#include "hw/boards.h"
/* debug PC/ISA interrupts */
//#define DEBUG_IRQ
@ -338,6 +340,21 @@ static void pc_cmos_init_late(void *opaque)
qemu_unregister_reset(pc_cmos_init_late, opaque);
}
typedef struct RTCCPUHotplugArg {
Notifier cpu_added_notifier;
ISADevice *rtc_state;
} RTCCPUHotplugArg;
static void rtc_notify_cpu_added(Notifier *notifier, void *data)
{
RTCCPUHotplugArg *arg = container_of(notifier, RTCCPUHotplugArg,
cpu_added_notifier);
ISADevice *s = arg->rtc_state;
/* increment the number of CPUs */
rtc_set_memory(s, 0x5f, rtc_get_memory(s, 0x5f) + 1);
}
void pc_cmos_init(ram_addr_t ram_size, ram_addr_t above_4g_mem_size,
const char *boot_device,
ISADevice *floppy, BusState *idebus0, BusState *idebus1,
@ -346,6 +363,7 @@ void pc_cmos_init(ram_addr_t ram_size, ram_addr_t above_4g_mem_size,
int val, nb, i;
FDriveType fd_type[2] = { FDRIVE_DRV_NONE, FDRIVE_DRV_NONE };
static pc_cmos_init_late_arg arg;
static RTCCPUHotplugArg cpu_hotplug_cb;
/* various important CMOS locations needed by PC/Bochs bios */
@ -384,6 +402,10 @@ void pc_cmos_init(ram_addr_t ram_size, ram_addr_t above_4g_mem_size,
/* set the number of CPU */
rtc_set_memory(s, 0x5f, smp_cpus - 1);
/* init CPU hotplug notifier */
cpu_hotplug_cb.rtc_state = s;
cpu_hotplug_cb.cpu_added_notifier.notify = rtc_notify_cpu_added;
qemu_register_cpu_added_notifier(&cpu_hotplug_cb.cpu_added_notifier);
/* set boot devices, and disable floppy signature check if requested */
if (set_boot_dev(s, boot_device, fd_bootchk)) {
@ -874,9 +896,59 @@ void pc_acpi_smi_interrupt(void *opaque, int irq, int level)
}
}
void pc_cpus_init(const char *cpu_model)
static X86CPU *pc_new_cpu(const char *cpu_model, int64_t apic_id,
DeviceState *icc_bridge, Error **errp)
{
X86CPU *cpu;
Error *local_err = NULL;
cpu = cpu_x86_create(cpu_model, icc_bridge, errp);
if (!cpu) {
return cpu;
}
object_property_set_int(OBJECT(cpu), apic_id, "apic-id", &local_err);
object_property_set_bool(OBJECT(cpu), true, "realized", &local_err);
if (local_err) {
if (cpu != NULL) {
object_unref(OBJECT(cpu));
cpu = NULL;
}
error_propagate(errp, local_err);
}
return cpu;
}
static const char *current_cpu_model;
void pc_hot_add_cpu(const int64_t id, Error **errp)
{
DeviceState *icc_bridge;
int64_t apic_id = x86_cpu_apic_id_from_index(id);
if (cpu_exists(apic_id)) {
error_setg(errp, "Unable to add CPU: %" PRIi64
", it already exists", id);
return;
}
if (id >= max_cpus) {
error_setg(errp, "Unable to add CPU: %" PRIi64
", max allowed: %d", id, max_cpus - 1);
return;
}
icc_bridge = DEVICE(object_resolve_path_type("icc-bridge",
TYPE_ICC_BRIDGE, NULL));
pc_new_cpu(current_cpu_model, apic_id, icc_bridge, errp);
}
void pc_cpus_init(const char *cpu_model, DeviceState *icc_bridge)
{
int i;
X86CPU *cpu = NULL;
Error *error = NULL;
/* init CPUs */
if (cpu_model == NULL) {
@ -886,12 +958,24 @@ void pc_cpus_init(const char *cpu_model)
cpu_model = "qemu32";
#endif
}
current_cpu_model = cpu_model;
for (i = 0; i < smp_cpus; i++) {
if (!cpu_x86_init(cpu_model)) {
cpu = pc_new_cpu(cpu_model, x86_cpu_apic_id_from_index(i),
icc_bridge, &error);
if (error) {
fprintf(stderr, "%s\n", error_get_pretty(error));
error_free(error);
exit(1);
}
}
/* map APIC MMIO area if CPU has APIC */
if (cpu && cpu->env.apic_state) {
/* XXX: what if the base changes? */
sysbus_mmio_map_overlap(SYS_BUS_DEVICE(icc_bridge), 0,
APIC_DEFAULT_ADDRESS, 0x1000);
}
}
void pc_acpi_init(const char *default_dsdt)

View File

@ -37,6 +37,7 @@
#include "hw/kvm/clock.h"
#include "sysemu/sysemu.h"
#include "hw/sysbus.h"
#include "hw/cpu/icc_bus.h"
#include "sysemu/arch_init.h"
#include "sysemu/blockdev.h"
#include "hw/i2c/smbus.h"
@ -87,9 +88,14 @@ static void pc_init1(MemoryRegion *system_memory,
MemoryRegion *ram_memory;
MemoryRegion *pci_memory;
MemoryRegion *rom_memory;
DeviceState *icc_bridge;
void *fw_cfg = NULL;
pc_cpus_init(cpu_model);
icc_bridge = qdev_create(NULL, TYPE_ICC_BRIDGE);
object_property_add_child(qdev_get_machine(), "icc-bridge",
OBJECT(icc_bridge), NULL);
pc_cpus_init(cpu_model, icc_bridge);
pc_acpi_init("acpi-dsdt.aml");
if (kvmclock_enabled) {
@ -163,6 +169,7 @@ static void pc_init1(MemoryRegion *system_memory,
if (pci_enabled) {
ioapic_init_gsi(gsi_state, "i440fx");
}
qdev_init_nofail(icc_bridge);
pc_register_ferr_irq(gsi[13]);
@ -328,6 +335,7 @@ static QEMUMachine pc_i440fx_machine_v1_5 = {
.alias = "pc",
.desc = "Standard PC (i440FX + PIIX, 1996)",
.init = pc_init_pci,
.hot_add_cpu = pc_hot_add_cpu,
.max_cpus = 255,
.is_default = 1,
DEFAULT_MACHINE_OPTIONS,

View File

@ -41,6 +41,7 @@
#include "hw/ide/pci.h"
#include "hw/ide/ahci.h"
#include "hw/usb.h"
#include "hw/cpu/icc_bus.h"
/* ICH9 AHCI has 6 ports */
#define MAX_SATA_PORTS 6
@ -75,8 +76,13 @@ static void pc_q35_init(QEMUMachineInitArgs *args)
int i;
ICH9LPCState *ich9_lpc;
PCIDevice *ahci;
DeviceState *icc_bridge;
pc_cpus_init(cpu_model);
icc_bridge = qdev_create(NULL, TYPE_ICC_BRIDGE);
object_property_add_child(qdev_get_machine(), "icc-bridge",
OBJECT(icc_bridge), NULL);
pc_cpus_init(cpu_model, icc_bridge);
pc_acpi_init("q35-acpi-dsdt.aml");
kvmclock_create();
@ -158,6 +164,7 @@ static void pc_q35_init(QEMUMachineInitArgs *args)
if (pci_enabled) {
ioapic_init_gsi(gsi_state, NULL);
}
qdev_init_nofail(icc_bridge);
pc_register_ferr_irq(gsi[13]);
@ -213,6 +220,7 @@ static QEMUMachine pc_q35_machine_v1_5 = {
.alias = "q35",
.desc = "Standard PC (Q35 + ICH9, 2009)",
.init = pc_q35_init,
.hot_add_cpu = pc_hot_add_cpu,
.max_cpus = 255,
DEFAULT_MACHINE_OPTIONS,
};

View File

@ -874,7 +874,7 @@ static const MemoryRegionOps apic_io_ops = {
static void apic_init(APICCommonState *s)
{
memory_region_init_io(&s->io_memory, &apic_io_ops, s, "apic-msi",
MSI_SPACE_SIZE);
APIC_SPACE_SIZE);
s->timer = qemu_new_timer_ns(vm_clock, apic_timer, s);
local_apics[s->idx] = s;

View File

@ -21,6 +21,8 @@
#include "hw/i386/apic_internal.h"
#include "trace.h"
#include "sysemu/kvm.h"
#include "hw/qdev.h"
#include "hw/sysbus.h"
static int apic_irq_delivered;
bool apic_report_tpr_access;
@ -282,12 +284,13 @@ static int apic_load_old(QEMUFile *f, void *opaque, int version_id)
return 0;
}
static int apic_init_common(SysBusDevice *dev)
static int apic_init_common(ICCDevice *dev)
{
APICCommonState *s = APIC_COMMON(dev);
APICCommonClass *info;
static DeviceState *vapic;
static int apic_no;
static bool mmio_registered;
if (apic_no >= MAX_APICS) {
return -1;
@ -296,8 +299,11 @@ static int apic_init_common(SysBusDevice *dev)
info = APIC_COMMON_GET_CLASS(s);
info->init(s);
sysbus_init_mmio(dev, &s->io_memory);
if (!mmio_registered) {
ICCBus *b = ICC_BUS(qdev_get_parent_bus(DEVICE(dev)));
memory_region_add_subregion(b->apic_address_space, 0, &s->io_memory);
mmio_registered = true;
}
/* Note: We need at least 1M to map the VAPIC option ROM */
if (!vapic && s->vapic_control & VAPIC_ENABLE_MASK &&
@ -375,19 +381,19 @@ static Property apic_properties_common[] = {
static void apic_common_class_init(ObjectClass *klass, void *data)
{
SysBusDeviceClass *sc = SYS_BUS_DEVICE_CLASS(klass);
ICCDeviceClass *idc = ICC_DEVICE_CLASS(klass);
DeviceClass *dc = DEVICE_CLASS(klass);
dc->vmsd = &vmstate_apic_common;
dc->reset = apic_reset_common;
dc->no_user = 1;
dc->props = apic_properties_common;
sc->init = apic_init_common;
idc->init = apic_init_common;
}
static const TypeInfo apic_common_type = {
.name = TYPE_APIC_COMMON,
.parent = TYPE_SYS_BUS_DEVICE,
.parent = TYPE_ICC_DEVICE,
.instance_size = sizeof(APICCommonState),
.class_size = sizeof(APICCommonClass),
.class_init = apic_common_class_init,

View File

@ -680,6 +680,13 @@ void rtc_set_memory(ISADevice *dev, int addr, int val)
s->cmos_data[addr] = val;
}
int rtc_get_memory(ISADevice *dev, int addr)
{
RTCState *s = MC146818_RTC(dev);
assert(addr >= 0 && addr <= 127);
return s->cmos_data[addr];
}
static void rtc_set_date_from_host(ISADevice *dev)
{
RTCState *s = MC146818_RTC(dev);

View File

@ -39,7 +39,7 @@ static const MemoryRegionOps xen_apic_io_ops = {
static void xen_apic_init(APICCommonState *s)
{
memory_region_init_io(&s->io_memory, &xen_apic_io_ops, s, "xen-apic-msi",
MSI_SPACE_SIZE);
APIC_SPACE_SIZE);
#if defined(CONFIG_XEN_CTRL_INTERFACE_VERSION) \
&& CONFIG_XEN_CTRL_INTERFACE_VERSION >= 420

View File

@ -22,12 +22,15 @@ typedef void QEMUMachineInitFunc(QEMUMachineInitArgs *args);
typedef void QEMUMachineResetFunc(void);
typedef void QEMUMachineHotAddCPUFunc(const int64_t id, Error **errp);
typedef struct QEMUMachine {
const char *name;
const char *alias;
const char *desc;
QEMUMachineInitFunc *init;
QEMUMachineResetFunc *reset;
QEMUMachineHotAddCPUFunc *hot_add_cpu;
BlockInterfaceType block_default_type;
int max_cpus;
unsigned int no_serial:1,

82
include/hw/cpu/icc_bus.h Normal file
View File

@ -0,0 +1,82 @@
/* icc_bus.h
* emulate x86 ICC (Interrupt Controller Communications) bus
*
* Copyright (c) 2013 Red Hat, Inc
*
* Authors:
* Igor Mammedov <imammedo@redhat.com>
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2 of the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, see <http://www.gnu.org/licenses/>
*/
#ifndef ICC_BUS_H
#define ICC_BUS_H
#include "exec/memory.h"
#include "hw/qdev-core.h"
#define TYPE_ICC_BUS "icc-bus"
#ifndef CONFIG_USER_ONLY
/**
* ICCBus:
*
* ICC bus
*/
typedef struct ICCBus {
/*< private >*/
BusState parent_obj;
/*< public >*/
MemoryRegion *apic_address_space;
} ICCBus;
#define ICC_BUS(obj) OBJECT_CHECK(ICCBus, (obj), TYPE_ICC_BUS)
/**
* ICCDevice:
*
* ICC device
*/
typedef struct ICCDevice {
/*< private >*/
DeviceState qdev;
/*< public >*/
} ICCDevice;
/**
* ICCDeviceClass:
* @init: Initialization callback for derived classes.
*
* ICC device class
*/
typedef struct ICCDeviceClass {
/*< private >*/
DeviceClass parent_class;
/*< public >*/
int (*init)(ICCDevice *dev); /* TODO replace with QOM realize */
} ICCDeviceClass;
#define TYPE_ICC_DEVICE "icc-device"
#define ICC_DEVICE(obj) OBJECT_CHECK(ICCDevice, (obj), TYPE_ICC_DEVICE)
#define ICC_DEVICE_CLASS(klass) \
OBJECT_CLASS_CHECK(ICCDeviceClass, (klass), TYPE_ICC_DEVICE)
#define ICC_DEVICE_GET_CLASS(obj) \
OBJECT_GET_CLASS(ICCDeviceClass, (obj), TYPE_ICC_DEVICE)
#define TYPE_ICC_BRIDGE "icc-bridge"
#endif /* CONFIG_USER_ONLY */
#endif

View File

@ -21,7 +21,7 @@
#define QEMU_APIC_INTERNAL_H
#include "exec/memory.h"
#include "hw/sysbus.h"
#include "hw/cpu/icc_bus.h"
#include "qemu/timer.h"
/* APIC Local Vector Table */
@ -66,8 +66,6 @@
#define MAX_APICS 255
#define MSI_SPACE_SIZE 0x100000
typedef struct APICCommonState APICCommonState;
#define TYPE_APIC_COMMON "apic-common"
@ -80,7 +78,7 @@ typedef struct APICCommonState APICCommonState;
typedef struct APICCommonClass
{
SysBusDeviceClass parent_class;
ICCDeviceClass parent_class;
void (*init)(APICCommonState *s);
void (*set_base)(APICCommonState *s, uint64_t val);
@ -94,7 +92,7 @@ typedef struct APICCommonClass
} APICCommonClass;
struct APICCommonState {
SysBusDevice busdev;
ICCDevice busdev;
MemoryRegion io_memory;
X86CPU *cpu;

View File

@ -78,7 +78,8 @@ extern int fd_bootchk;
void pc_register_ferr_irq(qemu_irq irq);
void pc_acpi_smi_interrupt(void *opaque, int irq, int level);
void pc_cpus_init(const char *cpu_model);
void pc_cpus_init(const char *cpu_model, DeviceState *icc_bridge);
void pc_hot_add_cpu(const int64_t id, Error **errp);
void pc_acpi_init(const char *default_dsdt);
void *pc_memory_init(MemoryRegion *system_memory,
const char *kernel_filename,

View File

@ -8,6 +8,7 @@
ISADevice *rtc_init(ISABus *bus, int base_year, qemu_irq intercept_irq);
void rtc_set_memory(ISADevice *dev, int addr, int val);
int rtc_get_memory(ISADevice *dev, int addr);
void rtc_set_date(ISADevice *dev, const struct tm *tm);
#endif /* !MC146818RTC_H */

View File

@ -24,6 +24,8 @@
#include "hw/qdev-core.h"
#include "qemu/thread.h"
typedef int (*WriteCoreDumpFunction)(void *buf, size_t size, void *opaque);
/**
* SECTION:cpu
* @section_id: QEMU-cpu
@ -45,6 +47,7 @@ typedef struct CPUState CPUState;
* instantiatable CPU type.
* @reset: Callback to reset the #CPUState to its initial state.
* @do_interrupt: Callback for interrupt handling.
* @get_arch_id: Callback for getting architecture-dependent CPU ID.
* @vmsd: State description for migration.
*
* Represents a CPU family or model.
@ -58,8 +61,17 @@ typedef struct CPUClass {
void (*reset)(CPUState *cpu);
void (*do_interrupt)(CPUState *cpu);
int64_t (*get_arch_id)(CPUState *cpu);
const struct VMStateDescription *vmsd;
int (*write_elf64_note)(WriteCoreDumpFunction f, CPUState *cpu,
int cpuid, void *opaque);
int (*write_elf64_qemunote)(WriteCoreDumpFunction f, CPUState *cpu,
void *opaque);
int (*write_elf32_note)(WriteCoreDumpFunction f, CPUState *cpu,
int cpuid, void *opaque);
int (*write_elf32_qemunote)(WriteCoreDumpFunction f, CPUState *cpu,
void *opaque);
} CPUClass;
struct KVMState;
@ -125,6 +137,45 @@ struct CPUState {
uint32_t halted; /* used by alpha, cris, ppc TCG */
};
/**
* cpu_write_elf64_note:
* @f: pointer to a function that writes memory to a file
* @cpu: The CPU whose memory is to be dumped
* @cpuid: ID number of the CPU
* @opaque: pointer to the CPUState struct
*/
int cpu_write_elf64_note(WriteCoreDumpFunction f, CPUState *cpu,
int cpuid, void *opaque);
/**
* cpu_write_elf64_qemunote:
* @f: pointer to a function that writes memory to a file
* @cpu: The CPU whose memory is to be dumped
* @cpuid: ID number of the CPU
* @opaque: pointer to the CPUState struct
*/
int cpu_write_elf64_qemunote(WriteCoreDumpFunction f, CPUState *cpu,
void *opaque);
/**
* cpu_write_elf32_note:
* @f: pointer to a function that writes memory to a file
* @cpu: The CPU whose memory is to be dumped
* @cpuid: ID number of the CPU
* @opaque: pointer to the CPUState struct
*/
int cpu_write_elf32_note(WriteCoreDumpFunction f, CPUState *cpu,
int cpuid, void *opaque);
/**
* cpu_write_elf32_qemunote:
* @f: pointer to a function that writes memory to a file
* @cpu: The CPU whose memory is to be dumped
* @cpuid: ID number of the CPU
* @opaque: pointer to the CPUState struct
*/
int cpu_write_elf32_qemunote(WriteCoreDumpFunction f, CPUState *cpu,
void *opaque);
/**
* cpu_reset:
@ -213,6 +264,15 @@ bool cpu_is_stopped(CPUState *cpu);
*/
void run_on_cpu(CPUState *cpu, void (*func)(void *data), void *data);
/**
* qemu_for_each_cpu:
* @func: The function to be executed.
* @data: Data to pass to the function.
*
* Executes @func for each CPU.
*/
void qemu_for_each_cpu(void (*func)(CPUState *cpu, void *data), void *data);
/**
* qemu_get_cpu:
* @index: The CPUState@cpu_index value of the CPU to obtain.
@ -223,6 +283,16 @@ void run_on_cpu(CPUState *cpu, void (*func)(void *data), void *data);
*/
CPUState *qemu_get_cpu(int index);
/**
* cpu_exists:
* @id: Guest-exposed CPU ID to lookup.
*
* Search for CPU with specified ID.
*
* Returns: %true - CPU is found, %false - CPU isn't found.
*/
bool cpu_exists(int64_t id);
#ifndef CONFIG_USER_ONLY
typedef void (*CPUInterruptHandler)(CPUState *, int);
@ -256,5 +326,12 @@ void cpu_interrupt(CPUState *cpu, int mask);
*/
void cpu_reset_interrupt(CPUState *cpu, int mask);
/**
* cpu_resume:
* @cpu: The CPU to resume.
*
* Resumes CPU, i.e. puts CPU into runnable state.
*/
void cpu_resume(CPUState *cpu);
#endif

View File

@ -20,15 +20,6 @@ typedef struct ArchDumpInfo {
int d_class; /* ELFCLASS32 or ELFCLASS64 */
} ArchDumpInfo;
typedef int (*write_core_dump_function)(void *buf, size_t size, void *opaque);
int cpu_write_elf64_note(write_core_dump_function f, CPUArchState *env,
int cpuid, void *opaque);
int cpu_write_elf32_note(write_core_dump_function f, CPUArchState *env,
int cpuid, void *opaque);
int cpu_write_elf64_qemunote(write_core_dump_function f, CPUArchState *env,
void *opaque);
int cpu_write_elf32_qemunote(write_core_dump_function f, CPUArchState *env,
void *opaque);
int cpu_get_dump_info(ArchDumpInfo *info);
ssize_t cpu_get_note_size(int class, int machine, int nr_cpus);

View File

@ -144,11 +144,11 @@ int kvm_cpu_exec(CPUArchState *env);
#if !defined(CONFIG_USER_ONLY)
void *kvm_vmalloc(ram_addr_t size);
void *kvm_arch_vmalloc(ram_addr_t size);
void kvm_setup_guest_memory(void *start, size_t size);
void kvm_flush_coalesced_mmio_buffer(void);
#endif
void kvm_setup_guest_memory(void *start, size_t size);
void kvm_flush_coalesced_mmio_buffer(void);
int kvm_insert_breakpoint(CPUArchState *current_env, target_ulong addr,
target_ulong len, int type);
int kvm_remove_breakpoint(CPUArchState *current_env, target_ulong addr,
@ -250,8 +250,6 @@ int kvm_check_extension(KVMState *s, unsigned int extension);
uint32_t kvm_arch_get_supported_cpuid(KVMState *env, uint32_t function,
uint32_t index, int reg);
void kvm_cpu_synchronize_state(CPUArchState *env);
void kvm_cpu_synchronize_post_reset(CPUState *cpu);
void kvm_cpu_synchronize_post_init(CPUState *cpu);
/* generic hooks - to be moved/refactored once there are more users */
@ -262,6 +260,16 @@ static inline void cpu_synchronize_state(CPUArchState *env)
}
}
#if !defined(CONFIG_USER_ONLY)
int kvm_physical_memory_addr_from_host(KVMState *s, void *ram_addr,
hwaddr *phys_addr);
#endif
#endif /* NEED_CPU_H */
void kvm_cpu_synchronize_post_reset(CPUState *cpu);
void kvm_cpu_synchronize_post_init(CPUState *cpu);
static inline void cpu_synchronize_post_reset(CPUState *cpu)
{
if (kvm_enabled()) {
@ -276,14 +284,6 @@ static inline void cpu_synchronize_post_init(CPUState *cpu)
}
}
#if !defined(CONFIG_USER_ONLY)
int kvm_physical_memory_addr_from_host(KVMState *s, void *ram_addr,
hwaddr *phys_addr);
#endif
#endif
int kvm_irqchip_add_msi_route(KVMState *s, MSIMessage msg);
int kvm_irqchip_update_msi_route(KVMState *s, int virq, MSIMessage msg);
void kvm_irqchip_release_virq(KVMState *s, int virq);

View File

@ -153,6 +153,9 @@ void do_pci_device_hot_remove(Monitor *mon, const QDict *qdict);
/* generic hotplug */
void drive_hot_add(Monitor *mon, const QDict *qdict);
/* CPU hotplug */
void qemu_register_cpu_added_notifier(Notifier *notifier);
/* pcie aer error injection */
void pcie_aer_inject_error_print(Monitor *mon, const QObject *data);
int do_pcie_aer_inject_error(Monitor *mon,

View File

@ -109,6 +109,7 @@ bool kvm_async_interrupts_allowed;
bool kvm_irqfds_allowed;
bool kvm_msi_via_irqfd_allowed;
bool kvm_gsi_routing_allowed;
bool kvm_allowed;
static const KVMCapabilityInfo kvm_required_capabilites[] = {
KVM_CAP_INFO(USER_MEMORY),

View File

@ -12,16 +12,20 @@
#include "qemu-common.h"
#include "hw/hw.h"
#include "hw/pci/msi.h"
#include "cpu.h"
#include "sysemu/kvm.h"
#ifndef CONFIG_USER_ONLY
#include "hw/pci/msi.h"
#endif
KVMState *kvm_state;
bool kvm_kernel_irqchip;
bool kvm_async_interrupts_allowed;
bool kvm_irqfds_allowed;
bool kvm_msi_via_irqfd_allowed;
bool kvm_gsi_routing_allowed;
bool kvm_allowed;
int kvm_init_vcpu(CPUState *cpu)
{
@ -111,6 +115,7 @@ int kvm_on_sigbus(int code, void *addr)
return 1;
}
#ifndef CONFIG_USER_ONLY
int kvm_irqchip_add_msi_route(KVMState *s, MSIMessage msg)
{
return -ENOSYS;
@ -134,3 +139,4 @@ int kvm_irqchip_remove_irqfd_notifier(KVMState *s, EventNotifier *n, int virq)
{
return -ENOSYS;
}
#endif

View File

@ -137,7 +137,7 @@ static const char *get_elf_platform(void)
static uint32_t get_elf_hwcap(void)
{
return thread_env->cpuid_features;
return thread_env->features[FEAT_1_EDX];
}
#ifdef TARGET_X86_64

View File

@ -3764,13 +3764,13 @@ int main(int argc, char **argv, char **envp)
env->cr[0] = CR0_PG_MASK | CR0_WP_MASK | CR0_PE_MASK;
env->hflags |= HF_PE_MASK;
if (env->cpuid_features & CPUID_SSE) {
if (env->features[FEAT_1_EDX] & CPUID_SSE) {
env->cr[4] |= CR4_OSFXSR_MASK;
env->hflags |= HF_OSFXSR_MASK;
}
#ifndef TARGET_ABI32
/* enable 64 bit mode if possible */
if (!(env->cpuid_ext2_features & CPUID_EXT2_LM)) {
if (!(env->features[FEAT_8000_0001_EDX] & CPUID_EXT2_LM)) {
fprintf(stderr, "The selected x86 CPU does not support 64 bit mode\n");
exit(1);
}

View File

@ -1389,6 +1389,19 @@
##
{ 'command': 'cpu', 'data': {'index': 'int'} }
##
# @cpu-add
#
# Adds CPU with specified ID
#
# @id: ID of CPU to be created, valid values [0..max_cpus)
#
# Returns: Nothing on success
#
# Since 1.5
##
{ 'command': 'cpu-add', 'data': {'id': 'int'} }
##
# @memsave:
#

View File

@ -382,6 +382,29 @@ Example:
Note: CPUs' indexes are obtained with the 'query-cpus' command.
EQMP
{
.name = "cpu-add",
.args_type = "id:i",
.mhandler.cmd_new = qmp_marshal_input_cpu_add,
},
SQMP
cpu-add
-------
Adds virtual cpu
Arguments:
- "id": cpu id (json-int)
Example:
-> { "execute": "cpu-add", "arguments": { "id": 2 } }
<- { "return": {} }
EQMP
{

10
qmp.c
View File

@ -24,6 +24,7 @@
#include "hw/qdev.h"
#include "sysemu/blockdev.h"
#include "qom/qom-qobject.h"
#include "hw/boards.h"
NameInfo *qmp_query_name(Error **errp)
{
@ -108,6 +109,15 @@ void qmp_cpu(int64_t index, Error **errp)
/* Just do nothing */
}
void qmp_cpu_add(int64_t id, Error **errp)
{
if (current_machine->hot_add_cpu) {
current_machine->hot_add_cpu(id, errp);
} else {
error_setg(errp, "Not supported");
}
}
#ifndef CONFIG_VNC
/* If VNC support is enabled, the "true" query-vnc command is
defined in the VNC subsystem */

114
qom/cpu.c
View File

@ -20,12 +20,109 @@
#include "qom/cpu.h"
#include "qemu-common.h"
#include "sysemu/kvm.h"
#include "qemu/notify.h"
#include "sysemu/sysemu.h"
typedef struct CPUExistsArgs {
int64_t id;
bool found;
} CPUExistsArgs;
static void cpu_exist_cb(CPUState *cpu, void *data)
{
CPUClass *klass = CPU_GET_CLASS(cpu);
CPUExistsArgs *arg = data;
if (klass->get_arch_id(cpu) == arg->id) {
arg->found = true;
}
}
bool cpu_exists(int64_t id)
{
CPUExistsArgs data = {
.id = id,
.found = false,
};
qemu_for_each_cpu(cpu_exist_cb, &data);
return data.found;
}
/* CPU hot-plug notifiers */
static NotifierList cpu_added_notifiers =
NOTIFIER_LIST_INITIALIZER(cpu_add_notifiers);
void qemu_register_cpu_added_notifier(Notifier *notifier)
{
notifier_list_add(&cpu_added_notifiers, notifier);
}
void cpu_reset_interrupt(CPUState *cpu, int mask)
{
cpu->interrupt_request &= ~mask;
}
int cpu_write_elf32_qemunote(WriteCoreDumpFunction f, CPUState *cpu,
void *opaque)
{
CPUClass *cc = CPU_GET_CLASS(cpu);
return (*cc->write_elf32_qemunote)(f, cpu, opaque);
}
static int cpu_common_write_elf32_qemunote(WriteCoreDumpFunction f,
CPUState *cpu, void *opaque)
{
return -1;
}
int cpu_write_elf32_note(WriteCoreDumpFunction f, CPUState *cpu,
int cpuid, void *opaque)
{
CPUClass *cc = CPU_GET_CLASS(cpu);
return (*cc->write_elf32_note)(f, cpu, cpuid, opaque);
}
static int cpu_common_write_elf32_note(WriteCoreDumpFunction f,
CPUState *cpu, int cpuid,
void *opaque)
{
return -1;
}
int cpu_write_elf64_qemunote(WriteCoreDumpFunction f, CPUState *cpu,
void *opaque)
{
CPUClass *cc = CPU_GET_CLASS(cpu);
return (*cc->write_elf64_qemunote)(f, cpu, opaque);
}
static int cpu_common_write_elf64_qemunote(WriteCoreDumpFunction f,
CPUState *cpu, void *opaque)
{
return -1;
}
int cpu_write_elf64_note(WriteCoreDumpFunction f, CPUState *cpu,
int cpuid, void *opaque)
{
CPUClass *cc = CPU_GET_CLASS(cpu);
return (*cc->write_elf64_note)(f, cpu, cpuid, opaque);
}
static int cpu_common_write_elf64_note(WriteCoreDumpFunction f,
CPUState *cpu, int cpuid,
void *opaque)
{
return -1;
}
void cpu_reset(CPUState *cpu)
{
CPUClass *klass = CPU_GET_CLASS(cpu);
@ -57,6 +154,18 @@ static ObjectClass *cpu_common_class_by_name(const char *cpu_model)
static void cpu_common_realizefn(DeviceState *dev, Error **errp)
{
CPUState *cpu = CPU(dev);
if (dev->hotplugged) {
cpu_synchronize_post_init(cpu);
notifier_list_notify(&cpu_added_notifiers, dev);
cpu_resume(cpu);
}
}
static int64_t cpu_common_get_arch_id(CPUState *cpu)
{
return cpu->cpu_index;
}
static void cpu_class_init(ObjectClass *klass, void *data)
@ -66,6 +175,11 @@ static void cpu_class_init(ObjectClass *klass, void *data)
k->class_by_name = cpu_common_class_by_name;
k->reset = cpu_common_reset;
k->get_arch_id = cpu_common_get_arch_id;
k->write_elf32_qemunote = cpu_common_write_elf32_qemunote;
k->write_elf32_note = cpu_common_write_elf32_note;
k->write_elf64_qemunote = cpu_common_write_elf64_qemunote;
k->write_elf64_note = cpu_common_write_elf64_note;
dc->realize = cpu_common_realizefn;
dc->no_user = 1;
}

View File

@ -23,3 +23,4 @@ stub-obj-y += sysbus.o
stub-obj-y += vm-stop.o
stub-obj-y += vmstate.o
stub-obj-$(CONFIG_WIN32) += fd-register.o
stub-obj-y += cpus.o

5
stubs/cpus.c Normal file
View File

@ -0,0 +1,5 @@
#include "qom/cpu.h"
void cpu_resume(CPUState *cpu)
{
}

View File

@ -34,7 +34,7 @@ typedef struct {
char pad3[8];
} x86_64_elf_prstatus;
static int x86_64_write_elf64_note(write_core_dump_function f,
static int x86_64_write_elf64_note(WriteCoreDumpFunction f,
CPUArchState *env, int id,
void *opaque)
{
@ -144,7 +144,7 @@ static void x86_fill_elf_prstatus(x86_elf_prstatus *prstatus, CPUArchState *env,
prstatus->pid = id;
}
static int x86_write_elf64_note(write_core_dump_function f, CPUArchState *env,
static int x86_write_elf64_note(WriteCoreDumpFunction f, CPUArchState *env,
int id, void *opaque)
{
x86_elf_prstatus prstatus;
@ -179,18 +179,19 @@ static int x86_write_elf64_note(write_core_dump_function f, CPUArchState *env,
return 0;
}
int cpu_write_elf64_note(write_core_dump_function f, CPUArchState *env,
int cpuid, void *opaque)
int x86_cpu_write_elf64_note(WriteCoreDumpFunction f, CPUState *cs,
int cpuid, void *opaque)
{
X86CPU *cpu = X86_CPU(cs);
int ret;
#ifdef TARGET_X86_64
bool lma = !!(first_cpu->hflags & HF_LMA_MASK);
if (lma) {
ret = x86_64_write_elf64_note(f, env, cpuid, opaque);
ret = x86_64_write_elf64_note(f, &cpu->env, cpuid, opaque);
} else {
#endif
ret = x86_write_elf64_note(f, env, cpuid, opaque);
ret = x86_write_elf64_note(f, &cpu->env, cpuid, opaque);
#ifdef TARGET_X86_64
}
#endif
@ -198,9 +199,10 @@ int cpu_write_elf64_note(write_core_dump_function f, CPUArchState *env,
return ret;
}
int cpu_write_elf32_note(write_core_dump_function f, CPUArchState *env,
int cpuid, void *opaque)
int x86_cpu_write_elf32_note(WriteCoreDumpFunction f, CPUState *cs,
int cpuid, void *opaque)
{
X86CPU *cpu = X86_CPU(cs);
x86_elf_prstatus prstatus;
Elf32_Nhdr *note;
char *buf;
@ -208,7 +210,7 @@ int cpu_write_elf32_note(write_core_dump_function f, CPUArchState *env,
const char *name = "CORE";
int ret;
x86_fill_elf_prstatus(&prstatus, env, cpuid);
x86_fill_elf_prstatus(&prstatus, &cpu->env, cpuid);
descsz = sizeof(x86_elf_prstatus);
note_size = ((sizeof(Elf32_Nhdr) + 3) / 4 + (name_size + 3) / 4 +
(descsz + 3) / 4) * 4;
@ -317,7 +319,7 @@ static void qemu_get_cpustate(QEMUCPUState *s, CPUArchState *env)
s->cr[4] = env->cr[4];
}
static inline int cpu_write_qemu_note(write_core_dump_function f,
static inline int cpu_write_qemu_note(WriteCoreDumpFunction f,
CPUArchState *env,
void *opaque,
int type)
@ -370,16 +372,20 @@ static inline int cpu_write_qemu_note(write_core_dump_function f,
return 0;
}
int cpu_write_elf64_qemunote(write_core_dump_function f, CPUArchState *env,
void *opaque)
int x86_cpu_write_elf64_qemunote(WriteCoreDumpFunction f, CPUState *cs,
void *opaque)
{
return cpu_write_qemu_note(f, env, opaque, 1);
X86CPU *cpu = X86_CPU(cs);
return cpu_write_qemu_note(f, &cpu->env, opaque, 1);
}
int cpu_write_elf32_qemunote(write_core_dump_function f, CPUArchState *env,
void *opaque)
int x86_cpu_write_elf32_qemunote(WriteCoreDumpFunction f, CPUState *cs,
void *opaque)
{
return cpu_write_qemu_note(f, env, opaque, 0);
X86CPU *cpu = X86_CPU(cs);
return cpu_write_qemu_note(f, &cpu->env, opaque, 0);
}
int cpu_get_dump_info(ArchDumpInfo *info)

View File

@ -86,4 +86,13 @@ extern const struct VMStateDescription vmstate_x86_cpu;
*/
void x86_cpu_do_interrupt(CPUState *cpu);
int x86_cpu_write_elf64_note(WriteCoreDumpFunction f, CPUState *cpu,
int cpuid, void *opaque);
int x86_cpu_write_elf32_note(WriteCoreDumpFunction f, CPUState *cpu,
int cpuid, void *opaque);
int x86_cpu_write_elf64_qemunote(WriteCoreDumpFunction f, CPUState *cpu,
void *opaque);
int x86_cpu_write_elf32_qemunote(WriteCoreDumpFunction f, CPUState *cpu,
void *opaque);
#endif

File diff suppressed because it is too large Load Diff

View File

@ -836,22 +836,15 @@ typedef struct CPUX86State {
/* processor features (e.g. for CPUID insn) */
uint32_t cpuid_level;
uint32_t cpuid_xlevel;
uint32_t cpuid_xlevel2;
uint32_t cpuid_vendor1;
uint32_t cpuid_vendor2;
uint32_t cpuid_vendor3;
uint32_t cpuid_version;
uint32_t cpuid_features;
uint32_t cpuid_ext_features;
uint32_t cpuid_xlevel;
FeatureWordArray features;
uint32_t cpuid_model[12];
uint32_t cpuid_ext2_features;
uint32_t cpuid_ext3_features;
uint32_t cpuid_apic_id;
/* Store the results of Centaur's CPUID instructions */
uint32_t cpuid_xlevel2;
uint32_t cpuid_ext4_features;
/* Flags from CPUID[EAX=7,ECX=0].EBX */
uint32_t cpuid_7_0_ebx_features;
/* MTRRs */
uint64_t mtrr_fixed[11];
@ -865,8 +858,6 @@ typedef struct CPUX86State {
uint8_t soft_interrupt;
uint8_t has_error_code;
uint32_t sipi_vector;
uint32_t cpuid_kvm_features;
uint32_t cpuid_svm_features;
bool tsc_valid;
int tsc_khz;
void *kvm_xsave_buf;
@ -897,7 +888,8 @@ typedef struct CPUX86State {
#include "cpu-qom.h"
X86CPU *cpu_x86_init(const char *cpu_model);
X86CPU *cpu_x86_create(const char *cpu_model, Error **errp);
X86CPU *cpu_x86_create(const char *cpu_model, DeviceState *icc_bridge,
Error **errp);
int cpu_x86_exec(CPUX86State *s);
void x86_cpu_list(FILE *f, fprintf_function cpu_fprintf);
void x86_cpudef_setup(void);
@ -1270,5 +1262,6 @@ uint32_t x86_cpu_apic_id_from_index(unsigned int cpu_index);
void enable_compat_apic_id_mode(void);
#define APIC_DEFAULT_ADDRESS 0xfee00000
#define APIC_SPACE_SIZE 0x100000
#endif /* CPU_I386_H */

View File

@ -463,7 +463,7 @@ void cpu_x86_update_cr4(CPUX86State *env, uint32_t new_cr4)
tlb_flush(env, 1);
}
/* SSE handling */
if (!(env->cpuid_features & CPUID_SSE)) {
if (!(env->features[FEAT_1_EDX] & CPUID_SSE)) {
new_cr4 &= ~CR4_OSFXSR_MASK;
}
env->hflags &= ~HF_OSFXSR_MASK;
@ -471,7 +471,7 @@ void cpu_x86_update_cr4(CPUX86State *env, uint32_t new_cr4)
env->hflags |= HF_OSFXSR_MASK;
}
if (!(env->cpuid_7_0_ebx_features & CPUID_7_0_EBX_SMAP)) {
if (!(env->features[FEAT_7_0_EBX] & CPUID_7_0_EBX_SMAP)) {
new_cr4 &= ~CR4_SMAP_MASK;
}
env->hflags &= ~HF_SMAP_MASK;

View File

@ -454,7 +454,7 @@ int kvm_arch_init_vcpu(CPUState *cs)
c = &cpuid_data.entries[cpuid_i++];
memset(c, 0, sizeof(*c));
c->function = KVM_CPUID_FEATURES;
c->eax = env->cpuid_kvm_features;
c->eax = env->features[FEAT_KVM];
if (hyperv_enabled()) {
memcpy(signature, "Hv#1\0\0\0\0\0\0\0\0", 12);
@ -613,7 +613,8 @@ int kvm_arch_init_vcpu(CPUState *cs)
cpuid_data.cpuid.nent = cpuid_i;
if (((env->cpuid_version >> 8)&0xF) >= 6
&& (env->cpuid_features&(CPUID_MCE|CPUID_MCA)) == (CPUID_MCE|CPUID_MCA)
&& (env->features[FEAT_1_EDX] & (CPUID_MCE | CPUID_MCA)) ==
(CPUID_MCE | CPUID_MCA)
&& kvm_check_extension(cs->kvm_state, KVM_CAP_MCE) > 0) {
uint64_t mcg_cap;
int banks;

View File

@ -291,22 +291,22 @@ void helper_wrmsr(CPUX86State *env)
uint64_t update_mask;
update_mask = 0;
if (env->cpuid_ext2_features & CPUID_EXT2_SYSCALL) {
if (env->features[FEAT_8000_0001_EDX] & CPUID_EXT2_SYSCALL) {
update_mask |= MSR_EFER_SCE;
}
if (env->cpuid_ext2_features & CPUID_EXT2_LM) {
if (env->features[FEAT_8000_0001_EDX] & CPUID_EXT2_LM) {
update_mask |= MSR_EFER_LME;
}
if (env->cpuid_ext2_features & CPUID_EXT2_FFXSR) {
if (env->features[FEAT_8000_0001_EDX] & CPUID_EXT2_FFXSR) {
update_mask |= MSR_EFER_FFXSR;
}
if (env->cpuid_ext2_features & CPUID_EXT2_NX) {
if (env->features[FEAT_8000_0001_EDX] & CPUID_EXT2_NX) {
update_mask |= MSR_EFER_NXE;
}
if (env->cpuid_ext3_features & CPUID_EXT3_SVM) {
if (env->features[FEAT_8000_0001_ECX] & CPUID_EXT3_SVM) {
update_mask |= MSR_EFER_SVME;
}
if (env->cpuid_ext2_features & CPUID_EXT2_FFXSR) {
if (env->features[FEAT_8000_0001_EDX] & CPUID_EXT2_FFXSR) {
update_mask |= MSR_EFER_FFXSR;
}
cpu_load_efer(env, (env->efer & ~update_mask) |
@ -513,7 +513,7 @@ void helper_rdmsr(CPUX86State *env)
val = env->mtrr_deftype;
break;
case MSR_MTRRcap:
if (env->cpuid_features & CPUID_MTRR) {
if (env->features[FEAT_1_EDX] & CPUID_MTRR) {
val = MSR_MTRRcap_VCNT | MSR_MTRRcap_FIXRANGE_SUPPORT |
MSR_MTRRcap_WC_SUPPORTED;
} else {

View File

@ -8290,11 +8290,11 @@ static inline void gen_intermediate_code_internal(CPUX86State *env,
if (flags & HF_SOFTMMU_MASK) {
dc->mem_index = (cpu_mmu_index(env) + 1) << 2;
}
dc->cpuid_features = env->cpuid_features;
dc->cpuid_ext_features = env->cpuid_ext_features;
dc->cpuid_ext2_features = env->cpuid_ext2_features;
dc->cpuid_ext3_features = env->cpuid_ext3_features;
dc->cpuid_7_0_ebx_features = env->cpuid_7_0_ebx_features;
dc->cpuid_features = env->features[FEAT_1_EDX];
dc->cpuid_ext_features = env->features[FEAT_1_ECX];
dc->cpuid_ext2_features = env->features[FEAT_8000_0001_EDX];
dc->cpuid_ext3_features = env->features[FEAT_8000_0001_ECX];
dc->cpuid_7_0_ebx_features = env->features[FEAT_7_0_EBX];
#ifdef TARGET_X86_64
dc->lma = (flags >> HF_LMA_SHIFT) & 1;
dc->code64 = (flags >> HF_CS64_SHIFT) & 1;

2
vl.c
View File

@ -267,7 +267,6 @@ static NotifierList machine_init_done_notifiers =
NOTIFIER_LIST_INITIALIZER(machine_init_done_notifiers);
static bool tcg_allowed = true;
bool kvm_allowed;
bool xen_allowed;
uint32_t xen_domid;
enum xen_mode xen_mode = XEN_EMULATE;
@ -4416,7 +4415,6 @@ int main(int argc, char **argv, char **envp)
os_setup_post();
resume_all_vcpus();
main_loop();
bdrv_close_all();
pause_all_vcpus();