]> www.pilppa.org Git - linux-2.6-omap-h63xx.git/blob - arch/mn10300/mm/misalignment.c
MN10300: Handle misaligned SP-based operands
[linux-2.6-omap-h63xx.git] / arch / mn10300 / mm / misalignment.c
1 /* MN10300 Misalignment fixup handler
2  *
3  * Copyright (C) 2007 Red Hat, Inc. All Rights Reserved.
4  * Written by David Howells (dhowells@redhat.com)
5  *
6  * This program is free software; you can redistribute it and/or
7  * modify it under the terms of the GNU General Public Licence
8  * as published by the Free Software Foundation; either version
9  * 2 of the Licence, or (at your option) any later version.
10  */
11 #include <linux/module.h>
12 #include <linux/sched.h>
13 #include <linux/kernel.h>
14 #include <linux/string.h>
15 #include <linux/errno.h>
16 #include <linux/ptrace.h>
17 #include <linux/timer.h>
18 #include <linux/mm.h>
19 #include <linux/smp.h>
20 #include <linux/smp_lock.h>
21 #include <linux/init.h>
22 #include <linux/delay.h>
23 #include <linux/spinlock.h>
24 #include <linux/interrupt.h>
25 #include <linux/pci.h>
26 #include <asm/processor.h>
27 #include <asm/system.h>
28 #include <asm/uaccess.h>
29 #include <asm/io.h>
30 #include <asm/atomic.h>
31 #include <asm/smp.h>
32 #include <asm/pgalloc.h>
33 #include <asm/cpu-regs.h>
34 #include <asm/busctl-regs.h>
35 #include <asm/fpu.h>
36 #include <asm/gdb-stub.h>
37 #include <asm/asm-offsets.h>
38
39 #if 0
40 #define kdebug(FMT, ...) printk(KERN_DEBUG "MISALIGN: "FMT"\n", ##__VA_ARGS__)
41 #else
42 #define kdebug(FMT, ...) do {} while (0)
43 #endif
44
45 static int misalignment_addr(unsigned long *registers, unsigned long sp,
46                              unsigned params, unsigned opcode,
47                              unsigned long disp,
48                              void **_address, unsigned long **_postinc,
49                              unsigned long *_inc);
50
51 static int misalignment_reg(unsigned long *registers, unsigned params,
52                             unsigned opcode, unsigned long disp,
53                             unsigned long **_register);
54
55 static void misalignment_MOV_Lcc(struct pt_regs *regs, uint32_t opcode);
56
57 static const unsigned Dreg_index[] = {
58         REG_D0 >> 2, REG_D1 >> 2, REG_D2 >> 2, REG_D3 >> 2
59 };
60
61 static const unsigned Areg_index[] = {
62         REG_A0 >> 2, REG_A1 >> 2, REG_A2 >> 2, REG_A3 >> 2
63 };
64
65 static const unsigned Rreg_index[] = {
66         REG_E0 >> 2, REG_E1 >> 2, REG_E2 >> 2, REG_E3 >> 2,
67         REG_E4 >> 2, REG_E5 >> 2, REG_E6 >> 2, REG_E7 >> 2,
68         REG_A0 >> 2, REG_A1 >> 2, REG_A2 >> 2, REG_A3 >> 2,
69         REG_D0 >> 2, REG_D1 >> 2, REG_D2 >> 2, REG_D3 >> 2
70 };
71
72 enum format_id {
73         FMT_S0,
74         FMT_S1,
75         FMT_S2,
76         FMT_S4,
77         FMT_D0,
78         FMT_D1,
79         FMT_D2,
80         FMT_D4,
81         FMT_D6,
82         FMT_D7,
83         FMT_D8,
84         FMT_D9,
85         FMT_D10,
86 };
87
88 static const struct {
89         u_int8_t opsz, dispsz;
90 } format_tbl[16] = {
91         [FMT_S0]        = { 8,  0       },
92         [FMT_S1]        = { 8,  8       },
93         [FMT_S2]        = { 8,  16      },
94         [FMT_S4]        = { 8,  32      },
95         [FMT_D0]        = { 16, 0       },
96         [FMT_D1]        = { 16, 8       },
97         [FMT_D2]        = { 16, 16      },
98         [FMT_D4]        = { 16, 32      },
99         [FMT_D6]        = { 24, 0       },
100         [FMT_D7]        = { 24, 8       },
101         [FMT_D8]        = { 24, 24      },
102         [FMT_D9]        = { 24, 32      },
103         [FMT_D10]       = { 32, 0       },
104 };
105
106 enum value_id {
107         DM0,            /* data reg in opcode in bits 0-1 */
108         DM1,            /* data reg in opcode in bits 2-3 */
109         DM2,            /* data reg in opcode in bits 4-5 */
110         AM0,            /* addr reg in opcode in bits 0-1 */
111         AM1,            /* addr reg in opcode in bits 2-3 */
112         AM2,            /* addr reg in opcode in bits 4-5 */
113         RM0,            /* reg in opcode in bits 0-3 */
114         RM1,            /* reg in opcode in bits 2-5 */
115         RM2,            /* reg in opcode in bits 4-7 */
116         RM4,            /* reg in opcode in bits 8-11 */
117         RM6,            /* reg in opcode in bits 12-15 */
118
119         RD0,            /* reg in displacement in bits 0-3 */
120         RD2,            /* reg in displacement in bits 4-7 */
121
122         SP,             /* stack pointer */
123
124         SD8,            /* 8-bit signed displacement */
125         SD16,           /* 16-bit signed displacement */
126         SD24,           /* 24-bit signed displacement */
127         SIMM4_2,        /* 4-bit signed displacement in opcode bits 4-7 */
128         SIMM8,          /* 8-bit signed immediate */
129         IMM8,           /* 8-bit unsigned immediate */
130         IMM16,          /* 16-bit unsigned immediate */
131         IMM24,          /* 24-bit unsigned immediate */
132         IMM32,          /* 32-bit unsigned immediate */
133         IMM32_HIGH8,    /* 32-bit unsigned immediate, LSB in opcode */
134
135         IMM32_MEM,      /* 32-bit unsigned displacement */
136         IMM32_HIGH8_MEM, /* 32-bit unsigned displacement, LSB in opcode */
137
138         DN0     = DM0,
139         DN1     = DM1,
140         DN2     = DM2,
141         AN0     = AM0,
142         AN1     = AM1,
143         AN2     = AM2,
144         RN0     = RM0,
145         RN1     = RM1,
146         RN2     = RM2,
147         RN4     = RM4,
148         RN6     = RM6,
149         DI      = DM1,
150         RI      = RM2,
151
152 };
153
154 struct mn10300_opcode {
155         const char      name[8];
156         u_int32_t       opcode;
157         u_int32_t       opmask;
158         unsigned        exclusion;
159
160         enum format_id  format;
161
162         unsigned        cpu_mask;
163 #define AM33    330
164
165         unsigned        params[2];
166 #define MEM(ADDR)               (0x80000000 | (ADDR))
167 #define MEM2(ADDR1, ADDR2)      (0x80000000 | (ADDR1) << 8 | (ADDR2))
168 #define MEMINC(ADDR)            (0x81000000 | (ADDR))
169 #define MEMINC2(ADDR, INC)      (0x81000000 | (ADDR) << 8 | (INC))
170 };
171
172 /* LIBOPCODES EXCERPT
173    Assemble Matsushita MN10300 instructions.
174    Copyright 1996, 1997, 1998, 1999, 2000 Free Software Foundation, Inc.
175
176    This program is free software; you can redistribute it and/or modify
177    it under the terms of the GNU General Public Licence as published by
178    the Free Software Foundation; either version 2 of the Licence, or
179    (at your option) any later version.
180
181    This program is distributed in the hope that it will be useful,
182    but WITHOUT ANY WARRANTY; without even the implied warranty of
183    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
184    GNU General Public Licence for more details.
185
186    You should have received a copy of the GNU General Public Licence
187    along with this program; if not, write to the Free Software
188    Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
189 */
190 static const struct mn10300_opcode mn10300_opcodes[] = {
191 { "mov",        0x4200,      0xf300,      0,    FMT_S1, 0,      {DM1, MEM2(IMM8, SP)}},
192 { "mov",        0x4300,      0xf300,      0,    FMT_S1, 0,      {AM1, MEM2(IMM8, SP)}},
193 { "mov",        0x5800,      0xfc00,      0,    FMT_S1, 0,      {MEM2(IMM8, SP), DN0}},
194 { "mov",        0x5c00,      0xfc00,      0,    FMT_S1, 0,      {MEM2(IMM8, SP), AN0}},
195 { "mov",        0x60,        0xf0,        0,    FMT_S0, 0,      {DM1, MEM(AN0)}},
196 { "mov",        0x70,        0xf0,        0,    FMT_S0, 0,      {MEM(AM0), DN1}},
197 { "mov",        0xf000,      0xfff0,      0,    FMT_D0, 0,      {MEM(AM0), AN1}},
198 { "mov",        0xf010,      0xfff0,      0,    FMT_D0, 0,      {AM1, MEM(AN0)}},
199 { "mov",        0xf300,      0xffc0,      0,    FMT_D0, 0,      {MEM2(DI, AM0), DN2}},
200 { "mov",        0xf340,      0xffc0,      0,    FMT_D0, 0,      {DM2, MEM2(DI, AN0)}},
201 { "mov",        0xf380,      0xffc0,      0,    FMT_D0, 0,      {MEM2(DI, AM0), AN2}},
202 { "mov",        0xf3c0,      0xffc0,      0,    FMT_D0, 0,      {AM2, MEM2(DI, AN0)}},
203 { "mov",        0xf80000,    0xfff000,    0,    FMT_D1, 0,      {MEM2(SD8, AM0), DN1}},
204 { "mov",        0xf81000,    0xfff000,    0,    FMT_D1, 0,      {DM1, MEM2(SD8, AN0)}},
205 { "mov",        0xf82000,    0xfff000,    0,    FMT_D1, 0,      {MEM2(SD8,AM0), AN1}},
206 { "mov",        0xf83000,    0xfff000,    0,    FMT_D1, 0,      {AM1, MEM2(SD8, AN0)}},
207 { "mov",        0xf8f000,    0xfffc00,    0,    FMT_D1, AM33,   {MEM2(SD8, AM0), SP}},
208 { "mov",        0xf8f400,    0xfffc00,    0,    FMT_D1, AM33,   {SP, MEM2(SD8, AN0)}},
209 { "mov",        0xf90a00,    0xffff00,    0,    FMT_D6, AM33,   {MEM(RM0), RN2}},
210 { "mov",        0xf91a00,    0xffff00,    0,    FMT_D6, AM33,   {RM2, MEM(RN0)}},
211 { "mov",        0xf96a00,    0xffff00,    0x12, FMT_D6, AM33,   {MEMINC(RM0), RN2}},
212 { "mov",        0xf97a00,    0xffff00,    0,    FMT_D6, AM33,   {RM2, MEMINC(RN0)}},
213 { "mov",        0xfa000000,  0xfff00000,  0,    FMT_D2, 0,      {MEM2(SD16, AM0), DN1}},
214 { "mov",        0xfa100000,  0xfff00000,  0,    FMT_D2, 0,      {DM1, MEM2(SD16, AN0)}},
215 { "mov",        0xfa200000,  0xfff00000,  0,    FMT_D2, 0,      {MEM2(SD16, AM0), AN1}},
216 { "mov",        0xfa300000,  0xfff00000,  0,    FMT_D2, 0,      {AM1, MEM2(SD16, AN0)}},
217 { "mov",        0xfa900000,  0xfff30000,  0,    FMT_D2, 0,      {AM1, MEM2(IMM16, SP)}},
218 { "mov",        0xfa910000,  0xfff30000,  0,    FMT_D2, 0,      {DM1, MEM2(IMM16, SP)}},
219 { "mov",        0xfab00000,  0xfffc0000,  0,    FMT_D2, 0,      {MEM2(IMM16, SP), AN0}},
220 { "mov",        0xfab40000,  0xfffc0000,  0,    FMT_D2, 0,      {MEM2(IMM16, SP), DN0}},
221 { "mov",        0xfb0a0000,  0xffff0000,  0,    FMT_D7, AM33,   {MEM2(SD8, RM0), RN2}},
222 { "mov",        0xfb1a0000,  0xffff0000,  0,    FMT_D7, AM33,   {RM2, MEM2(SD8, RN0)}},
223 { "mov",        0xfb6a0000,  0xffff0000,  0x22, FMT_D7, AM33,   {MEMINC2 (RM0, SIMM8), RN2}},
224 { "mov",        0xfb7a0000,  0xffff0000,  0,    FMT_D7, AM33,   {RM2, MEMINC2 (RN0, SIMM8)}},
225 { "mov",        0xfb8a0000,  0xffff0f00,  0,    FMT_D7, AM33,   {MEM2(IMM8, SP), RN2}},
226 { "mov",        0xfb8e0000,  0xffff000f,  0,    FMT_D7, AM33,   {MEM2(RI, RM0), RD2}},
227 { "mov",        0xfb9a0000,  0xffff0f00,  0,    FMT_D7, AM33,   {RM2, MEM2(IMM8, SP)}},
228 { "mov",        0xfb9e0000,  0xffff000f,  0,    FMT_D7, AM33,   {RD2, MEM2(RI, RN0)}},
229 { "mov",        0xfc000000,  0xfff00000,  0,    FMT_D4, 0,      {MEM2(IMM32,AM0), DN1}},
230 { "mov",        0xfc100000,  0xfff00000,  0,    FMT_D4, 0,      {DM1, MEM2(IMM32,AN0)}},
231 { "mov",        0xfc200000,  0xfff00000,  0,    FMT_D4, 0,      {MEM2(IMM32,AM0), AN1}},
232 { "mov",        0xfc300000,  0xfff00000,  0,    FMT_D4, 0,      {AM1, MEM2(IMM32,AN0)}},
233 { "mov",        0xfc800000,  0xfff30000,  0,    FMT_D4, 0,      {AM1, MEM(IMM32_MEM)}},
234 { "mov",        0xfc810000,  0xfff30000,  0,    FMT_D4, 0,      {DM1, MEM(IMM32_MEM)}},
235 { "mov",        0xfc900000,  0xfff30000,  0,    FMT_D4, 0,      {AM1, MEM2(IMM32, SP)}},
236 { "mov",        0xfc910000,  0xfff30000,  0,    FMT_D4, 0,      {DM1, MEM2(IMM32, SP)}},
237 { "mov",        0xfca00000,  0xfffc0000,  0,    FMT_D4, 0,      {MEM(IMM32_MEM), AN0}},
238 { "mov",        0xfca40000,  0xfffc0000,  0,    FMT_D4, 0,      {MEM(IMM32_MEM), DN0}},
239 { "mov",        0xfcb00000,  0xfffc0000,  0,    FMT_D4, 0,      {MEM2(IMM32, SP), AN0}},
240 { "mov",        0xfcb40000,  0xfffc0000,  0,    FMT_D4, 0,      {MEM2(IMM32, SP), DN0}},
241 { "mov",        0xfd0a0000,  0xffff0000,  0,    FMT_D8, AM33,   {MEM2(SD24, RM0), RN2}},
242 { "mov",        0xfd1a0000,  0xffff0000,  0,    FMT_D8, AM33,   {RM2, MEM2(SD24, RN0)}},
243 { "mov",        0xfd6a0000,  0xffff0000,  0x22, FMT_D8, AM33,   {MEMINC2 (RM0, IMM24), RN2}},
244 { "mov",        0xfd7a0000,  0xffff0000,  0,    FMT_D8, AM33,   {RM2, MEMINC2 (RN0, IMM24)}},
245 { "mov",        0xfd8a0000,  0xffff0f00,  0,    FMT_D8, AM33,   {MEM2(IMM24, SP), RN2}},
246 { "mov",        0xfd9a0000,  0xffff0f00,  0,    FMT_D8, AM33,   {RM2, MEM2(IMM24, SP)}},
247 { "mov",        0xfe0a0000,  0xffff0000,  0,    FMT_D9, AM33,   {MEM2(IMM32_HIGH8,RM0), RN2}},
248 { "mov",        0xfe0a0000,  0xffff0000,  0,    FMT_D9, AM33,   {MEM2(IMM32_HIGH8,RM0), RN2}},
249 { "mov",        0xfe0e0000,  0xffff0f00,  0,    FMT_D9, AM33,   {MEM(IMM32_HIGH8_MEM), RN2}},
250 { "mov",        0xfe1a0000,  0xffff0000,  0,    FMT_D9, AM33,   {RM2, MEM2(IMM32_HIGH8, RN0)}},
251 { "mov",        0xfe1a0000,  0xffff0000,  0,    FMT_D9, AM33,   {RM2, MEM2(IMM32_HIGH8, RN0)}},
252 { "mov",        0xfe1e0000,  0xffff0f00,  0,    FMT_D9, AM33,   {RM2, MEM(IMM32_HIGH8_MEM)}},
253 { "mov",        0xfe6a0000,  0xffff0000,  0x22, FMT_D9, AM33,   {MEMINC2 (RM0, IMM32_HIGH8), RN2}},
254 { "mov",        0xfe7a0000,  0xffff0000,  0,    FMT_D9, AM33,   {RN2, MEMINC2 (RM0, IMM32_HIGH8)}},
255 { "mov",        0xfe8a0000,  0xffff0f00,  0,    FMT_D9, AM33,   {MEM2(IMM32_HIGH8, SP), RN2}},
256 { "mov",        0xfe9a0000,  0xffff0f00,  0,    FMT_D9, AM33,   {RM2, MEM2(IMM32_HIGH8, SP)}},
257
258 { "movhu",      0xf060,      0xfff0,      0,    FMT_D0, 0,      {MEM(AM0), DN1}},
259 { "movhu",      0xf070,      0xfff0,      0,    FMT_D0, 0,      {DM1, MEM(AN0)}},
260 { "movhu",      0xf480,      0xffc0,      0,    FMT_D0, 0,      {MEM2(DI, AM0), DN2}},
261 { "movhu",      0xf4c0,      0xffc0,      0,    FMT_D0, 0,      {DM2, MEM2(DI, AN0)}},
262 { "movhu",      0xf86000,    0xfff000,    0,    FMT_D1, 0,      {MEM2(SD8, AM0), DN1}},
263 { "movhu",      0xf87000,    0xfff000,    0,    FMT_D1, 0,      {DM1, MEM2(SD8, AN0)}},
264 { "movhu",      0xf89300,    0xfff300,    0,    FMT_D1, 0,      {DM1, MEM2(IMM8, SP)}},
265 { "movhu",      0xf8bc00,    0xfffc00,    0,    FMT_D1, 0,      {MEM2(IMM8, SP), DN0}},
266 { "movhu",      0xf94a00,    0xffff00,    0,    FMT_D6, AM33,   {MEM(RM0), RN2}},
267 { "movhu",      0xf95a00,    0xffff00,    0,    FMT_D6, AM33,   {RM2, MEM(RN0)}},
268 { "movhu",      0xf9ea00,    0xffff00,    0x12, FMT_D6, AM33,   {MEMINC(RM0), RN2}},
269 { "movhu",      0xf9fa00,    0xffff00,    0,    FMT_D6, AM33,   {RM2, MEMINC(RN0)}},
270 { "movhu",      0xfa600000,  0xfff00000,  0,    FMT_D2, 0,      {MEM2(SD16, AM0), DN1}},
271 { "movhu",      0xfa700000,  0xfff00000,  0,    FMT_D2, 0,      {DM1, MEM2(SD16, AN0)}},
272 { "movhu",      0xfa930000,  0xfff30000,  0,    FMT_D2, 0,      {DM1, MEM2(IMM16, SP)}},
273 { "movhu",      0xfabc0000,  0xfffc0000,  0,    FMT_D2, 0,      {MEM2(IMM16, SP), DN0}},
274 { "movhu",      0xfb4a0000,  0xffff0000,  0,    FMT_D7, AM33,   {MEM2(SD8, RM0), RN2}},
275 { "movhu",      0xfb5a0000,  0xffff0000,  0,    FMT_D7, AM33,   {RM2, MEM2(SD8, RN0)}},
276 { "movhu",      0xfbca0000,  0xffff0f00,  0,    FMT_D7, AM33,   {MEM2(IMM8, SP), RN2}},
277 { "movhu",      0xfbce0000,  0xffff000f,  0,    FMT_D7, AM33,   {MEM2(RI, RM0), RD2}},
278 { "movhu",      0xfbda0000,  0xffff0f00,  0,    FMT_D7, AM33,   {RM2, MEM2(IMM8, SP)}},
279 { "movhu",      0xfbde0000,  0xffff000f,  0,    FMT_D7, AM33,   {RD2, MEM2(RI, RN0)}},
280 { "movhu",      0xfbea0000,  0xffff0000,  0x22, FMT_D7, AM33,   {MEMINC2 (RM0, SIMM8), RN2}},
281 { "movhu",      0xfbfa0000,  0xffff0000,  0,    FMT_D7, AM33,   {RM2, MEMINC2 (RN0, SIMM8)}},
282 { "movhu",      0xfc600000,  0xfff00000,  0,    FMT_D4, 0,      {MEM2(IMM32,AM0), DN1}},
283 { "movhu",      0xfc700000,  0xfff00000,  0,    FMT_D4, 0,      {DM1, MEM2(IMM32,AN0)}},
284 { "movhu",      0xfc830000,  0xfff30000,  0,    FMT_D4, 0,      {DM1, MEM(IMM32_MEM)}},
285 { "movhu",      0xfc930000,  0xfff30000,  0,    FMT_D4, 0,      {DM1, MEM2(IMM32, SP)}},
286 { "movhu",      0xfcac0000,  0xfffc0000,  0,    FMT_D4, 0,      {MEM(IMM32_MEM), DN0}},
287 { "movhu",      0xfcbc0000,  0xfffc0000,  0,    FMT_D4, 0,      {MEM2(IMM32, SP), DN0}},
288 { "movhu",      0xfd4a0000,  0xffff0000,  0,    FMT_D8, AM33,   {MEM2(SD24, RM0), RN2}},
289 { "movhu",      0xfd5a0000,  0xffff0000,  0,    FMT_D8, AM33,   {RM2, MEM2(SD24, RN0)}},
290 { "movhu",      0xfdca0000,  0xffff0f00,  0,    FMT_D8, AM33,   {MEM2(IMM24, SP), RN2}},
291 { "movhu",      0xfdda0000,  0xffff0f00,  0,    FMT_D8, AM33,   {RM2, MEM2(IMM24, SP)}},
292 { "movhu",      0xfdea0000,  0xffff0000,  0x22, FMT_D8, AM33,   {MEMINC2 (RM0, IMM24), RN2}},
293 { "movhu",      0xfdfa0000,  0xffff0000,  0,    FMT_D8, AM33,   {RM2, MEMINC2 (RN0, IMM24)}},
294 { "movhu",      0xfe4a0000,  0xffff0000,  0,    FMT_D9, AM33,   {MEM2(IMM32_HIGH8,RM0), RN2}},
295 { "movhu",      0xfe4e0000,  0xffff0f00,  0,    FMT_D9, AM33,   {MEM(IMM32_HIGH8_MEM), RN2}},
296 { "movhu",      0xfe5a0000,  0xffff0000,  0,    FMT_D9, AM33,   {RM2, MEM2(IMM32_HIGH8, RN0)}},
297 { "movhu",      0xfe5e0000,  0xffff0f00,  0,    FMT_D9, AM33,   {RM2, MEM(IMM32_HIGH8_MEM)}},
298 { "movhu",      0xfeca0000,  0xffff0f00,  0,    FMT_D9, AM33,   {MEM2(IMM32_HIGH8, SP), RN2}},
299 { "movhu",      0xfeda0000,  0xffff0f00,  0,    FMT_D9, AM33,   {RM2, MEM2(IMM32_HIGH8, SP)}},
300 { "movhu",      0xfeea0000,  0xffff0000,  0x22, FMT_D9, AM33,   {MEMINC2 (RM0, IMM32_HIGH8), RN2}},
301 { "movhu",      0xfefa0000,  0xffff0000,  0,    FMT_D9, AM33,   {RN2, MEMINC2 (RM0, IMM32_HIGH8)}},
302
303 { "mov_llt",    0xf7e00000,  0xffff000f,  0x22, FMT_D10, AM33,   {MEMINC2 (RN4,SIMM4_2), RM6}},
304 { "mov_lgt",    0xf7e00001,  0xffff000f,  0x22, FMT_D10, AM33,   {MEMINC2 (RN4,SIMM4_2), RM6}},
305 { "mov_lge",    0xf7e00002,  0xffff000f,  0x22, FMT_D10, AM33,   {MEMINC2 (RN4,SIMM4_2), RM6}},
306 { "mov_lle",    0xf7e00003,  0xffff000f,  0x22, FMT_D10, AM33,   {MEMINC2 (RN4,SIMM4_2), RM6}},
307 { "mov_lcs",    0xf7e00004,  0xffff000f,  0x22, FMT_D10, AM33,   {MEMINC2 (RN4,SIMM4_2), RM6}},
308 { "mov_lhi",    0xf7e00005,  0xffff000f,  0x22, FMT_D10, AM33,   {MEMINC2 (RN4,SIMM4_2), RM6}},
309 { "mov_lcc",    0xf7e00006,  0xffff000f,  0x22, FMT_D10, AM33,   {MEMINC2 (RN4,SIMM4_2), RM6}},
310 { "mov_lls",    0xf7e00007,  0xffff000f,  0x22, FMT_D10, AM33,   {MEMINC2 (RN4,SIMM4_2), RM6}},
311 { "mov_leq",    0xf7e00008,  0xffff000f,  0x22, FMT_D10, AM33,   {MEMINC2 (RN4,SIMM4_2), RM6}},
312 { "mov_lne",    0xf7e00009,  0xffff000f,  0x22, FMT_D10, AM33,   {MEMINC2 (RN4,SIMM4_2), RM6}},
313 { "mov_lra",    0xf7e0000a,  0xffff000f,  0x22, FMT_D10, AM33,   {MEMINC2 (RN4,SIMM4_2), RM6}},
314
315 { "", 0, 0, 0, 0, 0, {0}},
316 };
317
318 /*
319  * fix up misalignment problems where possible
320  */
321 asmlinkage void misalignment(struct pt_regs *regs, enum exception_code code)
322 {
323         const struct exception_table_entry *fixup;
324         const struct mn10300_opcode *pop;
325         unsigned long *registers = (unsigned long *) regs;
326         unsigned long data, *store, *postinc, disp, inc, sp;
327         mm_segment_t seg;
328         siginfo_t info;
329         uint32_t opcode, noc, xo, xm;
330         uint8_t *pc, byte, datasz;
331         void *address;
332         unsigned tmp, npop, dispsz, loop;
333
334         if (user_mode(regs))
335                 sp = regs->sp;
336         else
337                 sp = (unsigned long) regs + sizeof(*regs);
338
339         kdebug("==>misalignment({pc=%lx,sp=%lx})", regs->pc, sp);
340
341         if (regs->epsw & EPSW_IE)
342                 asm volatile("or %0,epsw" : : "i"(EPSW_IE));
343
344         seg = get_fs();
345         set_fs(KERNEL_DS);
346
347         fixup = search_exception_tables(regs->pc);
348
349         /* first thing to do is to match the opcode */
350         pc = (u_int8_t *) regs->pc;
351
352         if (__get_user(byte, pc) != 0)
353                 goto fetch_error;
354         opcode = byte;
355         noc = 8;
356
357         for (pop = mn10300_opcodes; pop->name[0]; pop++) {
358                 npop = ilog2(pop->opcode | pop->opmask);
359                 if (npop <= 0 || npop > 31)
360                         continue;
361                 npop = (npop + 8) & ~7;
362
363         got_more_bits:
364                 if (npop == noc) {
365                         if ((opcode & pop->opmask) == pop->opcode)
366                                 goto found_opcode;
367                 } else if (npop > noc) {
368                         xo = pop->opcode >> (npop - noc);
369                         xm = pop->opmask >> (npop - noc);
370
371                         if ((opcode & xm) != xo)
372                                 continue;
373
374                         /* we've got a partial match (an exact match on the
375                          * first N bytes), so we need to get some more data */
376                         pc++;
377                         if (__get_user(byte, pc) != 0)
378                                 goto fetch_error;
379                         opcode = opcode << 8 | byte;
380                         noc += 8;
381                         goto got_more_bits;
382                 } else {
383                         /* there's already been a partial match as long as the
384                          * complete match we're now considering, so this one
385                          * should't match */
386                         continue;
387                 }
388         }
389
390         /* didn't manage to find a fixup */
391         if (!user_mode(regs))
392                 printk(KERN_CRIT "MISALIGN: %lx: unsupported instruction %x\n",
393                        regs->pc, opcode);
394
395 failed:
396         set_fs(seg);
397         if (die_if_no_fixup("misalignment error", regs, code))
398                 return;
399
400         info.si_signo   = SIGBUS;
401         info.si_errno   = 0;
402         info.si_code    = BUS_ADRALN;
403         info.si_addr    = (void *) regs->pc;
404         force_sig_info(SIGBUS, &info, current);
405         return;
406
407         /* error reading opcodes */
408 fetch_error:
409         if (!user_mode(regs))
410                 printk(KERN_CRIT
411                        "MISALIGN: %p: fault whilst reading instruction data\n",
412                        pc);
413         goto failed;
414
415 bad_addr_mode:
416         if (!user_mode(regs))
417                 printk(KERN_CRIT
418                        "MISALIGN: %lx: unsupported addressing mode %x\n",
419                        regs->pc, opcode);
420         goto failed;
421
422 bad_reg_mode:
423         if (!user_mode(regs))
424                 printk(KERN_CRIT
425                        "MISALIGN: %lx: unsupported register mode %x\n",
426                        regs->pc, opcode);
427         goto failed;
428
429 unsupported_instruction:
430         if (!user_mode(regs))
431                 printk(KERN_CRIT
432                        "MISALIGN: %lx: unsupported instruction %x (%s)\n",
433                        regs->pc, opcode, pop->name);
434         goto failed;
435
436 transfer_failed:
437         set_fs(seg);
438         if (fixup) {
439                 regs->pc = fixup->fixup;
440                 return;
441         }
442         if (die_if_no_fixup("misalignment fixup", regs, code))
443                 return;
444
445         info.si_signo   = SIGSEGV;
446         info.si_errno   = 0;
447         info.si_code    = 0;
448         info.si_addr    = (void *) regs->pc;
449         force_sig_info(SIGSEGV, &info, current);
450         return;
451
452         /* we matched the opcode */
453 found_opcode:
454         kdebug("%lx: %x==%x { %x, %x }",
455                regs->pc, opcode, pop->opcode, pop->params[0], pop->params[1]);
456
457         tmp = format_tbl[pop->format].opsz;
458         if (tmp > noc)
459                 BUG(); /* match was less complete than it ought to have been */
460
461         if (tmp < noc) {
462                 tmp = noc - tmp;
463                 opcode >>= tmp;
464                 pc -= tmp >> 3;
465         }
466
467         /* grab the extra displacement (note it's LSB first) */
468         disp = 0;
469         dispsz = format_tbl[pop->format].dispsz;
470         for (loop = 0; loop < dispsz; loop += 8) {
471                 pc++;
472                 if (__get_user(byte, pc) != 0)
473                         goto fetch_error;
474                 disp |= byte << loop;
475                 kdebug("{%p} disp[%02x]=%02x", pc, loop, byte);
476         }
477
478         kdebug("disp=%lx", disp);
479
480         set_fs(KERNEL_XDS);
481         if (fixup || regs->epsw & EPSW_nSL)
482                 set_fs(seg);
483
484         tmp = (pop->params[0] ^ pop->params[1]) & 0x80000000;
485         if (!tmp) {
486                 if (!user_mode(regs))
487                         printk(KERN_CRIT
488                                "MISALIGN: %lx:"
489                                " insn not move to/from memory %x\n",
490                                regs->pc, opcode);
491                 goto failed;
492         }
493
494         /* determine the data transfer size of the move */
495         if (pop->name[3] == 0 || /* "mov" */
496             pop->name[4] == 'l') /* mov_lcc */
497                 inc = datasz = 4;
498         else if (pop->name[3] == 'h') /* movhu */
499                 inc = datasz = 2;
500         else
501                 goto unsupported_instruction;
502
503         if (pop->params[0] & 0x80000000) {
504                 /* move memory to register */
505                 if (!misalignment_addr(registers, sp,
506                                        pop->params[0], opcode, disp,
507                                        &address, &postinc, &inc))
508                         goto bad_addr_mode;
509
510                 if (!misalignment_reg(registers, pop->params[1], opcode, disp,
511                                       &store))
512                         goto bad_reg_mode;
513
514                 kdebug("mov%u (%p),DARn", datasz, address);
515                 if (copy_from_user(&data, (void *) address, datasz) != 0)
516                         goto transfer_failed;
517                 if (pop->params[0] & 0x1000000) {
518                         kdebug("inc=%lx", inc);
519                         *postinc += inc;
520                 }
521
522                 *store = data;
523                 kdebug("loaded %lx", data);
524         } else {
525                 /* move register to memory */
526                 if (!misalignment_reg(registers, pop->params[0], opcode, disp,
527                                       &store))
528                         goto bad_reg_mode;
529
530                 if (!misalignment_addr(registers, sp,
531                                        pop->params[1], opcode, disp,
532                                        &address, &postinc, &inc))
533                         goto bad_addr_mode;
534
535                 data = *store;
536
537                 kdebug("mov%u %lx,(%p)", datasz, data, address);
538                 if (copy_to_user((void *) address, &data, datasz) != 0)
539                         goto transfer_failed;
540                 if (pop->params[1] & 0x1000000)
541                         *postinc += inc;
542         }
543
544         tmp = format_tbl[pop->format].opsz + format_tbl[pop->format].dispsz;
545         regs->pc += tmp >> 3;
546
547         /* handle MOV_Lcc, which are currently the only FMT_D10 insns that
548          * access memory */
549         if (pop->format == FMT_D10)
550                 misalignment_MOV_Lcc(regs, opcode);
551
552         set_fs(seg);
553         return;
554 }
555
556 /*
557  * determine the address that was being accessed
558  */
559 static int misalignment_addr(unsigned long *registers, unsigned long sp,
560                              unsigned params, unsigned opcode,
561                              unsigned long disp,
562                              void **_address, unsigned long **_postinc,
563                              unsigned long *_inc)
564 {
565         unsigned long *postinc = NULL, address = 0, tmp;
566
567         if (!(params & 0x1000000)) {
568                 kdebug("noinc");
569                 *_inc = 0;
570                 _inc = NULL;
571         }
572
573         params &= 0x00ffffff;
574
575         do {
576                 switch (params & 0xff) {
577                 case DM0:
578                         postinc = &registers[Dreg_index[opcode & 0x03]];
579                         address += *postinc;
580                         break;
581                 case DM1:
582                         postinc = &registers[Dreg_index[opcode >> 2 & 0x03]];
583                         address += *postinc;
584                         break;
585                 case DM2:
586                         postinc = &registers[Dreg_index[opcode >> 4 & 0x03]];
587                         address += *postinc;
588                         break;
589                 case AM0:
590                         postinc = &registers[Areg_index[opcode & 0x03]];
591                         address += *postinc;
592                         break;
593                 case AM1:
594                         postinc = &registers[Areg_index[opcode >> 2 & 0x03]];
595                         address += *postinc;
596                         break;
597                 case AM2:
598                         postinc = &registers[Areg_index[opcode >> 4 & 0x03]];
599                         address += *postinc;
600                         break;
601                 case RM0:
602                         postinc = &registers[Rreg_index[opcode & 0x0f]];
603                         address += *postinc;
604                         break;
605                 case RM1:
606                         postinc = &registers[Rreg_index[opcode >> 2 & 0x0f]];
607                         address += *postinc;
608                         break;
609                 case RM2:
610                         postinc = &registers[Rreg_index[opcode >> 4 & 0x0f]];
611                         address += *postinc;
612                         break;
613                 case RM4:
614                         postinc = &registers[Rreg_index[opcode >> 8 & 0x0f]];
615                         address += *postinc;
616                         break;
617                 case RM6:
618                         postinc = &registers[Rreg_index[opcode >> 12 & 0x0f]];
619                         address += *postinc;
620                         break;
621                 case RD0:
622                         postinc = &registers[Rreg_index[disp & 0x0f]];
623                         address += *postinc;
624                         break;
625                 case RD2:
626                         postinc = &registers[Rreg_index[disp >> 4 & 0x0f]];
627                         address += *postinc;
628                         break;
629                 case SP:
630                         address += sp;
631                         break;
632
633                         /* displacements are either to be added to the address
634                          * before use, or, in the case of post-inc addressing,
635                          * to be added into the base register after use */
636                 case SD8:
637                 case SIMM8:
638                         disp = (long) (int8_t) (disp & 0xff);
639                         goto displace_or_inc;
640                 case SD16:
641                         disp = (long) (int16_t) (disp & 0xffff);
642                         goto displace_or_inc;
643                 case SD24:
644                         tmp = disp << 8;
645                         asm("asr 8,%0" : "=r"(tmp) : "0"(tmp));
646                         disp = (long) tmp;
647                         goto displace_or_inc;
648                 case SIMM4_2:
649                         tmp = opcode >> 4 & 0x0f;
650                         tmp <<= 28;
651                         asm("asr 28,%0" : "=r"(tmp) : "0"(tmp));
652                         disp = (long) tmp;
653                         goto displace_or_inc;
654                 case IMM8:
655                         disp &= 0x000000ff;
656                         goto displace_or_inc;
657                 case IMM16:
658                         disp &= 0x0000ffff;
659                         goto displace_or_inc;
660                 case IMM24:
661                         disp &= 0x00ffffff;
662                         goto displace_or_inc;
663                 case IMM32:
664                 case IMM32_MEM:
665                 case IMM32_HIGH8:
666                 case IMM32_HIGH8_MEM:
667                 displace_or_inc:
668                         kdebug("%s %lx", _inc ? "incr" : "disp", disp);
669                         if (!_inc)
670                                 address += disp;
671                         else
672                                 *_inc = disp;
673                         break;
674                 default:
675                         BUG();
676                         return 0;
677                 }
678         } while ((params >>= 8));
679
680         *_address = (void *) address;
681         *_postinc = postinc;
682         return 1;
683 }
684
685 /*
686  * determine the register that is acting as source/dest
687  */
688 static int misalignment_reg(unsigned long *registers, unsigned params,
689                             unsigned opcode, unsigned long disp,
690                             unsigned long **_register)
691 {
692         params &= 0x7fffffff;
693
694         if (params & 0xffffff00)
695                 return 0;
696
697         switch (params & 0xff) {
698         case DM0:
699                 *_register = &registers[Dreg_index[opcode & 0x03]];
700                 break;
701         case DM1:
702                 *_register = &registers[Dreg_index[opcode >> 2 & 0x03]];
703                 break;
704         case DM2:
705                 *_register = &registers[Dreg_index[opcode >> 4 & 0x03]];
706                 break;
707         case AM0:
708                 *_register = &registers[Areg_index[opcode & 0x03]];
709                 break;
710         case AM1:
711                 *_register = &registers[Areg_index[opcode >> 2 & 0x03]];
712                 break;
713         case AM2:
714                 *_register = &registers[Areg_index[opcode >> 4 & 0x03]];
715                 break;
716         case RM0:
717                 *_register = &registers[Rreg_index[opcode & 0x0f]];
718                 break;
719         case RM1:
720                 *_register = &registers[Rreg_index[opcode >> 2 & 0x0f]];
721                 break;
722         case RM2:
723                 *_register = &registers[Rreg_index[opcode >> 4 & 0x0f]];
724                 break;
725         case RM4:
726                 *_register = &registers[Rreg_index[opcode >> 8 & 0x0f]];
727                 break;
728         case RM6:
729                 *_register = &registers[Rreg_index[opcode >> 12 & 0x0f]];
730                 break;
731         case RD0:
732                 *_register = &registers[Rreg_index[disp & 0x0f]];
733                 break;
734         case RD2:
735                 *_register = &registers[Rreg_index[disp >> 4 & 0x0f]];
736                 break;
737         case SP:
738                 *_register = &registers[REG_SP >> 2];
739                 break;
740
741         default:
742                 BUG();
743                 return 0;
744         }
745
746         return 1;
747 }
748
749 /*
750  * handle the conditional loop part of the move-and-loop instructions
751  */
752 static void misalignment_MOV_Lcc(struct pt_regs *regs, uint32_t opcode)
753 {
754         unsigned long epsw = regs->epsw;
755         unsigned long NxorV;
756
757         kdebug("MOV_Lcc %x [flags=%lx]", opcode, epsw & 0xf);
758
759         /* calculate N^V and shift onto the same bit position as Z */
760         NxorV = ((epsw >> 3) ^ epsw >> 1) & 1;
761
762         switch (opcode & 0xf) {
763         case 0x0: /* MOV_LLT: N^V */
764                 if (NxorV)
765                         goto take_the_loop;
766                 return;
767         case 0x1: /* MOV_LGT: ~(Z or (N^V))*/
768                 if (!((epsw & EPSW_FLAG_Z) | NxorV))
769                         goto take_the_loop;
770                 return;
771         case 0x2: /* MOV_LGE: ~(N^V) */
772                 if (!NxorV)
773                         goto take_the_loop;
774                 return;
775         case 0x3: /* MOV_LLE: Z or (N^V) */
776                 if ((epsw & EPSW_FLAG_Z) | NxorV)
777                         goto take_the_loop;
778                 return;
779
780         case 0x4: /* MOV_LCS: C */
781                 if (epsw & EPSW_FLAG_C)
782                         goto take_the_loop;
783                 return;
784         case 0x5: /* MOV_LHI: ~(C or Z) */
785                 if (!(epsw & (EPSW_FLAG_C | EPSW_FLAG_Z)))
786                         goto take_the_loop;
787                 return;
788         case 0x6: /* MOV_LCC: ~C */
789                 if (!(epsw & EPSW_FLAG_C))
790                         goto take_the_loop;
791                 return;
792         case 0x7: /* MOV_LLS: C or Z */
793                 if (epsw & (EPSW_FLAG_C | EPSW_FLAG_Z))
794                         goto take_the_loop;
795                 return;
796
797         case 0x8: /* MOV_LEQ: Z */
798                 if (epsw & EPSW_FLAG_Z)
799                         goto take_the_loop;
800                 return;
801         case 0x9: /* MOV_LNE: ~Z */
802                 if (!(epsw & EPSW_FLAG_Z))
803                         goto take_the_loop;
804                 return;
805         case 0xa: /* MOV_LRA: always */
806                 goto take_the_loop;
807
808         default:
809                 BUG();
810         }
811
812 take_the_loop:
813         /* wind the PC back to just after the SETLB insn */
814         kdebug("loop LAR=%lx", regs->lar);
815         regs->pc = regs->lar - 4;
816 }
817
818 /*
819  * misalignment handler tests
820  */
821 #ifdef CONFIG_TEST_MISALIGNMENT_HANDLER
822 static u8 __initdata testbuf[512] __attribute__((aligned(16))) = {
823         [257] = 0x11,
824         [258] = 0x22,
825         [259] = 0x33,
826         [260] = 0x44,
827 };
828
829 #define ASSERTCMP(X, OP, Y)                                             \
830 do {                                                                    \
831         if (unlikely(!((X) OP (Y)))) {                                  \
832                 printk(KERN_ERR "\n");                                  \
833                 printk(KERN_ERR "MISALIGN: Assertion failed at line %u\n", \
834                        __LINE__);                                       \
835                 printk(KERN_ERR "0x%lx " #OP " 0x%lx is false\n",       \
836                        (unsigned long)(X), (unsigned long)(Y));         \
837                 BUG();                                                  \
838         }                                                               \
839 } while(0)
840
841 static int __init test_misalignment(void)
842 {
843         register void *r asm("e0");
844         register u32 y asm("e1");
845         void *p = testbuf, *q;
846         u32 tmp, tmp2, x;
847
848         printk(KERN_NOTICE "==>test_misalignment() [testbuf=%p]\n", p);
849         p++;
850
851         printk(KERN_NOTICE "___ MOV (Am),Dn ___\n");
852         q = p + 256;
853         asm volatile("mov       (%0),%1" : "+a"(q), "=d"(x));
854         ASSERTCMP(q, ==, p + 256);
855         ASSERTCMP(x, ==, 0x44332211);
856
857         printk(KERN_NOTICE "___ MOV (256,Am),Dn ___\n");
858         q = p;
859         asm volatile("mov       (256,%0),%1" : "+a"(q), "=d"(x));
860         ASSERTCMP(q, ==, p);
861         ASSERTCMP(x, ==, 0x44332211);
862
863         printk(KERN_NOTICE "___ MOV (Di,Am),Dn ___\n");
864         tmp = 256;
865         q = p;
866         asm volatile("mov       (%2,%0),%1" : "+a"(q), "=d"(x), "+d"(tmp));
867         ASSERTCMP(q, ==, p);
868         ASSERTCMP(x, ==, 0x44332211);
869         ASSERTCMP(tmp, ==, 256);
870
871         printk(KERN_NOTICE "___ MOV (256,Rm),Rn ___\n");
872         r = p;
873         asm volatile("mov       (256,%0),%1" : "+r"(r), "=r"(y));
874         ASSERTCMP(r, ==, p);
875         ASSERTCMP(y, ==, 0x44332211);
876
877         printk(KERN_NOTICE "___ MOV (Rm+),Rn ___\n");
878         r = p + 256;
879         asm volatile("mov       (%0+),%1" : "+r"(r), "=r"(y));
880         ASSERTCMP(r, ==, p + 256 + 4);
881         ASSERTCMP(y, ==, 0x44332211);
882
883         printk(KERN_NOTICE "___ MOV (Rm+,8),Rn ___\n");
884         r = p + 256;
885         asm volatile("mov       (%0+,8),%1" : "+r"(r), "=r"(y));
886         ASSERTCMP(r, ==, p + 256 + 8);
887         ASSERTCMP(y, ==, 0x44332211);
888
889         printk(KERN_NOTICE "___ MOV (7,SP),Rn ___\n");
890         asm volatile(
891                 "add    -16,sp          \n"
892                 "mov    +0x11,%0        \n"
893                 "movbu  %0,(7,sp)       \n"
894                 "mov    +0x22,%0        \n"
895                 "movbu  %0,(8,sp)       \n"
896                 "mov    +0x33,%0        \n"
897                 "movbu  %0,(9,sp)       \n"
898                 "mov    +0x44,%0        \n"
899                 "movbu  %0,(10,sp)      \n"
900                 "mov    (7,sp),%1       \n"
901                 "add    +16,sp          \n"
902                 : "+a"(q), "=d"(x));
903         ASSERTCMP(x, ==, 0x44332211);
904
905         printk(KERN_NOTICE "___ MOV (259,SP),Rn ___\n");
906         asm volatile(
907                 "add    -264,sp         \n"
908                 "mov    +0x11,%0        \n"
909                 "movbu  %0,(259,sp)     \n"
910                 "mov    +0x22,%0        \n"
911                 "movbu  %0,(260,sp)     \n"
912                 "mov    +0x33,%0        \n"
913                 "movbu  %0,(261,sp)     \n"
914                 "mov    +0x55,%0        \n"
915                 "movbu  %0,(262,sp)     \n"
916                 "mov    (259,sp),%1     \n"
917                 "add    +264,sp         \n"
918                 : "+d"(tmp), "=d"(x));
919         ASSERTCMP(x, ==, 0x55332211);
920
921         printk(KERN_NOTICE "___ MOV (260,SP),Rn ___\n");
922         asm volatile(
923                 "add    -264,sp         \n"
924                 "mov    +0x11,%0        \n"
925                 "movbu  %0,(260,sp)     \n"
926                 "mov    +0x22,%0        \n"
927                 "movbu  %0,(261,sp)     \n"
928                 "mov    +0x33,%0        \n"
929                 "movbu  %0,(262,sp)     \n"
930                 "mov    +0x55,%0        \n"
931                 "movbu  %0,(263,sp)     \n"
932                 "mov    (260,sp),%1     \n"
933                 "add    +264,sp         \n"
934                 : "+d"(tmp), "=d"(x));
935         ASSERTCMP(x, ==, 0x55332211);
936
937
938         printk(KERN_NOTICE "___ MOV_LNE ___\n");
939         tmp = 1;
940         tmp2 = 2;
941         q = p + 256;
942         asm volatile(
943                 "setlb                  \n"
944                 "mov    %2,%3           \n"
945                 "mov    %1,%2           \n"
946                 "cmp    +0,%1           \n"
947                 "mov_lne        (%0+,4),%1"
948                 : "+r"(q), "+d"(tmp), "+d"(tmp2), "=d"(x)
949                 :
950                 : "cc");
951         ASSERTCMP(q, ==, p + 256 + 12);
952         ASSERTCMP(x, ==, 0x44332211);
953
954         printk(KERN_NOTICE "___ MOV in SETLB ___\n");
955         tmp = 1;
956         tmp2 = 2;
957         q = p + 256;
958         asm volatile(
959                 "setlb                  \n"
960                 "mov    %1,%3           \n"
961                 "mov    (%0+),%1        \n"
962                 "cmp    +0,%1           \n"
963                 "lne                    "
964                 : "+a"(q), "+d"(tmp), "+d"(tmp2), "=d"(x)
965                 :
966                 : "cc");
967
968         ASSERTCMP(q, ==, p + 256 + 8);
969         ASSERTCMP(x, ==, 0x44332211);
970
971         printk(KERN_NOTICE "<==test_misalignment()\n");
972         return 0;
973 }
974
975 arch_initcall(test_misalignment);
976
977 #endif /* CONFIG_TEST_MISALIGNMENT_HANDLER */