@@ -332,6 +332,12 @@ int sbi_hsm_hart_start(struct sbi_scratch *scratch,
if (!hsm_start_ticket_acquire(hdata))
return SBI_EINVAL;
+ hstate = atomic_read(&hdata->state);
+ if (hstate != SBI_HSM_STATE_STOPPED) {
+ rc = hstate == SBI_HSM_STATE_STARTED ? SBI_EALREADY : SBI_EINVAL;
+ goto err;
+ }
+
init_count = sbi_init_count(hartindex);
entry_count = sbi_entry_count(hartindex);
@@ -346,17 +352,8 @@ int sbi_hsm_hart_start(struct sbi_scratch *scratch,
*/
hstate = atomic_cmpxchg(&hdata->state, SBI_HSM_STATE_STOPPED,
SBI_HSM_STATE_START_PENDING);
- if (hstate == SBI_HSM_STATE_STARTED) {
- rc = SBI_EALREADY;
- goto err;
- }
-
- /**
- * if a hart is already transition to start or stop, another start call
- * is considered as invalid request.
- */
if (hstate != SBI_HSM_STATE_STOPPED) {
- rc = SBI_EINVAL;
+ rc = hstate == SBI_HSM_STATE_STARTED ? SBI_EALREADY : SBI_EINVAL;
goto err;
}
sbi_hsm_hart_start() acquires the target hart's start ticket, then writes next_arg1, next_addr and next_mode before checking whether the target is stopped. A start request for a non-retentively suspended hart is rejected, but those writes have already replaced the resume context consumed by sbi_hsm_hart_resume_finish(). The same ordering also lets other rejected start requests modify target scratch state. Check the state immediately after acquiring the start ticket and before updating the scratch context. The ticket serializes start requests for the target; retain the cmpxchg as the publication barrier and defensive state check. Fixes: e8e9ed3790fe ("lib: sbi: Set the state of a hart to START_PENDING after the hart is ready") Signed-off-by: Pengpeng Hou <pengpeng@iscas.ac.cn> --- lib/sbi/sbi_hsm.c | 17 +++++++---------- 1 file changed, 7 insertions(+), 10 deletions(-)