From 79143f43ae0a6864c6f6aca9bcf313329122cd8c Mon Sep 17 00:00:00 2001 From: Chen Pei Date: Fri, 12 Jun 2026 16:52:18 +0800 Subject: [PATCH] lib: sbi_ipi: Validate hartids against domain, not HSM state MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Commit 37eaca4ab33d ("lib: sbi_ipi: Return error for invalid hartids") added a weight check against the HSM-interruptible mask, which excludes harts in STOPPED state. This causes sbi_ipi_send_many() to return SBI_EINVAL when the kernel sends a remote fence (e.g. TLB shootdown) whose hmask includes a hart that was stopped by CPU hotplug: __sbi_rfence_v02_call: hbase = [0] hmask = [0x3] failed (error [-22]) Validate requested hartids against the domain's assigned hartmask instead. This still rejects truly invalid or cross-domain hartids, but allows HSM-STOPPED harts to be silently skipped — which is safe because a stopped hart will do a full local TLB flush on its next HSM start before re-entering S-mode. Fixes: 37eaca4ab33d ("lib: sbi_ipi: Return error for invalid hartids") Signed-off-by: Chen Pei --- lib/sbi/sbi_ipi.c | 11 +++++++++-- 1 file changed, 9 insertions(+), 2 deletions(-) diff --git a/lib/sbi/sbi_ipi.c b/lib/sbi/sbi_ipi.c index 2de459b0..d2a81a40 100644 --- a/lib/sbi/sbi_ipi.c +++ b/lib/sbi/sbi_ipi.c @@ -128,6 +128,7 @@ int sbi_ipi_send_many(ulong hmask, ulong hbase, u32 event, void *data) if (hbase != -1UL) { struct sbi_hartmask tmp_mask = { 0 }; + struct sbi_hartmask domain_mask; int count = sbi_popcount(hmask); for (i = hbase; hmask; i++, hmask >>= 1) { @@ -135,10 +136,16 @@ int sbi_ipi_send_many(ulong hmask, ulong hbase, u32 event, void *data) sbi_hartmask_set_hartid(i, &tmp_mask); } - sbi_hartmask_and(&target_mask, &target_mask, &tmp_mask); + /* Validate hartids against domain assignment, not HSM state */ + rc = sbi_domain_get_assigned_hartmask(dom, &domain_mask); + if (rc) + return rc; - if (sbi_hartmask_weight(&target_mask) != count) + sbi_hartmask_and(&domain_mask, &domain_mask, &tmp_mask); + if (sbi_hartmask_weight(&domain_mask) != count) return SBI_EINVAL; + + sbi_hartmask_and(&target_mask, &target_mask, &tmp_mask); } /* Send IPIs */