OpenCores
URL https://opencores.org/ocsvn/or1k_soc_on_altera_embedded_dev_kit/or1k_soc_on_altera_embedded_dev_kit/trunk

Subversion Repositories or1k_soc_on_altera_embedded_dev_kit

[/] [or1k_soc_on_altera_embedded_dev_kit/] [trunk/] [linux-2.6/] [linux-2.6.24/] [arch/] [powerpc/] [kernel/] [align.c] - Blame information for rev 17

Go to most recent revision | Details | Compare with Previous | View Log

Line No. Rev Author Line
1 3 xianfeng
/* align.c - handle alignment exceptions for the Power PC.
2
 *
3
 * Copyright (c) 1996 Paul Mackerras <paulus@cs.anu.edu.au>
4
 * Copyright (c) 1998-1999 TiVo, Inc.
5
 *   PowerPC 403GCX modifications.
6
 * Copyright (c) 1999 Grant Erickson <grant@lcse.umn.edu>
7
 *   PowerPC 403GCX/405GP modifications.
8
 * Copyright (c) 2001-2002 PPC64 team, IBM Corp
9
 *   64-bit and Power4 support
10
 * Copyright (c) 2005 Benjamin Herrenschmidt, IBM Corp
11
 *                    <benh@kernel.crashing.org>
12
 *   Merge ppc32 and ppc64 implementations
13
 *
14
 * This program is free software; you can redistribute it and/or
15
 * modify it under the terms of the GNU General Public License
16
 * as published by the Free Software Foundation; either version
17
 * 2 of the License, or (at your option) any later version.
18
 */
19
 
20
#include <linux/kernel.h>
21
#include <linux/mm.h>
22
#include <asm/processor.h>
23
#include <asm/uaccess.h>
24
#include <asm/system.h>
25
#include <asm/cache.h>
26
#include <asm/cputable.h>
27
 
28
struct aligninfo {
29
        unsigned char len;
30
        unsigned char flags;
31
};
32
 
33
#define IS_XFORM(inst)  (((inst) >> 26) == 31)
34
#define IS_DSFORM(inst) (((inst) >> 26) >= 56)
35
 
36
#define INVALID { 0, 0 }
37
 
38
/* Bits in the flags field */
39
#define LD      0        /* load */
40
#define ST      1       /* store */
41
#define SE      2       /* sign-extend value, or FP ld/st as word */
42
#define F       4       /* to/from fp regs */
43
#define U       8       /* update index register */
44
#define M       0x10    /* multiple load/store */
45
#define SW      0x20    /* byte swap */
46
#define S       0x40    /* single-precision fp or... */
47
#define SX      0x40    /* ... byte count in XER */
48
#define HARD    0x80    /* string, stwcx. */
49
#define E4      0x40    /* SPE endianness is word */
50
#define E8      0x80    /* SPE endianness is double word */
51
 
52
/* DSISR bits reported for a DCBZ instruction: */
53
#define DCBZ    0x5f    /* 8xx/82xx dcbz faults when cache not enabled */
54
 
55
#define SWAP(a, b)      (t = (a), (a) = (b), (b) = t)
56
 
57
/*
58
 * The PowerPC stores certain bits of the instruction that caused the
59
 * alignment exception in the DSISR register.  This array maps those
60
 * bits to information about the operand length and what the
61
 * instruction would do.
62
 */
