blob: 98865a7868f18fd2efb6c105501b384e2434dfc0 [file] [log] [blame]
Punit Agrawal587064b2014-11-18 11:41:24 +00001/*
2 * Copyright (C) 2014 ARM Limited
3 *
4 * This program is free software; you can redistribute it and/or modify
5 * it under the terms of the GNU General Public License version 2 as
6 * published by the Free Software Foundation.
7 */
8
9#include <linux/init.h>
10#include <linux/list.h>
Punit Agrawalbd35a4a2014-11-18 11:41:25 +000011#include <linux/perf_event.h>
12#include <linux/sched.h>
Punit Agrawal587064b2014-11-18 11:41:24 +000013#include <linux/slab.h>
14#include <linux/sysctl.h>
15
Punit Agrawalbd35a4a2014-11-18 11:41:25 +000016#include <asm/insn.h>
17#include <asm/opcodes.h>
18#include <asm/system_misc.h>
Punit Agrawal587064b2014-11-18 11:41:24 +000019#include <asm/traps.h>
Punit Agrawalbd35a4a2014-11-18 11:41:25 +000020#include <asm/uaccess.h>
Punit Agrawal587064b2014-11-18 11:41:24 +000021
22/*
23 * The runtime support for deprecated instruction support can be in one of
24 * following three states -
25 *
26 * 0 = undef
27 * 1 = emulate (software emulation)
28 * 2 = hw (supported in hardware)
29 */
30enum insn_emulation_mode {
31 INSN_UNDEF,
32 INSN_EMULATE,
33 INSN_HW,
34};
35
36enum legacy_insn_status {
37 INSN_DEPRECATED,
38 INSN_OBSOLETE,
39};
40
41struct insn_emulation_ops {
42 const char *name;
43 enum legacy_insn_status status;
44 struct undef_hook *hooks;
45 int (*set_hw_mode)(bool enable);
46};
47
48struct insn_emulation {
49 struct list_head node;
50 struct insn_emulation_ops *ops;
51 int current_mode;
52 int min;
53 int max;
54};
55
56static LIST_HEAD(insn_emulation);
57static int nr_insn_emulated;
58static DEFINE_RAW_SPINLOCK(insn_emulation_lock);
59
60static void register_emulation_hooks(struct insn_emulation_ops *ops)
61{
62 struct undef_hook *hook;
63
64 BUG_ON(!ops->hooks);
65
66 for (hook = ops->hooks; hook->instr_mask; hook++)
67 register_undef_hook(hook);
68
69 pr_notice("Registered %s emulation handler\n", ops->name);
70}
71
72static void remove_emulation_hooks(struct insn_emulation_ops *ops)
73{
74 struct undef_hook *hook;
75
76 BUG_ON(!ops->hooks);
77
78 for (hook = ops->hooks; hook->instr_mask; hook++)
79 unregister_undef_hook(hook);
80
81 pr_notice("Removed %s emulation handler\n", ops->name);
82}
83
84static int update_insn_emulation_mode(struct insn_emulation *insn,
85 enum insn_emulation_mode prev)
86{
87 int ret = 0;
88
89 switch (prev) {
90 case INSN_UNDEF: /* Nothing to be done */
91 break;
92 case INSN_EMULATE:
93 remove_emulation_hooks(insn->ops);
94 break;
95 case INSN_HW:
96 if (insn->ops->set_hw_mode) {
97 insn->ops->set_hw_mode(false);
98 pr_notice("Disabled %s support\n", insn->ops->name);
99 }
100 break;
101 }
102
103 switch (insn->current_mode) {
104 case INSN_UNDEF:
105 break;
106 case INSN_EMULATE:
107 register_emulation_hooks(insn->ops);
108 break;
109 case INSN_HW:
110 if (insn->ops->set_hw_mode && insn->ops->set_hw_mode(true))
111 pr_notice("Enabled %s support\n", insn->ops->name);
112 else
113 ret = -EINVAL;
114 break;
115 }
116
117 return ret;
118}
119
120static void register_insn_emulation(struct insn_emulation_ops *ops)
121{
122 unsigned long flags;
123 struct insn_emulation *insn;
124
125 insn = kzalloc(sizeof(*insn), GFP_KERNEL);
126 insn->ops = ops;
127 insn->min = INSN_UNDEF;
128
129 switch (ops->status) {
130 case INSN_DEPRECATED:
131 insn->current_mode = INSN_EMULATE;
132 insn->max = INSN_HW;
133 break;
134 case INSN_OBSOLETE:
135 insn->current_mode = INSN_UNDEF;
136 insn->max = INSN_EMULATE;
137 break;
138 }
139
140 raw_spin_lock_irqsave(&insn_emulation_lock, flags);
141 list_add(&insn->node, &insn_emulation);
142 nr_insn_emulated++;
143 raw_spin_unlock_irqrestore(&insn_emulation_lock, flags);
144
145 /* Register any handlers if required */
146 update_insn_emulation_mode(insn, INSN_UNDEF);
147}
148
149static int emulation_proc_handler(struct ctl_table *table, int write,
150 void __user *buffer, size_t *lenp,
151 loff_t *ppos)
152{
153 int ret = 0;
154 struct insn_emulation *insn = (struct insn_emulation *) table->data;
155 enum insn_emulation_mode prev_mode = insn->current_mode;
156
157 table->data = &insn->current_mode;
158 ret = proc_dointvec_minmax(table, write, buffer, lenp, ppos);
159
160 if (ret || !write || prev_mode == insn->current_mode)
161 goto ret;
162
163 ret = update_insn_emulation_mode(insn, prev_mode);
164 if (!ret) {
165 /* Mode change failed, revert to previous mode. */
166 insn->current_mode = prev_mode;
167 update_insn_emulation_mode(insn, INSN_UNDEF);
168 }
169ret:
170 table->data = insn;
171 return ret;
172}
173
174static struct ctl_table ctl_abi[] = {
175 {
176 .procname = "abi",
177 .mode = 0555,
178 },
179 { }
180};
181
182static void register_insn_emulation_sysctl(struct ctl_table *table)
183{
184 unsigned long flags;
185 int i = 0;
186 struct insn_emulation *insn;
187 struct ctl_table *insns_sysctl, *sysctl;
188
189 insns_sysctl = kzalloc(sizeof(*sysctl) * (nr_insn_emulated + 1),
190 GFP_KERNEL);
191
192 raw_spin_lock_irqsave(&insn_emulation_lock, flags);
193 list_for_each_entry(insn, &insn_emulation, node) {
194 sysctl = &insns_sysctl[i];
195
196 sysctl->mode = 0644;
197 sysctl->maxlen = sizeof(int);
198
199 sysctl->procname = insn->ops->name;
200 sysctl->data = insn;
201 sysctl->extra1 = &insn->min;
202 sysctl->extra2 = &insn->max;
203 sysctl->proc_handler = emulation_proc_handler;
204 i++;
205 }
206 raw_spin_unlock_irqrestore(&insn_emulation_lock, flags);
207
208 table->child = insns_sysctl;
209 register_sysctl_table(table);
210}
211
212/*
Punit Agrawalbd35a4a2014-11-18 11:41:25 +0000213 * Implement emulation of the SWP/SWPB instructions using load-exclusive and
214 * store-exclusive.
215 *
216 * Syntax of SWP{B} instruction: SWP{B}<c> <Rt>, <Rt2>, [<Rn>]
217 * Where: Rt = destination
218 * Rt2 = source
219 * Rn = address
220 */
221
222/*
223 * Error-checking SWP macros implemented using ldxr{b}/stxr{b}
224 */
225#define __user_swpX_asm(data, addr, res, temp, B) \
226 __asm__ __volatile__( \
227 " mov %w2, %w1\n" \
228 "0: ldxr"B" %w1, [%3]\n" \
229 "1: stxr"B" %w0, %w2, [%3]\n" \
230 " cbz %w0, 2f\n" \
231 " mov %w0, %w4\n" \
232 "2:\n" \
233 " .pushsection .fixup,\"ax\"\n" \
234 " .align 2\n" \
235 "3: mov %w0, %w5\n" \
236 " b 2b\n" \
237 " .popsection" \
238 " .pushsection __ex_table,\"a\"\n" \
239 " .align 3\n" \
240 " .quad 0b, 3b\n" \
241 " .quad 1b, 3b\n" \
242 " .popsection" \
243 : "=&r" (res), "+r" (data), "=&r" (temp) \
244 : "r" (addr), "i" (-EAGAIN), "i" (-EFAULT) \
245 : "memory")
246
247#define __user_swp_asm(data, addr, res, temp) \
248 __user_swpX_asm(data, addr, res, temp, "")
249#define __user_swpb_asm(data, addr, res, temp) \
250 __user_swpX_asm(data, addr, res, temp, "b")
251
252/*
253 * Bit 22 of the instruction encoding distinguishes between
254 * the SWP and SWPB variants (bit set means SWPB).
255 */
256#define TYPE_SWPB (1 << 22)
257
258/*
259 * Set up process info to signal segmentation fault - called on access error.
260 */
261static void set_segfault(struct pt_regs *regs, unsigned long addr)
262{
263 siginfo_t info;
264
265 down_read(&current->mm->mmap_sem);
266 if (find_vma(current->mm, addr) == NULL)
267 info.si_code = SEGV_MAPERR;
268 else
269 info.si_code = SEGV_ACCERR;
270 up_read(&current->mm->mmap_sem);
271
272 info.si_signo = SIGSEGV;
273 info.si_errno = 0;
274 info.si_addr = (void *) instruction_pointer(regs);
275
276 pr_debug("SWP{B} emulation: access caused memory abort!\n");
277 arm64_notify_die("Illegal memory access", regs, &info, 0);
278}
279
280static int emulate_swpX(unsigned int address, unsigned int *data,
281 unsigned int type)
282{
283 unsigned int res = 0;
284
285 if ((type != TYPE_SWPB) && (address & 0x3)) {
286 /* SWP to unaligned address not permitted */
287 pr_debug("SWP instruction on unaligned pointer!\n");
288 return -EFAULT;
289 }
290
291 while (1) {
292 unsigned long temp;
293
294 if (type == TYPE_SWPB)
295 __user_swpb_asm(*data, address, res, temp);
296 else
297 __user_swp_asm(*data, address, res, temp);
298
299 if (likely(res != -EAGAIN) || signal_pending(current))
300 break;
301
302 cond_resched();
303 }
304
305 return res;
306}
307
308/*
309 * swp_handler logs the id of calling process, dissects the instruction, sanity
310 * checks the memory location, calls emulate_swpX for the actual operation and
311 * deals with fixup/error handling before returning
312 */
313static int swp_handler(struct pt_regs *regs, u32 instr)
314{
315 u32 destreg, data, type, address = 0;
316 int rn, rt2, res = 0;
317
318 perf_sw_event(PERF_COUNT_SW_EMULATION_FAULTS, 1, regs, regs->pc);
319
320 type = instr & TYPE_SWPB;
321
322 switch (arm_check_condition(instr, regs->pstate)) {
323 case ARM_OPCODE_CONDTEST_PASS:
324 break;
325 case ARM_OPCODE_CONDTEST_FAIL:
326 /* Condition failed - return to next instruction */
327 goto ret;
328 case ARM_OPCODE_CONDTEST_UNCOND:
329 /* If unconditional encoding - not a SWP, undef */
330 return -EFAULT;
331 default:
332 return -EINVAL;
333 }
334
335 rn = aarch32_insn_extract_reg_num(instr, A32_RN_OFFSET);
336 rt2 = aarch32_insn_extract_reg_num(instr, A32_RT2_OFFSET);
337
338 address = (u32)regs->user_regs.regs[rn];
339 data = (u32)regs->user_regs.regs[rt2];
340 destreg = aarch32_insn_extract_reg_num(instr, A32_RT_OFFSET);
341
342 pr_debug("addr in r%d->0x%08x, dest is r%d, source in r%d->0x%08x)\n",
343 rn, address, destreg,
344 aarch32_insn_extract_reg_num(instr, A32_RT2_OFFSET), data);
345
346 /* Check access in reasonable access range for both SWP and SWPB */
347 if (!access_ok(VERIFY_WRITE, (address & ~3), 4)) {
348 pr_debug("SWP{B} emulation: access to 0x%08x not allowed!\n",
349 address);
350 goto fault;
351 }
352
353 res = emulate_swpX(address, &data, type);
354 if (res == -EFAULT)
355 goto fault;
356 else if (res == 0)
357 regs->user_regs.regs[destreg] = data;
358
359ret:
360 pr_warn_ratelimited("\"%s\" (%ld) uses obsolete SWP{B} instruction at 0x%llx\n",
361 current->comm, (unsigned long)current->pid, regs->pc);
362
363 regs->pc += 4;
364 return 0;
365
366fault:
367 set_segfault(regs, address);
368
369 return 0;
370}
371
372/*
373 * Only emulate SWP/SWPB executed in ARM state/User mode.
374 * The kernel must be SWP free and SWP{B} does not exist in Thumb.
375 */
376static struct undef_hook swp_hooks[] = {
377 {
378 .instr_mask = 0x0fb00ff0,
379 .instr_val = 0x01000090,
380 .pstate_mask = COMPAT_PSR_MODE_MASK,
381 .pstate_val = COMPAT_PSR_MODE_USR,
382 .fn = swp_handler
383 },
384 { }
385};
386
387static struct insn_emulation_ops swp_ops = {
388 .name = "swp",
389 .status = INSN_OBSOLETE,
390 .hooks = swp_hooks,
391 .set_hw_mode = NULL,
392};
393
394/*
Punit Agrawal587064b2014-11-18 11:41:24 +0000395 * Invoked as late_initcall, since not needed before init spawned.
396 */
397static int __init armv8_deprecated_init(void)
398{
Punit Agrawalbd35a4a2014-11-18 11:41:25 +0000399 if (IS_ENABLED(CONFIG_SWP_EMULATION))
400 register_insn_emulation(&swp_ops);
401
Punit Agrawal587064b2014-11-18 11:41:24 +0000402 register_insn_emulation_sysctl(ctl_abi);
403
404 return 0;
405}
406
407late_initcall(armv8_deprecated_init);