Skip to content

Commit cd9b290

Browse files
andrea-parripalmer-dabbelt
authored andcommitted
membarrier: riscv: Provide core serializing command
RISC-V uses xRET instructions on return from interrupt and to go back to user-space; the xRET instruction is not core serializing. Use FENCE.I for providing core serialization as follows: - by calling sync_core_before_usermode() on return from interrupt (cf. ipi_sync_core()), - via switch_mm() and sync_core_before_usermode() (respectively, for uthread->uthread and kthread->uthread transitions) before returning to user-space. On RISC-V, the serialization in switch_mm() is activated by resetting the icache_stale_mask of the mm at prepare_sync_core_cmd(). Suggested-by: Palmer Dabbelt <palmer@dabbelt.com> Signed-off-by: Andrea Parri <parri.andrea@gmail.com> Reviewed-by: Mathieu Desnoyers <mathieu.desnoyers@efficios.com> Link: https://lore.kernel.org/r/20240131144936.29190-5-parri.andrea@gmail.com Signed-off-by: Palmer Dabbelt <palmer@rivosinc.com>
1 parent 4ff4c74 commit cd9b290

File tree

7 files changed

+77
-1
lines changed

7 files changed

+77
-1
lines changed

Documentation/features/sched/membarrier-sync-core/arch-support.txt

Lines changed: 17 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,22 @@
1010
# Rely on implicit context synchronization as a result of exception return
1111
# when returning from IPI handler, and when returning to user-space.
1212
#
13+
# * riscv
14+
#
15+
# riscv uses xRET as return from interrupt and to return to user-space.
16+
#
17+
# Given that xRET is not core serializing, we rely on FENCE.I for providing
18+
# core serialization:
19+
#
20+
# - by calling sync_core_before_usermode() on return from interrupt (cf.
21+
# ipi_sync_core()),
22+
#
23+
# - via switch_mm() and sync_core_before_usermode() (respectively, for
24+
# uthread->uthread and kthread->uthread transitions) before returning
25+
# to user-space.
26+
#
27+
# The serialization in switch_mm() is activated by prepare_sync_core_cmd().
28+
#
1329
# * x86
1430
#
1531
# x86-32 uses IRET as return from interrupt, which takes care of the IPI.
@@ -43,7 +59,7 @@
4359
| openrisc: | TODO |
4460
| parisc: | TODO |
4561
| powerpc: | ok |
46-
| riscv: | TODO |
62+
| riscv: | ok |
4763
| s390: | ok |
4864
| sh: | TODO |
4965
| sparc: | TODO |

MAINTAINERS

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -14041,6 +14041,7 @@ L: linux-kernel@vger.kernel.org
1404114041
S: Supported
1404214042
F: Documentation/scheduler/membarrier.rst
1404314043
F: arch/*/include/asm/membarrier.h
14044+
F: arch/*/include/asm/sync_core.h
1404414045
F: include/uapi/linux/membarrier.h
1404514046
F: kernel/sched/membarrier.c
1404614047

arch/riscv/Kconfig

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -28,14 +28,17 @@ config RISCV
2828
select ARCH_HAS_GIGANTIC_PAGE
2929
select ARCH_HAS_KCOV
3030
select ARCH_HAS_MEMBARRIER_CALLBACKS
31+
select ARCH_HAS_MEMBARRIER_SYNC_CORE
3132
select ARCH_HAS_MMIOWB
3233
select ARCH_HAS_NON_OVERLAPPING_ADDRESS_SPACE
3334
select ARCH_HAS_PMEM_API
35+
select ARCH_HAS_PREPARE_SYNC_CORE_CMD
3436
select ARCH_HAS_PTE_SPECIAL
3537
select ARCH_HAS_SET_DIRECT_MAP if MMU
3638
select ARCH_HAS_SET_MEMORY if MMU
3739
select ARCH_HAS_STRICT_KERNEL_RWX if MMU && !XIP_KERNEL
3840
select ARCH_HAS_STRICT_MODULE_RWX if MMU && !XIP_KERNEL
41+
select ARCH_HAS_SYNC_CORE_BEFORE_USERMODE
3942
select ARCH_HAS_SYSCALL_WRAPPER
4043
select ARCH_HAS_TICK_BROADCAST if GENERIC_CLOCKEVENTS_BROADCAST
4144
select ARCH_HAS_UBSAN_SANITIZE_ALL

