19def656eSClaudio Fontana /* 29def656eSClaudio Fontana * Copyright (C) 2014 - Linaro 39def656eSClaudio Fontana * Author: Rob Herring <rob.herring@linaro.org> 49def656eSClaudio Fontana * 59def656eSClaudio Fontana * This program is free software; you can redistribute it and/or modify 69def656eSClaudio Fontana * it under the terms of the GNU General Public License as published by 79def656eSClaudio Fontana * the Free Software Foundation; either version 2 of the License, or 89def656eSClaudio Fontana * (at your option) any later version. 99def656eSClaudio Fontana * 109def656eSClaudio Fontana * This program is distributed in the hope that it will be useful, 119def656eSClaudio Fontana * but WITHOUT ANY WARRANTY; without even the implied warranty of 129def656eSClaudio Fontana * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 139def656eSClaudio Fontana * GNU General Public License for more details. 149def656eSClaudio Fontana * 159def656eSClaudio Fontana * You should have received a copy of the GNU General Public License 169def656eSClaudio Fontana * along with this program; if not, see <http://www.gnu.org/licenses/>. 179def656eSClaudio Fontana */ 189def656eSClaudio Fontana 199def656eSClaudio Fontana #include "qemu/osdep.h" 209def656eSClaudio Fontana #include "cpu.h" 219def656eSClaudio Fontana #include "exec/helper-proto.h" 229def656eSClaudio Fontana #include "kvm-consts.h" 239def656eSClaudio Fontana #include "qemu/main-loop.h" 249def656eSClaudio Fontana #include "sysemu/runstate.h" 259def656eSClaudio Fontana #include "internals.h" 269def656eSClaudio Fontana #include "arm-powerctl.h" 279def656eSClaudio Fontana 289def656eSClaudio Fontana bool arm_is_psci_call(ARMCPU *cpu, int excp_type) 299def656eSClaudio Fontana { 309def656eSClaudio Fontana /* 319def656eSClaudio Fontana * Return true if the exception type matches the configured PSCI conduit. 329def656eSClaudio Fontana * This is called before the SMC/HVC instruction is executed, to decide 339def656eSClaudio Fontana * whether we should treat it as a PSCI call or with the architecturally 349def656eSClaudio Fontana * defined behaviour for an SMC or HVC (which might be UNDEF or trap 359def656eSClaudio Fontana * to EL2 or to EL3). 369def656eSClaudio Fontana */ 379def656eSClaudio Fontana 389def656eSClaudio Fontana switch (excp_type) { 399def656eSClaudio Fontana case EXCP_HVC: 409def656eSClaudio Fontana if (cpu->psci_conduit != QEMU_PSCI_CONDUIT_HVC) { 419def656eSClaudio Fontana return false; 429def656eSClaudio Fontana } 439def656eSClaudio Fontana break; 449def656eSClaudio Fontana case EXCP_SMC: 459def656eSClaudio Fontana if (cpu->psci_conduit != QEMU_PSCI_CONDUIT_SMC) { 469def656eSClaudio Fontana return false; 479def656eSClaudio Fontana } 489def656eSClaudio Fontana break; 499def656eSClaudio Fontana default: 509def656eSClaudio Fontana return false; 519def656eSClaudio Fontana } 529def656eSClaudio Fontana 539def656eSClaudio Fontana return true; 549def656eSClaudio Fontana } 559def656eSClaudio Fontana 569def656eSClaudio Fontana void arm_handle_psci_call(ARMCPU *cpu) 579def656eSClaudio Fontana { 589def656eSClaudio Fontana /* 599def656eSClaudio Fontana * This function partially implements the logic for dispatching Power State 609def656eSClaudio Fontana * Coordination Interface (PSCI) calls (as described in ARM DEN 0022D.b), 619def656eSClaudio Fontana * to the extent required for bringing up and taking down secondary cores, 629def656eSClaudio Fontana * and for handling reset and poweroff requests. 639def656eSClaudio Fontana * Additional information about the calling convention used is available in 649def656eSClaudio Fontana * the document 'SMC Calling Convention' (ARM DEN 0028) 659def656eSClaudio Fontana */ 669def656eSClaudio Fontana CPUARMState *env = &cpu->env; 679def656eSClaudio Fontana uint64_t param[4]; 689def656eSClaudio Fontana uint64_t context_id, mpidr; 699def656eSClaudio Fontana target_ulong entry; 709def656eSClaudio Fontana int32_t ret = 0; 719def656eSClaudio Fontana int i; 729def656eSClaudio Fontana 739def656eSClaudio Fontana for (i = 0; i < 4; i++) { 749def656eSClaudio Fontana /* 759def656eSClaudio Fontana * All PSCI functions take explicit 32-bit or native int sized 769def656eSClaudio Fontana * arguments so we can simply zero-extend all arguments regardless 779def656eSClaudio Fontana * of which exact function we are about to call. 789def656eSClaudio Fontana */ 799def656eSClaudio Fontana param[i] = is_a64(env) ? env->xregs[i] : env->regs[i]; 809def656eSClaudio Fontana } 819def656eSClaudio Fontana 829def656eSClaudio Fontana if ((param[0] & QEMU_PSCI_0_2_64BIT) && !is_a64(env)) { 839def656eSClaudio Fontana ret = QEMU_PSCI_RET_NOT_SUPPORTED; 849def656eSClaudio Fontana goto err; 859def656eSClaudio Fontana } 869def656eSClaudio Fontana 879def656eSClaudio Fontana switch (param[0]) { 889def656eSClaudio Fontana CPUState *target_cpu_state; 899def656eSClaudio Fontana ARMCPU *target_cpu; 909def656eSClaudio Fontana 919def656eSClaudio Fontana case QEMU_PSCI_0_2_FN_PSCI_VERSION: 929def656eSClaudio Fontana ret = QEMU_PSCI_VERSION_1_1; 939def656eSClaudio Fontana break; 949def656eSClaudio Fontana case QEMU_PSCI_0_2_FN_MIGRATE_INFO_TYPE: 959def656eSClaudio Fontana ret = QEMU_PSCI_0_2_RET_TOS_MIGRATION_NOT_REQUIRED; /* No trusted OS */ 969def656eSClaudio Fontana break; 979def656eSClaudio Fontana case QEMU_PSCI_0_2_FN_AFFINITY_INFO: 989def656eSClaudio Fontana case QEMU_PSCI_0_2_FN64_AFFINITY_INFO: 999def656eSClaudio Fontana mpidr = param[1]; 1009def656eSClaudio Fontana 1019def656eSClaudio Fontana switch (param[2]) { 1029def656eSClaudio Fontana case 0: 1039def656eSClaudio Fontana target_cpu_state = arm_get_cpu_by_id(mpidr); 1049def656eSClaudio Fontana if (!target_cpu_state) { 1059def656eSClaudio Fontana ret = QEMU_PSCI_RET_INVALID_PARAMS; 1069def656eSClaudio Fontana break; 1079def656eSClaudio Fontana } 1089def656eSClaudio Fontana target_cpu = ARM_CPU(target_cpu_state); 1099def656eSClaudio Fontana 110195801d7SStefan Hajnoczi g_assert(bql_locked()); 1119def656eSClaudio Fontana ret = target_cpu->power_state; 1129def656eSClaudio Fontana break; 1139def656eSClaudio Fontana default: 1149def656eSClaudio Fontana /* Everything above affinity level 0 is always on. */ 1159def656eSClaudio Fontana ret = 0; 1169def656eSClaudio Fontana } 1179def656eSClaudio Fontana break; 1189def656eSClaudio Fontana case QEMU_PSCI_0_2_FN_SYSTEM_RESET: 1199def656eSClaudio Fontana qemu_system_reset_request(SHUTDOWN_CAUSE_GUEST_RESET); 1209def656eSClaudio Fontana /* QEMU reset and shutdown are async requests, but PSCI 1219def656eSClaudio Fontana * mandates that we never return from the reset/shutdown 1229def656eSClaudio Fontana * call, so power the CPU off now so it doesn't execute 1239def656eSClaudio Fontana * anything further. 1249def656eSClaudio Fontana */ 1259def656eSClaudio Fontana goto cpu_off; 1269def656eSClaudio Fontana case QEMU_PSCI_0_2_FN_SYSTEM_OFF: 1279def656eSClaudio Fontana qemu_system_shutdown_request(SHUTDOWN_CAUSE_GUEST_SHUTDOWN); 1289def656eSClaudio Fontana goto cpu_off; 1299def656eSClaudio Fontana case QEMU_PSCI_0_1_FN_CPU_ON: 1309def656eSClaudio Fontana case QEMU_PSCI_0_2_FN_CPU_ON: 1319def656eSClaudio Fontana case QEMU_PSCI_0_2_FN64_CPU_ON: 1329def656eSClaudio Fontana { 1339def656eSClaudio Fontana /* The PSCI spec mandates that newly brought up CPUs start 1349def656eSClaudio Fontana * in the highest exception level which exists and is enabled 1359def656eSClaudio Fontana * on the calling CPU. Since the QEMU PSCI implementation is 1369def656eSClaudio Fontana * acting as a "fake EL3" or "fake EL2" firmware, this for us 1379def656eSClaudio Fontana * means that we want to start at the highest NS exception level 1389def656eSClaudio Fontana * that we are providing to the guest. 1399def656eSClaudio Fontana * The execution mode should be that which is currently in use 1409def656eSClaudio Fontana * by the same exception level on the calling CPU. 1419def656eSClaudio Fontana * The CPU should be started with the context_id value 1429def656eSClaudio Fontana * in x0 (if AArch64) or r0 (if AArch32). 1439def656eSClaudio Fontana */ 1449def656eSClaudio Fontana int target_el = arm_feature(env, ARM_FEATURE_EL2) ? 2 : 1; 1459def656eSClaudio Fontana bool target_aarch64 = arm_el_is_aa64(env, target_el); 1469def656eSClaudio Fontana 1479def656eSClaudio Fontana mpidr = param[1]; 1489def656eSClaudio Fontana entry = param[2]; 1499def656eSClaudio Fontana context_id = param[3]; 1509def656eSClaudio Fontana ret = arm_set_cpu_on(mpidr, entry, context_id, 1519def656eSClaudio Fontana target_el, target_aarch64); 1529def656eSClaudio Fontana break; 1539def656eSClaudio Fontana } 1549def656eSClaudio Fontana case QEMU_PSCI_0_1_FN_CPU_OFF: 1559def656eSClaudio Fontana case QEMU_PSCI_0_2_FN_CPU_OFF: 1569def656eSClaudio Fontana goto cpu_off; 1579def656eSClaudio Fontana case QEMU_PSCI_0_1_FN_CPU_SUSPEND: 1589def656eSClaudio Fontana case QEMU_PSCI_0_2_FN_CPU_SUSPEND: 1599def656eSClaudio Fontana case QEMU_PSCI_0_2_FN64_CPU_SUSPEND: 1609def656eSClaudio Fontana /* Affinity levels are not supported in QEMU */ 1619def656eSClaudio Fontana if (param[1] & 0xfffe0000) { 1629def656eSClaudio Fontana ret = QEMU_PSCI_RET_INVALID_PARAMS; 1639def656eSClaudio Fontana break; 1649def656eSClaudio Fontana } 1659def656eSClaudio Fontana /* Powerdown is not supported, we always go into WFI */ 1669def656eSClaudio Fontana if (is_a64(env)) { 1679def656eSClaudio Fontana env->xregs[0] = 0; 1689def656eSClaudio Fontana } else { 1699def656eSClaudio Fontana env->regs[0] = 0; 1709def656eSClaudio Fontana } 1719def656eSClaudio Fontana helper_wfi(env, 4); 1729def656eSClaudio Fontana break; 1739def656eSClaudio Fontana case QEMU_PSCI_1_0_FN_PSCI_FEATURES: 1749def656eSClaudio Fontana switch (param[1]) { 1759def656eSClaudio Fontana case QEMU_PSCI_0_2_FN_PSCI_VERSION: 1769def656eSClaudio Fontana case QEMU_PSCI_0_2_FN_MIGRATE_INFO_TYPE: 1779def656eSClaudio Fontana case QEMU_PSCI_0_2_FN_AFFINITY_INFO: 1789def656eSClaudio Fontana case QEMU_PSCI_0_2_FN64_AFFINITY_INFO: 1799def656eSClaudio Fontana case QEMU_PSCI_0_2_FN_SYSTEM_RESET: 1809def656eSClaudio Fontana case QEMU_PSCI_0_2_FN_SYSTEM_OFF: 1819def656eSClaudio Fontana case QEMU_PSCI_0_1_FN_CPU_ON: 1829def656eSClaudio Fontana case QEMU_PSCI_0_2_FN_CPU_ON: 1839def656eSClaudio Fontana case QEMU_PSCI_0_2_FN64_CPU_ON: 1849def656eSClaudio Fontana case QEMU_PSCI_0_1_FN_CPU_OFF: 1859def656eSClaudio Fontana case QEMU_PSCI_0_2_FN_CPU_OFF: 1869def656eSClaudio Fontana case QEMU_PSCI_0_1_FN_CPU_SUSPEND: 1879def656eSClaudio Fontana case QEMU_PSCI_0_2_FN_CPU_SUSPEND: 1889def656eSClaudio Fontana case QEMU_PSCI_0_2_FN64_CPU_SUSPEND: 1899def656eSClaudio Fontana case QEMU_PSCI_1_0_FN_PSCI_FEATURES: 1909def656eSClaudio Fontana if (!(param[1] & QEMU_PSCI_0_2_64BIT) || is_a64(env)) { 1919def656eSClaudio Fontana ret = 0; 1929def656eSClaudio Fontana break; 1939def656eSClaudio Fontana } 1949def656eSClaudio Fontana /* fallthrough */ 1959def656eSClaudio Fontana case QEMU_PSCI_0_1_FN_MIGRATE: 1969def656eSClaudio Fontana case QEMU_PSCI_0_2_FN_MIGRATE: 1979def656eSClaudio Fontana default: 1989def656eSClaudio Fontana ret = QEMU_PSCI_RET_NOT_SUPPORTED; 1999def656eSClaudio Fontana break; 2009def656eSClaudio Fontana } 2019def656eSClaudio Fontana break; 2029def656eSClaudio Fontana case QEMU_PSCI_0_1_FN_MIGRATE: 2039def656eSClaudio Fontana case QEMU_PSCI_0_2_FN_MIGRATE: 2049def656eSClaudio Fontana default: 2059def656eSClaudio Fontana ret = QEMU_PSCI_RET_NOT_SUPPORTED; 2069def656eSClaudio Fontana break; 2079def656eSClaudio Fontana } 2089def656eSClaudio Fontana 2099def656eSClaudio Fontana err: 2109def656eSClaudio Fontana if (is_a64(env)) { 2119def656eSClaudio Fontana env->xregs[0] = ret; 2129def656eSClaudio Fontana } else { 2139def656eSClaudio Fontana env->regs[0] = ret; 2149def656eSClaudio Fontana } 2159def656eSClaudio Fontana return; 2169def656eSClaudio Fontana 2179def656eSClaudio Fontana cpu_off: 218*c4380f7bSRichard Henderson ret = arm_set_cpu_off(arm_cpu_mp_affinity(cpu)); 2199def656eSClaudio Fontana /* notreached */ 2209def656eSClaudio Fontana /* sanity check in case something failed */ 2219def656eSClaudio Fontana assert(ret == QEMU_ARM_POWERCTL_RET_SUCCESS); 2229def656eSClaudio Fontana } 223