198128601SRob Herring /* 298128601SRob Herring * Copyright (C) 2014 - Linaro 398128601SRob Herring * Author: Rob Herring <rob.herring@linaro.org> 498128601SRob Herring * 598128601SRob Herring * This program is free software; you can redistribute it and/or modify 698128601SRob Herring * it under the terms of the GNU General Public License as published by 798128601SRob Herring * the Free Software Foundation; either version 2 of the License, or 898128601SRob Herring * (at your option) any later version. 998128601SRob Herring * 1098128601SRob Herring * This program is distributed in the hope that it will be useful, 1198128601SRob Herring * but WITHOUT ANY WARRANTY; without even the implied warranty of 1298128601SRob Herring * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 1398128601SRob Herring * GNU General Public License for more details. 1498128601SRob Herring * 1598128601SRob Herring * You should have received a copy of the GNU General Public License 1698128601SRob Herring * along with this program; if not, see <http://www.gnu.org/licenses/>. 1798128601SRob Herring */ 1898128601SRob Herring #include <cpu.h> 1998128601SRob Herring #include <cpu-qom.h> 2098128601SRob Herring #include <exec/helper-proto.h> 2198128601SRob Herring #include <kvm-consts.h> 2298128601SRob Herring #include <sysemu/sysemu.h> 2398128601SRob Herring #include "internals.h" 2498128601SRob Herring 2598128601SRob Herring bool arm_is_psci_call(ARMCPU *cpu, int excp_type) 2698128601SRob Herring { 2798128601SRob Herring /* Return true if the r0/x0 value indicates a PSCI call and 2898128601SRob Herring * the exception type matches the configured PSCI conduit. This is 2998128601SRob Herring * called before the SMC/HVC instruction is executed, to decide whether 3098128601SRob Herring * we should treat it as a PSCI call or with the architecturally 3198128601SRob Herring * defined behaviour for an SMC or HVC (which might be UNDEF or trap 3298128601SRob Herring * to EL2 or to EL3). 3398128601SRob Herring */ 3498128601SRob Herring CPUARMState *env = &cpu->env; 3598128601SRob Herring uint64_t param = is_a64(env) ? env->xregs[0] : env->regs[0]; 3698128601SRob Herring 3798128601SRob Herring switch (excp_type) { 3898128601SRob Herring case EXCP_HVC: 3998128601SRob Herring if (cpu->psci_conduit != QEMU_PSCI_CONDUIT_HVC) { 4098128601SRob Herring return false; 4198128601SRob Herring } 4298128601SRob Herring break; 4398128601SRob Herring case EXCP_SMC: 4498128601SRob Herring if (cpu->psci_conduit != QEMU_PSCI_CONDUIT_SMC) { 4598128601SRob Herring return false; 4698128601SRob Herring } 4798128601SRob Herring break; 4898128601SRob Herring default: 4998128601SRob Herring return false; 5098128601SRob Herring } 5198128601SRob Herring 5298128601SRob Herring switch (param) { 5398128601SRob Herring case QEMU_PSCI_0_2_FN_PSCI_VERSION: 5498128601SRob Herring case QEMU_PSCI_0_2_FN_MIGRATE_INFO_TYPE: 5598128601SRob Herring case QEMU_PSCI_0_2_FN_AFFINITY_INFO: 5698128601SRob Herring case QEMU_PSCI_0_2_FN64_AFFINITY_INFO: 5798128601SRob Herring case QEMU_PSCI_0_2_FN_SYSTEM_RESET: 5898128601SRob Herring case QEMU_PSCI_0_2_FN_SYSTEM_OFF: 5998128601SRob Herring case QEMU_PSCI_0_1_FN_CPU_ON: 6098128601SRob Herring case QEMU_PSCI_0_2_FN_CPU_ON: 6198128601SRob Herring case QEMU_PSCI_0_2_FN64_CPU_ON: 6298128601SRob Herring case QEMU_PSCI_0_1_FN_CPU_OFF: 6398128601SRob Herring case QEMU_PSCI_0_2_FN_CPU_OFF: 6498128601SRob Herring case QEMU_PSCI_0_1_FN_CPU_SUSPEND: 6598128601SRob Herring case QEMU_PSCI_0_2_FN_CPU_SUSPEND: 6698128601SRob Herring case QEMU_PSCI_0_2_FN64_CPU_SUSPEND: 6798128601SRob Herring case QEMU_PSCI_0_1_FN_MIGRATE: 6898128601SRob Herring case QEMU_PSCI_0_2_FN_MIGRATE: 6998128601SRob Herring return true; 7098128601SRob Herring default: 7198128601SRob Herring return false; 7298128601SRob Herring } 7398128601SRob Herring } 7498128601SRob Herring 75eb5e1d3cSPavel Fedin static CPUState *get_cpu_by_id(uint64_t id) 76eb5e1d3cSPavel Fedin { 77eb5e1d3cSPavel Fedin CPUState *cpu; 78eb5e1d3cSPavel Fedin 79eb5e1d3cSPavel Fedin CPU_FOREACH(cpu) { 80eb5e1d3cSPavel Fedin ARMCPU *armcpu = ARM_CPU(cpu); 81eb5e1d3cSPavel Fedin 82eb5e1d3cSPavel Fedin if (armcpu->mp_affinity == id) { 83eb5e1d3cSPavel Fedin return cpu; 84eb5e1d3cSPavel Fedin } 85eb5e1d3cSPavel Fedin } 86eb5e1d3cSPavel Fedin 87eb5e1d3cSPavel Fedin return NULL; 88eb5e1d3cSPavel Fedin } 89eb5e1d3cSPavel Fedin 9098128601SRob Herring void arm_handle_psci_call(ARMCPU *cpu) 9198128601SRob Herring { 9298128601SRob Herring /* 9398128601SRob Herring * This function partially implements the logic for dispatching Power State 9498128601SRob Herring * Coordination Interface (PSCI) calls (as described in ARM DEN 0022B.b), 9598128601SRob Herring * to the extent required for bringing up and taking down secondary cores, 9698128601SRob Herring * and for handling reset and poweroff requests. 9798128601SRob Herring * Additional information about the calling convention used is available in 9898128601SRob Herring * the document 'SMC Calling Convention' (ARM DEN 0028) 9998128601SRob Herring */ 10098128601SRob Herring CPUState *cs = CPU(cpu); 10198128601SRob Herring CPUARMState *env = &cpu->env; 10298128601SRob Herring uint64_t param[4]; 10398128601SRob Herring uint64_t context_id, mpidr; 10498128601SRob Herring target_ulong entry; 10598128601SRob Herring int32_t ret = 0; 10698128601SRob Herring int i; 10798128601SRob Herring 10898128601SRob Herring for (i = 0; i < 4; i++) { 10998128601SRob Herring /* 11098128601SRob Herring * All PSCI functions take explicit 32-bit or native int sized 11198128601SRob Herring * arguments so we can simply zero-extend all arguments regardless 11298128601SRob Herring * of which exact function we are about to call. 11398128601SRob Herring */ 11498128601SRob Herring param[i] = is_a64(env) ? env->xregs[i] : env->regs[i]; 11598128601SRob Herring } 11698128601SRob Herring 11798128601SRob Herring if ((param[0] & QEMU_PSCI_0_2_64BIT) && !is_a64(env)) { 11898128601SRob Herring ret = QEMU_PSCI_RET_INVALID_PARAMS; 11998128601SRob Herring goto err; 12098128601SRob Herring } 12198128601SRob Herring 12298128601SRob Herring switch (param[0]) { 12398128601SRob Herring CPUState *target_cpu_state; 12498128601SRob Herring ARMCPU *target_cpu; 12598128601SRob Herring CPUClass *target_cpu_class; 12698128601SRob Herring 12798128601SRob Herring case QEMU_PSCI_0_2_FN_PSCI_VERSION: 12898128601SRob Herring ret = QEMU_PSCI_0_2_RET_VERSION_0_2; 12998128601SRob Herring break; 13098128601SRob Herring case QEMU_PSCI_0_2_FN_MIGRATE_INFO_TYPE: 13198128601SRob Herring ret = QEMU_PSCI_0_2_RET_TOS_MIGRATION_NOT_REQUIRED; /* No trusted OS */ 13298128601SRob Herring break; 13398128601SRob Herring case QEMU_PSCI_0_2_FN_AFFINITY_INFO: 13498128601SRob Herring case QEMU_PSCI_0_2_FN64_AFFINITY_INFO: 13598128601SRob Herring mpidr = param[1]; 13698128601SRob Herring 13798128601SRob Herring switch (param[2]) { 13898128601SRob Herring case 0: 139eb5e1d3cSPavel Fedin target_cpu_state = get_cpu_by_id(mpidr); 14098128601SRob Herring if (!target_cpu_state) { 14198128601SRob Herring ret = QEMU_PSCI_RET_INVALID_PARAMS; 14298128601SRob Herring break; 14398128601SRob Herring } 14498128601SRob Herring target_cpu = ARM_CPU(target_cpu_state); 14598128601SRob Herring ret = target_cpu->powered_off ? 1 : 0; 14698128601SRob Herring break; 14798128601SRob Herring default: 14898128601SRob Herring /* Everything above affinity level 0 is always on. */ 14998128601SRob Herring ret = 0; 15098128601SRob Herring } 15198128601SRob Herring break; 15298128601SRob Herring case QEMU_PSCI_0_2_FN_SYSTEM_RESET: 15398128601SRob Herring qemu_system_reset_request(); 15498128601SRob Herring /* QEMU reset and shutdown are async requests, but PSCI 15598128601SRob Herring * mandates that we never return from the reset/shutdown 15698128601SRob Herring * call, so power the CPU off now so it doesn't execute 15798128601SRob Herring * anything further. 15898128601SRob Herring */ 15998128601SRob Herring goto cpu_off; 16098128601SRob Herring case QEMU_PSCI_0_2_FN_SYSTEM_OFF: 16198128601SRob Herring qemu_system_shutdown_request(); 16298128601SRob Herring goto cpu_off; 16398128601SRob Herring case QEMU_PSCI_0_1_FN_CPU_ON: 16498128601SRob Herring case QEMU_PSCI_0_2_FN_CPU_ON: 16598128601SRob Herring case QEMU_PSCI_0_2_FN64_CPU_ON: 16698128601SRob Herring mpidr = param[1]; 16798128601SRob Herring entry = param[2]; 16898128601SRob Herring context_id = param[3]; 16998128601SRob Herring 17098128601SRob Herring /* change to the cpu we are powering up */ 171eb5e1d3cSPavel Fedin target_cpu_state = get_cpu_by_id(mpidr); 17298128601SRob Herring if (!target_cpu_state) { 17398128601SRob Herring ret = QEMU_PSCI_RET_INVALID_PARAMS; 17498128601SRob Herring break; 17598128601SRob Herring } 17698128601SRob Herring target_cpu = ARM_CPU(target_cpu_state); 17798128601SRob Herring if (!target_cpu->powered_off) { 17898128601SRob Herring ret = QEMU_PSCI_RET_ALREADY_ON; 17998128601SRob Herring break; 18098128601SRob Herring } 18198128601SRob Herring target_cpu_class = CPU_GET_CLASS(target_cpu); 18298128601SRob Herring 18398128601SRob Herring /* Initialize the cpu we are turning on */ 18498128601SRob Herring cpu_reset(target_cpu_state); 18598128601SRob Herring target_cpu->powered_off = false; 18698128601SRob Herring target_cpu_state->halted = 0; 18798128601SRob Herring 18898128601SRob Herring /* 18998128601SRob Herring * The PSCI spec mandates that newly brought up CPUs enter the 19098128601SRob Herring * exception level of the caller in the same execution mode as 19198128601SRob Herring * the caller, with context_id in x0/r0, respectively. 19298128601SRob Herring * 19398128601SRob Herring * For now, it is sufficient to assert() that CPUs come out of 19498128601SRob Herring * reset in the same mode as the calling CPU, since we only 19598128601SRob Herring * implement EL1, which means that 19698128601SRob Herring * (a) there is no EL2 for the calling CPU to trap into to change 19798128601SRob Herring * its state 19898128601SRob Herring * (b) the newly brought up CPU enters EL1 immediately after coming 19998128601SRob Herring * out of reset in the default state 20098128601SRob Herring */ 20198128601SRob Herring assert(is_a64(env) == is_a64(&target_cpu->env)); 20298128601SRob Herring if (is_a64(env)) { 20398128601SRob Herring if (entry & 1) { 20498128601SRob Herring ret = QEMU_PSCI_RET_INVALID_PARAMS; 20598128601SRob Herring break; 20698128601SRob Herring } 20798128601SRob Herring target_cpu->env.xregs[0] = context_id; 20898128601SRob Herring } else { 20998128601SRob Herring target_cpu->env.regs[0] = context_id; 21098128601SRob Herring target_cpu->env.thumb = entry & 1; 21198128601SRob Herring } 21298128601SRob Herring target_cpu_class->set_pc(target_cpu_state, entry); 21398128601SRob Herring 21498128601SRob Herring ret = 0; 21598128601SRob Herring break; 21698128601SRob Herring case QEMU_PSCI_0_1_FN_CPU_OFF: 21798128601SRob Herring case QEMU_PSCI_0_2_FN_CPU_OFF: 21898128601SRob Herring goto cpu_off; 21998128601SRob Herring case QEMU_PSCI_0_1_FN_CPU_SUSPEND: 22098128601SRob Herring case QEMU_PSCI_0_2_FN_CPU_SUSPEND: 22198128601SRob Herring case QEMU_PSCI_0_2_FN64_CPU_SUSPEND: 22298128601SRob Herring /* Affinity levels are not supported in QEMU */ 22398128601SRob Herring if (param[1] & 0xfffe0000) { 22498128601SRob Herring ret = QEMU_PSCI_RET_INVALID_PARAMS; 22598128601SRob Herring break; 22698128601SRob Herring } 22798128601SRob Herring /* Powerdown is not supported, we always go into WFI */ 22898128601SRob Herring if (is_a64(env)) { 22998128601SRob Herring env->xregs[0] = 0; 23098128601SRob Herring } else { 23198128601SRob Herring env->regs[0] = 0; 23298128601SRob Herring } 23398128601SRob Herring helper_wfi(env); 23498128601SRob Herring break; 23598128601SRob Herring case QEMU_PSCI_0_1_FN_MIGRATE: 23698128601SRob Herring case QEMU_PSCI_0_2_FN_MIGRATE: 23798128601SRob Herring ret = QEMU_PSCI_RET_NOT_SUPPORTED; 23898128601SRob Herring break; 23998128601SRob Herring default: 24098128601SRob Herring g_assert_not_reached(); 24198128601SRob Herring } 24298128601SRob Herring 24398128601SRob Herring err: 24498128601SRob Herring if (is_a64(env)) { 24598128601SRob Herring env->xregs[0] = ret; 24698128601SRob Herring } else { 24798128601SRob Herring env->regs[0] = ret; 24898128601SRob Herring } 24998128601SRob Herring return; 25098128601SRob Herring 25198128601SRob Herring cpu_off: 25298128601SRob Herring cpu->powered_off = true; 25398128601SRob Herring cs->halted = 1; 25498128601SRob Herring cs->exception_index = EXCP_HLT; 25598128601SRob Herring cpu_loop_exit(cs); 25698128601SRob Herring /* notreached */ 25798128601SRob Herring } 258