1 /* 2 * QEMU support -- ARM Power Control specific functions. 3 * 4 * Copyright (c) 2016 Jean-Christophe Dubois 5 * 6 * This work is licensed under the terms of the GNU GPL, version 2 or later. 7 * See the COPYING file in the top-level directory. 8 * 9 */ 10 11 #include "qemu/osdep.h" 12 #include "cpu.h" 13 #include "cpu-qom.h" 14 #include "internals.h" 15 #include "arm-powerctl.h" 16 #include "qemu/log.h" 17 #include "qemu/main-loop.h" 18 19 #ifndef DEBUG_ARM_POWERCTL 20 #define DEBUG_ARM_POWERCTL 0 21 #endif 22 23 #define DPRINTF(fmt, args...) \ 24 do { \ 25 if (DEBUG_ARM_POWERCTL) { \ 26 fprintf(stderr, "[ARM]%s: " fmt , __func__, ##args); \ 27 } \ 28 } while (0) 29 30 CPUState *arm_get_cpu_by_id(uint64_t id) 31 { 32 CPUState *cpu; 33 34 DPRINTF("cpu %" PRId64 "\n", id); 35 36 CPU_FOREACH(cpu) { 37 ARMCPU *armcpu = ARM_CPU(cpu); 38 39 if (armcpu->mp_affinity == id) { 40 return cpu; 41 } 42 } 43 44 qemu_log_mask(LOG_GUEST_ERROR, 45 "[ARM]%s: Requesting unknown CPU %" PRId64 "\n", 46 __func__, id); 47 48 return NULL; 49 } 50 51 struct CpuOnInfo { 52 uint64_t entry; 53 uint64_t context_id; 54 uint32_t target_el; 55 bool target_aa64; 56 }; 57 58 59 static void arm_set_cpu_on_async_work(CPUState *target_cpu_state, 60 run_on_cpu_data data) 61 { 62 ARMCPU *target_cpu = ARM_CPU(target_cpu_state); 63 struct CpuOnInfo *info = (struct CpuOnInfo *) data.host_ptr; 64 65 /* Initialize the cpu we are turning on */ 66 cpu_reset(target_cpu_state); 67 target_cpu_state->halted = 0; 68 69 if (info->target_aa64) { 70 if ((info->target_el < 3) && arm_feature(&target_cpu->env, 71 ARM_FEATURE_EL3)) { 72 /* 73 * As target mode is AArch64, we need to set lower 74 * exception level (the requested level 2) to AArch64 75 */ 76 target_cpu->env.cp15.scr_el3 |= SCR_RW; 77 } 78 79 if ((info->target_el < 2) && arm_feature(&target_cpu->env, 80 ARM_FEATURE_EL2)) { 81 /* 82 * As target mode is AArch64, we need to set lower 83 * exception level (the requested level 1) to AArch64 84 */ 85 target_cpu->env.cp15.hcr_el2 |= HCR_RW; 86 } 87 88 target_cpu->env.pstate = aarch64_pstate_mode(info->target_el, true); 89 } else { 90 /* We are requested to boot in AArch32 mode */ 91 static const uint32_t mode_for_el[] = { 0, 92 ARM_CPU_MODE_SVC, 93 ARM_CPU_MODE_HYP, 94 ARM_CPU_MODE_SVC }; 95 96 cpsr_write(&target_cpu->env, mode_for_el[info->target_el], CPSR_M, 97 CPSRWriteRaw); 98 } 99 100 if (info->target_el == 3) { 101 /* Processor is in secure mode */ 102 target_cpu->env.cp15.scr_el3 &= ~SCR_NS; 103 } else { 104 /* Processor is not in secure mode */ 105 target_cpu->env.cp15.scr_el3 |= SCR_NS; 106 107 /* 108 * If QEMU is providing the equivalent of EL3 firmware, then we need 109 * to make sure a CPU targeting EL2 comes out of reset with a 110 * functional HVC insn. 111 */ 112 if (arm_feature(&target_cpu->env, ARM_FEATURE_EL3) 113 && info->target_el == 2) { 114 target_cpu->env.cp15.scr_el3 |= SCR_HCE; 115 } 116 } 117 118 /* We check if the started CPU is now at the correct level */ 119 assert(info->target_el == arm_current_el(&target_cpu->env)); 120 121 if (info->target_aa64) { 122 target_cpu->env.xregs[0] = info->context_id; 123 target_cpu->env.thumb = false; 124 } else { 125 target_cpu->env.regs[0] = info->context_id; 126 target_cpu->env.thumb = info->entry & 1; 127 info->entry &= 0xfffffffe; 128 } 129 130 /* Start the new CPU at the requested address */ 131 cpu_set_pc(target_cpu_state, info->entry); 132 133 g_free(info); 134 135 /* Finally set the power status */ 136 assert(qemu_mutex_iothread_locked()); 137 target_cpu->power_state = PSCI_ON; 138 } 139 140 int arm_set_cpu_on(uint64_t cpuid, uint64_t entry, uint64_t context_id, 141 uint32_t target_el, bool target_aa64) 142 { 143 CPUState *target_cpu_state; 144 ARMCPU *target_cpu; 145 struct CpuOnInfo *info; 146 147 assert(qemu_mutex_iothread_locked()); 148 149 DPRINTF("cpu %" PRId64 " (EL %d, %s) @ 0x%" PRIx64 " with R0 = 0x%" PRIx64 150 "\n", cpuid, target_el, target_aa64 ? "aarch64" : "aarch32", entry, 151 context_id); 152 153 /* requested EL level need to be in the 1 to 3 range */ 154 assert((target_el > 0) && (target_el < 4)); 155 156 if (target_aa64 && (entry & 3)) { 157 /* 158 * if we are booting in AArch64 mode then "entry" needs to be 4 bytes 159 * aligned. 160 */ 161 return QEMU_ARM_POWERCTL_INVALID_PARAM; 162 } 163 164 /* Retrieve the cpu we are powering up */ 165 target_cpu_state = arm_get_cpu_by_id(cpuid); 166 if (!target_cpu_state) { 167 /* The cpu was not found */ 168 return QEMU_ARM_POWERCTL_INVALID_PARAM; 169 } 170 171 target_cpu = ARM_CPU(target_cpu_state); 172 if (target_cpu->power_state == PSCI_ON) { 173 qemu_log_mask(LOG_GUEST_ERROR, 174 "[ARM]%s: CPU %" PRId64 " is already on\n", 175 __func__, cpuid); 176 return QEMU_ARM_POWERCTL_ALREADY_ON; 177 } 178 179 /* 180 * The newly brought CPU is requested to enter the exception level 181 * "target_el" and be in the requested mode (AArch64 or AArch32). 182 */ 183 184 if (((target_el == 3) && !arm_feature(&target_cpu->env, ARM_FEATURE_EL3)) || 185 ((target_el == 2) && !arm_feature(&target_cpu->env, ARM_FEATURE_EL2))) { 186 /* 187 * The CPU does not support requested level 188 */ 189 return QEMU_ARM_POWERCTL_INVALID_PARAM; 190 } 191 192 if (!target_aa64 && arm_feature(&target_cpu->env, ARM_FEATURE_AARCH64)) { 193 /* 194 * For now we don't support booting an AArch64 CPU in AArch32 mode 195 * TODO: We should add this support later 196 */ 197 qemu_log_mask(LOG_UNIMP, 198 "[ARM]%s: Starting AArch64 CPU %" PRId64 199 " in AArch32 mode is not supported yet\n", 200 __func__, cpuid); 201 return QEMU_ARM_POWERCTL_INVALID_PARAM; 202 } 203 204 /* 205 * If another CPU has powered the target on we are in the state 206 * ON_PENDING and additional attempts to power on the CPU should 207 * fail (see 6.6 Implementation CPU_ON/CPU_OFF races in the PSCI 208 * spec) 209 */ 210 if (target_cpu->power_state == PSCI_ON_PENDING) { 211 qemu_log_mask(LOG_GUEST_ERROR, 212 "[ARM]%s: CPU %" PRId64 " is already powering on\n", 213 __func__, cpuid); 214 return QEMU_ARM_POWERCTL_ON_PENDING; 215 } 216 217 /* To avoid racing with a CPU we are just kicking off we do the 218 * final bit of preparation for the work in the target CPUs 219 * context. 220 */ 221 info = g_new(struct CpuOnInfo, 1); 222 info->entry = entry; 223 info->context_id = context_id; 224 info->target_el = target_el; 225 info->target_aa64 = target_aa64; 226 227 async_run_on_cpu(target_cpu_state, arm_set_cpu_on_async_work, 228 RUN_ON_CPU_HOST_PTR(info)); 229 230 /* We are good to go */ 231 return QEMU_ARM_POWERCTL_RET_SUCCESS; 232 } 233 234 static void arm_set_cpu_off_async_work(CPUState *target_cpu_state, 235 run_on_cpu_data data) 236 { 237 ARMCPU *target_cpu = ARM_CPU(target_cpu_state); 238 239 assert(qemu_mutex_iothread_locked()); 240 target_cpu->power_state = PSCI_OFF; 241 target_cpu_state->halted = 1; 242 target_cpu_state->exception_index = EXCP_HLT; 243 } 244 245 int arm_set_cpu_off(uint64_t cpuid) 246 { 247 CPUState *target_cpu_state; 248 ARMCPU *target_cpu; 249 250 assert(qemu_mutex_iothread_locked()); 251 252 DPRINTF("cpu %" PRId64 "\n", cpuid); 253 254 /* change to the cpu we are powering up */ 255 target_cpu_state = arm_get_cpu_by_id(cpuid); 256 if (!target_cpu_state) { 257 return QEMU_ARM_POWERCTL_INVALID_PARAM; 258 } 259 target_cpu = ARM_CPU(target_cpu_state); 260 if (target_cpu->power_state == PSCI_OFF) { 261 qemu_log_mask(LOG_GUEST_ERROR, 262 "[ARM]%s: CPU %" PRId64 " is already off\n", 263 __func__, cpuid); 264 return QEMU_ARM_POWERCTL_IS_OFF; 265 } 266 267 /* Queue work to run under the target vCPUs context */ 268 async_run_on_cpu(target_cpu_state, arm_set_cpu_off_async_work, 269 RUN_ON_CPU_NULL); 270 271 return QEMU_ARM_POWERCTL_RET_SUCCESS; 272 } 273 274 static void arm_reset_cpu_async_work(CPUState *target_cpu_state, 275 run_on_cpu_data data) 276 { 277 /* Reset the cpu */ 278 cpu_reset(target_cpu_state); 279 } 280 281 int arm_reset_cpu(uint64_t cpuid) 282 { 283 CPUState *target_cpu_state; 284 ARMCPU *target_cpu; 285 286 assert(qemu_mutex_iothread_locked()); 287 288 DPRINTF("cpu %" PRId64 "\n", cpuid); 289 290 /* change to the cpu we are resetting */ 291 target_cpu_state = arm_get_cpu_by_id(cpuid); 292 if (!target_cpu_state) { 293 return QEMU_ARM_POWERCTL_INVALID_PARAM; 294 } 295 target_cpu = ARM_CPU(target_cpu_state); 296 297 if (target_cpu->power_state == PSCI_OFF) { 298 qemu_log_mask(LOG_GUEST_ERROR, 299 "[ARM]%s: CPU %" PRId64 " is off\n", 300 __func__, cpuid); 301 return QEMU_ARM_POWERCTL_IS_OFF; 302 } 303 304 /* Queue work to run under the target vCPUs context */ 305 async_run_on_cpu(target_cpu_state, arm_reset_cpu_async_work, 306 RUN_ON_CPU_NULL); 307 308 return QEMU_ARM_POWERCTL_RET_SUCCESS; 309 } 310