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