xref: /linux/arch/arm64/mm/gcs.c (revision fc84bc5378a8c852308fa022957b8976adb5aa6a)
1*fc84bc53SMark Brown // SPDX-License-Identifier: GPL-2.0-only
2*fc84bc53SMark Brown 
3*fc84bc53SMark Brown #include <linux/mm.h>
4*fc84bc53SMark Brown #include <linux/mman.h>
5*fc84bc53SMark Brown #include <linux/syscalls.h>
6*fc84bc53SMark Brown #include <linux/types.h>
7*fc84bc53SMark Brown 
8*fc84bc53SMark Brown #include <asm/cpufeature.h>
9*fc84bc53SMark Brown #include <asm/page.h>
10*fc84bc53SMark Brown 
11*fc84bc53SMark Brown /*
12*fc84bc53SMark Brown  * Apply the GCS mode configured for the specified task to the
13*fc84bc53SMark Brown  * hardware.
14*fc84bc53SMark Brown  */
15*fc84bc53SMark Brown void gcs_set_el0_mode(struct task_struct *task)
16*fc84bc53SMark Brown {
17*fc84bc53SMark Brown 	u64 gcscre0_el1 = GCSCRE0_EL1_nTR;
18*fc84bc53SMark Brown 
19*fc84bc53SMark Brown 	if (task->thread.gcs_el0_mode & PR_SHADOW_STACK_ENABLE)
20*fc84bc53SMark Brown 		gcscre0_el1 |= GCSCRE0_EL1_RVCHKEN | GCSCRE0_EL1_PCRSEL;
21*fc84bc53SMark Brown 
22*fc84bc53SMark Brown 	if (task->thread.gcs_el0_mode & PR_SHADOW_STACK_WRITE)
23*fc84bc53SMark Brown 		gcscre0_el1 |= GCSCRE0_EL1_STREn;
24*fc84bc53SMark Brown 
25*fc84bc53SMark Brown 	if (task->thread.gcs_el0_mode & PR_SHADOW_STACK_PUSH)
26*fc84bc53SMark Brown 		gcscre0_el1 |= GCSCRE0_EL1_PUSHMEn;
27*fc84bc53SMark Brown 
28*fc84bc53SMark Brown 	write_sysreg_s(gcscre0_el1, SYS_GCSCRE0_EL1);
29*fc84bc53SMark Brown }
30*fc84bc53SMark Brown 
31*fc84bc53SMark Brown void gcs_free(struct task_struct *task)
32*fc84bc53SMark Brown {
33*fc84bc53SMark Brown 	if (!system_supports_gcs())
34*fc84bc53SMark Brown 		return;
35*fc84bc53SMark Brown 
36*fc84bc53SMark Brown 	if (task->thread.gcs_base)
37*fc84bc53SMark Brown 		vm_munmap(task->thread.gcs_base, task->thread.gcs_size);
38*fc84bc53SMark Brown 
39*fc84bc53SMark Brown 	task->thread.gcspr_el0 = 0;
40*fc84bc53SMark Brown 	task->thread.gcs_base = 0;
41*fc84bc53SMark Brown 	task->thread.gcs_size = 0;
42*fc84bc53SMark Brown }
43