arch/riscv/include/asm/membarrier.h

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,25 @@ static inline void membarrier_arch_switch_mm(struct mm_struct *prev,
2222
/*
2323
* The membarrier system call requires a full memory barrier
2424
* after storing to rq->curr, before going back to user-space.
25+
*
26+
* This barrier is also needed for the SYNC_CORE command when
27+
* switching between processes; in particular, on a transition
28+
* from a thread belonging to another mm to a thread belonging
29+
* to the mm for which a membarrier SYNC_CORE is done on CPU0:
30+
*
31+
* - [CPU0] sets all bits in the mm icache_stale_mask (in
32+
* prepare_sync_core_cmd());
33+
*
34+
* - [CPU1] stores to rq->curr (by the scheduler);
35+
*
36+
* - [CPU0] loads rq->curr within membarrier and observes
37+
* cpu_rq(1)->curr->mm != mm, so the IPI is skipped on
38+
* CPU1; this means membarrier relies on switch_mm() to
39+
* issue the sync-core;
40+
*
41+
* - [CPU1] switch_mm() loads icache_stale_mask; if the bit
42+
* is zero, switch_mm() may incorrectly skip the sync-core.
43+
*
2544
* Matches a full barrier in the proximity of the membarrier
2645
* system call entry.
2746
*/

arch/riscv/include/asm/sync_core.h

Lines changed: 29 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,29 @@
1+
/* SPDX-License-Identifier: GPL-2.0 */
2+
#ifndef _ASM_RISCV_SYNC_CORE_H
3+
#define _ASM_RISCV_SYNC_CORE_H
4+
5+
/*
6+
* RISC-V implements return to user-space through an xRET instruction,
7+
* which is not core serializing.
8+
*/
9+
static inline void sync_core_before_usermode(void)
10+
{
11+
asm volatile ("fence.i" ::: "memory");
12+
}
13+
14+
#ifdef CONFIG_SMP
15+
/*
16+
* Ensure the next switch_mm() on every CPU issues a core serializing
17+
* instruction for the given @mm.
18+
*/
19+
static inline void prepare_sync_core_cmd(struct mm_struct *mm)
20+
{
21+
cpumask_setall(&mm->context.icache_stale_mask);
22+
}
23+
#else
24+
static inline void prepare_sync_core_cmd(struct mm_struct *mm)
25+
{
26+
}
27+
#endif /* CONFIG_SMP */
28+
29+
#endif /* _ASM_RISCV_SYNC_CORE_H */

kernel/sched/core.c

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6721,6 +6721,10 @@ static void __sched notrace __schedule(unsigned int sched_mode)
67216721
*
67226722
* The barrier matches a full barrier in the proximity of
67236723
* the membarrier system call entry.
6724+
*
6725+
* On RISC-V, this barrier pairing is also needed for the
6726+
* SYNC_CORE command when switching between processes, cf.
6727+
* the inline comments in membarrier_arch_switch_mm().
67246728
*/
67256729
++*switch_count;
67266730

kernel/sched/membarrier.c

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -342,6 +342,10 @@ static int membarrier_private_expedited(int flags, int cpu_id)
342342
/*
343343
* Matches memory barriers after rq->curr modification in
344344
* scheduler.
345+
*
346+
* On RISC-V, this barrier pairing is also needed for the
347+
* SYNC_CORE command when switching between processes, cf.
348+
* the inline comments in membarrier_arch_switch_mm().
345349
*/
346350
smp_mb(); /* system call entry is not a mb. */
347351

0 commit comments

Comments
 (0)