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 7598128601SRob Herring void arm_handle_psci_call(ARMCPU *cpu) 7698128601SRob Herring { 7798128601SRob Herring /* 7898128601SRob Herring * This function partially implements the logic for dispatching Power State 7998128601SRob Herring * Coordination Interface (PSCI) calls (as described in ARM DEN 0022B.b), 8098128601SRob Herring * to the extent required for bringing up and taking down secondary cores, 8198128601SRob Herring * and for handling reset and poweroff requests. 8298128601SRob Herring * Additional information about the calling convention used is available in 8398128601SRob Herring * the document 'SMC Calling Convention' (ARM DEN 0028) 8498128601SRob Herring */ 8598128601SRob Herring CPUState *cs = CPU(cpu); 8698128601SRob Herring CPUARMState *env = &cpu->env; 8798128601SRob Herring uint64_t param[4]; 8898128601SRob Herring uint64_t context_id, mpidr; 8998128601SRob Herring target_ulong entry; 9098128601SRob Herring int32_t ret = 0; 9198128601SRob Herring int i; 9298128601SRob Herring 9398128601SRob Herring for (i = 0; i < 4; i++) { 9498128601SRob Herring /* 9598128601SRob Herring * All PSCI functions take explicit 32-bit or native int sized 9698128601SRob Herring * arguments so we can simply zero-extend all arguments regardless 9798128601SRob Herring * of which exact function we are about to call. 9898128601SRob Herring */ 9998128601SRob Herring param[i] = is_a64(env) ? env->xregs[i] : env->regs[i]; 10098128601SRob Herring } 10198128601SRob Herring 10298128601SRob Herring if ((param[0] & QEMU_PSCI_0_2_64BIT) && !is_a64(env)) { 10398128601SRob Herring ret = QEMU_PSCI_RET_INVALID_PARAMS; 10498128601SRob Herring goto err; 10598128601SRob Herring } 10698128601SRob Herring 10798128601SRob Herring switch (param[0]) { 10898128601SRob Herring CPUState *target_cpu_state; 10998128601SRob Herring ARMCPU *target_cpu; 11098128601SRob Herring CPUClass *target_cpu_class; 11198128601SRob Herring 11298128601SRob Herring case QEMU_PSCI_0_2_FN_PSCI_VERSION: 11398128601SRob Herring ret = QEMU_PSCI_0_2_RET_VERSION_0_2; 11498128601SRob Herring break; 11598128601SRob Herring case QEMU_PSCI_0_2_FN_MIGRATE_INFO_TYPE: 11698128601SRob Herring ret = QEMU_PSCI_0_2_RET_TOS_MIGRATION_NOT_REQUIRED; /* No trusted OS */ 11798128601SRob Herring break; 11898128601SRob Herring case QEMU_PSCI_0_2_FN_AFFINITY_INFO: 11998128601SRob Herring case QEMU_PSCI_0_2_FN64_AFFINITY_INFO: 12098128601SRob Herring mpidr = param[1]; 12198128601SRob Herring 12298128601SRob Herring switch (param[2]) { 12398128601SRob Herring case 0: 12498128601SRob Herring target_cpu_state = qemu_get_cpu(mpidr & 0xff); 12598128601SRob Herring if (!target_cpu_state) { 12698128601SRob Herring ret = QEMU_PSCI_RET_INVALID_PARAMS; 12798128601SRob Herring break; 12898128601SRob Herring } 12998128601SRob Herring target_cpu = ARM_CPU(target_cpu_state); 13098128601SRob Herring ret = target_cpu->powered_off ? 1 : 0; 13198128601SRob Herring break; 13298128601SRob Herring default: 13398128601SRob Herring /* Everything above affinity level 0 is always on. */ 13498128601SRob Herring ret = 0; 13598128601SRob Herring } 13698128601SRob Herring break; 13798128601SRob Herring case QEMU_PSCI_0_2_FN_SYSTEM_RESET: 13898128601SRob Herring qemu_system_reset_request(); 13998128601SRob Herring /* QEMU reset and shutdown are async requests, but PSCI 14098128601SRob Herring * mandates that we never return from the reset/shutdown 14198128601SRob Herring * call, so power the CPU off now so it doesn't execute 14298128601SRob Herring * anything further. 14398128601SRob Herring */ 14498128601SRob Herring goto cpu_off; 14598128601SRob Herring case QEMU_PSCI_0_2_FN_SYSTEM_OFF: 14698128601SRob Herring qemu_system_shutdown_request(); 14798128601SRob Herring goto cpu_off; 14898128601SRob Herring case QEMU_PSCI_0_1_FN_CPU_ON: 14998128601SRob Herring case QEMU_PSCI_0_2_FN_CPU_ON: 15098128601SRob Herring case QEMU_PSCI_0_2_FN64_CPU_ON: 15198128601SRob Herring mpidr = param[1]; 15298128601SRob Herring entry = param[2]; 15398128601SRob Herring context_id = param[3]; 15498128601SRob Herring 15598128601SRob Herring /* change to the cpu we are powering up */ 15698128601SRob Herring target_cpu_state = qemu_get_cpu(mpidr & 0xff); 15798128601SRob Herring if (!target_cpu_state) { 15898128601SRob Herring ret = QEMU_PSCI_RET_INVALID_PARAMS; 15998128601SRob Herring break; 16098128601SRob Herring } 16198128601SRob Herring target_cpu = ARM_CPU(target_cpu_state); 16298128601SRob Herring if (!target_cpu->powered_off) { 16398128601SRob Herring ret = QEMU_PSCI_RET_ALREADY_ON; 16498128601SRob Herring break; 16598128601SRob Herring } 16698128601SRob Herring target_cpu_class = CPU_GET_CLASS(target_cpu); 16798128601SRob Herring 16898128601SRob Herring /* Initialize the cpu we are turning on */ 16998128601SRob Herring cpu_reset(target_cpu_state); 17098128601SRob Herring target_cpu->powered_off = false; 17198128601SRob Herring target_cpu_state->halted = 0; 17298128601SRob Herring 17398128601SRob Herring /* 17498128601SRob Herring * The PSCI spec mandates that newly brought up CPUs enter the 17598128601SRob Herring * exception level of the caller in the same execution mode as 17698128601SRob Herring * the caller, with context_id in x0/r0, respectively. 17798128601SRob Herring * 17898128601SRob Herring * For now, it is sufficient to assert() that CPUs come out of 17998128601SRob Herring * reset in the same mode as the calling CPU, since we only 18098128601SRob Herring * implement EL1, which means that 18198128601SRob Herring * (a) there is no EL2 for the calling CPU to trap into to change 18298128601SRob Herring * its state 18398128601SRob Herring * (b) the newly brought up CPU enters EL1 immediately after coming 18498128601SRob Herring * out of reset in the default state 18598128601SRob Herring */ 18698128601SRob Herring assert(is_a64(env) == is_a64(&target_cpu->env)); 18798128601SRob Herring if (is_a64(env)) { 18898128601SRob Herring if (entry & 1) { 18998128601SRob Herring ret = QEMU_PSCI_RET_INVALID_PARAMS; 19098128601SRob Herring break; 19198128601SRob Herring } 19298128601SRob Herring target_cpu->env.xregs[0] = context_id; 19398128601SRob Herring } else { 19498128601SRob Herring target_cpu->env.regs[0] = context_id; 19598128601SRob Herring target_cpu->env.thumb = entry & 1; 19698128601SRob Herring } 19798128601SRob Herring target_cpu_class->set_pc(target_cpu_state, entry); 19898128601SRob Herring 19998128601SRob Herring ret = 0; 20098128601SRob Herring break; 20198128601SRob Herring case QEMU_PSCI_0_1_FN_CPU_OFF: 20298128601SRob Herring case QEMU_PSCI_0_2_FN_CPU_OFF: 20398128601SRob Herring goto cpu_off; 20498128601SRob Herring case QEMU_PSCI_0_1_FN_CPU_SUSPEND: 20598128601SRob Herring case QEMU_PSCI_0_2_FN_CPU_SUSPEND: 20698128601SRob Herring case QEMU_PSCI_0_2_FN64_CPU_SUSPEND: 20798128601SRob Herring /* Affinity levels are not supported in QEMU */ 20898128601SRob Herring if (param[1] & 0xfffe0000) { 20998128601SRob Herring ret = QEMU_PSCI_RET_INVALID_PARAMS; 21098128601SRob Herring break; 21198128601SRob Herring } 21298128601SRob Herring /* Powerdown is not supported, we always go into WFI */ 21398128601SRob Herring if (is_a64(env)) { 21498128601SRob Herring env->xregs[0] = 0; 21598128601SRob Herring } else { 21698128601SRob Herring env->regs[0] = 0; 21798128601SRob Herring } 21898128601SRob Herring helper_wfi(env); 21998128601SRob Herring break; 22098128601SRob Herring case QEMU_PSCI_0_1_FN_MIGRATE: 22198128601SRob Herring case QEMU_PSCI_0_2_FN_MIGRATE: 22298128601SRob Herring ret = QEMU_PSCI_RET_NOT_SUPPORTED; 22398128601SRob Herring break; 22498128601SRob Herring default: 22598128601SRob Herring g_assert_not_reached(); 22698128601SRob Herring } 22798128601SRob Herring 22898128601SRob Herring err: 22998128601SRob Herring if (is_a64(env)) { 23098128601SRob Herring env->xregs[0] = ret; 23198128601SRob Herring } else { 23298128601SRob Herring env->regs[0] = ret; 23398128601SRob Herring } 23498128601SRob Herring return; 23598128601SRob Herring 23698128601SRob Herring cpu_off: 23798128601SRob Herring cpu->powered_off = true; 23898128601SRob Herring cs->halted = 1; 23998128601SRob Herring cs->exception_index = EXCP_HLT; 24098128601SRob Herring cpu_loop_exit(cs); 24198128601SRob Herring /* notreached */ 24298128601SRob Herring } 243