xref: /linux/arch/riscv/include/asm/scs.h (revision 8e8cd9a4c6dc006e9bd51b8ad0079fb4576b48d3)
1 /* SPDX-License-Identifier: GPL-2.0 */
2 #ifndef _ASM_SCS_H
3 #define _ASM_SCS_H
4 
5 #ifdef __ASSEMBLER__
6 #include <asm/asm-offsets.h>
7 #include <asm/csr.h>
8 
9 #ifdef CONFIG_SHADOW_CALL_STACK
10 
11 /* Load init_shadow_call_stack to gp. */
12 .macro scs_load_init_stack
13 	la	gp, init_shadow_call_stack
14 .endm
15 
16 /* Load the per-CPU IRQ shadow call stack to gp. */
17 .macro scs_load_irq_stack tmp
18 	load_per_cpu gp, irq_shadow_call_stack_ptr, \tmp
19 .endm
20 
21 /* Load task_scs_sp(current) to gp. */
22 .macro scs_load_current
23 	REG_L	gp, TASK_TI_SCS_SP(tp)
24 .endm
25 
26 /*
27  * Load task_scs_sp(current) to gp, but only when the trap came from U-mode.
28  * The source privilege level is taken from the saved sstatus.SPP bit (written
29  * by hardware on trap entry), not by comparing tp.  tp is a user-writable
30  * register, so gating the shadow call stack reload on it let a user task that
31  * set tp == &current skip the reload and run the kernel with an attacker
32  * controlled gp (the shadow call stack pointer).
33  */
34 .macro scs_load_current_if_from_user status, tmp
35 	andi	\tmp, \status, SR_SPP
36 	bnez	\tmp, _skip_scs
37 	scs_load_current
38 _skip_scs:
39 .endm
40 
41 /* Save gp to task_scs_sp(current). */
42 .macro scs_save_current
43 	REG_S	gp, TASK_TI_SCS_SP(tp)
44 .endm
45 
46 #else /* CONFIG_SHADOW_CALL_STACK */
47 
48 .macro scs_load_init_stack
49 .endm
50 .macro scs_load_irq_stack tmp
51 .endm
52 .macro scs_load_current
53 .endm
54 .macro scs_load_current_if_from_user status, tmp
55 .endm
56 .macro scs_save_current
57 .endm
58 
59 #endif /* CONFIG_SHADOW_CALL_STACK */
60 #endif /* __ASSEMBLER__ */
61 
62 #endif /* _ASM_SCS_H */
63