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" 27*e2d8cf9bSPhilippe Mathieu-Daudé #include "target/arm/multiprocessing.h" 289def656eSClaudio Fontana 299def656eSClaudio Fontana bool arm_is_psci_call(ARMCPU *cpu, int excp_type) 309def656eSClaudio Fontana { 319def656eSClaudio Fontana /* 329def656eSClaudio Fontana * Return true if the exception type matches the configured PSCI conduit. 339def656eSClaudio Fontana * This is called before the SMC/HVC instruction is executed, to decide 349def656eSClaudio Fontana * whether we should treat it as a PSCI call or with the architecturally 359def656eSClaudio Fontana * defined behaviour for an SMC or HVC (which might be UNDEF or trap 369def656eSClaudio Fontana * to EL2 or to EL3). 379def656eSClaudio Fontana */ 389def656eSClaudio Fontana 399def656eSClaudio Fontana switch (excp_type) { 409def656eSClaudio Fontana case EXCP_HVC: 419def656eSClaudio Fontana if (cpu->psci_conduit != QEMU_PSCI_CONDUIT_HVC) { 429def656eSClaudio Fontana return false; 439def656eSClaudio Fontana } 449def656eSClaudio Fontana break; 459def656eSClaudio Fontana case EXCP_SMC: 469def656eSClaudio Fontana if (cpu->psci_conduit != QEMU_PSCI_CONDUIT_SMC) { 479def656eSClaudio Fontana return false; 489def656eSClaudio Fontana } 499def656eSClaudio Fontana break; 509def656eSClaudio Fontana default: 519def656eSClaudio Fontana return false; 529def656eSClaudio Fontana } 539def656eSClaudio Fontana 549def656eSClaudio Fontana return true; 559def656eSClaudio Fontana } 569def656eSClaudio Fontana 579def656eSClaudio Fontana void arm_handle_psci_call(ARMCPU *cpu) 589def656eSClaudio Fontana { 599def656eSClaudio Fontana /* 609def656eSClaudio Fontana * This function partially implements the logic for dispatching Power State 619def656eSClaudio Fontana * Coordination Interface (PSCI) calls (as described in ARM DEN 0022D.b), 629def656eSClaudio Fontana * to the extent required for bringing up and taking down secondary cores, 639def656eSClaudio Fontana * and for handling reset and poweroff requests. 649def656eSClaudio Fontana * Additional information about the calling convention used is available in 659def656eSClaudio Fontana * the document 'SMC Calling Convention' (ARM DEN 0028) 669def656eSClaudio Fontana */ 679def656eSClaudio Fontana CPUARMState *env = &cpu->env; 689def656eSClaudio Fontana uint64_t param[4]; 699def656eSClaudio Fontana uint64_t context_id, mpidr; 709def656eSClaudio Fontana target_ulong entry; 719def656eSClaudio Fontana int32_t ret = 0; 729def656eSClaudio Fontana int i; 739def656eSClaudio Fontana 749def656eSClaudio Fontana for (i = 0; i < 4; i++) { 759def656eSClaudio Fontana /* 769def656eSClaudio Fontana * All PSCI functions take explicit 32-bit or native int sized 779def656eSClaudio Fontana * arguments so we can simply zero-extend all arguments regardless 789def656eSClaudio Fontana * of which exact function we are about to call. 799def656eSClaudio Fontana */ 809def656eSClaudio Fontana param[i] = is_a64(env) ? env->xregs[i] : env->regs[i]; 819def656eSClaudio Fontana } 829def656eSClaudio Fontana 839def656eSClaudio Fontana if ((param[0] & QEMU_PSCI_0_2_64BIT) && !is_a64(env)) { 849def656eSClaudio Fontana ret = QEMU_PSCI_RET_NOT_SUPPORTED; 859def656eSClaudio Fontana goto err; 869def656eSClaudio Fontana } 879def656eSClaudio Fontana 889def656eSClaudio Fontana switch (param[0]) { 899def656eSClaudio Fontana CPUState *target_cpu_state; 909def656eSClaudio Fontana ARMCPU *target_cpu; 919def656eSClaudio Fontana 929def656eSClaudio Fontana case QEMU_PSCI_0_2_FN_PSCI_VERSION: 939def656eSClaudio Fontana ret = QEMU_PSCI_VERSION_1_1; 949def656eSClaudio Fontana break; 959def656eSClaudio Fontana case QEMU_PSCI_0_2_FN_MIGRATE_INFO_TYPE: 969def656eSClaudio Fontana ret = QEMU_PSCI_0_2_RET_TOS_MIGRATION_NOT_REQUIRED; /* No trusted OS */ 979def656eSClaudio Fontana break; 989def656eSClaudio Fontana case QEMU_PSCI_0_2_FN_AFFINITY_INFO: 999def656eSClaudio Fontana case QEMU_PSCI_0_2_FN64_AFFINITY_INFO: 1009def656eSClaudio Fontana mpidr = param[1]; 1019def656eSClaudio Fontana 1029def656eSClaudio Fontana switch (param[2]) { 1039def656eSClaudio Fontana case 0: 1049def656eSClaudio Fontana target_cpu_state = arm_get_cpu_by_id(mpidr); 1059def656eSClaudio Fontana if (!target_cpu_state) { 1069def656eSClaudio Fontana ret = QEMU_PSCI_RET_INVALID_PARAMS; 1079def656eSClaudio Fontana break; 1089def656eSClaudio Fontana } 1099def656eSClaudio Fontana target_cpu = ARM_CPU(target_cpu_state); 1109def656eSClaudio Fontana 111195801d7SStefan Hajnoczi g_assert(bql_locked()); 1129def656eSClaudio Fontana ret = target_cpu->power_state; 1139def656eSClaudio Fontana break; 1149def656eSClaudio Fontana default: 1159def656eSClaudio Fontana /* Everything above affinity level 0 is always on. */ 1169def656eSClaudio Fontana ret = 0; 1179def656eSClaudio Fontana } 1189def656eSClaudio Fontana break; 1199def656eSClaudio Fontana case QEMU_PSCI_0_2_FN_SYSTEM_RESET: 1209def656eSClaudio Fontana qemu_system_reset_request(SHUTDOWN_CAUSE_GUEST_RESET); 1219def656eSClaudio Fontana /* QEMU reset and shutdown are async requests, but PSCI 1229def656eSClaudio Fontana * mandates that we never return from the reset/shutdown 1239def656eSClaudio Fontana * call, so power the CPU off now so it doesn't execute 1249def656eSClaudio Fontana * anything further. 1259def656eSClaudio Fontana */ 1269def656eSClaudio Fontana goto cpu_off; 1279def656eSClaudio Fontana case QEMU_PSCI_0_2_FN_SYSTEM_OFF: 1289def656eSClaudio Fontana qemu_system_shutdown_request(SHUTDOWN_CAUSE_GUEST_SHUTDOWN); 1299def656eSClaudio Fontana goto cpu_off; 1309def656eSClaudio Fontana case QEMU_PSCI_0_1_FN_CPU_ON: 1319def656eSClaudio Fontana case QEMU_PSCI_0_2_FN_CPU_ON: 1329def656eSClaudio Fontana case QEMU_PSCI_0_2_FN64_CPU_ON: 1339def656eSClaudio Fontana { 1349def656eSClaudio Fontana /* The PSCI spec mandates that newly brought up CPUs start 1359def656eSClaudio Fontana * in the highest exception level which exists and is enabled 1369def656eSClaudio Fontana * on the calling CPU. Since the QEMU PSCI implementation is 1379def656eSClaudio Fontana * acting as a "fake EL3" or "fake EL2" firmware, this for us 1389def656eSClaudio Fontana * means that we want to start at the highest NS exception level 1399def656eSClaudio Fontana * that we are providing to the guest. 1409def656eSClaudio Fontana * The execution mode should be that which is currently in use 1419def656eSClaudio Fontana * by the same exception level on the calling CPU. 1429def656eSClaudio Fontana * The CPU should be started with the context_id value 1439def656eSClaudio Fontana * in x0 (if AArch64) or r0 (if AArch32). 1449def656eSClaudio Fontana */ 1459def656eSClaudio Fontana int target_el = arm_feature(env, ARM_FEATURE_EL2) ? 2 : 1; 1469def656eSClaudio Fontana bool target_aarch64 = arm_el_is_aa64(env, target_el); 1479def656eSClaudio Fontana 1489def656eSClaudio Fontana mpidr = param[1]; 1499def656eSClaudio Fontana entry = param[2]; 1509def656eSClaudio Fontana context_id = param[3]; 1519def656eSClaudio Fontana ret = arm_set_cpu_on(mpidr, entry, context_id, 1529def656eSClaudio Fontana target_el, target_aarch64); 1539def656eSClaudio Fontana break; 1549def656eSClaudio Fontana } 1559def656eSClaudio Fontana case QEMU_PSCI_0_1_FN_CPU_OFF: 1569def656eSClaudio Fontana case QEMU_PSCI_0_2_FN_CPU_OFF: 1579def656eSClaudio Fontana goto cpu_off; 1589def656eSClaudio Fontana case QEMU_PSCI_0_1_FN_CPU_SUSPEND: 1599def656eSClaudio Fontana case QEMU_PSCI_0_2_FN_CPU_SUSPEND: 1609def656eSClaudio Fontana case QEMU_PSCI_0_2_FN64_CPU_SUSPEND: 1619def656eSClaudio Fontana /* Affinity levels are not supported in QEMU */ 1629def656eSClaudio Fontana if (param[1] & 0xfffe0000) { 1639def656eSClaudio Fontana ret = QEMU_PSCI_RET_INVALID_PARAMS; 1649def656eSClaudio Fontana break; 1659def656eSClaudio Fontana } 1669def656eSClaudio Fontana /* Powerdown is not supported, we always go into WFI */ 1679def656eSClaudio Fontana if (is_a64(env)) { 1689def656eSClaudio Fontana env->xregs[0] = 0; 1699def656eSClaudio Fontana } else { 1709def656eSClaudio Fontana env->regs[0] = 0; 1719def656eSClaudio Fontana } 1729def656eSClaudio Fontana helper_wfi(env, 4); 1739def656eSClaudio Fontana break; 1749def656eSClaudio Fontana case QEMU_PSCI_1_0_FN_PSCI_FEATURES: 1759def656eSClaudio Fontana switch (param[1]) { 1769def656eSClaudio Fontana case QEMU_PSCI_0_2_FN_PSCI_VERSION: 1779def656eSClaudio Fontana case QEMU_PSCI_0_2_FN_MIGRATE_INFO_TYPE: 1789def656eSClaudio Fontana case QEMU_PSCI_0_2_FN_AFFINITY_INFO: 1799def656eSClaudio Fontana case QEMU_PSCI_0_2_FN64_AFFINITY_INFO: 1809def656eSClaudio Fontana case QEMU_PSCI_0_2_FN_SYSTEM_RESET: 1819def656eSClaudio Fontana case QEMU_PSCI_0_2_FN_SYSTEM_OFF: 1829def656eSClaudio Fontana case QEMU_PSCI_0_1_FN_CPU_ON: 1839def656eSClaudio Fontana case QEMU_PSCI_0_2_FN_CPU_ON: 1849def656eSClaudio Fontana case QEMU_PSCI_0_2_FN64_CPU_ON: 1859def656eSClaudio Fontana case QEMU_PSCI_0_1_FN_CPU_OFF: 1869def656eSClaudio Fontana case QEMU_PSCI_0_2_FN_CPU_OFF: 1879def656eSClaudio Fontana case QEMU_PSCI_0_1_FN_CPU_SUSPEND: 1889def656eSClaudio Fontana case QEMU_PSCI_0_2_FN_CPU_SUSPEND: 1899def656eSClaudio Fontana case QEMU_PSCI_0_2_FN64_CPU_SUSPEND: 1909def656eSClaudio Fontana case QEMU_PSCI_1_0_FN_PSCI_FEATURES: 1919def656eSClaudio Fontana if (!(param[1] & QEMU_PSCI_0_2_64BIT) || is_a64(env)) { 1929def656eSClaudio Fontana ret = 0; 1939def656eSClaudio Fontana break; 1949def656eSClaudio Fontana } 1959def656eSClaudio Fontana /* fallthrough */ 1969def656eSClaudio Fontana case QEMU_PSCI_0_1_FN_MIGRATE: 1979def656eSClaudio Fontana case QEMU_PSCI_0_2_FN_MIGRATE: 1989def656eSClaudio Fontana default: 1999def656eSClaudio Fontana ret = QEMU_PSCI_RET_NOT_SUPPORTED; 2009def656eSClaudio Fontana break; 2019def656eSClaudio Fontana } 2029def656eSClaudio Fontana break; 2039def656eSClaudio Fontana case QEMU_PSCI_0_1_FN_MIGRATE: 2049def656eSClaudio Fontana case QEMU_PSCI_0_2_FN_MIGRATE: 2059def656eSClaudio Fontana default: 2069def656eSClaudio Fontana ret = QEMU_PSCI_RET_NOT_SUPPORTED; 2079def656eSClaudio Fontana break; 2089def656eSClaudio Fontana } 2099def656eSClaudio Fontana 2109def656eSClaudio Fontana err: 2119def656eSClaudio Fontana if (is_a64(env)) { 2129def656eSClaudio Fontana env->xregs[0] = ret; 2139def656eSClaudio Fontana } else { 2149def656eSClaudio Fontana env->regs[0] = ret; 2159def656eSClaudio Fontana } 2169def656eSClaudio Fontana return; 2179def656eSClaudio Fontana 2189def656eSClaudio Fontana cpu_off: 219c4380f7bSRichard Henderson ret = arm_set_cpu_off(arm_cpu_mp_affinity(cpu)); 2209def656eSClaudio Fontana /* notreached */ 2219def656eSClaudio Fontana /* sanity check in case something failed */ 2229def656eSClaudio Fontana assert(ret == QEMU_ARM_POWERCTL_RET_SUCCESS); 2239def656eSClaudio Fontana } 224