mirror of
https://github.com/izzy2lost/xemu.git
synced 2026-07-06 00:20:22 -07:00
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:
@@ -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>
|
||||
|
||||
+7
-7
@@ -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
|
||||
|
||||
+1
-1
@@ -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
|
||||
|
||||
+2
-2
@@ -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);
|
||||
}
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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
@@ -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;
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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);
|
||||
|
||||
+88
-2
@@ -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
|
||||
|
||||
|
||||
@@ -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)
|
||||
+1
-1
@@ -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;
|
||||
|
||||
+1
-1
@@ -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
|
||||
|
||||
|
||||
+86
-2
@@ -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)
|
||||
|
||||
+9
-1
@@ -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,
|
||||
|
||||
+9
-1
@@ -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,
|
||||
};
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user