* This work is licensed under the terms of the GNU GPL, version 2 or later.
* See the COPYING file in the top-level directory.
*/
+
#include "qemu/osdep.h"
#include "hw/cpu/core.h"
#include "hw/ppc/spapr_cpu_core.h"
+#include "hw/qdev-properties.h"
+#include "migration/vmstate.h"
#include "target/ppc/cpu.h"
#include "hw/ppc/spapr.h"
-#include "hw/boards.h"
#include "qapi/error.h"
#include "sysemu/cpus.h"
#include "sysemu/kvm.h"
#include "hw/ppc/ppc.h"
#include "target/ppc/mmu-hash64.h"
#include "sysemu/numa.h"
+#include "sysemu/reset.h"
#include "sysemu/hw_accel.h"
#include "qemu/error-report.h"
-static void spapr_cpu_reset(void *opaque)
+static void spapr_reset_vcpu(PowerPCCPU *cpu)
{
- PowerPCCPU *cpu = opaque;
CPUState *cs = CPU(cpu);
CPUPPCState *env = &cpu->env;
PowerPCCPUClass *pcc = POWERPC_CPU_GET_CLASS(cpu);
+ SpaprCpuState *spapr_cpu = spapr_cpu_state(cpu);
target_ulong lpcr;
+ SpaprMachineState *spapr = SPAPR_MACHINE(qdev_get_machine());
cpu_reset(cs);
- /* Set compatibility mode to match the boot CPU, which was either set
- * by the machine reset code or by CAS. This should never fail.
- */
- ppc_set_compat(cpu, POWERPC_CPU(first_cpu)->compat_pvr, &error_abort);
-
/* All CPUs start halted. CPU0 is unhalted from the machine level
* reset code and the rest are explicitly started up by the guest
* using an RTAS call */
* the settings below ensure proper operations with TCG in absence of
* a real hypervisor.
*
- * Clearing VPM0 will also cause us to use RMOR in mmu-hash64.c for
- * real mode accesses, which thankfully defaults to 0 and isn't
- * accessible in guest mode.
- *
* Disable Power-saving mode Exit Cause exceptions for the CPU, so
* we don't get spurious wakups before an RTAS start-cpu call.
+ * For the same reason, set PSSCR_EC.
*/
- lpcr &= ~(LPCR_VPM0 | LPCR_VPM1 | LPCR_ISL | LPCR_KBV | pcc->lpcr_pm);
+ lpcr &= ~(LPCR_VPM1 | LPCR_ISL | LPCR_KBV | pcc->lpcr_pm);
lpcr |= LPCR_LPES0 | LPCR_LPES1;
-
- /* Set RMLS to the max (ie, 16G) */
- lpcr &= ~LPCR_RMLS;
- lpcr |= 1ull << LPCR_RMLS_SHIFT;
+ env->spr[SPR_PSSCR] |= PSSCR_EC;
ppc_store_lpcr(cpu, lpcr);
/* Set a full AMOR so guest can use the AMR as it sees fit */
env->spr[SPR_AMOR] = 0xffffffffffffffffull;
+
+ spapr_cpu->vpa_addr = 0;
+ spapr_cpu->slb_shadow_addr = 0;
+ spapr_cpu->slb_shadow_size = 0;
+ spapr_cpu->dtl_addr = 0;
+ spapr_cpu->dtl_size = 0;
+
+ spapr_caps_cpu_apply(spapr, cpu);
+
+ kvm_check_mmu(cpu, &error_fatal);
+
+ spapr_irq_cpu_intc_reset(spapr, cpu);
}
-void spapr_cpu_set_entry_state(PowerPCCPU *cpu, target_ulong nip, target_ulong r3)
+void spapr_cpu_set_entry_state(PowerPCCPU *cpu, target_ulong nip,
+ target_ulong r1, target_ulong r3,
+ target_ulong r4)
{
PowerPCCPUClass *pcc = POWERPC_CPU_GET_CLASS(cpu);
CPUPPCState *env = &cpu->env;
env->nip = nip;
+ env->gpr[1] = r1;
env->gpr[3] = r3;
+ env->gpr[4] = r4;
+ kvmppc_set_reg_ppc_online(cpu, 1);
CPU(cpu)->halted = 0;
/* Enable Power-saving mode Exit Cause exceptions */
ppc_store_lpcr(cpu, env->spr[SPR_LPCR] | pcc->lpcr_pm);
return object_class_get_name(oc);
}
-static void spapr_unrealize_vcpu(PowerPCCPU *cpu)
+static bool slb_shadow_needed(void *opaque)
+{
+ SpaprCpuState *spapr_cpu = opaque;
+
+ return spapr_cpu->slb_shadow_addr != 0;
+}
+
+static const VMStateDescription vmstate_spapr_cpu_slb_shadow = {
+ .name = "spapr_cpu/vpa/slb_shadow",
+ .version_id = 1,
+ .minimum_version_id = 1,
+ .needed = slb_shadow_needed,
+ .fields = (VMStateField[]) {
+ VMSTATE_UINT64(slb_shadow_addr, SpaprCpuState),
+ VMSTATE_UINT64(slb_shadow_size, SpaprCpuState),
+ VMSTATE_END_OF_LIST()
+ }
+};
+
+static bool dtl_needed(void *opaque)
+{
+ SpaprCpuState *spapr_cpu = opaque;
+
+ return spapr_cpu->dtl_addr != 0;
+}
+
+static const VMStateDescription vmstate_spapr_cpu_dtl = {
+ .name = "spapr_cpu/vpa/dtl",
+ .version_id = 1,
+ .minimum_version_id = 1,
+ .needed = dtl_needed,
+ .fields = (VMStateField[]) {
+ VMSTATE_UINT64(dtl_addr, SpaprCpuState),
+ VMSTATE_UINT64(dtl_size, SpaprCpuState),
+ VMSTATE_END_OF_LIST()
+ }
+};
+
+static bool vpa_needed(void *opaque)
+{
+ SpaprCpuState *spapr_cpu = opaque;
+
+ return spapr_cpu->vpa_addr != 0;
+}
+
+static const VMStateDescription vmstate_spapr_cpu_vpa = {
+ .name = "spapr_cpu/vpa",
+ .version_id = 1,
+ .minimum_version_id = 1,
+ .needed = vpa_needed,
+ .fields = (VMStateField[]) {
+ VMSTATE_UINT64(vpa_addr, SpaprCpuState),
+ VMSTATE_END_OF_LIST()
+ },
+ .subsections = (const VMStateDescription * []) {
+ &vmstate_spapr_cpu_slb_shadow,
+ &vmstate_spapr_cpu_dtl,
+ NULL
+ }
+};
+
+static const VMStateDescription vmstate_spapr_cpu_state = {
+ .name = "spapr_cpu",
+ .version_id = 1,
+ .minimum_version_id = 1,
+ .fields = (VMStateField[]) {
+ VMSTATE_END_OF_LIST()
+ },
+ .subsections = (const VMStateDescription * []) {
+ &vmstate_spapr_cpu_vpa,
+ NULL
+ }
+};
+
+static void spapr_unrealize_vcpu(PowerPCCPU *cpu, SpaprCpuCore *sc)
{
- qemu_unregister_reset(spapr_cpu_reset, cpu);
- object_unparent(cpu->intc);
+ if (!sc->pre_3_0_migration) {
+ vmstate_unregister(NULL, &vmstate_spapr_cpu_state, cpu->machine_data);
+ }
+ spapr_irq_cpu_intc_destroy(SPAPR_MACHINE(qdev_get_machine()), cpu);
cpu_remove_sync(CPU(cpu));
object_unparent(OBJECT(cpu));
}
-static void spapr_cpu_core_unrealize(DeviceState *dev, Error **errp)
+/*
+ * Called when CPUs are hot-plugged.
+ */
+static void spapr_cpu_core_reset(DeviceState *dev)
{
- sPAPRCPUCore *sc = SPAPR_CPU_CORE(OBJECT(dev));
CPUCore *cc = CPU_CORE(dev);
+ SpaprCpuCore *sc = SPAPR_CPU_CORE(dev);
int i;
for (i = 0; i < cc->nr_threads; i++) {
- spapr_unrealize_vcpu(sc->threads[i]);
+ spapr_reset_vcpu(sc->threads[i]);
+ }
+}
+
+/*
+ * Called by the machine reset.
+ */
+static void spapr_cpu_core_reset_handler(void *opaque)
+{
+ spapr_cpu_core_reset(opaque);
+}
+
+static void spapr_cpu_core_unrealize(DeviceState *dev)
+{
+ SpaprCpuCore *sc = SPAPR_CPU_CORE(OBJECT(dev));
+ CPUCore *cc = CPU_CORE(dev);
+ int i;
+
+ qemu_unregister_reset(spapr_cpu_core_reset_handler, sc);
+
+ for (i = 0; i < cc->nr_threads; i++) {
+ spapr_unrealize_vcpu(sc->threads[i], sc);
}
g_free(sc->threads);
}
-static void spapr_realize_vcpu(PowerPCCPU *cpu, sPAPRMachineState *spapr,
- Error **errp)
+static void spapr_realize_vcpu(PowerPCCPU *cpu, SpaprMachineState *spapr,
+ SpaprCpuCore *sc, Error **errp)
{
CPUPPCState *env = &cpu->env;
+ CPUState *cs = CPU(cpu);
Error *local_err = NULL;
- object_property_set_bool(OBJECT(cpu), true, "realized", &local_err);
- if (local_err) {
- goto error;
+ if (!qdev_realize(DEVICE(cpu), NULL, errp)) {
+ return;
}
/* Set time-base frequency to 512 MHz */
cpu_ppc_set_vhyp(cpu, PPC_VIRTUAL_HYPERVISOR(spapr));
kvmppc_set_papr(cpu);
- qemu_register_reset(spapr_cpu_reset, cpu);
- spapr_cpu_reset(cpu);
-
- cpu->intc = icp_create(OBJECT(cpu), spapr->icp_type, XICS_FABRIC(spapr),
- &local_err);
- if (local_err) {
- goto error_unregister;
+ if (spapr_irq_cpu_intc_create(spapr, cpu, &local_err) < 0) {
+ cpu_remove_sync(CPU(cpu));
+ return;
}
- return;
-
-error_unregister:
- qemu_unregister_reset(spapr_cpu_reset, cpu);
- cpu_remove_sync(CPU(cpu));
-error:
- error_propagate(errp, local_err);
+ if (!sc->pre_3_0_migration) {
+ vmstate_register(NULL, cs->cpu_index, &vmstate_spapr_cpu_state,
+ cpu->machine_data);
+ }
}
-static PowerPCCPU *spapr_create_vcpu(sPAPRCPUCore *sc, int i, Error **errp)
+static PowerPCCPU *spapr_create_vcpu(SpaprCpuCore *sc, int i, Error **errp)
{
- sPAPRCPUCoreClass *scc = SPAPR_CPU_CORE_GET_CLASS(sc);
+ SpaprCpuCoreClass *scc = SPAPR_CPU_CORE_GET_CLASS(sc);
CPUCore *cc = CPU_CORE(sc);
Object *obj;
char *id;
cpu->node_id = sc->node_id;
id = g_strdup_printf("thread[%d]", i);
- object_property_add_child(OBJECT(sc), id, obj, &local_err);
+ object_property_add_child(OBJECT(sc), id, obj);
g_free(id);
- if (local_err) {
- goto err;
- }
+
+ cpu->machine_data = g_new0(SpaprCpuState, 1);
object_unref(obj);
return cpu;
return NULL;
}
-static void spapr_delete_vcpu(PowerPCCPU *cpu)
+static void spapr_delete_vcpu(PowerPCCPU *cpu, SpaprCpuCore *sc)
{
+ SpaprCpuState *spapr_cpu = spapr_cpu_state(cpu);
+
+ cpu->machine_data = NULL;
+ g_free(spapr_cpu);
object_unparent(OBJECT(cpu));
}
/* We don't use SPAPR_MACHINE() in order to exit gracefully if the user
* tries to add a sPAPR CPU core to a non-pseries machine.
*/
- sPAPRMachineState *spapr =
- (sPAPRMachineState *) object_dynamic_cast(qdev_get_machine(),
+ SpaprMachineState *spapr =
+ (SpaprMachineState *) object_dynamic_cast(qdev_get_machine(),
TYPE_SPAPR_MACHINE);
- sPAPRCPUCore *sc = SPAPR_CPU_CORE(OBJECT(dev));
+ SpaprCpuCore *sc = SPAPR_CPU_CORE(OBJECT(dev));
CPUCore *cc = CPU_CORE(OBJECT(dev));
Error *local_err = NULL;
int i, j;
}
for (j = 0; j < cc->nr_threads; j++) {
- spapr_realize_vcpu(sc->threads[j], spapr, &local_err);
+ spapr_realize_vcpu(sc->threads[j], spapr, sc, &local_err);
if (local_err) {
goto err_unrealize;
}
}
+
+ qemu_register_reset(spapr_cpu_core_reset_handler, sc);
return;
err_unrealize:
while (--j >= 0) {
- spapr_unrealize_vcpu(sc->threads[j]);
+ spapr_unrealize_vcpu(sc->threads[j], sc);
}
err:
while (--i >= 0) {
- spapr_delete_vcpu(sc->threads[i]);
+ spapr_delete_vcpu(sc->threads[i], sc);
}
g_free(sc->threads);
error_propagate(errp, local_err);
}
static Property spapr_cpu_core_properties[] = {
- DEFINE_PROP_INT32("node-id", sPAPRCPUCore, node_id, CPU_UNSET_NUMA_NODE_ID),
+ DEFINE_PROP_INT32("node-id", SpaprCpuCore, node_id, CPU_UNSET_NUMA_NODE_ID),
+ DEFINE_PROP_BOOL("pre-3.0-migration", SpaprCpuCore, pre_3_0_migration,
+ false),
DEFINE_PROP_END_OF_LIST()
};
static void spapr_cpu_core_class_init(ObjectClass *oc, void *data)
{
DeviceClass *dc = DEVICE_CLASS(oc);
- sPAPRCPUCoreClass *scc = SPAPR_CPU_CORE_CLASS(oc);
+ SpaprCpuCoreClass *scc = SPAPR_CPU_CORE_CLASS(oc);
dc->realize = spapr_cpu_core_realize;
dc->unrealize = spapr_cpu_core_unrealize;
- dc->props = spapr_cpu_core_properties;
+ dc->reset = spapr_cpu_core_reset;
+ device_class_set_props(dc, spapr_cpu_core_properties);
scc->cpu_type = data;
}
.name = TYPE_SPAPR_CPU_CORE,
.parent = TYPE_CPU_CORE,
.abstract = true,
- .instance_size = sizeof(sPAPRCPUCore),
- .class_size = sizeof(sPAPRCPUCoreClass),
+ .instance_size = sizeof(SpaprCpuCore),
+ .class_size = sizeof(SpaprCpuCoreClass),
},
DEFINE_SPAPR_CPU_CORE_TYPE("970_v2.2"),
DEFINE_SPAPR_CPU_CORE_TYPE("970mp_v1.0"),
DEFINE_SPAPR_CPU_CORE_TYPE("power8nvl_v1.0"),
DEFINE_SPAPR_CPU_CORE_TYPE("power9_v1.0"),
DEFINE_SPAPR_CPU_CORE_TYPE("power9_v2.0"),
+ DEFINE_SPAPR_CPU_CORE_TYPE("power10_v1.0"),
#ifdef CONFIG_KVM
DEFINE_SPAPR_CPU_CORE_TYPE("host"),
#endif