~ [ source navigation ] ~ [ diff markup ] ~ [ identifier search ] ~

TOMOYO Linux Cross Reference
Linux/arch/arc/kernel/unaligned.c

Version: ~ [ linux-5.6-rc1 ] ~ [ linux-5.5.2 ] ~ [ linux-5.4.17 ] ~ [ linux-5.3.18 ] ~ [ linux-5.2.21 ] ~ [ linux-5.1.21 ] ~ [ linux-5.0.21 ] ~ [ linux-4.20.17 ] ~ [ linux-4.19.102 ] ~ [ linux-4.18.20 ] ~ [ linux-4.17.19 ] ~ [ linux-4.16.18 ] ~ [ linux-4.15.18 ] ~ [ linux-4.14.170 ] ~ [ linux-4.13.16 ] ~ [ linux-4.12.14 ] ~ [ linux-4.11.12 ] ~ [ linux-4.10.17 ] ~ [ linux-4.9.213 ] ~ [ linux-4.8.17 ] ~ [ linux-4.7.10 ] ~ [ linux-4.6.7 ] ~ [ linux-4.5.7 ] ~ [ linux-4.4.213 ] ~ [ linux-4.3.6 ] ~ [ linux-4.2.8 ] ~ [ linux-4.1.52 ] ~ [ linux-4.0.9 ] ~ [ linux-3.19.8 ] ~ [ linux-3.18.140 ] ~ [ linux-3.17.8 ] ~ [ linux-3.16.81 ] ~ [ linux-3.15.10 ] ~ [ linux-3.14.79 ] ~ [ linux-3.13.11 ] ~ [ linux-3.12.74 ] ~ [ linux-3.11.10 ] ~ [ linux-3.10.108 ] ~ [ linux-3.9.11 ] ~ [ linux-3.8.13 ] ~ [ linux-3.7.10 ] ~ [ linux-3.6.11 ] ~ [ linux-3.5.7 ] ~ [ linux-3.4.113 ] ~ [ linux-3.3.8 ] ~ [ linux-3.2.102 ] ~ [ linux-3.1.10 ] ~ [ linux-3.0.101 ] ~ [ linux-2.6.32.71 ] ~ [ linux-2.6.0 ] ~ [ linux-2.4.37.11 ] ~ [ unix-v6-master ] ~ [ ccs-tools-1.8.5 ] ~ [ policy-sample ] ~
Architecture: ~ [ i386 ] ~ [ alpha ] ~ [ m68k ] ~ [ mips ] ~ [ ppc ] ~ [ sparc ] ~ [ sparc64 ] ~

  1 /*
  2  * Copyright (C) 2011-2012 Synopsys (www.synopsys.com)
  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  * vineetg : May 2011
  9  *  -Adapted (from .26 to .35)
 10  *  -original contribution by Tim.yao@amlogic.com
 11  *
 12  */
 13 
 14 #include <linux/types.h>
 15 #include <linux/ptrace.h>
 16 #include <linux/uaccess.h>
 17 #include <asm/disasm.h>
 18 
 19 #define __get8_unaligned_check(val, addr, err)          \
 20         __asm__(                                        \
 21         "1:     ldb.ab  %1, [%2, 1]\n"                  \
 22         "2:\n"                                          \
 23         "       .section .fixup,\"ax\"\n"               \
 24         "       .align  4\n"                            \
 25         "3:     mov     %0, 1\n"                        \
 26         "       b       2b\n"                           \
 27         "       .previous\n"                            \
 28         "       .section __ex_table,\"a\"\n"            \
 29         "       .align  4\n"                            \
 30         "       .long   1b, 3b\n"                       \
 31         "       .previous\n"                            \
 32         : "=r" (err), "=&r" (val), "=r" (addr)          \
 33         : "" (err), "2" (addr))
 34 
 35 #define get16_unaligned_check(val, addr)                \
 36         do {                                            \
 37                 unsigned int err = 0, v, a = addr;      \
 38                 __get8_unaligned_check(v, a, err);      \
 39                 val =  v ;                              \
 40                 __get8_unaligned_check(v, a, err);      \
 41                 val |= v << 8;                          \
 42                 if (err)                                \
 43                         goto fault;                     \
 44         } while (0)
 45 
 46 #define get32_unaligned_check(val, addr)                \
 47         do {                                            \
 48                 unsigned int err = 0, v, a = addr;      \
 49                 __get8_unaligned_check(v, a, err);      \
 50                 val =  v << 0;                          \
 51                 __get8_unaligned_check(v, a, err);      \
 52                 val |= v << 8;                          \
 53                 __get8_unaligned_check(v, a, err);      \
 54                 val |= v << 16;                         \
 55                 __get8_unaligned_check(v, a, err);      \
 56                 val |= v << 24;                         \
 57                 if (err)                                \
 58                         goto fault;                     \
 59         } while (0)
 60 
 61 #define put16_unaligned_check(val, addr)                \
 62         do {                                            \
 63                 unsigned int err = 0, v = val, a = addr;\
 64                                                         \
 65                 __asm__(                                \
 66                 "1:     stb.ab  %1, [%2, 1]\n"          \
 67                 "       lsr %1, %1, 8\n"                \
 68                 "2:     stb     %1, [%2]\n"             \
 69                 "3:\n"                                  \
 70                 "       .section .fixup,\"ax\"\n"       \
 71                 "       .align  4\n"                    \
 72                 "4:     mov     %0, 1\n"                \
 73                 "       b       3b\n"                   \
 74                 "       .previous\n"                    \
 75                 "       .section __ex_table,\"a\"\n"    \
 76                 "       .align  4\n"                    \
 77                 "       .long   1b, 4b\n"               \
 78                 "       .long   2b, 4b\n"               \
 79                 "       .previous\n"                    \
 80                 : "=r" (err), "=&r" (v), "=&r" (a)      \
 81                 : "" (err), "1" (v), "2" (a));         \
 82                                                         \
 83                 if (err)                                \
 84                         goto fault;                     \
 85         } while (0)
 86 
 87 #define put32_unaligned_check(val, addr)                \
 88         do {                                            \
 89                 unsigned int err = 0, v = val, a = addr;\
 90                 __asm__(                                \
 91                                                         \
 92                 "1:     stb.ab  %1, [%2, 1]\n"          \
 93                 "       lsr %1, %1, 8\n"                \
 94                 "2:     stb.ab  %1, [%2, 1]\n"          \
 95                 "       lsr %1, %1, 8\n"                \
 96                 "3:     stb.ab  %1, [%2, 1]\n"          \
 97                 "       lsr %1, %1, 8\n"                \
 98                 "4:     stb     %1, [%2]\n"             \
 99                 "5:\n"                                  \
100                 "       .section .fixup,\"ax\"\n"       \
101                 "       .align  4\n"                    \
102                 "6:     mov     %0, 1\n"                \
103                 "       b       5b\n"                   \
104                 "       .previous\n"                    \
105                 "       .section __ex_table,\"a\"\n"    \
106                 "       .align  4\n"                    \
107                 "       .long   1b, 6b\n"               \
108                 "       .long   2b, 6b\n"               \
109                 "       .long   3b, 6b\n"               \
110                 "       .long   4b, 6b\n"               \
111                 "       .previous\n"                    \
112                 : "=r" (err), "=&r" (v), "=&r" (a)      \
113                 : "" (err), "1" (v), "2" (a));         \
114                                                         \
115                 if (err)                                \
116                         goto fault;                     \
117         } while (0)
118 
119 /* sysctl hooks */
120 int unaligned_enabled __read_mostly = 1;        /* Enabled by default */
121 int no_unaligned_warning __read_mostly = 1;     /* Only 1 warning by default */
122 
123 static void fixup_load(struct disasm_state *state, struct pt_regs *regs,
124                         struct callee_regs *cregs)
125 {
126         int val;
127 
128         /* register write back */
129         if ((state->aa == 1) || (state->aa == 2)) {
130                 set_reg(state->wb_reg, state->src1 + state->src2, regs, cregs);
131 
132                 if (state->aa == 2)
133                         state->src2 = 0;
134         }
135 
136         if (state->zz == 0) {
137                 get32_unaligned_check(val, state->src1 + state->src2);
138         } else {
139                 get16_unaligned_check(val, state->src1 + state->src2);
140 
141                 if (state->x)
142                         val = (val << 16) >> 16;
143         }
144 
145         if (state->pref == 0)
146                 set_reg(state->dest, val, regs, cregs);
147 
148         return;
149 
150 fault:  state->fault = 1;
151 }
152 
153 static void fixup_store(struct disasm_state *state, struct pt_regs *regs,
154                         struct callee_regs *cregs)
155 {
156         /* register write back */
157         if ((state->aa == 1) || (state->aa == 2)) {
158                 set_reg(state->wb_reg, state->src2 + state->src3, regs, cregs);
159 
160                 if (state->aa == 3)
161                         state->src3 = 0;
162         } else if (state->aa == 3) {
163                 if (state->zz == 2) {
164                         set_reg(state->wb_reg, state->src2 + (state->src3 << 1),
165                                 regs, cregs);
166                 } else if (!state->zz) {
167                         set_reg(state->wb_reg, state->src2 + (state->src3 << 2),
168                                 regs, cregs);
169                 } else {
170                         goto fault;
171                 }
172         }
173 
174         /* write fix-up */
175         if (!state->zz)
176                 put32_unaligned_check(state->src1, state->src2 + state->src3);
177         else
178                 put16_unaligned_check(state->src1, state->src2 + state->src3);
179 
180         return;
181 
182 fault:  state->fault = 1;
183 }
184 
185 /*
186  * Handle an unaligned access
187  * Returns 0 if successfully handled, 1 if some error happened
188  */
189 int misaligned_fixup(unsigned long address, struct pt_regs *regs,
190                      unsigned long cause, struct callee_regs *cregs)
191 {
192         struct disasm_state state;
193         char buf[TASK_COMM_LEN];
194 
195         /* handle user mode only and only if enabled by sysadmin */
196         if (!user_mode(regs) || !unaligned_enabled)
197                 return 1;
198 
199         if (no_unaligned_warning) {
200                 pr_warn_once("%s(%d) made unaligned access which was emulated"
201                              " by kernel assist\n. This can degrade application"
202                              " performance significantly\n. To enable further"
203                              " logging of such instances, please \n"
204                              " echo 0 > /proc/sys/kernel/ignore-unaligned-usertrap\n",
205                              get_task_comm(buf, current), task_pid_nr(current));
206         } else {
207                 /* Add rate limiting if it gets down to it */
208                 pr_warn("%s(%d): unaligned access to/from 0x%lx by PC: 0x%lx\n",
209                         get_task_comm(buf, current), task_pid_nr(current),
210                         address, regs->ret);
211 
212         }
213 
214         disasm_instr(regs->ret, &state, 1, regs, cregs);
215 
216         if (state.fault)
217                 goto fault;
218 
219         /* ldb/stb should not have unaligned exception */
220         if ((state.zz == 1) || (state.di))
221                 goto fault;
222 
223         if (!state.write)
224                 fixup_load(&state, regs, cregs);
225         else
226                 fixup_store(&state, regs, cregs);
227 
228         if (state.fault)
229                 goto fault;
230 
231         if (delay_mode(regs)) {
232                 regs->ret = regs->bta;
233                 regs->status32 &= ~STATUS_DE_MASK;
234         } else {
235                 regs->ret += state.instr_len;
236         }
237 
238         return 0;
239 
240 fault:
241         pr_err("Alignment trap: fault in fix-up %08lx at [<%08lx>]\n",
242                 state.words[0], address);
243 
244         return 1;
245 }
246 

~ [ source navigation ] ~ [ diff markup ] ~ [ identifier search ] ~

kernel.org | git.kernel.org | LWN.net | Project Home | Wiki (Japanese) | Wiki (English) | SVN repository | Mail admin

Linux® is a registered trademark of Linus Torvalds in the United States and other countries.
TOMOYO® is a registered trademark of NTT DATA CORPORATION.

osdn.jp