Linux Kernel
3.7.1
Main Page
Related Pages
Modules
Namespaces
Data Structures
Files
File List
Globals
All
Data Structures
Namespaces
Files
Functions
Variables
Typedefs
Enumerations
Enumerator
Macros
Groups
Pages
arch
parisc
kernel
unaligned.c
Go to the documentation of this file.
1
/*
2
* Unaligned memory access handler
3
*
4
* Copyright (C) 2001 Randolph Chung <
[email protected]
>
5
* Significantly tweaked by LaMont Jones <
[email protected]
>
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 as published by
9
* the Free Software Foundation; either version 2, or (at your option)
10
* any later version.
11
*
12
* This program is distributed in the hope that it will be useful,
13
* but WITHOUT ANY WARRANTY; without even the implied warranty of
14
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15
* GNU General Public License for more details.
16
*
17
* You should have received a copy of the GNU General Public License
18
* along with this program; if not, write to the Free Software
19
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
20
*
21
*/
22
23
#include <
linux/jiffies.h
>
24
#include <linux/kernel.h>
25
#include <linux/module.h>
26
#include <linux/sched.h>
27
#include <linux/signal.h>
28
#include <
linux/ratelimit.h
>
29
#include <asm/uaccess.h>
30
31
/* #define DEBUG_UNALIGNED 1 */
32
33
#ifdef DEBUG_UNALIGNED
34
#define DPRINTF(fmt, args...) do { printk(KERN_DEBUG "%s:%d:%s ", __FILE__, __LINE__, __func__ ); printk(KERN_DEBUG fmt, ##args ); } while (0)
35
#else
36
#define DPRINTF(fmt, args...)
37
#endif
38
39
#ifdef CONFIG_64BIT
40
#define RFMT "%016lx"
41
#else
42
#define RFMT "%08lx"
43
#endif
44
45
#define FIXUP_BRANCH(lbl) \
46
"\tldil L%%" #lbl ", %%r1\n" \
47
"\tldo R%%" #lbl "(%%r1), %%r1\n" \
48
"\tbv,n %%r0(%%r1)\n"
49
/* If you use FIXUP_BRANCH, then you must list this clobber */
50
#define FIXUP_BRANCH_CLOBBER "r1"
51
52
/* 1111 1100 0000 0000 0001 0011 1100 0000 */
53
#define OPCODE1(a,b,c) ((a)<<26|(b)<<12|(c)<<6)
54
#define OPCODE2(a,b) ((a)<<26|(b)<<1)
55
#define OPCODE3(a,b) ((a)<<26|(b)<<2)
56
#define OPCODE4(a) ((a)<<26)
57
#define OPCODE1_MASK OPCODE1(0x3f,1,0xf)
58
#define OPCODE2_MASK OPCODE2(0x3f,1)
59
#define OPCODE3_MASK OPCODE3(0x3f,1)
60
#define OPCODE4_MASK OPCODE4(0x3f)
61
62
/* skip LDB - never unaligned (index) */
63
#define OPCODE_LDH_I OPCODE1(0x03,0,0x1)
64
#define OPCODE_LDW_I OPCODE1(0x03,0,0x2)
65
#define OPCODE_LDD_I OPCODE1(0x03,0,0x3)
66
#define OPCODE_LDDA_I OPCODE1(0x03,0,0x4)
67
#define OPCODE_LDCD_I OPCODE1(0x03,0,0x5)
68
#define OPCODE_LDWA_I OPCODE1(0x03,0,0x6)
69
#define OPCODE_LDCW_I OPCODE1(0x03,0,0x7)
70
/* skip LDB - never unaligned (short) */
71
#define OPCODE_LDH_S OPCODE1(0x03,1,0x1)
72
#define OPCODE_LDW_S OPCODE1(0x03,1,0x2)
73
#define OPCODE_LDD_S OPCODE1(0x03,1,0x3)
74
#define OPCODE_LDDA_S OPCODE1(0x03,1,0x4)
75
#define OPCODE_LDCD_S OPCODE1(0x03,1,0x5)
76
#define OPCODE_LDWA_S OPCODE1(0x03,1,0x6)
77
#define OPCODE_LDCW_S OPCODE1(0x03,1,0x7)
78
/* skip STB - never unaligned */
79
#define OPCODE_STH OPCODE1(0x03,1,0x9)
80
#define OPCODE_STW OPCODE1(0x03,1,0xa)
81
#define OPCODE_STD OPCODE1(0x03,1,0xb)
82
/* skip STBY - never unaligned */
83
/* skip STDBY - never unaligned */
84
#define OPCODE_STWA OPCODE1(0x03,1,0xe)
85
#define OPCODE_STDA OPCODE1(0x03,1,0xf)
86
87
#define OPCODE_FLDWX OPCODE1(0x09,0,0x0)
88
#define OPCODE_FLDWXR OPCODE1(0x09,0,0x1)
89
#define OPCODE_FSTWX OPCODE1(0x09,0,0x8)
90
#define OPCODE_FSTWXR OPCODE1(0x09,0,0x9)
91
#define OPCODE_FLDWS OPCODE1(0x09,1,0x0)
92
#define OPCODE_FLDWSR OPCODE1(0x09,1,0x1)
93
#define OPCODE_FSTWS OPCODE1(0x09,1,0x8)
94
#define OPCODE_FSTWSR OPCODE1(0x09,1,0x9)
95
#define OPCODE_FLDDX OPCODE1(0x0b,0,0x0)
96
#define OPCODE_FSTDX OPCODE1(0x0b,0,0x8)
97
#define OPCODE_FLDDS OPCODE1(0x0b,1,0x0)
98
#define OPCODE_FSTDS OPCODE1(0x0b,1,0x8)
99
100
#define OPCODE_LDD_L OPCODE2(0x14,0)
101
#define OPCODE_FLDD_L OPCODE2(0x14,1)
102
#define OPCODE_STD_L OPCODE2(0x1c,0)
103
#define OPCODE_FSTD_L OPCODE2(0x1c,1)
104
105
#define OPCODE_LDW_M OPCODE3(0x17,1)
106
#define OPCODE_FLDW_L OPCODE3(0x17,0)
107
#define OPCODE_FSTW_L OPCODE3(0x1f,0)
108
#define OPCODE_STW_M OPCODE3(0x1f,1)
109
110
#define OPCODE_LDH_L OPCODE4(0x11)
111
#define OPCODE_LDW_L OPCODE4(0x12)
112
#define OPCODE_LDWM OPCODE4(0x13)
113
#define OPCODE_STH_L OPCODE4(0x19)
114
#define OPCODE_STW_L OPCODE4(0x1A)
115
#define OPCODE_STWM OPCODE4(0x1B)
116
117
#define MAJOR_OP(i) (((i)>>26)&0x3f)
118
#define R1(i) (((i)>>21)&0x1f)
119
#define R2(i) (((i)>>16)&0x1f)
120
#define R3(i) ((i)&0x1f)
121
#define FR3(i) ((((i)<<1)&0x1f)|(((i)>>6)&1))
122
#define IM(i,n) (((i)>>1&((1<<(n-1))-1))|((i)&1?((0-1L)<<(n-1)):0))
123
#define IM5_2(i) IM((i)>>16,5)
124
#define IM5_3(i) IM((i),5)
125
#define IM14(i) IM((i),14)
126
127
#define ERR_NOTHANDLED -1
128
#define ERR_PAGEFAULT -2
129
130
int
unaligned_enabled
__read_mostly
= 1;
131
132
void
die_if_kernel
(
char
*
str
,
struct
pt_regs
*
regs
,
long
err
);
133
134
static
int
emulate_ldh(
struct
pt_regs
*
regs
,
int
toreg)
135
{
136
unsigned
long
saddr
= regs->
ior
;
137
unsigned
long
val
= 0;
138
int
ret
;
139
140
DPRINTF
(
"load "
RFMT
":"
RFMT
" to r%d for 2 bytes\n"
,
141
regs->
isr
, regs->
ior
, toreg);
142
143
__asm__
__volatile__ (
144
" mtsp %4, %%sr1\n"
145
"1: ldbs 0(%%sr1,%3), %%r20\n"
146
"2: ldbs 1(%%sr1,%3), %0\n"
147
" depw %%r20, 23, 24, %0\n"
148
" copy %%r0, %1\n"
149
"3: \n"
150
" .section .fixup,\"ax\"\n"
151
"4: ldi -2, %1\n"
152
FIXUP_BRANCH
(3
b
)
153
" .previous\n"
154
ASM_EXCEPTIONTABLE_ENTRY
(1
b
, 4
b
)
155
ASM_EXCEPTIONTABLE_ENTRY
(2
b
, 4
b
)
156
:
"=r"
(val),
"=r"
(ret)
157
:
"0"
(val),
"r"
(saddr),
"r"
(regs->
isr
)
158
:
"r20"
,
FIXUP_BRANCH_CLOBBER
);
159
160
DPRINTF
(
"val = 0x"
RFMT
"\n"
, val);
161
162
if
(toreg)
163
regs->
gr
[toreg] =
val
;
164
165
return
ret
;
166
}
167
168
static
int
emulate_ldw(
struct
pt_regs
*regs,
int
toreg,
int
flop)
169
{
170
unsigned
long
saddr = regs->
ior
;
171
unsigned
long
val = 0;
172
int
ret
;
173
174
DPRINTF
(
"load "
RFMT
":"
RFMT
" to r%d for 4 bytes\n"
,
175
regs->
isr
, regs->
ior
, toreg);
176
177
__asm__
__volatile__ (
178
" zdep %3,28,2,%%r19\n"
/* r19=(ofs&3)*8 */
179
" mtsp %4, %%sr1\n"
180
" depw %%r0,31,2,%3\n"
181
"1: ldw 0(%%sr1,%3),%0\n"
182
"2: ldw 4(%%sr1,%3),%%r20\n"
183
" subi 32,%%r19,%%r19\n"
184
" mtctl %%r19,11\n"
185
" vshd %0,%%r20,%0\n"
186
" copy %%r0, %1\n"
187
"3: \n"
188
" .section .fixup,\"ax\"\n"
189
"4: ldi -2, %1\n"
190
FIXUP_BRANCH
(3
b
)
191
" .previous\n"
192
ASM_EXCEPTIONTABLE_ENTRY
(1
b
, 4
b
)
193
ASM_EXCEPTIONTABLE_ENTRY
(2
b
, 4
b
)
194
:
"=r"
(val),
"=r"
(ret)
195
:
"0"
(val),
"r"
(saddr),
"r"
(regs->
isr
)
196
:
"r19"
,
"r20"
,
FIXUP_BRANCH_CLOBBER
);
197
198
DPRINTF
(
"val = 0x"
RFMT
"\n"
, val);
199
200
if
(flop)
201
((
__u32
*)(regs->
fr
))[toreg] = val;
202
else
if
(toreg)
203
regs->
gr
[toreg] =
val
;
204
205
return
ret
;
206
}
207
static
int
emulate_ldd(
struct
pt_regs
*regs,
int
toreg,
int
flop)
208
{
209
unsigned
long
saddr = regs->
ior
;
210
__u64
val = 0;
211
int
ret
;
212
213
DPRINTF
(
"load "
RFMT
":"
RFMT
" to r%d for 8 bytes\n"
,
214
regs->
isr
, regs->
ior
, toreg);
215
#ifdef CONFIG_PA20
216
217
#ifndef CONFIG_64BIT
218
if
(!flop)
219
return
-1;
220
#endif
221
__asm__
__volatile__ (
222
" depd,z %3,60,3,%%r19\n"
/* r19=(ofs&7)*8 */
223
" mtsp %4, %%sr1\n"
224
" depd %%r0,63,3,%3\n"
225
"1: ldd 0(%%sr1,%3),%0\n"
226
"2: ldd 8(%%sr1,%3),%%r20\n"
227
" subi 64,%%r19,%%r19\n"
228
" mtsar %%r19\n"
229
" shrpd %0,%%r20,%%sar,%0\n"
230
" copy %%r0, %1\n"
231
"3: \n"
232
" .section .fixup,\"ax\"\n"
233
"4: ldi -2, %1\n"
234
FIXUP_BRANCH
(3
b
)
235
" .previous\n"
236
ASM_EXCEPTIONTABLE_ENTRY
(1
b
,4
b
)
237
ASM_EXCEPTIONTABLE_ENTRY
(2
b
,4
b
)
238
:
"=r"
(val),
"=r"
(ret)
239
:
"0"
(val),
"r"
(saddr),
"r"
(regs->
isr
)
240
:
"r19"
,
"r20"
,
FIXUP_BRANCH_CLOBBER
);
241
#else
242
{
243
unsigned
long
valh=0,vall=0;
244
__asm__
__volatile__ (
245
" zdep %5,29,2,%%r19\n"
/* r19=(ofs&3)*8 */
246
" mtsp %6, %%sr1\n"
247
" dep %%r0,31,2,%5\n"
248
"1: ldw 0(%%sr1,%5),%0\n"
249
"2: ldw 4(%%sr1,%5),%1\n"
250
"3: ldw 8(%%sr1,%5),%%r20\n"
251
" subi 32,%%r19,%%r19\n"
252
" mtsar %%r19\n"
253
" vshd %0,%1,%0\n"
254
" vshd %1,%%r20,%1\n"
255
" copy %%r0, %2\n"
256
"4: \n"
257
" .section .fixup,\"ax\"\n"
258
"5: ldi -2, %2\n"
259
FIXUP_BRANCH
(4
b
)
260
" .previous\n"
261
ASM_EXCEPTIONTABLE_ENTRY
(1
b
,5
b
)
262
ASM_EXCEPTIONTABLE_ENTRY
(2
b
,5
b
)
263
ASM_EXCEPTIONTABLE_ENTRY
(3
b
,5
b
)
264
:
"=r"
(valh),
"=r"
(vall),
"=r"
(ret)
265
:
"0"
(valh),
"1"
(vall),
"r"
(saddr),
"r"
(regs->
isr
)
266
:
"r19"
,
"r20"
,
FIXUP_BRANCH_CLOBBER
);
267
val=((
__u64
)valh<<32)|(
__u64
)vall;
268
}
269
#endif
270
271
DPRINTF
(
"val = 0x%llx\n"
, val);
272
273
if
(flop)
274
regs->
fr
[toreg] =
val
;
275
else
if
(toreg)
276
regs->
gr
[toreg] =
val
;
277
278
return
ret
;
279
}
280
281
static
int
emulate_sth(
struct
pt_regs
*regs,
int
frreg)
282
{
283
unsigned
long
val = regs->
gr
[frreg];
284
int
ret
;
285
286
if
(!frreg)
287
val = 0;
288
289
DPRINTF
(
"store r%d (0x"
RFMT
") to "
RFMT
":"
RFMT
" for 2 bytes\n"
, frreg,
290
val, regs->
isr
, regs->
ior
);
291
292
__asm__
__volatile__ (
293
" mtsp %3, %%sr1\n"
294
" extrw,u %1, 23, 8, %%r19\n"
295
"1: stb %1, 1(%%sr1, %2)\n"
296
"2: stb %%r19, 0(%%sr1, %2)\n"
297
" copy %%r0, %0\n"
298
"3: \n"
299
" .section .fixup,\"ax\"\n"
300
"4: ldi -2, %0\n"
301
FIXUP_BRANCH
(3
b
)
302
" .previous\n"
303
ASM_EXCEPTIONTABLE_ENTRY
(1
b
,4
b
)
304
ASM_EXCEPTIONTABLE_ENTRY
(2
b
,4
b
)
305
:
"=r"
(ret)
306
:
"r"
(val),
"r"
(regs->
ior
),
"r"
(regs->
isr
)
307
:
"r19"
,
FIXUP_BRANCH_CLOBBER
);
308
309
return
ret
;
310
}
311
312
static
int
emulate_stw(
struct
pt_regs
*regs,
int
frreg,
int
flop)
313
{
314
unsigned
long
val
;
315
int
ret
;
316
317
if
(flop)
318
val = ((
__u32
*)(regs->
fr
))[frreg];
319
else
if
(frreg)
320
val = regs->
gr
[frreg];
321
else
322
val = 0;
323
324
DPRINTF
(
"store r%d (0x"
RFMT
") to "
RFMT
":"
RFMT
" for 4 bytes\n"
, frreg,
325
val, regs->
isr
, regs->
ior
);
326
327
328
__asm__
__volatile__ (
329
" mtsp %3, %%sr1\n"
330
" zdep %2, 28, 2, %%r19\n"
331
" dep %%r0, 31, 2, %2\n"
332
" mtsar %%r19\n"
333
" depwi,z -2, %%sar, 32, %%r19\n"
334
"1: ldw 0(%%sr1,%2),%%r20\n"
335
"2: ldw 4(%%sr1,%2),%%r21\n"
336
" vshd %%r0, %1, %%r22\n"
337
" vshd %1, %%r0, %%r1\n"
338
" and %%r20, %%r19, %%r20\n"
339
" andcm %%r21, %%r19, %%r21\n"
340
" or %%r22, %%r20, %%r20\n"
341
" or %%r1, %%r21, %%r21\n"
342
" stw %%r20,0(%%sr1,%2)\n"
343
" stw %%r21,4(%%sr1,%2)\n"
344
" copy %%r0, %0\n"
345
"3: \n"
346
" .section .fixup,\"ax\"\n"
347
"4: ldi -2, %0\n"
348
FIXUP_BRANCH
(3
b
)
349
" .previous\n"
350
ASM_EXCEPTIONTABLE_ENTRY
(1
b
,4
b
)
351
ASM_EXCEPTIONTABLE_ENTRY
(2
b
,4
b
)
352
:
"=r"
(ret)
353
:
"r"
(val),
"r"
(regs->
ior
),
"r"
(regs->
isr
)
354
:
"r19"
,
"r20"
,
"r21"
,
"r22"
,
"r1"
,
FIXUP_BRANCH_CLOBBER
);
355
356
return
0;
357
}
358
static
int
emulate_std(
struct
pt_regs
*regs,
int
frreg,
int
flop)
359
{
360
__u64
val
;
361
int
ret
;
362
363
if
(flop)
364
val = regs->
fr
[frreg];
365
else
if
(frreg)
366
val = regs->
gr
[frreg];
367
else
368
val = 0;
369
370
DPRINTF
(
"store r%d (0x%016llx) to "
RFMT
":"
RFMT
" for 8 bytes\n"
, frreg,
371
val, regs->
isr
, regs->
ior
);
372
373
#ifdef CONFIG_PA20
374
#ifndef CONFIG_64BIT
375
if
(!flop)
376
return
-1;
377
#endif
378
__asm__
__volatile__ (
379
" mtsp %3, %%sr1\n"
380
" depd,z %2, 60, 3, %%r19\n"
381
" depd %%r0, 63, 3, %2\n"
382
" mtsar %%r19\n"
383
" depdi,z -2, %%sar, 64, %%r19\n"
384
"1: ldd 0(%%sr1,%2),%%r20\n"
385
"2: ldd 8(%%sr1,%2),%%r21\n"
386
" shrpd %%r0, %1, %%sar, %%r22\n"
387
" shrpd %1, %%r0, %%sar, %%r1\n"
388
" and %%r20, %%r19, %%r20\n"
389
" andcm %%r21, %%r19, %%r21\n"
390
" or %%r22, %%r20, %%r20\n"
391
" or %%r1, %%r21, %%r21\n"
392
"3: std %%r20,0(%%sr1,%2)\n"
393
"4: std %%r21,8(%%sr1,%2)\n"
394
" copy %%r0, %0\n"
395
"5: \n"
396
" .section .fixup,\"ax\"\n"
397
"6: ldi -2, %0\n"
398
FIXUP_BRANCH
(5
b
)
399
" .previous\n"
400
ASM_EXCEPTIONTABLE_ENTRY
(1
b
,6
b
)
401
ASM_EXCEPTIONTABLE_ENTRY
(2
b
,6
b
)
402
ASM_EXCEPTIONTABLE_ENTRY
(3
b
,6
b
)
403
ASM_EXCEPTIONTABLE_ENTRY
(4
b
,6
b
)
404
:
"=r"
(ret)
405
:
"r"
(val),
"r"
(regs->
ior
),
"r"
(regs->
isr
)
406
:
"r19"
,
"r20"
,
"r21"
,
"r22"
,
"r1"
,
FIXUP_BRANCH_CLOBBER
);
407
#else
408
{
409
unsigned
long
valh=(val>>32),vall=(val&0xffffffffl);
410
__asm__
__volatile__ (
411
" mtsp %4, %%sr1\n"
412
" zdep %2, 29, 2, %%r19\n"
413
" dep %%r0, 31, 2, %2\n"
414
" mtsar %%r19\n"
415
" zvdepi -2, 32, %%r19\n"
416
"1: ldw 0(%%sr1,%3),%%r20\n"
417
"2: ldw 8(%%sr1,%3),%%r21\n"
418
" vshd %1, %2, %%r1\n"
419
" vshd %%r0, %1, %1\n"
420
" vshd %2, %%r0, %2\n"
421
" and %%r20, %%r19, %%r20\n"
422
" andcm %%r21, %%r19, %%r21\n"
423
" or %1, %%r20, %1\n"
424
" or %2, %%r21, %2\n"
425
"3: stw %1,0(%%sr1,%1)\n"
426
"4: stw %%r1,4(%%sr1,%3)\n"
427
"5: stw %2,8(%%sr1,%3)\n"
428
" copy %%r0, %0\n"
429
"6: \n"
430
" .section .fixup,\"ax\"\n"
431
"7: ldi -2, %0\n"
432
FIXUP_BRANCH
(6
b
)
433
" .previous\n"
434
ASM_EXCEPTIONTABLE_ENTRY
(1
b
,7
b
)
435
ASM_EXCEPTIONTABLE_ENTRY
(2
b
,7
b
)
436
ASM_EXCEPTIONTABLE_ENTRY
(3
b
,7
b
)
437
ASM_EXCEPTIONTABLE_ENTRY
(4
b
,7
b
)
438
ASM_EXCEPTIONTABLE_ENTRY
(5
b
,7
b
)
439
:
"=r"
(ret)
440
:
"r"
(valh),
"r"
(vall),
"r"
(regs->
ior
),
"r"
(regs->
isr
)
441
:
"r19"
,
"r20"
,
"r21"
,
"r1"
,
FIXUP_BRANCH_CLOBBER
);
442
}
443
#endif
444
445
return
ret
;
446
}
447
448
void
handle_unaligned
(
struct
pt_regs
*regs)
449
{
450
static
DEFINE_RATELIMIT_STATE
(ratelimit, 5 *
HZ
, 5);
451
unsigned
long
newbase =
R1
(regs->
iir
)?regs->
gr
[
R1
(regs->
iir
)]:0;
452
int
modify = 0;
453
int
ret =
ERR_NOTHANDLED
;
454
struct
siginfo
si;
455
register
int
flop=0;
/* true if this is a flop */
456
457
/* log a message with pacing */
458
if
(
user_mode
(regs)) {
459
if
(
current
->thread.flags &
PARISC_UAC_SIGBUS
) {
460
goto
force_sigbus;
461
}
462
463
if
(!(
current
->thread.flags &
PARISC_UAC_NOPRINT
) &&
464
__ratelimit
(&ratelimit)) {
465
char
buf
[256];
466
sprintf
(buf,
"%s(%d): unaligned access to 0x"
RFMT
" at ip=0x"
RFMT
"\n"
,
467
current
->comm, task_pid_nr(
current
), regs->
ior
, regs->
iaoq
[0]);
468
printk
(
KERN_WARNING
"%s"
, buf);
469
#ifdef DEBUG_UNALIGNED
470
show_regs
(regs);
471
#endif
472
}
473
474
if
(!unaligned_enabled)
475
goto
force_sigbus;
476
}
477
478
/* handle modification - OK, it's ugly, see the instruction manual */
479
switch
(
MAJOR_OP
(regs->
iir
))
480
{
481
case
0x03:
482
case
0x09:
483
case
0x0b:
484
if
(regs->
iir
&0x20)
485
{
486
modify = 1;
487
if
(regs->
iir
&0x1000)
/* short loads */
488
if
(regs->
iir
&0x200)
489
newbase +=
IM5_3
(regs->
iir
);
490
else
491
newbase +=
IM5_2
(regs->
iir
);
492
else
if
(regs->
iir
&0x2000)
/* scaled indexed */
493
{
494
int
shift=0;
495
switch
(regs->
iir
&
OPCODE1_MASK
)
496
{
497
case
OPCODE_LDH_I
:
498
shift= 1;
break
;
499
case
OPCODE_LDW_I
:
500
shift= 2;
break
;
501
case
OPCODE_LDD_I
:
502
case
OPCODE_LDDA_I
:
503
shift= 3;
break
;
504
}
505
newbase += (
R2
(regs->
iir
)?regs->
gr
[
R2
(regs->
iir
)]:0)<<shift;
506
}
else
/* simple indexed */
507
newbase += (
R2
(regs->
iir
)?regs->
gr
[
R2
(regs->
iir
)]:0);
508
}
509
break
;
510
case
0x13:
511
case
0x1b:
512
modify = 1;
513
newbase +=
IM14
(regs->
iir
);
514
break
;
515
case
0x14:
516
case
0x1c:
517
if
(regs->
iir
&8)
518
{
519
modify = 1;
520
newbase +=
IM14
(regs->
iir
&~0
xe
);
521
}
522
break
;
523
case
0x16:
524
case
0x1e:
525
modify = 1;
526
newbase +=
IM14
(regs->
iir
&6);
527
break
;
528
case
0x17:
529
case
0x1f:
530
if
(regs->
iir
&4)
531
{
532
modify = 1;
533
newbase +=
IM14
(regs->
iir
&~4);
534
}
535
break
;
536
}
537
538
/* TODO: make this cleaner... */
539
switch
(regs->
iir
&
OPCODE1_MASK
)
540
{
541
case
OPCODE_LDH_I
:
542
case
OPCODE_LDH_S
:
543
ret = emulate_ldh(regs,
R3
(regs->
iir
));
544
break
;
545
546
case
OPCODE_LDW_I
:
547
case
OPCODE_LDWA_I
:
548
case
OPCODE_LDW_S
:
549
case
OPCODE_LDWA_S
:
550
ret = emulate_ldw(regs,
R3
(regs->
iir
),0);
551
break
;
552
553
case
OPCODE_STH
:
554
ret = emulate_sth(regs,
R2
(regs->
iir
));
555
break
;
556
557
case
OPCODE_STW
:
558
case
OPCODE_STWA
:
559
ret = emulate_stw(regs,
R2
(regs->
iir
),0);
560
break
;
561
562
#ifdef CONFIG_PA20
563
case
OPCODE_LDD_I
:
564
case
OPCODE_LDDA_I
:
565
case
OPCODE_LDD_S
:
566
case
OPCODE_LDDA_S
:
567
ret = emulate_ldd(regs,
R3
(regs->
iir
),0);
568
break
;
569
570
case
OPCODE_STD
:
571
case
OPCODE_STDA
:
572
ret = emulate_std(regs,
R2
(regs->
iir
),0);
573
break
;
574
#endif
575
576
case
OPCODE_FLDWX
:
577
case
OPCODE_FLDWS
:
578
case
OPCODE_FLDWXR
:
579
case
OPCODE_FLDWSR
:
580
flop=1;
581
ret = emulate_ldw(regs,
FR3
(regs->
iir
),1);
582
break
;
583
584
case
OPCODE_FLDDX
:
585
case
OPCODE_FLDDS
:
586
flop=1;
587
ret = emulate_ldd(regs,
R3
(regs->
iir
),1);
588
break
;
589
590
case
OPCODE_FSTWX
:
591
case
OPCODE_FSTWS
:
592
case
OPCODE_FSTWXR
:
593
case
OPCODE_FSTWSR
:
594
flop=1;
595
ret = emulate_stw(regs,
FR3
(regs->
iir
),1);
596
break
;
597
598
case
OPCODE_FSTDX
:
599
case
OPCODE_FSTDS
:
600
flop=1;
601
ret = emulate_std(regs,
R3
(regs->
iir
),1);
602
break
;
603
604
case
OPCODE_LDCD_I
:
605
case
OPCODE_LDCW_I
:
606
case
OPCODE_LDCD_S
:
607
case
OPCODE_LDCW_S
:
608
ret =
ERR_NOTHANDLED
;
/* "undefined", but lets kill them. */
609
break
;
610
}
611
#ifdef CONFIG_PA20
612
switch
(regs->
iir
&
OPCODE2_MASK
)
613
{
614
case
OPCODE_FLDD_L
:
615
flop=1;
616
ret = emulate_ldd(regs,
R2
(regs->
iir
),1);
617
break
;
618
case
OPCODE_FSTD_L
:
619
flop=1;
620
ret = emulate_std(regs,
R2
(regs->
iir
),1);
621
break
;
622
case
OPCODE_LDD_L
:
623
ret = emulate_ldd(regs,
R2
(regs->
iir
),0);
624
break
;
625
case
OPCODE_STD_L
:
626
ret = emulate_std(regs,
R2
(regs->
iir
),0);
627
break
;
628
}
629
#endif
630
switch
(regs->
iir
&
OPCODE3_MASK
)
631
{
632
case
OPCODE_FLDW_L
:
633
flop=1;
634
ret = emulate_ldw(regs,
R2
(regs->
iir
),0);
635
break
;
636
case
OPCODE_LDW_M
:
637
ret = emulate_ldw(regs,
R2
(regs->
iir
),1);
638
break
;
639
640
case
OPCODE_FSTW_L
:
641
flop=1;
642
ret = emulate_stw(regs,
R2
(regs->
iir
),1);
643
break
;
644
case
OPCODE_STW_M
:
645
ret = emulate_stw(regs,
R2
(regs->
iir
),0);
646
break
;
647
}
648
switch
(regs->
iir
&
OPCODE4_MASK
)
649
{
650
case
OPCODE_LDH_L
:
651
ret = emulate_ldh(regs,
R2
(regs->
iir
));
652
break
;
653
case
OPCODE_LDW_L
:
654
case
OPCODE_LDWM
:
655
ret = emulate_ldw(regs,
R2
(regs->
iir
),0);
656
break
;
657
case
OPCODE_STH_L
:
658
ret = emulate_sth(regs,
R2
(regs->
iir
));
659
break
;
660
case
OPCODE_STW_L
:
661
case
OPCODE_STWM
:
662
ret = emulate_stw(regs,
R2
(regs->
iir
),0);
663
break
;
664
}
665
666
if
(modify &&
R1
(regs->
iir
))
667
regs->
gr
[
R1
(regs->
iir
)] = newbase;
668
669
670
if
(ret ==
ERR_NOTHANDLED
)
671
printk
(
KERN_CRIT
"Not-handled unaligned insn 0x%08lx\n"
, regs->
iir
);
672
673
DPRINTF
(
"ret = %d\n"
, ret);
674
675
if
(ret)
676
{
677
printk
(
KERN_CRIT
"Unaligned handler failed, ret = %d\n"
, ret);
678
die_if_kernel
(
"Unaligned data reference"
, regs, 28);
679
680
if
(ret ==
ERR_PAGEFAULT
)
681
{
682
si.
si_signo
=
SIGSEGV
;
683
si.
si_errno
= 0;
684
si.
si_code
=
SEGV_MAPERR
;
685
si.si_addr = (
void
__user
*)regs->
ior
;
686
force_sig_info
(
SIGSEGV
, &si,
current
);
687
}
688
else
689
{
690
force_sigbus:
691
/* couldn't handle it ... */
692
si.
si_signo
=
SIGBUS
;
693
si.
si_errno
= 0;
694
si.
si_code
=
BUS_ADRALN
;
695
si.si_addr = (
void
__user
*)regs->
ior
;
696
force_sig_info
(
SIGBUS
, &si,
current
);
697
}
698
699
return
;
700
}
701
702
/* else we handled it, let life go on. */
703
regs->
gr
[0]|=
PSW_N
;
704
}
705
706
/*
707
* NB: check_unaligned() is only used for PCXS processors right
708
* now, so we only check for PA1.1 encodings at this point.
709
*/
710
711
int
712
check_unaligned
(
struct
pt_regs
*regs)
713
{
714
unsigned
long
align_mask;
715
716
/* Get alignment mask */
717
718
align_mask = 0
UL
;
719
switch
(regs->
iir
&
OPCODE1_MASK
) {
720
721
case
OPCODE_LDH_I
:
722
case
OPCODE_LDH_S
:
723
case
OPCODE_STH
:
724
align_mask = 1
UL
;
725
break
;
726
727
case
OPCODE_LDW_I
:
728
case
OPCODE_LDWA_I
:
729
case
OPCODE_LDW_S
:
730
case
OPCODE_LDWA_S
:
731
case
OPCODE_STW
:
732
case
OPCODE_STWA
:
733
align_mask = 3
UL
;
734
break
;
735
736
default
:
737
switch
(regs->
iir
&
OPCODE4_MASK
) {
738
case
OPCODE_LDH_L
:
739
case
OPCODE_STH_L
:
740
align_mask = 1
UL
;
741
break
;
742
case
OPCODE_LDW_L
:
743
case
OPCODE_LDWM
:
744
case
OPCODE_STW_L
:
745
case
OPCODE_STWM
:
746
align_mask = 3
UL
;
747
break
;
748
}
749
break
;
750
}
751
752
return
(
int
)(regs->
ior
& align_mask);
753
}
754
Generated on Thu Jan 10 2013 13:07:00 for Linux Kernel by
1.8.2