armv8_deprecated.c revision f2e97ae6b98e61fa4f1539a47661baef41992b04
1/* 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> 11#include <linux/perf_event.h> 12#include <linux/sched.h> 13#include <linux/slab.h> 14#include <linux/sysctl.h> 15 16#include <asm/insn.h> 17#include <asm/opcodes.h> 18#include <asm/system_misc.h> 19#include <asm/traps.h> 20#include <asm/uaccess.h> 21 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/* 213 * 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(¤t->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(¤t->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/* 395 * Invoked as late_initcall, since not needed before init spawned. 396 */ 397static int __init armv8_deprecated_init(void) 398{ 399 if (IS_ENABLED(CONFIG_SWP_EMULATION)) 400 register_insn_emulation(&swp_ops); 401 402 register_insn_emulation_sysctl(ctl_abi); 403 404 return 0; 405} 406 407late_initcall(armv8_deprecated_init); 408