arm64: emulate the swp/swpb instruction
[firefly-linux-kernel-4.4.55.git] / arch / arm64 / kernel / swp_emulate.c
1 /*
2  *  Derived from from linux/arch/arm/kernel/swp_emulate.c
3  *
4  *  Copyright (C) 2009 ARM Limited
5  *  Copyright (c) 2014, NVIDIA CORPORATION.  All rights reserved.
6  *
7  * This program is free software; you can redistribute it and/or modify
8  * it under the terms of the GNU General Public License version 2 as
9  * published by the Free Software Foundation.
10  *
11  *  Implements emulation of the SWP/SWPB instructions using load-exclusive and
12  *  store-exclusive for processors that have them disabled (or future ones that
13  *  might not implement them).
14  *
15  *  Syntax of SWP{B} instruction: SWP{B}<c> <Rt>, <Rt2>, [<Rn>]
16  *  Where: Rt  = destination
17  *         Rt2 = source
18  *         Rn  = address
19  */
20
21 #include <linux/init.h>
22 #include <linux/kernel.h>
23 #include <linux/proc_fs.h>
24 #include <linux/seq_file.h>
25 #include <linux/sched.h>
26 #include <linux/syscalls.h>
27 #include <linux/perf_event.h>
28
29 #include <asm/opcodes.h>
30 #include <asm/traps.h>
31 #include <asm/uaccess.h>
32 #include <asm/system_misc.h>
33 #include <linux/debugfs.h>
34
35 /*
36  * Macros/defines for extracting register numbers from instruction.
37  */
38 #define EXTRACT_REG_NUM(instruction, offset) \
39         (((instruction) & (0xf << (offset))) >> (offset))
40 #define RN_OFFSET  16
41 #define RT_OFFSET  12
42 #define RT2_OFFSET  0
43 /*
44  * Bit 22 of the instruction encoding distinguishes between
45  * the SWP and SWPB variants (bit set means SWPB).
46  */
47 #define TYPE_SWPB (1 << 22)
48
49 static pid_t previous_pid;
50
51 u64 swpb_count = 0;
52 u64 swp_count = 0;
53
54 /*
55  * swp_handler logs the id of calling process, dissects the instruction, sanity
56  * checks the memory location, calls emulate_swpX for the actual operation and
57  * deals with fixup/error handling before returning
58  */
59 static int swp_handler(struct pt_regs *regs, unsigned int instr)
60 {
61         u32 address_reg, destreg, data, type;
62         uintptr_t address;
63         unsigned int res = 0;
64         u32 temp32;
65         u8 temp8;
66
67         perf_sw_event(PERF_COUNT_SW_EMULATION_FAULTS, 1, regs, regs->pc);
68
69         res = arm_check_condition(instr, regs->pstate);
70         switch (res) {
71         case ARM_OPCODE_CONDTEST_PASS:
72                 break;
73         case ARM_OPCODE_CONDTEST_FAIL:
74                 /* Condition failed - return to next instruction */
75                 regs->pc += 4;
76                 return 0;
77         case ARM_OPCODE_CONDTEST_UNCOND:
78                 /* If unconditional encoding - not a SWP, undef */
79                 return -EFAULT;
80         default:
81                 return -EINVAL;
82         }
83
84         if (current->pid != previous_pid) {
85                 pr_warn("\"%s\" (%ld) uses obsolete SWP{B} instruction\n",
86                          current->comm, (unsigned long)current->pid);
87                 previous_pid = current->pid;
88         }
89
90         address = regs->regs[EXTRACT_REG_NUM(instr, RN_OFFSET)] & 0xffffffff;
91         data = regs->regs[EXTRACT_REG_NUM(instr, RT2_OFFSET)];
92         destreg = EXTRACT_REG_NUM(instr, RT_OFFSET);
93
94         type = instr & TYPE_SWPB;
95
96         /* Check access in reasonable access range for both SWP and SWPB */
97         if (!access_ok(VERIFY_WRITE, (address & ~3), 4)) {
98                 pr_debug("SWP{B} emulation: access to %p not allowed!\n",
99                          (void *)address);
100                 res = -EFAULT;
101         }
102         if (type == TYPE_SWPB) {
103                 do {
104                         temp8 = ldax8((u8 *) address);
105                 } while (stx8((u8 *) address, (u8) data));
106                 regs->regs[destreg] = temp8;
107                 regs->pc += 4;
108                 swpb_count++;
109         } else if (address & 0x3) {
110                 /* SWP to unaligned address not permitted */
111                 pr_debug("SWP instruction on unaligned pointer!\n");
112                 return -EFAULT;
113         } else {
114                 do {
115                         temp32 = ldax32((u32 *) address);
116                 } while (stlx32((u32 *) address, (u32) data));
117                 regs->regs[destreg] = temp32;
118                 regs->pc += 4;
119                 swp_count++;
120         }
121
122         return 0;
123 }
124
125 /*
126  * Only emulate SWP/SWPB executed in ARM state/User mode.
127  * The kernel must be SWP free and SWP{B} does not exist in Thumb/ThumbEE.
128  */
129 static struct undef_hook swp_hook = {
130         .instr_mask     = 0x0fb00ff0,
131         .instr_val      = 0x01000090,
132         .pstate_mask    = COMPAT_PSR_MODE_MASK | COMPAT_PSR_T_BIT,
133         .pstate_val     = COMPAT_PSR_MODE_USR,
134         .fn             = swp_handler
135 };
136
137 /*
138  * Register handler and create status file in /proc/cpu
139  * Invoked as late_initcall, since not needed before init spawned.
140  */
141 static int __init swp_emulation_init(void)
142 {
143         struct dentry *dir;
144         dir = debugfs_create_dir("swp_emulate", NULL);
145         debugfs_create_u64("swp_count", S_IRUGO | S_IWUSR, dir, &swp_count);
146         debugfs_create_u64("swpb_count", S_IRUGO | S_IWUSR, dir, &swpb_count);
147
148         pr_notice("Registering SWP/SWPB emulation handler\n");
149         register_undef_hook(&swp_hook);
150
151
152         return 0;
153 }
154
155 late_initcall(swp_emulation_init);