63
static struct aligninfo aligninfo[128] = {
64
        { 4, LD },              /* 00 0 0000: lwz / lwarx */
65
        INVALID,                /* 00 0 0001 */
66
        { 4, ST },              /* 00 0 0010: stw */
67
        INVALID,                /* 00 0 0011 */
68
        { 2, LD },              /* 00 0 0100: lhz */
69
        { 2, LD+SE },           /* 00 0 0101: lha */
70
        { 2, ST },              /* 00 0 0110: sth */
71
        { 4, LD+M },            /* 00 0 0111: lmw */
72
        { 4, LD+F+S },          /* 00 0 1000: lfs */
73
        { 8, LD+F },            /* 00 0 1001: lfd */
74
        { 4, ST+F+S },          /* 00 0 1010: stfs */
75
        { 8, ST+F },            /* 00 0 1011: stfd */
76
        INVALID,                /* 00 0 1100 */
77
        { 8, LD },              /* 00 0 1101: ld/ldu/lwa */
78
        INVALID,                /* 00 0 1110 */
79
        { 8, ST },              /* 00 0 1111: std/stdu */
80
        { 4, LD+U },            /* 00 1 0000: lwzu */
81
        INVALID,                /* 00 1 0001 */
82
        { 4, ST+U },            /* 00 1 0010: stwu */
83
        INVALID,                /* 00 1 0011 */
84
        { 2, LD+U },            /* 00 1 0100: lhzu */
85
        { 2, LD+SE+U },         /* 00 1 0101: lhau */
86
        { 2, ST+U },            /* 00 1 0110: sthu */
87
        { 4, ST+M },            /* 00 1 0111: stmw */
88
        { 4, LD+F+S+U },        /* 00 1 1000: lfsu */
89
        { 8, LD+F+U },          /* 00 1 1001: lfdu */
90
        { 4, ST+F+S+U },        /* 00 1 1010: stfsu */
91
        { 8, ST+F+U },          /* 00 1 1011: stfdu */
92
        { 16, LD+F },           /* 00 1 1100: lfdp */
93
        INVALID,                /* 00 1 1101 */
94
        { 16, ST+F },           /* 00 1 1110: stfdp */
95
        INVALID,                /* 00 1 1111 */
96
        { 8, LD },              /* 01 0 0000: ldx */
97
        INVALID,                /* 01 0 0001 */
98
        { 8, ST },              /* 01 0 0010: stdx */
99
        INVALID,                /* 01 0 0011 */
100
        INVALID,                /* 01 0 0100 */
101
        { 4, LD+SE },           /* 01 0 0101: lwax */
102
        INVALID,                /* 01 0 0110 */
103
        INVALID,                /* 01 0 0111 */
104
        { 4, LD+M+HARD+SX },    /* 01 0 1000: lswx */
105
        { 4, LD+M+HARD },       /* 01 0 1001: lswi */
106
        { 4, ST+M+HARD+SX },    /* 01 0 1010: stswx */
107
        { 4, ST+M+HARD },       /* 01 0 1011: stswi */
108
        INVALID,                /* 01 0 1100 */
109
        { 8, LD+U },            /* 01 0 1101: ldu */
110
        INVALID,                /* 01 0 1110 */
111
        { 8, ST+U },            /* 01 0 1111: stdu */
112
        { 8, LD+U },            /* 01 1 0000: ldux */
113
        INVALID,                /* 01 1 0001 */
114
        { 8, ST+U },            /* 01 1 0010: stdux */
115
        INVALID,                /* 01 1 0011 */
116
        INVALID,                /* 01 1 0100 */
117
        { 4, LD+SE+U },         /* 01 1 0101: lwaux */
118
        INVALID,                /* 01 1 0110 */
119
        INVALID,                /* 01 1 0111 */
120
        INVALID,                /* 01 1 1000 */
121
        INVALID,                /* 01 1 1001 */
122
        INVALID,                /* 01 1 1010 */
123
        INVALID,                /* 01 1 1011 */
124
        INVALID,                /* 01 1 1100 */
125
        INVALID,                /* 01 1 1101 */
126
        INVALID,                /* 01 1 1110 */
127
        INVALID,                /* 01 1 1111 */
128
        INVALID,                /* 10 0 0000 */
129
        INVALID,                /* 10 0 0001 */
130
        INVALID,                /* 10 0 0010: stwcx. */
131
        INVALID,                /* 10 0 0011 */
132
        INVALID,                /* 10 0 0100 */
133
        INVALID,                /* 10 0 0101 */
134
        INVALID,                /* 10 0 0110 */
135
        INVALID,                /* 10 0 0111 */
136
        { 4, LD+SW },           /* 10 0 1000: lwbrx */
137
        INVALID,                /* 10 0 1001 */
138
        { 4, ST+SW },           /* 10 0 1010: stwbrx */
139
        INVALID,                /* 10 0 1011 */
140
        { 2, LD+SW },           /* 10 0 1100: lhbrx */
141
        { 4, LD+SE },           /* 10 0 1101  lwa */
142
        { 2, ST+SW },           /* 10 0 1110: sthbrx */
143
        INVALID,                /* 10 0 1111 */
144
        INVALID,                /* 10 1 0000 */
145
        INVALID,                /* 10 1 0001 */
146
        INVALID,                /* 10 1 0010 */
147
        INVALID,                /* 10 1 0011 */
148
        INVALID,                /* 10 1 0100 */
149
        INVALID,                /* 10 1 0101 */
150
        INVALID,                /* 10 1 0110 */
151
        INVALID,                /* 10 1 0111 */
152
        INVALID,                /* 10 1 1000 */
153
        INVALID,                /* 10 1 1001 */
154
        INVALID,                /* 10 1 1010 */
155
        INVALID,                /* 10 1 1011 */
156
        INVALID,                /* 10 1 1100 */
157
        INVALID,                /* 10 1 1101 */
158
        INVALID,                /* 10 1 1110 */
159
        { 0, ST+HARD },          /* 10 1 1111: dcbz */
160
        { 4, LD },              /* 11 0 0000: lwzx */
161
        INVALID,                /* 11 0 0001 */
162
        { 4, ST },              /* 11 0 0010: stwx */
163
        INVALID,                /* 11 0 0011 */
164
        { 2, LD },              /* 11 0 0100: lhzx */
165
        { 2, LD+SE },           /* 11 0 0101: lhax */
166
        { 2, ST },              /* 11 0 0110: sthx */
167
        INVALID,                /* 11 0 0111 */
168
        { 4, LD+F+S },          /* 11 0 1000: lfsx */
169
        { 8, LD+F },            /* 11 0 1001: lfdx */
170
        { 4, ST+F+S },          /* 11 0 1010: stfsx */
171
        { 8, ST+F },            /* 11 0 1011: stfdx */
172
        { 16, LD+F },           /* 11 0 1100: lfdpx */
173
        { 4, LD+F+SE },         /* 11 0 1101: lfiwax */
174
        { 16, ST+F },           /* 11 0 1110: stfdpx */
175
        { 4, ST+F },            /* 11 0 1111: stfiwx */
176
        { 4, LD+U },            /* 11 1 0000: lwzux */
177
        INVALID,                /* 11 1 0001 */
178
        { 4, ST+U },            /* 11 1 0010: stwux */
179
        INVALID,                /* 11 1 0011 */
180
        { 2, LD+U },            /* 11 1 0100: lhzux */
181
        { 2, LD+SE+U },         /* 11 1 0101: lhaux */
182
        { 2, ST+U },            /* 11 1 0110: sthux */
183
        INVALID,                /* 11 1 0111 */
184
        { 4, LD+F+S+U },        /* 11 1 1000: lfsux */
185
        { 8, LD+F+U },          /* 11 1 1001: lfdux */
186
        { 4, ST+F+S+U },        /* 11 1 1010: stfsux */
187
        { 8, ST+F+U },          /* 11 1 1011: stfdux */
188
        INVALID,                /* 11 1 1100 */
189
        INVALID,                /* 11 1 1101 */
190
        INVALID,                /* 11 1 1110 */
191
        INVALID,                /* 11 1 1111 */
192
};
193
 
