Skip to content

Commit 5feef64

Browse files
geertupalmer-dabbelt
authored andcommitted
RISC-V: Fix IPI/RFENCE hmask on non-monotonic hartid ordering
If the boot CPU does not have the lowest hartid, "hartid - hbase" can become negative, leading to an incorrect hmask, causing userspace to crash with SEGV. This is observed on e.g. Starlight Beta, where cpuid 1 maps to hartid 0, and cpuid 0 maps to hartid 1. Fix this by detecting this case, and shifting the accumulated mask and updating hbase, if possible. Fixes: 26fb751 ("RISC-V: Do not use cpumask data structure for hartid bitmap") Signed-off-by: Geert Uytterhoeven <[email protected]> Reviewed-by: Atish Patra <[email protected]> Tested-by: Atish Patra <[email protected]> Signed-off-by: Palmer Dabbelt <[email protected]>
1 parent 2b35d5b commit 5feef64

File tree

1 file changed

+39
-18
lines changed

1 file changed

+39
-18
lines changed

arch/riscv/kernel/sbi.c

Lines changed: 39 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -250,7 +250,7 @@ static void __sbi_set_timer_v02(uint64_t stime_value)
250250

251251
static int __sbi_send_ipi_v02(const struct cpumask *cpu_mask)
252252
{
253-
unsigned long hartid, cpuid, hmask = 0, hbase = 0;
253+
unsigned long hartid, cpuid, hmask = 0, hbase = 0, htop = 0;
254254
struct sbiret ret = {0};
255255
int result;
256256

@@ -259,16 +259,27 @@ static int __sbi_send_ipi_v02(const struct cpumask *cpu_mask)
259259

260260
for_each_cpu(cpuid, cpu_mask) {
261261
hartid = cpuid_to_hartid_map(cpuid);
262-
if (hmask && ((hbase + BITS_PER_LONG) <= hartid)) {
263-
ret = sbi_ecall(SBI_EXT_IPI, SBI_EXT_IPI_SEND_IPI,
264-
hmask, hbase, 0, 0, 0, 0);
265-
if (ret.error)
266-
goto ecall_failed;
267-
hmask = 0;
268-
hbase = 0;
262+
if (hmask) {
263+
if (hartid + BITS_PER_LONG <= htop ||
264+
hbase + BITS_PER_LONG <= hartid) {
265+
ret = sbi_ecall(SBI_EXT_IPI,
266+
SBI_EXT_IPI_SEND_IPI, hmask,
267+
hbase, 0, 0, 0, 0);
268+
if (ret.error)
269+
goto ecall_failed;
270+
hmask = 0;
271+
} else if (hartid < hbase) {
272+
/* shift the mask to fit lower hartid */
273+
hmask <<= hbase - hartid;
274+
hbase = hartid;
275+
}
269276
}
270-
if (!hmask)
277+
if (!hmask) {
271278
hbase = hartid;
279+
htop = hartid;
280+
} else if (hartid > htop) {
281+
htop = hartid;
282+
}
272283
hmask |= BIT(hartid - hbase);
273284
}
274285

@@ -345,24 +356,34 @@ static int __sbi_rfence_v02(int fid, const struct cpumask *cpu_mask,
345356
unsigned long start, unsigned long size,
346357
unsigned long arg4, unsigned long arg5)
347358
{
348-
unsigned long hartid, cpuid, hmask = 0, hbase = 0;
359+
unsigned long hartid, cpuid, hmask = 0, hbase = 0, htop = 0;
349360
int result;
350361

351362
if (!cpu_mask || cpumask_empty(cpu_mask))
352363
cpu_mask = cpu_online_mask;
353364

354365
for_each_cpu(cpuid, cpu_mask) {
355366
hartid = cpuid_to_hartid_map(cpuid);
356-
if (hmask && ((hbase + BITS_PER_LONG) <= hartid)) {
357-
result = __sbi_rfence_v02_call(fid, hmask, hbase,
358-
start, size, arg4, arg5);
359-
if (result)
360-
return result;
361-
hmask = 0;
362-
hbase = 0;
367+
if (hmask) {
368+
if (hartid + BITS_PER_LONG <= htop ||
369+
hbase + BITS_PER_LONG <= hartid) {
370+
result = __sbi_rfence_v02_call(fid, hmask,
371+
hbase, start, size, arg4, arg5);
372+
if (result)
373+
return result;
374+
hmask = 0;
375+
} else if (hartid < hbase) {
376+
/* shift the mask to fit lower hartid */
377+
hmask <<= hbase - hartid;
378+
hbase = hartid;
379+
}
363380
}
364-
if (!hmask)
381+
if (!hmask) {
365382
hbase = hartid;
383+
htop = hartid;
384+
} else if (hartid > htop) {
385+
htop = hartid;
386+
}
366387
hmask |= BIT(hartid - hbase);
367388
}
368389

0 commit comments

Comments
 (0)