[PATCH 2/2] lib: sbi: serialize HSM hart_start ownership check with assignment lock
Huamao Wu
huamao.wu at linux.spacemit.com
Wed Aug 19 00:51:38 PDT 2026
sbi_hsm_hart_start() checks domain ownership, acquires the start
ticket, and transitions the hart to START_PENDING in three unlocked
steps. A concurrent domain assignment can reassign the hart
between the check and the state transition, causing HART_START to
proceed for a domain that no longer owns the target hart.
Hold domain_assignment_lock across the ownership check, ticket
acquisition, and STOPPED -> START_PENDING cmpxchg so that no
assignment can occur between check and commit. Release the lock
before hardware start or IPI dispatch.
Convert switch_to_next_domain_context() to use
sbi_domain_assign_hart() instead of its open-coded three-step
sequence, eliminating the same TOCTOU window on the context switch
path.
Signed-off-by: Huamao Wu <huamao.wu at linux.spacemit.com>
---
lib/sbi/sbi_domain_context.c | 13 ++-----------
lib/sbi/sbi_hsm.c | 15 ++++++++++++---
2 files changed, 14 insertions(+), 14 deletions(-)
diff --git a/lib/sbi/sbi_domain_context.c b/lib/sbi/sbi_domain_context.c
index 0861d541..f71dd94f 100644
--- a/lib/sbi/sbi_domain_context.c
+++ b/lib/sbi/sbi_domain_context.c
@@ -110,24 +110,15 @@ static int switch_to_next_domain_context(struct hart_context *ctx,
{
u32 hartindex = current_hartindex();
struct sbi_trap_context *trap_ctx;
- struct sbi_domain *current_dom, *target_dom;
+ struct sbi_domain *target_dom;
struct sbi_scratch *scratch = sbi_scratch_thishart_ptr();
if (!ctx || !dom_ctx || ctx == dom_ctx)
return SBI_EINVAL;
- current_dom = ctx->dom;
target_dom = dom_ctx->dom;
/* Assign current hart to target domain */
- spin_lock(¤t_dom->assigned_harts_lock);
- sbi_hartmask_clear_hartindex(hartindex, ¤t_dom->assigned_harts);
- spin_unlock(¤t_dom->assigned_harts_lock);
-
- sbi_update_hartindex_to_domain(hartindex, target_dom);
-
- spin_lock(&target_dom->assigned_harts_lock);
- sbi_hartmask_set_hartindex(hartindex, &target_dom->assigned_harts);
- spin_unlock(&target_dom->assigned_harts_lock);
+ sbi_domain_assign_hart(hartindex, target_dom);
/* Save current CSR context and restore target domain's CSR context */
ctx->sstatus = csr_swap(CSR_SSTATUS, dom_ctx->sstatus);
diff --git a/lib/sbi/sbi_hsm.c b/lib/sbi/sbi_hsm.c
index 0a355f9c..5293f995 100644
--- a/lib/sbi/sbi_hsm.c
+++ b/lib/sbi/sbi_hsm.c
@@ -318,8 +318,6 @@ int sbi_hsm_hart_start(struct sbi_scratch *scratch,
/* For now, we only allow start mode to be S-mode or U-mode. */
if (smode != PRV_S && smode != PRV_U)
return SBI_EINVAL;
- if (dom && !sbi_domain_is_assigned_hart(dom, hartindex))
- return SBI_EINVAL;
if (dom && !sbi_domain_check_addr(dom, saddr, smode,
SBI_DOMAIN_EXECUTE))
return SBI_EINVALID_ADDR;
@@ -329,8 +327,18 @@ int sbi_hsm_hart_start(struct sbi_scratch *scratch,
return SBI_EINVAL;
hdata = sbi_scratch_offset_ptr(rscratch, hart_data_offset);
- if (!hsm_start_ticket_acquire(hdata))
+
+ /* Serialize ownership validation with acceptance of this HART_START. */
+ sbi_domain_assignment_lock();
+ if (dom && !sbi_domain_check_hart_assignment_locked(dom, hartindex,
+ NULL)) {
+ sbi_domain_assignment_unlock();
return SBI_EINVAL;
+ }
+ if (!hsm_start_ticket_acquire(hdata)) {
+ sbi_domain_assignment_unlock();
+ return SBI_EINVAL;
+ }
init_count = sbi_init_count(hartindex);
entry_count = sbi_entry_count(hartindex);
@@ -346,6 +354,7 @@ int sbi_hsm_hart_start(struct sbi_scratch *scratch,
*/
hstate = atomic_cmpxchg(&hdata->state, SBI_HSM_STATE_STOPPED,
SBI_HSM_STATE_START_PENDING);
+ sbi_domain_assignment_unlock();
if (hstate == SBI_HSM_STATE_STARTED) {
rc = SBI_EALREADY;
goto err;
--
2.43.0
More information about the opensbi
mailing list