194
/*
195
 * Create a DSISR value from the instruction
196
 */
197
static inline unsigned make_dsisr(unsigned instr)
198
{
199
        unsigned dsisr;
200
 
201
 
202
        /* bits  6:15 --> 22:31 */
203
        dsisr = (instr & 0x03ff0000) >> 16;
204
 
205
        if (IS_XFORM(instr)) {
206
                /* bits 29:30 --> 15:16 */
207
                dsisr |= (instr & 0x00000006) << 14;
208
                /* bit     25 -->    17 */
209
                dsisr |= (instr & 0x00000040) << 8;
210
                /* bits 21:24 --> 18:21 */
211
                dsisr |= (instr & 0x00000780) << 3;
212
        } else {
213
                /* bit      5 -->    17 */
214
                dsisr |= (instr & 0x04000000) >> 12;
215
                /* bits  1: 4 --> 18:21 */
216
                dsisr |= (instr & 0x78000000) >> 17;
217
                /* bits 30:31 --> 12:13 */
218
                if (IS_DSFORM(instr))
219
                        dsisr |= (instr & 0x00000003) << 18;
220
        }
221
 
222
        return dsisr;
223
}
224
 
225
/*
226
 * The dcbz (data cache block zero) instruction
227
 * gives an alignment fault if used on non-cacheable
228
 * memory.  We handle the fault mainly for the
229
 * case when we are running with the cache disabled
230
 * for debugging.
231
 */
232
static int emulate_dcbz(struct pt_regs *regs, unsigned char __user *addr)
233
{
234
        long __user *p;
235
        int i, size;
236
 
237
#ifdef __powerpc64__
238
        size = ppc64_caches.dline_size;
239
#else
240
        size = L1_CACHE_BYTES;
241
#endif
242
        p = (long __user *) (regs->dar & -size);
243
        if (user_mode(regs) && !access_ok(VERIFY_WRITE, p, size))
244
                return -EFAULT;
245
        for (i = 0; i < size / sizeof(long); ++i)
246
                if (__put_user_inatomic(0, p+i))
247
                        return -EFAULT;
248
        return 1;
249
}
250
 
251
/*
252
 * Emulate load & store multiple instructions
253
 * On 64-bit machines, these instructions only affect/use the
254
 * bottom 4 bytes of each register, and the loads clear the
255
 * top 4 bytes of the affected register.
256
 */
257
#ifdef CONFIG_PPC64
258
#define REG_BYTE(rp, i)         *((u8 *)((rp) + ((i) >> 2)) + ((i) & 3) + 4)
259
#else
260
#define REG_BYTE(rp, i)         *((u8 *)(rp) + (i))
261
#endif
262
 
263
#define SWIZ_PTR(p)             ((unsigned char __user *)((p) ^ swiz))
264
 
265
static int emulate_multiple(struct pt_regs *regs, unsigned char __user *addr,
266
                            unsigned int reg, unsigned int nb,
267
                            unsigned int flags, unsigned int instr,
268
                            unsigned long swiz)
