.. | .. |
---|
| 1 | +// SPDX-License-Identifier: GPL-2.0-only |
---|
1 | 2 | /* |
---|
2 | 3 | * 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 | 4 | */ |
---|
8 | 5 | |
---|
9 | 6 | #include <linux/cpu.h> |
---|
.. | .. |
---|
62 | 59 | static LIST_HEAD(insn_emulation); |
---|
63 | 60 | static int nr_insn_emulated __initdata; |
---|
64 | 61 | static DEFINE_RAW_SPINLOCK(insn_emulation_lock); |
---|
| 62 | +static DEFINE_MUTEX(insn_emulation_mutex); |
---|
65 | 63 | |
---|
66 | 64 | static void register_emulation_hooks(struct insn_emulation_ops *ops) |
---|
67 | 65 | { |
---|
.. | .. |
---|
206 | 204 | } |
---|
207 | 205 | |
---|
208 | 206 | static int emulation_proc_handler(struct ctl_table *table, int write, |
---|
209 | | - void __user *buffer, size_t *lenp, |
---|
| 207 | + void *buffer, size_t *lenp, |
---|
210 | 208 | loff_t *ppos) |
---|
211 | 209 | { |
---|
212 | 210 | int ret = 0; |
---|
213 | | - struct insn_emulation *insn = (struct insn_emulation *) table->data; |
---|
| 211 | + struct insn_emulation *insn = container_of(table->data, struct insn_emulation, current_mode); |
---|
214 | 212 | enum insn_emulation_mode prev_mode = insn->current_mode; |
---|
215 | 213 | |
---|
216 | | - table->data = &insn->current_mode; |
---|
| 214 | + mutex_lock(&insn_emulation_mutex); |
---|
217 | 215 | ret = proc_dointvec_minmax(table, write, buffer, lenp, ppos); |
---|
218 | 216 | |
---|
219 | 217 | if (ret || !write || prev_mode == insn->current_mode) |
---|
.. | .. |
---|
226 | 224 | update_insn_emulation_mode(insn, INSN_UNDEF); |
---|
227 | 225 | } |
---|
228 | 226 | ret: |
---|
229 | | - table->data = insn; |
---|
| 227 | + mutex_unlock(&insn_emulation_mutex); |
---|
230 | 228 | return ret; |
---|
231 | 229 | } |
---|
232 | 230 | |
---|
.. | .. |
---|
250 | 248 | sysctl->maxlen = sizeof(int); |
---|
251 | 249 | |
---|
252 | 250 | sysctl->procname = insn->ops->name; |
---|
253 | | - sysctl->data = insn; |
---|
| 251 | + sysctl->data = &insn->current_mode; |
---|
254 | 252 | sysctl->extra1 = &insn->min; |
---|
255 | 253 | sysctl->extra2 = &insn->max; |
---|
256 | 254 | sysctl->proc_handler = emulation_proc_handler; |
---|
.. | .. |
---|
280 | 278 | |
---|
281 | 279 | #define __user_swpX_asm(data, addr, res, temp, temp2, B) \ |
---|
282 | 280 | do { \ |
---|
283 | | - uaccess_enable(); \ |
---|
| 281 | + uaccess_enable_privileged(); \ |
---|
284 | 282 | __asm__ __volatile__( \ |
---|
285 | 283 | " mov %w3, %w7\n" \ |
---|
286 | 284 | "0: ldxr"B" %w2, [%4]\n" \ |
---|
.. | .. |
---|
305 | 303 | "i" (-EFAULT), \ |
---|
306 | 304 | "i" (__SWP_LL_SC_LOOPS) \ |
---|
307 | 305 | : "memory"); \ |
---|
308 | | - uaccess_disable(); \ |
---|
| 306 | + uaccess_disable_privileged(); \ |
---|
309 | 307 | } while (0) |
---|
310 | 308 | |
---|
311 | 309 | #define __user_swp_asm(data, addr, res, temp, temp2) \ |
---|
.. | .. |
---|
407 | 405 | |
---|
408 | 406 | /* Check access in reasonable access range for both SWP and SWPB */ |
---|
409 | 407 | user_ptr = (const void __user *)(unsigned long)(address & ~3); |
---|
410 | | - if (!access_ok(VERIFY_WRITE, user_ptr, 4)) { |
---|
| 408 | + if (!access_ok(user_ptr, 4)) { |
---|
411 | 409 | pr_debug("SWP{B} emulation: access to 0x%08x not allowed!\n", |
---|
412 | 410 | address); |
---|
413 | 411 | goto fault; |
---|
.. | .. |
---|
621 | 619 | }; |
---|
622 | 620 | |
---|
623 | 621 | /* |
---|
624 | | - * Invoked as late_initcall, since not needed before init spawned. |
---|
| 622 | + * Invoked as core_initcall, which guarantees that the instruction |
---|
| 623 | + * emulation is ready for userspace. |
---|
625 | 624 | */ |
---|
626 | 625 | static int __init armv8_deprecated_init(void) |
---|
627 | 626 | { |
---|
.. | .. |
---|
632 | 631 | register_insn_emulation(&cp15_barrier_ops); |
---|
633 | 632 | |
---|
634 | 633 | if (IS_ENABLED(CONFIG_SETEND_EMULATION)) { |
---|
635 | | - if(system_supports_mixed_endian_el0()) |
---|
| 634 | + if (system_supports_mixed_endian_el0()) |
---|
636 | 635 | register_insn_emulation(&setend_ops); |
---|
637 | 636 | else |
---|
638 | 637 | pr_info("setend instruction emulation is not supported on this system\n"); |
---|