1*9def656eSClaudio Fontana /* 2*9def656eSClaudio Fontana * Copyright (C) 2014 - Linaro 3*9def656eSClaudio Fontana * Author: Rob Herring <rob.herring@linaro.org> 4*9def656eSClaudio Fontana * 5*9def656eSClaudio Fontana * This program is free software; you can redistribute it and/or modify 6*9def656eSClaudio Fontana * it under the terms of the GNU General Public License as published by 7*9def656eSClaudio Fontana * the Free Software Foundation; either version 2 of the License, or 8*9def656eSClaudio Fontana * (at your option) any later version. 9*9def656eSClaudio Fontana * 10*9def656eSClaudio Fontana * This program is distributed in the hope that it will be useful, 11*9def656eSClaudio Fontana * but WITHOUT ANY WARRANTY; without even the implied warranty of 12*9def656eSClaudio Fontana * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13*9def656eSClaudio Fontana * GNU General Public License for more details. 14*9def656eSClaudio Fontana * 15*9def656eSClaudio Fontana * You should have received a copy of the GNU General Public License 16*9def656eSClaudio Fontana * along with this program; if not, see <http://www.gnu.org/licenses/>. 17*9def656eSClaudio Fontana */ 18*9def656eSClaudio Fontana 19*9def656eSClaudio Fontana #include "qemu/osdep.h" 20*9def656eSClaudio Fontana #include "cpu.h" 21*9def656eSClaudio Fontana #include "exec/helper-proto.h" 22*9def656eSClaudio Fontana #include "kvm-consts.h" 23*9def656eSClaudio Fontana #include "qemu/main-loop.h" 24*9def656eSClaudio Fontana #include "sysemu/runstate.h" 25*9def656eSClaudio Fontana #include "internals.h" 26*9def656eSClaudio Fontana #include "arm-powerctl.h" 27*9def656eSClaudio Fontana 28*9def656eSClaudio Fontana bool arm_is_psci_call(ARMCPU *cpu, int excp_type) 29*9def656eSClaudio Fontana { 30*9def656eSClaudio Fontana /* 31*9def656eSClaudio Fontana * Return true if the exception type matches the configured PSCI conduit. 32*9def656eSClaudio Fontana * This is called before the SMC/HVC instruction is executed, to decide 33*9def656eSClaudio Fontana * whether we should treat it as a PSCI call or with the architecturally 34*9def656eSClaudio Fontana * defined behaviour for an SMC or HVC (which might be UNDEF or trap 35*9def656eSClaudio Fontana * to EL2 or to EL3). 36*9def656eSClaudio Fontana */ 37*9def656eSClaudio Fontana 38*9def656eSClaudio Fontana switch (excp_type) { 39*9def656eSClaudio Fontana case EXCP_HVC: 40*9def656eSClaudio Fontana if (cpu->psci_conduit != QEMU_PSCI_CONDUIT_HVC) { 41*9def656eSClaudio Fontana return false; 42*9def656eSClaudio Fontana } 43*9def656eSClaudio Fontana break; 44*9def656eSClaudio Fontana case EXCP_SMC: 45*9def656eSClaudio Fontana if (cpu->psci_conduit != QEMU_PSCI_CONDUIT_SMC) { 46*9def656eSClaudio Fontana return false; 47*9def656eSClaudio Fontana } 48*9def656eSClaudio Fontana break; 49*9def656eSClaudio Fontana default: 50*9def656eSClaudio Fontana return false; 51*9def656eSClaudio Fontana } 52*9def656eSClaudio Fontana 53*9def656eSClaudio Fontana return true; 54*9def656eSClaudio Fontana } 55*9def656eSClaudio Fontana 56*9def656eSClaudio Fontana void arm_handle_psci_call(ARMCPU *cpu) 57*9def656eSClaudio Fontana { 58*9def656eSClaudio Fontana /* 59*9def656eSClaudio Fontana * This function partially implements the logic for dispatching Power State 60*9def656eSClaudio Fontana * Coordination Interface (PSCI) calls (as described in ARM DEN 0022D.b), 61*9def656eSClaudio Fontana * to the extent required for bringing up and taking down secondary cores, 62*9def656eSClaudio Fontana * and for handling reset and poweroff requests. 63*9def656eSClaudio Fontana * Additional information about the calling convention used is available in 64*9def656eSClaudio Fontana * the document 'SMC Calling Convention' (ARM DEN 0028) 65*9def656eSClaudio Fontana */ 66*9def656eSClaudio Fontana CPUARMState *env = &cpu->env; 67*9def656eSClaudio Fontana uint64_t param[4]; 68*9def656eSClaudio Fontana uint64_t context_id, mpidr; 69*9def656eSClaudio Fontana target_ulong entry; 70*9def656eSClaudio Fontana int32_t ret = 0; 71*9def656eSClaudio Fontana int i; 72*9def656eSClaudio Fontana 73*9def656eSClaudio Fontana for (i = 0; i < 4; i++) { 74*9def656eSClaudio Fontana /* 75*9def656eSClaudio Fontana * All PSCI functions take explicit 32-bit or native int sized 76*9def656eSClaudio Fontana * arguments so we can simply zero-extend all arguments regardless 77*9def656eSClaudio Fontana * of which exact function we are about to call. 78*9def656eSClaudio Fontana */ 79*9def656eSClaudio Fontana param[i] = is_a64(env) ? env->xregs[i] : env->regs[i]; 80*9def656eSClaudio Fontana } 81*9def656eSClaudio Fontana 82*9def656eSClaudio Fontana if ((param[0] & QEMU_PSCI_0_2_64BIT) && !is_a64(env)) { 83*9def656eSClaudio Fontana ret = QEMU_PSCI_RET_NOT_SUPPORTED; 84*9def656eSClaudio Fontana goto err; 85*9def656eSClaudio Fontana } 86*9def656eSClaudio Fontana 87*9def656eSClaudio Fontana switch (param[0]) { 88*9def656eSClaudio Fontana CPUState *target_cpu_state; 89*9def656eSClaudio Fontana ARMCPU *target_cpu; 90*9def656eSClaudio Fontana 91*9def656eSClaudio Fontana case QEMU_PSCI_0_2_FN_PSCI_VERSION: 92*9def656eSClaudio Fontana ret = QEMU_PSCI_VERSION_1_1; 93*9def656eSClaudio Fontana break; 94*9def656eSClaudio Fontana case QEMU_PSCI_0_2_FN_MIGRATE_INFO_TYPE: 95*9def656eSClaudio Fontana ret = QEMU_PSCI_0_2_RET_TOS_MIGRATION_NOT_REQUIRED; /* No trusted OS */ 96*9def656eSClaudio Fontana break; 97*9def656eSClaudio Fontana case QEMU_PSCI_0_2_FN_AFFINITY_INFO: 98*9def656eSClaudio Fontana case QEMU_PSCI_0_2_FN64_AFFINITY_INFO: 99*9def656eSClaudio Fontana mpidr = param[1]; 100*9def656eSClaudio Fontana 101*9def656eSClaudio Fontana switch (param[2]) { 102*9def656eSClaudio Fontana case 0: 103*9def656eSClaudio Fontana target_cpu_state = arm_get_cpu_by_id(mpidr); 104*9def656eSClaudio Fontana if (!target_cpu_state) { 105*9def656eSClaudio Fontana ret = QEMU_PSCI_RET_INVALID_PARAMS; 106*9def656eSClaudio Fontana break; 107*9def656eSClaudio Fontana } 108*9def656eSClaudio Fontana target_cpu = ARM_CPU(target_cpu_state); 109*9def656eSClaudio Fontana 110*9def656eSClaudio Fontana g_assert(qemu_mutex_iothread_locked()); 111*9def656eSClaudio Fontana ret = target_cpu->power_state; 112*9def656eSClaudio Fontana break; 113*9def656eSClaudio Fontana default: 114*9def656eSClaudio Fontana /* Everything above affinity level 0 is always on. */ 115*9def656eSClaudio Fontana ret = 0; 116*9def656eSClaudio Fontana } 117*9def656eSClaudio Fontana break; 118*9def656eSClaudio Fontana case QEMU_PSCI_0_2_FN_SYSTEM_RESET: 119*9def656eSClaudio Fontana qemu_system_reset_request(SHUTDOWN_CAUSE_GUEST_RESET); 120*9def656eSClaudio Fontana /* QEMU reset and shutdown are async requests, but PSCI 121*9def656eSClaudio Fontana * mandates that we never return from the reset/shutdown 122*9def656eSClaudio Fontana * call, so power the CPU off now so it doesn't execute 123*9def656eSClaudio Fontana * anything further. 124*9def656eSClaudio Fontana */ 125*9def656eSClaudio Fontana goto cpu_off; 126*9def656eSClaudio Fontana case QEMU_PSCI_0_2_FN_SYSTEM_OFF: 127*9def656eSClaudio Fontana qemu_system_shutdown_request(SHUTDOWN_CAUSE_GUEST_SHUTDOWN); 128*9def656eSClaudio Fontana goto cpu_off; 129*9def656eSClaudio Fontana case QEMU_PSCI_0_1_FN_CPU_ON: 130*9def656eSClaudio Fontana case QEMU_PSCI_0_2_FN_CPU_ON: 131*9def656eSClaudio Fontana case QEMU_PSCI_0_2_FN64_CPU_ON: 132*9def656eSClaudio Fontana { 133*9def656eSClaudio Fontana /* The PSCI spec mandates that newly brought up CPUs start 134*9def656eSClaudio Fontana * in the highest exception level which exists and is enabled 135*9def656eSClaudio Fontana * on the calling CPU. Since the QEMU PSCI implementation is 136*9def656eSClaudio Fontana * acting as a "fake EL3" or "fake EL2" firmware, this for us 137*9def656eSClaudio Fontana * means that we want to start at the highest NS exception level 138*9def656eSClaudio Fontana * that we are providing to the guest. 139*9def656eSClaudio Fontana * The execution mode should be that which is currently in use 140*9def656eSClaudio Fontana * by the same exception level on the calling CPU. 141*9def656eSClaudio Fontana * The CPU should be started with the context_id value 142*9def656eSClaudio Fontana * in x0 (if AArch64) or r0 (if AArch32). 143*9def656eSClaudio Fontana */ 144*9def656eSClaudio Fontana int target_el = arm_feature(env, ARM_FEATURE_EL2) ? 2 : 1; 145*9def656eSClaudio Fontana bool target_aarch64 = arm_el_is_aa64(env, target_el); 146*9def656eSClaudio Fontana 147*9def656eSClaudio Fontana mpidr = param[1]; 148*9def656eSClaudio Fontana entry = param[2]; 149*9def656eSClaudio Fontana context_id = param[3]; 150*9def656eSClaudio Fontana ret = arm_set_cpu_on(mpidr, entry, context_id, 151*9def656eSClaudio Fontana target_el, target_aarch64); 152*9def656eSClaudio Fontana break; 153*9def656eSClaudio Fontana } 154*9def656eSClaudio Fontana case QEMU_PSCI_0_1_FN_CPU_OFF: 155*9def656eSClaudio Fontana case QEMU_PSCI_0_2_FN_CPU_OFF: 156*9def656eSClaudio Fontana goto cpu_off; 157*9def656eSClaudio Fontana case QEMU_PSCI_0_1_FN_CPU_SUSPEND: 158*9def656eSClaudio Fontana case QEMU_PSCI_0_2_FN_CPU_SUSPEND: 159*9def656eSClaudio Fontana case QEMU_PSCI_0_2_FN64_CPU_SUSPEND: 160*9def656eSClaudio Fontana /* Affinity levels are not supported in QEMU */ 161*9def656eSClaudio Fontana if (param[1] & 0xfffe0000) { 162*9def656eSClaudio Fontana ret = QEMU_PSCI_RET_INVALID_PARAMS; 163*9def656eSClaudio Fontana break; 164*9def656eSClaudio Fontana } 165*9def656eSClaudio Fontana /* Powerdown is not supported, we always go into WFI */ 166*9def656eSClaudio Fontana if (is_a64(env)) { 167*9def656eSClaudio Fontana env->xregs[0] = 0; 168*9def656eSClaudio Fontana } else { 169*9def656eSClaudio Fontana env->regs[0] = 0; 170*9def656eSClaudio Fontana } 171*9def656eSClaudio Fontana helper_wfi(env, 4); 172*9def656eSClaudio Fontana break; 173*9def656eSClaudio Fontana case QEMU_PSCI_1_0_FN_PSCI_FEATURES: 174*9def656eSClaudio Fontana switch (param[1]) { 175*9def656eSClaudio Fontana case QEMU_PSCI_0_2_FN_PSCI_VERSION: 176*9def656eSClaudio Fontana case QEMU_PSCI_0_2_FN_MIGRATE_INFO_TYPE: 177*9def656eSClaudio Fontana case QEMU_PSCI_0_2_FN_AFFINITY_INFO: 178*9def656eSClaudio Fontana case QEMU_PSCI_0_2_FN64_AFFINITY_INFO: 179*9def656eSClaudio Fontana case QEMU_PSCI_0_2_FN_SYSTEM_RESET: 180*9def656eSClaudio Fontana case QEMU_PSCI_0_2_FN_SYSTEM_OFF: 181*9def656eSClaudio Fontana case QEMU_PSCI_0_1_FN_CPU_ON: 182*9def656eSClaudio Fontana case QEMU_PSCI_0_2_FN_CPU_ON: 183*9def656eSClaudio Fontana case QEMU_PSCI_0_2_FN64_CPU_ON: 184*9def656eSClaudio Fontana case QEMU_PSCI_0_1_FN_CPU_OFF: 185*9def656eSClaudio Fontana case QEMU_PSCI_0_2_FN_CPU_OFF: 186*9def656eSClaudio Fontana case QEMU_PSCI_0_1_FN_CPU_SUSPEND: 187*9def656eSClaudio Fontana case QEMU_PSCI_0_2_FN_CPU_SUSPEND: 188*9def656eSClaudio Fontana case QEMU_PSCI_0_2_FN64_CPU_SUSPEND: 189*9def656eSClaudio Fontana case QEMU_PSCI_1_0_FN_PSCI_FEATURES: 190*9def656eSClaudio Fontana if (!(param[1] & QEMU_PSCI_0_2_64BIT) || is_a64(env)) { 191*9def656eSClaudio Fontana ret = 0; 192*9def656eSClaudio Fontana break; 193*9def656eSClaudio Fontana } 194*9def656eSClaudio Fontana /* fallthrough */ 195*9def656eSClaudio Fontana case QEMU_PSCI_0_1_FN_MIGRATE: 196*9def656eSClaudio Fontana case QEMU_PSCI_0_2_FN_MIGRATE: 197*9def656eSClaudio Fontana default: 198*9def656eSClaudio Fontana ret = QEMU_PSCI_RET_NOT_SUPPORTED; 199*9def656eSClaudio Fontana break; 200*9def656eSClaudio Fontana } 201*9def656eSClaudio Fontana break; 202*9def656eSClaudio Fontana case QEMU_PSCI_0_1_FN_MIGRATE: 203*9def656eSClaudio Fontana case QEMU_PSCI_0_2_FN_MIGRATE: 204*9def656eSClaudio Fontana default: 205*9def656eSClaudio Fontana ret = QEMU_PSCI_RET_NOT_SUPPORTED; 206*9def656eSClaudio Fontana break; 207*9def656eSClaudio Fontana } 208*9def656eSClaudio Fontana 209*9def656eSClaudio Fontana err: 210*9def656eSClaudio Fontana if (is_a64(env)) { 211*9def656eSClaudio Fontana env->xregs[0] = ret; 212*9def656eSClaudio Fontana } else { 213*9def656eSClaudio Fontana env->regs[0] = ret; 214*9def656eSClaudio Fontana } 215*9def656eSClaudio Fontana return; 216*9def656eSClaudio Fontana 217*9def656eSClaudio Fontana cpu_off: 218*9def656eSClaudio Fontana ret = arm_set_cpu_off(cpu->mp_affinity); 219*9def656eSClaudio Fontana /* notreached */ 220*9def656eSClaudio Fontana /* sanity check in case something failed */ 221*9def656eSClaudio Fontana assert(ret == QEMU_ARM_POWERCTL_RET_SUCCESS); 222*9def656eSClaudio Fontana } 223