1 // SPDX-License-Identifier: GPL-2.0-or-later
2 /*
3 * Copyright (c) 2023 Huawei Device Co., Ltd.
4 */
5
6 #include <asm/asm-offsets.h>
7 #include <asm/ptrace.h>
8 #include <linux/irqflags.h>
9
10 /* The members of arrays below are corresponding to the enum defined in pointer_auth_context.h:
11 * enum pac_pt_regs {
12 * REGS_X16 = 0,
13 * REGS_X17,
14 * REGS_LR,
15 * REGS_SP,
16 * REGS_PC,
17 * REGS_PSTATE,
18 * };
19 *
20 * compat_regs_offset_array[]:
21 * S_X14: the offset of compat_lr
22 * S_X13: the offset of compat_sp
23 */
24 static off_t compat_regs_offset_array[] = {0, 0, S_X14, S_X13, S_PC, S_PSTATE};
25 static off_t regs_offset_array[] = {S_X16, S_X17, S_LR, S_SP, S_PC, S_PSTATE};
26
set_compat_exception_context_register(void * regs,enum pac_pt_regs regs_enum,u64 val)27 int set_compat_exception_context_register(void *regs, enum pac_pt_regs regs_enum, u64 val)
28 {
29 switch (regs_enum) {
30 case REGS_LR:
31 case REGS_SP:
32 case REGS_PC:
33 case REGS_PSTATE:
34 return set_compat_exception_context_register_asm(regs, compat_regs_offset_array[regs_enum], val);
35 default:
36 return -EINVAL;
37 }
38 }
39
set_exception_context_register(void * regs,enum pac_pt_regs regs_enum,u64 val)40 int set_exception_context_register(void *regs, enum pac_pt_regs regs_enum, u64 val)
41 {
42 if (compat_user_mode((struct pt_regs *)regs)) {
43 return set_compat_exception_context_register(regs, regs_enum, val);
44 } else {
45 switch (regs_enum) {
46 case REGS_X16:
47 case REGS_X17:
48 case REGS_LR:
49 case REGS_SP:
50 case REGS_PC:
51 case REGS_PSTATE:
52 return set_exception_context_register_asm(regs, regs_offset_array[regs_enum], val);
53 default:
54 return -EINVAL;
55 }
56 }
57 }
58
set_compat_exception_context_register_index(struct pt_regs * regs,int index,uint64_t val)59 void set_compat_exception_context_register_index(struct pt_regs *regs, int index, uint64_t val)
60 {
61 /* 14 means the index of compat_lr */
62 if (index == 14) {
63 set_compat_exception_context_register_asm(regs, S_X14, val);
64 /* 13 means the index of compat_sp */
65 } else if (index == 13) {
66 set_compat_exception_context_register_asm(regs, S_X13, val);
67 } else {
68 regs->regs[index] = val;
69 }
70 }
71
set_exception_context_register_index(struct pt_regs * regs,int index,uint64_t val)72 void set_exception_context_register_index(struct pt_regs *regs, int index, uint64_t val)
73 {
74 off_t offset;
75
76 if (compat_user_mode(regs)) {
77 set_compat_exception_context_register_index(regs, index, val);
78 } else {
79 switch (index) {
80 /* 16 means the index of regs[16] */
81 case 16:
82 /* 17 means the index of regs[17] */
83 case 17:
84 /* 30 means the index of regs[30] */
85 case 30:
86 offset = offsetof(struct pt_regs, regs[index]);
87 set_exception_context_register_asm(regs, offset, val);
88 break;
89 default:
90 regs->regs[index] = val;
91 }
92 }
93 }
94
sign_compat_exception_context(void * regs)95 void sign_compat_exception_context(void *regs)
96 {
97 unsigned long irq_flags;
98 local_irq_save(irq_flags);
99 sign_compat_exception_context_asm(regs);
100 local_irq_restore(irq_flags);
101 }
102
auth_compat_exception_context(void * regs)103 void auth_compat_exception_context(void *regs)
104 {
105 unsigned long irq_flags;
106 local_irq_save(irq_flags);
107 auth_compat_exception_context_asm(regs);
108 local_irq_restore(irq_flags);
109 }
110
sign_exception_context(void * regs)111 void sign_exception_context(void *regs)
112 {
113 unsigned long irq_flags;
114 local_irq_save(irq_flags);
115 if (compat_user_mode((struct pt_regs *)regs)) {
116 sign_compat_exception_context_asm(regs);
117 } else {
118 sign_exception_context_asm(regs);
119 }
120 local_irq_restore(irq_flags);
121 }
122
auth_exception_context(void * regs)123 void auth_exception_context(void *regs)
124 {
125 unsigned long irq_flags;
126 local_irq_save(irq_flags);
127 if (compat_user_mode((struct pt_regs *)regs)) {
128 auth_compat_exception_context_asm(regs);
129 } else {
130 auth_exception_context_asm(regs);
131 }
132 local_irq_restore(irq_flags);
133 }
134