aboutsummaryrefslogtreecommitdiffstats
path: root/arch/powerpc/kernel/align.c
diff options
context:
space:
mode:
Diffstat (limited to 'arch/powerpc/kernel/align.c')
-rw-r--r--arch/powerpc/kernel/align.c52
1 files changed, 44 insertions, 8 deletions
diff --git a/arch/powerpc/kernel/align.c b/arch/powerpc/kernel/align.c
index de91f3ae631e..94908af308d8 100644
--- a/arch/powerpc/kernel/align.c
+++ b/arch/powerpc/kernel/align.c
@@ -73,7 +73,7 @@ static struct aligninfo aligninfo[128] = {
73 { 8, LD+F }, /* 00 0 1001: lfd */ 73 { 8, LD+F }, /* 00 0 1001: lfd */
74 { 4, ST+F+S }, /* 00 0 1010: stfs */ 74 { 4, ST+F+S }, /* 00 0 1010: stfs */
75 { 8, ST+F }, /* 00 0 1011: stfd */ 75 { 8, ST+F }, /* 00 0 1011: stfd */
76 INVALID, /* 00 0 1100 */ 76 { 16, LD }, /* 00 0 1100: lq */
77 { 8, LD }, /* 00 0 1101: ld/ldu/lwa */ 77 { 8, LD }, /* 00 0 1101: ld/ldu/lwa */
78 INVALID, /* 00 0 1110 */ 78 INVALID, /* 00 0 1110 */
79 { 8, ST }, /* 00 0 1111: std/stdu */ 79 { 8, ST }, /* 00 0 1111: std/stdu */
@@ -140,7 +140,7 @@ static struct aligninfo aligninfo[128] = {
140 { 2, LD+SW }, /* 10 0 1100: lhbrx */ 140 { 2, LD+SW }, /* 10 0 1100: lhbrx */
141 { 4, LD+SE }, /* 10 0 1101 lwa */ 141 { 4, LD+SE }, /* 10 0 1101 lwa */
142 { 2, ST+SW }, /* 10 0 1110: sthbrx */ 142 { 2, ST+SW }, /* 10 0 1110: sthbrx */
143 INVALID, /* 10 0 1111 */ 143 { 16, ST }, /* 10 0 1111: stq */
144 INVALID, /* 10 1 0000 */ 144 INVALID, /* 10 1 0000 */
145 INVALID, /* 10 1 0001 */ 145 INVALID, /* 10 1 0001 */
146 INVALID, /* 10 1 0010 */ 146 INVALID, /* 10 1 0010 */
@@ -385,8 +385,6 @@ static int emulate_fp_pair(unsigned char __user *addr, unsigned int reg,
385 char *ptr1 = (char *) &current->thread.TS_FPR(reg+1); 385 char *ptr1 = (char *) &current->thread.TS_FPR(reg+1);
386 int i, ret, sw = 0; 386 int i, ret, sw = 0;
387 387
388 if (!(flags & F))
389 return 0;
390 if (reg & 1) 388 if (reg & 1)
391 return 0; /* invalid form: FRS/FRT must be even */ 389 return 0; /* invalid form: FRS/FRT must be even */
392 if (flags & SW) 390 if (flags & SW)
@@ -406,6 +404,34 @@ static int emulate_fp_pair(unsigned char __user *addr, unsigned int reg,
406 return 1; /* exception handled and fixed up */ 404 return 1; /* exception handled and fixed up */
407} 405}
408 406
407#ifdef CONFIG_PPC64
408static int emulate_lq_stq(struct pt_regs *regs, unsigned char __user *addr,
409 unsigned int reg, unsigned int flags)
410{
411 char *ptr0 = (char *)&regs->gpr[reg];
412 char *ptr1 = (char *)&regs->gpr[reg+1];
413 int i, ret, sw = 0;
414
415 if (reg & 1)
416 return 0; /* invalid form: GPR must be even */
417 if (flags & SW)
418 sw = 7;
419 ret = 0;
420 for (i = 0; i < 8; ++i) {
421 if (!(flags & ST)) {
422 ret |= __get_user(ptr0[i^sw], addr + i);
423 ret |= __get_user(ptr1[i^sw], addr + i + 8);
424 } else {
425 ret |= __put_user(ptr0[i^sw], addr + i);
426 ret |= __put_user(ptr1[i^sw], addr + i + 8);
427 }
428 }
429 if (ret)
430 return -EFAULT;
431 return 1; /* exception handled and fixed up */
432}
433#endif /* CONFIG_PPC64 */
434
409#ifdef CONFIG_SPE 435#ifdef CONFIG_SPE
410 436
411static struct aligninfo spe_aligninfo[32] = { 437static struct aligninfo spe_aligninfo[32] = {
@@ -914,10 +940,20 @@ int fix_alignment(struct pt_regs *regs)
914 flush_fp_to_thread(current); 940 flush_fp_to_thread(current);
915 } 941 }
916 942
917 /* Special case for 16-byte FP loads and stores */ 943 if ((nb == 16)) {
918 if (nb == 16) { 944 if (flags & F) {
919 PPC_WARN_ALIGNMENT(fp_pair, regs); 945 /* Special case for 16-byte FP loads and stores */
920 return emulate_fp_pair(addr, reg, flags); 946 PPC_WARN_ALIGNMENT(fp_pair, regs);
947 return emulate_fp_pair(addr, reg, flags);
948 } else {
949#ifdef CONFIG_PPC64
950 /* Special case for 16-byte loads and stores */
951 PPC_WARN_ALIGNMENT(lq_stq, regs);
952 return emulate_lq_stq(regs, addr, reg, flags);
953#else
954 return 0;
955#endif
956 }
921 } 957 }
922 958
923 PPC_WARN_ALIGNMENT(unaligned, regs); 959 PPC_WARN_ALIGNMENT(unaligned, regs);