[PATCH 2/2] lib: sbi: serialize HSM hart_start ownership check with assignment lock
Huamao Wu <[email protected]>
| Newsgroups | org.infradead.lists.opensbi |
|---|---|
| Message-ID | <E62F6A70B52E7CF9+20260819075138.31535-3-huamao.wu@linux.spacemit.com> |
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 <[email protected]> --- 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 -- opensbi mailing list [email protected] http://lists.infradead.org/mailman/listinfo/opensbi