target/arm/whpx: fix whpx-arm post-reset CPU state

Reset should leave CPU 0 running, and should leave all other CPUs
suspended. Instead, no CPUs are suspended and CPUs may be left in
low-power states.

Fix by updating state in whpx_set_registers WHPX_LEVEL_RESET_STATE.

Signed-off-by: Doug Cook <dcook@microsoft.com>
Reviewed-by: Mohamed Mediouni <mohamed@unpredictable.fr>
Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
(cherry picked from commit 57197bf183)
Signed-off-by: Michael Tokarev <mjt@tls.msk.ru>
This commit is contained in:
Doug Cook
2026-09-14 09:41:04 +01:00
committed by Michael Tokarev
parent 4908ac02c7
commit a4f83debce

View File

@@ -617,6 +617,37 @@ void whpx_set_registers(CPUState *cpu, WHPXStateLevel level)
whpx_set_reg(cpu, whpx_sreg_match[i].reg, val);
}
}
if (level == WHPX_LEVEL_RESET_STATE) {
/*
* WHPX keeps the "vCPU is in a low-power wait" state (entered when the
* guest executes WFI/WFE) in WHvRegisterInternalActivityState, and that
* state is not affected by writing the architectural registers above.
* If the guest happened to be idle when the reset was requested, the
* vCPU would stay suspended forever.
*
* StartupSuspend is the bit WHP uses to hold a vCPU that has not been
* started yet, and it is how secondary vCPUs are parked until PSCI
* CPU_ON releases them.
*/
WHV_REGISTER_NAME name = WHvRegisterInternalActivityState;
bool powered_off = arm_cpu->power_state == PSCI_OFF;
WHV_REGISTER_VALUE ia;
HRESULT hr;
clean_whv_register_value(&ia);
hr = whp_dispatch.WHvGetVirtualProcessorRegisters(
whpx_global.partition, cpu->cpu_index, &name, 1, &ia);
if (SUCCEEDED(hr) &&
(ia.InternalActivity.IdleSuspend ||
ia.InternalActivity.HaltSuspend ||
ia.InternalActivity.StartupSuspend != powered_off)) {
ia.InternalActivity.IdleSuspend = 0;
ia.InternalActivity.HaltSuspend = 0;
ia.InternalActivity.StartupSuspend = powered_off;
whpx_set_reg(cpu, WHvRegisterInternalActivityState, ia);
}
}
}
static uint32_t max_vcpu_index;