269
{
270
        unsigned long *rptr;
271
        unsigned int nb0, i, bswiz;
272
        unsigned long p;
273
 
274
        /*
275
         * We do not try to emulate 8 bytes multiple as they aren't really
276
         * available in our operating environments and we don't try to
277
         * emulate multiples operations in kernel land as they should never
278
         * be used/generated there at least not on unaligned boundaries
279
         */
280
        if (unlikely((nb > 4) || !user_mode(regs)))
281
                return 0;
282
 
283
        /* lmw, stmw, lswi/x, stswi/x */
284
        nb0 = 0;
285
        if (flags & HARD) {
286
                if (flags & SX) {
287
                        nb = regs->xer & 127;
288
                        if (nb == 0)
289
                                return 1;
290
                } else {
291
                        unsigned long pc = regs->nip ^ (swiz & 4);
292
 
293
                        if (__get_user_inatomic(instr,
294
                                                (unsigned int __user *)pc))
295
                                return -EFAULT;
296
                        if (swiz == 0 && (flags & SW))
297
                                instr = cpu_to_le32(instr);
298
                        nb = (instr >> 11) & 0x1f;
299
                        if (nb == 0)
300
                                nb = 32;
301
                }
302
                if (nb + reg * 4 > 128) {
303
                        nb0 = nb + reg * 4 - 128;
304
                        nb = 128 - reg * 4;
305
                }
306
        } else {
307
                /* lwm, stmw */
308
                nb = (32 - reg) * 4;
309
        }
310
 
311
        if (!access_ok((flags & ST ? VERIFY_WRITE: VERIFY_READ), addr, nb+nb0))
312
                return -EFAULT; /* bad address */
313
 
314
        rptr = &regs->gpr[reg];
315
        p = (unsigned long) addr;
316
        bswiz = (flags & SW)? 3: 0;
317
 
318
        if (!(flags & ST)) {
319
                /*
320
                 * This zeroes the top 4 bytes of the affected registers
321
                 * in 64-bit mode, and also zeroes out any remaining
322
                 * bytes of the last register for lsw*.
323
                 */
324
                memset(rptr, 0, ((nb + 3) / 4) * sizeof(unsigned long));
325
                if (nb0 > 0)
326
                        memset(&regs->gpr[0], 0,
327
                               ((nb0 + 3) / 4) * sizeof(unsigned long));
328
 
329
                for (i = 0; i < nb; ++i, ++p)
330
                        if (__get_user_inatomic(REG_BYTE(rptr, i ^ bswiz),
331
                                                SWIZ_PTR(p)))
332
                                return -EFAULT;
333
                if (nb0 > 0) {
334
                        rptr = &regs->gpr[0];
335
                        addr += nb;
336
                        for (i = 0; i < nb0; ++i, ++p)
337
                                if (__get_user_inatomic(REG_BYTE(rptr,
338
                                                                 i ^ bswiz),
339
                                                        SWIZ_PTR(p)))
340
                                        return -EFAULT;
341
                }
342
 
343
        } else {
344
                for (i = 0; i < nb; ++i, ++p)
345
                        if (__put_user_inatomic(REG_BYTE(rptr, i ^ bswiz),
346
                                                SWIZ_PTR(p)))
347
                                return -EFAULT;
348
                if (nb0 > 0) {
349
                        rptr = &regs->gpr[0];
350
                        addr += nb;
351
                        for (i = 0; i < nb0; ++i, ++p)
352
                                if (__put_user_inatomic(REG_BYTE(rptr,
353
                                                                 i ^ bswiz),
354
                                                        SWIZ_PTR(p)))
355
                                        return -EFAULT;
356
                }
357
        }
358
        return 1;
359
}
360
 
361
/*
362
 * Emulate floating-point pair loads and stores.
363
 * Only POWER6 has these instructions, and it does true little-endian,
364
 * so we don't need the address swizzling.
365
 */
366
static int emulate_fp_pair(struct pt_regs *regs, unsigned char __user *addr,
367
                           unsigned int reg, unsigned int flags)
368
{
369
        char *ptr = (char *) &current->thread.fpr[reg];
370
        int i, ret;
371
 
372
        if (!(flags & F))
373
                return 0;
374
        if (reg & 1)
375
                return 0;        /* invalid form: FRS/FRT must be even */
376
        if (!(flags & SW)) {
377
                /* not byte-swapped - easy */
378
                if (!(flags & ST))
379
                        ret = __copy_from_user(ptr, addr, 16);
380
                else
381
                        ret = __copy_to_user(addr, ptr, 16);
382
        } else {
383
                /* each FPR value is byte-swapped separately */
384
                ret = 0;
385
                for (i = 0; i < 16; ++i) {
386
                        if (!(flags & ST))
387
                                ret |= __get_user(ptr[i^7], addr + i);
388
                        else
389
                                ret |= __put_user(ptr[i^7], addr + i);
390
                }
391
        }
392
        if (ret)
393
                return -EFAULT;
394
        return 1;       /* exception handled and fixed up */
395
}
396
 
