Commit f83319d7 authored by Anton Blanchard's avatar Anton Blanchard Committed by Benjamin Herrenschmidt

powerpc: Add lq/stq emulation

Recent CPUs support quad word load and store instructions. Add
support to the alignment handler for them.
Signed-off-by: default avatarAnton Blanchard <anton@samba.org>
Signed-off-by: default avatarBenjamin Herrenschmidt <benh@kernel.crashing.org>
parent e28b05e7
...@@ -54,6 +54,7 @@ extern struct ppc_emulated { ...@@ -54,6 +54,7 @@ extern struct ppc_emulated {
#ifdef CONFIG_PPC64 #ifdef CONFIG_PPC64
struct ppc_emulated_entry mfdscr; struct ppc_emulated_entry mfdscr;
struct ppc_emulated_entry mtdscr; struct ppc_emulated_entry mtdscr;
struct ppc_emulated_entry lq_stq;
#endif #endif
} ppc_emulated; } ppc_emulated;
......
...@@ -73,7 +73,7 @@ static struct aligninfo aligninfo[128] = { ...@@ -73,7 +73,7 @@ static struct aligninfo aligninfo[128] = {
{ 8, LD+F }, /* 00 0 1001: lfd */ { 8, LD+F }, /* 00 0 1001: lfd */
{ 4, ST+F+S }, /* 00 0 1010: stfs */ { 4, ST+F+S }, /* 00 0 1010: stfs */
{ 8, ST+F }, /* 00 0 1011: stfd */ { 8, ST+F }, /* 00 0 1011: stfd */
INVALID, /* 00 0 1100 */ { 16, LD }, /* 00 0 1100: lq */
{ 8, LD }, /* 00 0 1101: ld/ldu/lwa */ { 8, LD }, /* 00 0 1101: ld/ldu/lwa */
INVALID, /* 00 0 1110 */ INVALID, /* 00 0 1110 */
{ 8, ST }, /* 00 0 1111: std/stdu */ { 8, ST }, /* 00 0 1111: std/stdu */
...@@ -140,7 +140,7 @@ static struct aligninfo aligninfo[128] = { ...@@ -140,7 +140,7 @@ static struct aligninfo aligninfo[128] = {
{ 2, LD+SW }, /* 10 0 1100: lhbrx */ { 2, LD+SW }, /* 10 0 1100: lhbrx */
{ 4, LD+SE }, /* 10 0 1101 lwa */ { 4, LD+SE }, /* 10 0 1101 lwa */
{ 2, ST+SW }, /* 10 0 1110: sthbrx */ { 2, ST+SW }, /* 10 0 1110: sthbrx */
INVALID, /* 10 0 1111 */ { 16, ST }, /* 10 0 1111: stq */
INVALID, /* 10 1 0000 */ INVALID, /* 10 1 0000 */
INVALID, /* 10 1 0001 */ INVALID, /* 10 1 0001 */
INVALID, /* 10 1 0010 */ INVALID, /* 10 1 0010 */
...@@ -385,8 +385,6 @@ static int emulate_fp_pair(unsigned char __user *addr, unsigned int reg, ...@@ -385,8 +385,6 @@ static int emulate_fp_pair(unsigned char __user *addr, unsigned int reg,
char *ptr1 = (char *) &current->thread.TS_FPR(reg+1); char *ptr1 = (char *) &current->thread.TS_FPR(reg+1);
int i, ret, sw = 0; int i, ret, sw = 0;
if (!(flags & F))
return 0;
if (reg & 1) if (reg & 1)
return 0; /* invalid form: FRS/FRT must be even */ return 0; /* invalid form: FRS/FRT must be even */
if (flags & SW) if (flags & SW)
...@@ -406,6 +404,34 @@ static int emulate_fp_pair(unsigned char __user *addr, unsigned int reg, ...@@ -406,6 +404,34 @@ static int emulate_fp_pair(unsigned char __user *addr, unsigned int reg,
return 1; /* exception handled and fixed up */ return 1; /* exception handled and fixed up */
} }
#ifdef CONFIG_PPC64
static int emulate_lq_stq(struct pt_regs *regs, unsigned char __user *addr,
unsigned int reg, unsigned int flags)
{
char *ptr0 = (char *)&regs->gpr[reg];
char *ptr1 = (char *)&regs->gpr[reg+1];
int i, ret, sw = 0;
if (reg & 1)
return 0; /* invalid form: GPR must be even */
if (flags & SW)
sw = 7;
ret = 0;
for (i = 0; i < 8; ++i) {
if (!(flags & ST)) {
ret |= __get_user(ptr0[i^sw], addr + i);
ret |= __get_user(ptr1[i^sw], addr + i + 8);
} else {
ret |= __put_user(ptr0[i^sw], addr + i);
ret |= __put_user(ptr1[i^sw], addr + i + 8);
}
}
if (ret)
return -EFAULT;
return 1; /* exception handled and fixed up */
}
#endif /* CONFIG_PPC64 */
#ifdef CONFIG_SPE #ifdef CONFIG_SPE
static struct aligninfo spe_aligninfo[32] = { static struct aligninfo spe_aligninfo[32] = {
...@@ -914,10 +940,20 @@ int fix_alignment(struct pt_regs *regs) ...@@ -914,10 +940,20 @@ int fix_alignment(struct pt_regs *regs)
flush_fp_to_thread(current); flush_fp_to_thread(current);
} }
/* Special case for 16-byte FP loads and stores */ if ((nb == 16)) {
if (nb == 16) { if (flags & F) {
PPC_WARN_ALIGNMENT(fp_pair, regs); /* Special case for 16-byte FP loads and stores */
return emulate_fp_pair(addr, reg, flags); PPC_WARN_ALIGNMENT(fp_pair, regs);
return emulate_fp_pair(addr, reg, flags);
} else {
#ifdef CONFIG_PPC64
/* Special case for 16-byte loads and stores */
PPC_WARN_ALIGNMENT(lq_stq, regs);
return emulate_lq_stq(regs, addr, reg, flags);
#else
return 0;
#endif
}
} }
PPC_WARN_ALIGNMENT(unaligned, regs); PPC_WARN_ALIGNMENT(unaligned, regs);
......
...@@ -1868,6 +1868,7 @@ struct ppc_emulated ppc_emulated = { ...@@ -1868,6 +1868,7 @@ struct ppc_emulated ppc_emulated = {
#ifdef CONFIG_PPC64 #ifdef CONFIG_PPC64
WARN_EMULATED_SETUP(mfdscr), WARN_EMULATED_SETUP(mfdscr),
WARN_EMULATED_SETUP(mtdscr), WARN_EMULATED_SETUP(mtdscr),
WARN_EMULATED_SETUP(lq_stq),
#endif #endif
}; };
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment