| .. | .. |
|---|
| 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"); |
|---|