397
#ifdef CONFIG_SPE
398
 
399
static struct aligninfo spe_aligninfo[32] = {
400
        { 8, LD+E8 },           /* 0 00 00: evldd[x] */
401
        { 8, LD+E4 },           /* 0 00 01: evldw[x] */
402
        { 8, LD },              /* 0 00 10: evldh[x] */
403
        INVALID,                /* 0 00 11 */
404
        { 2, LD },              /* 0 01 00: evlhhesplat[x] */
405
        INVALID,                /* 0 01 01 */
406
        { 2, LD },              /* 0 01 10: evlhhousplat[x] */
407
        { 2, LD+SE },           /* 0 01 11: evlhhossplat[x] */
408
        { 4, LD },              /* 0 10 00: evlwhe[x] */
409
        INVALID,                /* 0 10 01 */
410
        { 4, LD },              /* 0 10 10: evlwhou[x] */
411
        { 4, LD+SE },           /* 0 10 11: evlwhos[x] */
412
        { 4, LD+E4 },           /* 0 11 00: evlwwsplat[x] */
413
        INVALID,                /* 0 11 01 */
414
        { 4, LD },              /* 0 11 10: evlwhsplat[x] */
415
        INVALID,                /* 0 11 11 */
416
 
417
        { 8, ST+E8 },           /* 1 00 00: evstdd[x] */
418
        { 8, ST+E4 },           /* 1 00 01: evstdw[x] */
419
        { 8, ST },              /* 1 00 10: evstdh[x] */
420
        INVALID,                /* 1 00 11 */
421
        INVALID,                /* 1 01 00 */
422
        INVALID,                /* 1 01 01 */
423
        INVALID,                /* 1 01 10 */
424
        INVALID,                /* 1 01 11 */
425
        { 4, ST },              /* 1 10 00: evstwhe[x] */
426
        INVALID,                /* 1 10 01 */
427
        { 4, ST },              /* 1 10 10: evstwho[x] */
428
        INVALID,                /* 1 10 11 */
429
        { 4, ST+E4 },           /* 1 11 00: evstwwe[x] */
430
        INVALID,                /* 1 11 01 */
431
        { 4, ST+E4 },           /* 1 11 10: evstwwo[x] */
432
        INVALID,                /* 1 11 11 */
433
};
434
 
435
#define EVLDD           0x00
436
#define EVLDW           0x01
437
#define EVLDH           0x02
438
#define EVLHHESPLAT     0x04
439
#define EVLHHOUSPLAT    0x06
440
#define EVLHHOSSPLAT    0x07
441
#define EVLWHE          0x08
442
#define EVLWHOU         0x0A
443
#define EVLWHOS         0x0B
444
#define EVLWWSPLAT      0x0C
445
#define EVLWHSPLAT      0x0E
446
#define EVSTDD          0x10
447
#define EVSTDW          0x11
448
#define EVSTDH          0x12
449
#define EVSTWHE         0x18
450
#define EVSTWHO         0x1A
451
#define EVSTWWE         0x1C
452
#define EVSTWWO         0x1E
453
 
454
/*
455
 * Emulate SPE loads and stores.
456
 * Only Book-E has these instructions, and it does true little-endian,
457
 * so we don't need the address swizzling.
458
 */
459
static int emulate_spe(struct pt_regs *regs, unsigned int reg,
460
                       unsigned int instr)
