diff options
Diffstat (limited to 'hw/ppc/spapr_rtas.c')
| -rw-r--r-- | hw/ppc/spapr_rtas.c | 108 |
1 files changed, 53 insertions, 55 deletions
diff --git a/hw/ppc/spapr_rtas.c b/hw/ppc/spapr_rtas.c index 0ec5fa4cfe..7f9738daed 100644 --- a/hw/ppc/spapr_rtas.c +++ b/hw/ppc/spapr_rtas.c @@ -32,11 +32,12 @@ #include "hw/qdev.h" #include "sysemu/device_tree.h" #include "sysemu/cpus.h" -#include "sysemu/kvm.h" +#include "sysemu/hw_accel.h" #include "hw/ppc/spapr.h" #include "hw/ppc/spapr_vio.h" #include "hw/ppc/spapr_rtas.h" +#include "hw/ppc/spapr_cpu_core.h" #include "hw/ppc/ppc.h" #include "hw/boards.h" @@ -45,6 +46,8 @@ #include "qemu/cutils.h" #include "trace.h" #include "hw/ppc/fdt.h" +#include "target/ppc/mmu-hash64.h" +#include "target/ppc/mmu-book3s-v3.h" static void rtas_display_character(PowerPCCPU *cpu, sPAPRMachineState *spapr, uint32_t token, uint32_t nargs, @@ -119,34 +122,16 @@ static void rtas_query_cpu_stopped_state(PowerPCCPU *cpu_, rtas_st(rets, 0, RTAS_OUT_PARAM_ERROR); } -/* - * Set the timebase offset of the CPU to that of first CPU. - * This helps hotplugged CPU to have the correct timebase offset. - */ -static void spapr_cpu_update_tb_offset(PowerPCCPU *cpu) -{ - PowerPCCPU *fcpu = POWERPC_CPU(first_cpu); - - cpu->env.tb_env->tb_offset = fcpu->env.tb_env->tb_offset; -} - -static void spapr_cpu_set_endianness(PowerPCCPU *cpu) -{ - PowerPCCPU *fcpu = POWERPC_CPU(first_cpu); - PowerPCCPUClass *pcc = POWERPC_CPU_GET_CLASS(fcpu); - - if (!pcc->interrupts_big_endian(fcpu)) { - cpu->env.spr[SPR_LPCR] |= LPCR_ILE; - } -} - -static void rtas_start_cpu(PowerPCCPU *cpu_, sPAPRMachineState *spapr, +static void rtas_start_cpu(PowerPCCPU *callcpu, sPAPRMachineState *spapr, uint32_t token, uint32_t nargs, target_ulong args, uint32_t nret, target_ulong rets) { target_ulong id, start, r3; - PowerPCCPU *cpu; + PowerPCCPU *newcpu; + CPUPPCState *env; + PowerPCCPUClass *pcc; + target_ulong lpcr; if (nargs != 3 || nret != 1) { rtas_st(rets, 0, RTAS_OUT_PARAM_ERROR); @@ -157,41 +142,55 @@ static void rtas_start_cpu(PowerPCCPU *cpu_, sPAPRMachineState *spapr, start = rtas_ld(args, 1); r3 = rtas_ld(args, 2); - cpu = spapr_find_cpu(id); - if (cpu != NULL) { - CPUState *cs = CPU(cpu); - CPUPPCState *env = &cpu->env; - PowerPCCPUClass *pcc = POWERPC_CPU_GET_CLASS(cpu); + newcpu = spapr_find_cpu(id); + if (!newcpu) { + /* Didn't find a matching cpu */ + rtas_st(rets, 0, RTAS_OUT_PARAM_ERROR); + return; + } - if (!cs->halted) { - rtas_st(rets, 0, RTAS_OUT_HW_ERROR); - return; - } + env = &newcpu->env; + pcc = POWERPC_CPU_GET_CLASS(newcpu); + + if (!CPU(newcpu)->halted) { + rtas_st(rets, 0, RTAS_OUT_HW_ERROR); + return; + } - /* This will make sure qemu state is up to date with kvm, and - * mark it dirty so our changes get flushed back before the - * new cpu enters */ - kvm_cpu_synchronize_state(cs); + cpu_synchronize_state(CPU(newcpu)); - env->msr = (1ULL << MSR_SF) | (1ULL << MSR_ME); + env->msr = (1ULL << MSR_SF) | (1ULL << MSR_ME); - /* Enable Power-saving mode Exit Cause exceptions for the new CPU */ - env->spr[SPR_LPCR] |= pcc->lpcr_pm; + /* Enable Power-saving mode Exit Cause exceptions for the new CPU */ + lpcr = env->spr[SPR_LPCR]; + if (!pcc->interrupts_big_endian(callcpu)) { + lpcr |= LPCR_ILE; + } + if (env->mmu_model == POWERPC_MMU_3_00) { + /* + * New cpus are expected to start in the same radix/hash mode + * as the existing CPUs + */ + if (ppc64_radix_guest(callcpu)) { + lpcr |= LPCR_UPRT | LPCR_GTSE; + } else { + lpcr &= ~(LPCR_UPRT | LPCR_GTSE); + } + } + ppc_store_lpcr(newcpu, lpcr); - env->nip = start; - env->gpr[3] = r3; - cs->halted = 0; - spapr_cpu_set_endianness(cpu); - spapr_cpu_update_tb_offset(cpu); + /* + * Set the timebase offset of the new CPU to that of the invoking + * CPU. This helps hotplugged CPU to have the correct timebase + * offset. + */ + newcpu->env.tb_env->tb_offset = callcpu->env.tb_env->tb_offset; - qemu_cpu_kick(cs); + spapr_cpu_set_entry_state(newcpu, start, r3); - rtas_st(rets, 0, RTAS_OUT_SUCCESS); - return; - } + qemu_cpu_kick(CPU(newcpu)); - /* Didn't find a matching cpu */ - rtas_st(rets, 0, RTAS_OUT_PARAM_ERROR); + rtas_st(rets, 0, RTAS_OUT_SUCCESS); } static void rtas_stop_self(PowerPCCPU *cpu, sPAPRMachineState *spapr, @@ -203,13 +202,12 @@ static void rtas_stop_self(PowerPCCPU *cpu, sPAPRMachineState *spapr, CPUPPCState *env = &cpu->env; PowerPCCPUClass *pcc = POWERPC_CPU_GET_CLASS(cpu); - cs->halted = 1; - qemu_cpu_kick(cs); - /* Disable Power-saving mode Exit Cause exceptions for the CPU. * This could deliver an interrupt on a dying CPU and crash the * guest */ - env->spr[SPR_LPCR] &= ~pcc->lpcr_pm; + ppc_store_lpcr(cpu, env->spr[SPR_LPCR] & ~pcc->lpcr_pm); + cs->halted = 1; + qemu_cpu_kick(cs); } static inline int sysparm_st(target_ulong addr, target_ulong len, |