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:
commit
8ca27ce2e1
@ -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>
|
||||
|
@ -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
|
||||
|
@ -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
|
||||
|
@ -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
27
cpus.c
@ -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;
|
||||
}
|
||||
}
|
||||
|
@ -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
|
||||
|
@ -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
|
||||
|
22
docs/specs/acpi_cpu_hotplug.txt
Normal file
22
docs/specs/acpi_cpu_hotplug.txt
Normal 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.
|
28
dump-stub.c
28
dump-stub.c
@ -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
8
dump.c
@ -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
10
exec.c
@ -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);
|
||||
|
@ -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)
|
||||
|
@ -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
119
hw/cpu/icc_bus.c
Normal 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)
|
@ -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;
|
||||
|
@ -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);
|
||||
}
|
||||
|
@ -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
|
||||
|
||||
|
88
hw/i386/pc.c
88
hw/i386/pc.c
@ -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)
|
||||
|
@ -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,
|
||||
|
@ -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,
|
||||
};
|
||||
|
@ -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;
|
||||
|
@ -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,
|
||||
|
@ -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);
|
||||
|
@ -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
|
||||
|
@ -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
82
include/hw/cpu/icc_bus.h
Normal 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
|
@ -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;
|
||||
|
@ -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,
|
||||
|
@ -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 */
|
||||
|
@ -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
|
||||
|
@ -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);
|
||||
|
||||
|
@ -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);
|
||||
|
@ -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,
|
||||
|
@ -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),
|
||||
|
@ -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
|
||||
|
@ -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
|
||||
|
@ -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);
|
||||
}
|
||||
|
@ -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:
|
||||
#
|
||||
|
@ -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
10
qmp.c
@ -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
114
qom/cpu.c
@ -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;
|
||||
}
|
||||
|
@ -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
5
stubs/cpus.c
Normal file
@ -0,0 +1,5 @@
|
||||
#include "qom/cpu.h"
|
||||
|
||||
void cpu_resume(CPUState *cpu)
|
||||
{
|
||||
}
|
@ -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)
|
||||
|
@ -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
@ -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 */
|
||||
|
@ -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;
|
||||
|
@ -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;
|
||||
|
@ -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 {
|
||||
|
@ -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
2
vl.c
@ -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();
|
||||
|
Loading…
Reference in New Issue
Block a user