461
{
462
        int t, ret;
463
        union {
464
                u64 ll;
465
                u32 w[2];
466
                u16 h[4];
467
                u8 v[8];
468
        } data, temp;
469
        unsigned char __user *p, *addr;
470
        unsigned long *evr = &current->thread.evr[reg];
471
        unsigned int nb, flags;
472
 
473
        instr = (instr >> 1) & 0x1f;
474
 
475
        /* DAR has the operand effective address */
476
        addr = (unsigned char __user *)regs->dar;
477
 
478
        nb = spe_aligninfo[instr].len;
479
        flags = spe_aligninfo[instr].flags;
480
 
481
        /* Verify the address of the operand */
482
        if (unlikely(user_mode(regs) &&
483
                     !access_ok((flags & ST ? VERIFY_WRITE : VERIFY_READ),
484
                                addr, nb)))
485
                return -EFAULT;
486
 
487
        /* userland only */
488
        if (unlikely(!user_mode(regs)))
489
                return 0;
490
 
491
        flush_spe_to_thread(current);
492
 
493
        /* If we are loading, get the data from user space, else
494
         * get it from register values
495
         */
496
        if (flags & ST) {
497
                data.ll = 0;
498
                switch (instr) {
499
                case EVSTDD:
500
                case EVSTDW:
501
                case EVSTDH:
502
                        data.w[0] = *evr;
503
                        data.w[1] = regs->gpr[reg];
504
                        break;
505
                case EVSTWHE:
506
                        data.h[2] = *evr >> 16;
507
                        data.h[3] = regs->gpr[reg] >> 16;
508
                        break;
509
                case EVSTWHO:
510
                        data.h[2] = *evr & 0xffff;
511
                        data.h[3] = regs->gpr[reg] & 0xffff;
512
                        break;
513
                case EVSTWWE:
514
                        data.w[1] = *evr;
515
                        break;
516
                case EVSTWWO:
517
                        data.w[1] = regs->gpr[reg];
518
                        break;
519
                default:
520
                        return -EINVAL;
521
                }
522
        } else {
523
                temp.ll = data.ll = 0;
524
                ret = 0;
525
                p = addr;
526
 
527
                switch (nb) {
528
                case 8:
529
                        ret |= __get_user_inatomic(temp.v[0], p++);
530
                        ret |= __get_user_inatomic(temp.v[1], p++);
531
                        ret |= __get_user_inatomic(temp.v[2], p++);
532
                        ret |= __get_user_inatomic(temp.v[3], p++);
533
                case 4:
534
                        ret |= __get_user_inatomic(temp.v[4], p++);
535
                        ret |= __get_user_inatomic(temp.v[5], p++);
536
                case 2:
537
                        ret |= __get_user_inatomic(temp.v[6], p++);
538
                        ret |= __get_user_inatomic(temp.v[7], p++);
539
                        if (unlikely(ret))
540
                                return -EFAULT;
541
                }
542
 
543
                switch (instr) {
544
                case EVLDD:
545
                case EVLDW:
546
                case EVLDH:
547
                        data.ll = temp.ll;
548
                        break;
549
                case EVLHHESPLAT:
550
                        data.h[0] = temp.h[3];
551
                        data.h[2] = temp.h[3];
552
                        break;
553
                case EVLHHOUSPLAT:
554
                case EVLHHOSSPLAT:
555
                        data.h[1] = temp.h[3];
556
                        data.h[3] = temp.h[3];
557
                        break;
558
                case EVLWHE:
559
                        data.h[0] = temp.h[2];
560
                        data.h[2] = temp.h[3];
561
                        break;
562
                case EVLWHOU:
563
                case EVLWHOS:
564
                        data.h[1] = temp.h[2];
565
                        data.h[3] = temp.h[3];
566
                        break;
567
                case EVLWWSPLAT:
568
                        data.w[0] = temp.w[1];
569
                        data.w[1] = temp.w[1];
570
                        break;
571
                case EVLWHSPLAT:
572
                        data.h[0] = temp.h[2];
573
                        data.h[1] = temp.h[2];
574
                        data.h[2] = temp.h[3];
575
                        data.h[3] = temp.h[3];
576
                        break;
577
                default:
578
                        return -EINVAL;
579
                }
580
        }
581
 
582
        if (flags & SW) {
583
                switch (flags & 0xf0) {
584
                case E8:
585
                        SWAP(data.v[0], data.v[7]);
586
                        SWAP(data.v[1], data.v[6]);
587
                        SWAP(data.v[2], data.v[5]);
588
                        SWAP(data.v[3], data.v[4]);
589
                        break;
590
                case E4:
591
 
592
                        SWAP(data.v[0], data.v[3]);
593
                        SWAP(data.v[1], data.v[2]);
594
                        SWAP(data.v[4], data.v[7]);
595
                        SWAP(data.v[5], data.v[6]);
596
                        break;
597
                /* Its half word endian */
598
                default:
599
                        SWAP(data.v[0], data.v[1]);
600
                        SWAP(data.v[2], data.v[3]);
601
                        SWAP(data.v[4], data.v[5]);
602
                        SWAP(data.v[6], data.v[7]);
603
                        break;
604
                }
605
        }
606
 
607
        if (flags & SE) {
608
                data.w[0] = (s16)data.h[1];
609
                data.w[1] = (s16)data.h[3];
610
        }
611
 
612
        /* Store result to memory or update registers */
613
        if (flags & ST) {
614
                ret = 0;
615
                p = addr;
616
                switch (nb) {
617
                case 8:
618
                        ret |= __put_user_inatomic(data.v[0], p++);
619
                        ret |= __put_user_inatomic(data.v[1], p++);
620
                        ret |= __put_user_inatomic(data.v[2], p++);
621
                        ret |= __put_user_inatomic(data.v[3], p++);
622
                case 4:
623
                        ret |= __put_user_inatomic(data.v[4], p++);
624
                        ret |= __put_user_inatomic(data.v[5], p++);
625
                case 2:
626
                        ret |= __put_user_inatomic(data.v[6], p++);
627
                        ret |= __put_user_inatomic(data.v[7], p++);
628
                }
629
                if (unlikely(ret))
630
                        return -EFAULT;
631
        } else {
632
                *evr = data.w[0];
633
                regs->gpr[reg] = data.w[1];
634
        }
635
 
636
        return 1;
637
}
638
#endif /* CONFIG_SPE */
639
 
