qemu with hax to log dma reads & writes jcs.org/2018/11/12/vfio

target/arm/arm-powerctl: Add new arm_set_cpu_on_and_reset()

Currently the Arm arm-powerctl.h APIs allow:
* arm_set_cpu_on(), which powers on a CPU and sets its
initial PC and other startup state
* arm_reset_cpu(), which resets a CPU which is already on
(and fails if the CPU is powered off)

but there is no way to say "power on a CPU as if it had
just come out of reset and don't do anything else to it".

Add a new function arm_set_cpu_on_and_reset(), which does this.

Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
Reviewed-by: Richard Henderson <richard.henderson@linaro.org>
Message-id: 20190219125808.25174-5-peter.maydell@linaro.org

+72
+56
target/arm/arm-powerctl.c
··· 228 228 return QEMU_ARM_POWERCTL_RET_SUCCESS; 229 229 } 230 230 231 + static void arm_set_cpu_on_and_reset_async_work(CPUState *target_cpu_state, 232 + run_on_cpu_data data) 233 + { 234 + ARMCPU *target_cpu = ARM_CPU(target_cpu_state); 235 + 236 + /* Initialize the cpu we are turning on */ 237 + cpu_reset(target_cpu_state); 238 + target_cpu_state->halted = 0; 239 + 240 + /* Finally set the power status */ 241 + assert(qemu_mutex_iothread_locked()); 242 + target_cpu->power_state = PSCI_ON; 243 + } 244 + 245 + int arm_set_cpu_on_and_reset(uint64_t cpuid) 246 + { 247 + CPUState *target_cpu_state; 248 + ARMCPU *target_cpu; 249 + 250 + assert(qemu_mutex_iothread_locked()); 251 + 252 + /* Retrieve the cpu we are powering up */ 253 + target_cpu_state = arm_get_cpu_by_id(cpuid); 254 + if (!target_cpu_state) { 255 + /* The cpu was not found */ 256 + return QEMU_ARM_POWERCTL_INVALID_PARAM; 257 + } 258 + 259 + target_cpu = ARM_CPU(target_cpu_state); 260 + if (target_cpu->power_state == PSCI_ON) { 261 + qemu_log_mask(LOG_GUEST_ERROR, 262 + "[ARM]%s: CPU %" PRId64 " is already on\n", 263 + __func__, cpuid); 264 + return QEMU_ARM_POWERCTL_ALREADY_ON; 265 + } 266 + 267 + /* 268 + * If another CPU has powered the target on we are in the state 269 + * ON_PENDING and additional attempts to power on the CPU should 270 + * fail (see 6.6 Implementation CPU_ON/CPU_OFF races in the PSCI 271 + * spec) 272 + */ 273 + if (target_cpu->power_state == PSCI_ON_PENDING) { 274 + qemu_log_mask(LOG_GUEST_ERROR, 275 + "[ARM]%s: CPU %" PRId64 " is already powering on\n", 276 + __func__, cpuid); 277 + return QEMU_ARM_POWERCTL_ON_PENDING; 278 + } 279 + 280 + async_run_on_cpu(target_cpu_state, arm_set_cpu_on_and_reset_async_work, 281 + RUN_ON_CPU_NULL); 282 + 283 + /* We are good to go */ 284 + return QEMU_ARM_POWERCTL_RET_SUCCESS; 285 + } 286 + 231 287 static void arm_set_cpu_off_async_work(CPUState *target_cpu_state, 232 288 run_on_cpu_data data) 233 289 {
+16
target/arm/arm-powerctl.h
··· 74 74 */ 75 75 int arm_reset_cpu(uint64_t cpuid); 76 76 77 + /* 78 + * arm_set_cpu_on_and_reset: 79 + * @cpuid: the id of the CPU we want to star 80 + * 81 + * Start the cpu designated by @cpuid and put it through its normal 82 + * CPU reset process. The CPU will start in the way it is architected 83 + * to start after a power-on reset. 84 + * 85 + * Returns: QEMU_ARM_POWERCTL_RET_SUCCESS on success. 86 + * QEMU_ARM_POWERCTL_INVALID_PARAM if there is no CPU with that ID. 87 + * QEMU_ARM_POWERCTL_ALREADY_ON if the CPU is already on. 88 + * QEMU_ARM_POWERCTL_ON_PENDING if the CPU is already partway through 89 + * powering on. 90 + */ 91 + int arm_set_cpu_on_and_reset(uint64_t cpuid); 92 + 77 93 #endif