640
/*
641
 * Called on alignment exception. Attempts to fixup
642
 *
643
 * Return 1 on success
644
 * Return 0 if unable to handle the interrupt
645
 * Return -EFAULT if data address is bad
646
 */
647
 
648
int fix_alignment(struct pt_regs *regs)
649
{
650
        unsigned int instr, nb, flags;
651
        unsigned int reg, areg;
652
        unsigned int dsisr;
653
        unsigned char __user *addr;
654
        unsigned long p, swiz;
655
        int ret, t;
656
        union {
657
                u64 ll;
658
                double dd;
659
                unsigned char v[8];
660
                struct {
661
                        unsigned hi32;
662
                        int      low32;
663
                } x32;
664
                struct {
665
                        unsigned char hi48[6];
666
                        short         low16;
667
                } x16;
668
        } data;
669
 
670
        /*
671
         * We require a complete register set, if not, then our assembly
672
         * is broken
673
         */
674
        CHECK_FULL_REGS(regs);
675
 
676
        dsisr = regs->dsisr;
677
 
678
        /* Some processors don't provide us with a DSISR we can use here,
679
         * let's make one up from the instruction
680
         */
681
        if (cpu_has_feature(CPU_FTR_NODSISRALIGN)) {
682
                unsigned long pc = regs->nip;
683
 
684
                if (cpu_has_feature(CPU_FTR_PPC_LE) && (regs->msr & MSR_LE))
685
                        pc ^= 4;
686
                if (unlikely(__get_user_inatomic(instr,
687
                                                 (unsigned int __user *)pc)))
688
                        return -EFAULT;
689
                if (cpu_has_feature(CPU_FTR_REAL_LE) && (regs->msr & MSR_LE))
690
                        instr = cpu_to_le32(instr);
691
                dsisr = make_dsisr(instr);
692
        }
693
 
694
        /* extract the operation and registers from the dsisr */
695
        reg = (dsisr >> 5) & 0x1f;      /* source/dest register */
696
        areg = dsisr & 0x1f;            /* register to update */
697
 
698
#ifdef CONFIG_SPE
699
        if ((instr >> 26) == 0x4)
700
                return emulate_spe(regs, reg, instr);
701
#endif
702
 
703
        instr = (dsisr >> 10) & 0x7f;
704
        instr |= (dsisr >> 13) & 0x60;
705
 
706
        /* Lookup the operation in our table */
707
        nb = aligninfo[instr].len;
708
        flags = aligninfo[instr].flags;
709
 
710
        /* Byteswap little endian loads and stores */
711
        swiz = 0;
712
        if (regs->msr & MSR_LE) {
713
                flags ^= SW;
714
                /*
715
                 * So-called "PowerPC little endian" mode works by
716
                 * swizzling addresses rather than by actually doing
717
                 * any byte-swapping.  To emulate this, we XOR each
718
                 * byte address with 7.  We also byte-swap, because
719
                 * the processor's address swizzling depends on the
720
                 * operand size (it xors the address with 7 for bytes,
721
                 * 6 for halfwords, 4 for words, 0 for doublewords) but
722
                 * we will xor with 7 and load/store each byte separately.
723
                 */
724
                if (cpu_has_feature(CPU_FTR_PPC_LE))
725
                        swiz = 7;
726
        }
727
 
728
        /* DAR has the operand effective address */
729
        addr = (unsigned char __user *)regs->dar;
730
 
731
        /* A size of 0 indicates an instruction we don't support, with
732
         * the exception of DCBZ which is handled as a special case here
733
         */
734
        if (instr == DCBZ)
735
                return emulate_dcbz(regs, addr);
736
        if (unlikely(nb == 0))
737
                return 0;
738
 
739
        /* Load/Store Multiple instructions are handled in their own
740
         * function
741
         */
742
        if (flags & M)
743
                return emulate_multiple(regs, addr, reg, nb,
744
                                        flags, instr, swiz);
745
 
746
        /* Verify the address of the operand */
747
        if (unlikely(user_mode(regs) &&
748
                     !access_ok((flags & ST ? VERIFY_WRITE : VERIFY_READ),
749
                                addr, nb)))
750
                return -EFAULT;
751
 
752
        /* Force the fprs into the save area so we can reference them */
753
        if (flags & F) {
754
                /* userland only */
755
                if (unlikely(!user_mode(regs)))
756
                        return 0;
757
                flush_fp_to_thread(current);
758
        }
759
 
760
        /* Special case for 16-byte FP loads and stores */
761
        if (nb == 16)
762
                return emulate_fp_pair(regs, addr, reg, flags);
763
 
764
        /* If we are loading, get the data from user space, else
765
         * get it from register values
766
         */
767
        if (!(flags & ST)) {
768
                data.ll = 0;
769
                ret = 0;
770
                p = (unsigned long) addr;
771
                switch (nb) {
772
                case 8:
773
                        ret |= __get_user_inatomic(data.v[0], SWIZ_PTR(p++));
774
                        ret |= __get_user_inatomic(data.v[1], SWIZ_PTR(p++));
775
                        ret |= __get_user_inatomic(data.v[2], SWIZ_PTR(p++));
776
                        ret |= __get_user_inatomic(data.v[3], SWIZ_PTR(p++));
777
                case 4:
778
                        ret |= __get_user_inatomic(data.v[4], SWIZ_PTR(p++));
779
                        ret |= __get_user_inatomic(data.v[5], SWIZ_PTR(p++));
780
                case 2:
781
                        ret |= __get_user_inatomic(data.v[6], SWIZ_PTR(p++));
782
                        ret |= __get_user_inatomic(data.v[7], SWIZ_PTR(p++));
783
                        if (unlikely(ret))
784
                                return -EFAULT;
785
                }
786
        } else if (flags & F) {
787
                data.dd = current->thread.fpr[reg];
788
                if (flags & S) {
789
                        /* Single-precision FP store requires conversion... */
790
#ifdef CONFIG_PPC_FPU
791
                        preempt_disable();
792
                        enable_kernel_fp();
793
                        cvt_df(&data.dd, (float *)&data.v[4], &current->thread);
794
                        preempt_enable();
795
#else
796
                        return 0;
797
#endif
798
                }
799
        } else
800
                data.ll = regs->gpr[reg];
801
 
802
        if (flags & SW) {
803
                switch (nb) {
804
                case 8:
805
                        SWAP(data.v[0], data.v[7]);
806
                        SWAP(data.v[1], data.v[6]);
807
                        SWAP(data.v[2], data.v[5]);
808
                        SWAP(data.v[3], data.v[4]);
809
                        break;
810
                case 4:
811
                        SWAP(data.v[4], data.v[7]);
812
                        SWAP(data.v[5], data.v[6]);
813
                        break;
814
                case 2:
815
                        SWAP(data.v[6], data.v[7]);
816
                        break;
817
                }
818
        }
819
 
820
        /* Perform other misc operations like sign extension
821
         * or floating point single precision conversion
822
         */
823
        switch (flags & ~(U|SW)) {
824
        case LD+SE:     /* sign extending integer loads */
825
        case LD+F+SE:   /* sign extend for lfiwax */
826
                if ( nb == 2 )
827
                        data.ll = data.x16.low16;
828
                else    /* nb must be 4 */
829
                        data.ll = data.x32.low32;
830
                break;
831
 
832
        /* Single-precision FP load requires conversion... */
833
        case LD+F+S:
834
#ifdef CONFIG_PPC_FPU
835
                preempt_disable();
836
                enable_kernel_fp();
837
                cvt_fd((float *)&data.v[4], &data.dd, &current->thread);
838
                preempt_enable();
839
#else
840
                return 0;
841
#endif
842
                break;
843
        }
844
 
845
        /* Store result to memory or update registers */
846
        if (flags & ST) {
847
                ret = 0;
848
                p = (unsigned long) addr;
849
                switch (nb) {
850
                case 8:
851
                        ret |= __put_user_inatomic(data.v[0], SWIZ_PTR(p++));
852
                        ret |= __put_user_inatomic(data.v[1], SWIZ_PTR(p++));
853
                        ret |= __put_user_inatomic(data.v[2], SWIZ_PTR(p++));
854
                        ret |= __put_user_inatomic(data.v[3], SWIZ_PTR(p++));
855
                case 4:
856
                        ret |= __put_user_inatomic(data.v[4], SWIZ_PTR(p++));
857
                        ret |= __put_user_inatomic(data.v[5], SWIZ_PTR(p++));
858
                case 2:
859
                        ret |= __put_user_inatomic(data.v[6], SWIZ_PTR(p++));
860
                        ret |= __put_user_inatomic(data.v[7], SWIZ_PTR(p++));
861
                }
862
                if (unlikely(ret))
863
                        return -EFAULT;
864
        } else if (flags & F)
865
                current->thread.fpr[reg] = data.dd;
866
        else
867
                regs->gpr[reg] = data.ll;
868
 
869
        /* Update RA as needed */
870
        if (flags & U)
871
                regs->gpr[areg] = regs->dar;
872
 
873
        return 1;
874
}

powered by: WebSVN 2.1.0

© copyright 1999-2024 OpenCores.org, equivalent to Oliscience, all rights reserved. OpenCores®, registered trademark.