Skip to content

Commit

Permalink
parisc/unaligned: Use EFAULT fixup handler in unaligned handlers
Browse files Browse the repository at this point in the history
Convert the inline assembly code to use the automatic EFAULT exception
handler. With that the fixup code can be dropped.

The other change is to allow double-word only when a 64-bit kernel is
used instead of depending on CONFIG_PA20.

Signed-off-by: Helge Deller <deller@gmx.de>
  • Loading branch information
Helge Deller committed Mar 11, 2022
1 parent 8278cc1 commit d1434e0
Showing 1 changed file with 55 additions and 105 deletions.
160 changes: 55 additions & 105 deletions arch/parisc/kernel/unaligned.c
Original file line number Diff line number Diff line change
Expand Up @@ -31,13 +31,6 @@
#define RFMT "%08lx"
#endif

#define FIXUP_BRANCH(lbl) \
"\tldil L%%" #lbl ", %%r1\n" \
"\tldo R%%" #lbl "(%%r1), %%r1\n" \
"\tbv,n %%r0(%%r1)\n"
/* If you use FIXUP_BRANCH, then you must list this clobber */
#define FIXUP_BRANCH_CLOBBER "r1"

/* 1111 1100 0000 0000 0001 0011 1100 0000 */
#define OPCODE1(a,b,c) ((a)<<26|(b)<<12|(c)<<6)
#define OPCODE2(a,b) ((a)<<26|(b)<<1)
Expand Down Expand Up @@ -114,15 +107,14 @@
#define IM14(i) IM((i),14)

#define ERR_NOTHANDLED -1
#define ERR_PAGEFAULT -2

int unaligned_enabled __read_mostly = 1;

static int emulate_ldh(struct pt_regs *regs, int toreg)
{
unsigned long saddr = regs->ior;
unsigned long val = 0;
int ret;
ASM_EXCEPTIONTABLE_VAR(ret);

DPRINTF("load " RFMT ":" RFMT " to r%d for 2 bytes\n",
regs->isr, regs->ior, toreg);
Expand All @@ -132,17 +124,12 @@ static int emulate_ldh(struct pt_regs *regs, int toreg)
"1: ldbs 0(%%sr1,%3), %%r20\n"
"2: ldbs 1(%%sr1,%3), %0\n"
" depw %%r20, 23, 24, %0\n"
" copy %%r0, %1\n"
"3: \n"
" .section .fixup,\"ax\"\n"
"4: ldi -2, %1\n"
FIXUP_BRANCH(3b)
" .previous\n"
ASM_EXCEPTIONTABLE_ENTRY(1b, 4b)
ASM_EXCEPTIONTABLE_ENTRY(2b, 4b)
: "=r" (val), "=r" (ret)
ASM_EXCEPTIONTABLE_ENTRY_EFAULT(1b, 3b)
ASM_EXCEPTIONTABLE_ENTRY_EFAULT(2b, 3b)
: "=r" (val), "+r" (ret)
: "0" (val), "r" (saddr), "r" (regs->isr)
: "r20", FIXUP_BRANCH_CLOBBER );
: "r20" );

DPRINTF("val = 0x" RFMT "\n", val);

Expand All @@ -156,7 +143,7 @@ static int emulate_ldw(struct pt_regs *regs, int toreg, int flop)
{
unsigned long saddr = regs->ior;
unsigned long val = 0;
int ret;
ASM_EXCEPTIONTABLE_VAR(ret);

DPRINTF("load " RFMT ":" RFMT " to r%d for 4 bytes\n",
regs->isr, regs->ior, toreg);
Expand All @@ -170,17 +157,12 @@ static int emulate_ldw(struct pt_regs *regs, int toreg, int flop)
" subi 32,%%r19,%%r19\n"
" mtctl %%r19,11\n"
" vshd %0,%%r20,%0\n"
" copy %%r0, %1\n"
"3: \n"
" .section .fixup,\"ax\"\n"
"4: ldi -2, %1\n"
FIXUP_BRANCH(3b)
" .previous\n"
ASM_EXCEPTIONTABLE_ENTRY(1b, 4b)
ASM_EXCEPTIONTABLE_ENTRY(2b, 4b)
: "=r" (val), "=r" (ret)
ASM_EXCEPTIONTABLE_ENTRY_EFAULT(1b, 3b)
ASM_EXCEPTIONTABLE_ENTRY_EFAULT(2b, 3b)
: "=r" (val), "+r" (ret)
: "0" (val), "r" (saddr), "r" (regs->isr)
: "r19", "r20", FIXUP_BRANCH_CLOBBER );
: "r19", "r20" );

DPRINTF("val = 0x" RFMT "\n", val);

Expand All @@ -195,16 +177,15 @@ static int emulate_ldd(struct pt_regs *regs, int toreg, int flop)
{
unsigned long saddr = regs->ior;
__u64 val = 0;
int ret;
ASM_EXCEPTIONTABLE_VAR(ret);

DPRINTF("load " RFMT ":" RFMT " to r%d for 8 bytes\n",
regs->isr, regs->ior, toreg);
#ifdef CONFIG_PA20

#ifndef CONFIG_64BIT
if (!flop)
return -1;
#endif
if (!IS_ENABLED(CONFIG_64BIT) && !flop)
return ERR_NOTHANDLED;

#ifdef CONFIG_64BIT
__asm__ __volatile__ (
" depd,z %3,60,3,%%r19\n" /* r19=(ofs&7)*8 */
" mtsp %4, %%sr1\n"
Expand All @@ -214,17 +195,12 @@ static int emulate_ldd(struct pt_regs *regs, int toreg, int flop)
" subi 64,%%r19,%%r19\n"
" mtsar %%r19\n"
" shrpd %0,%%r20,%%sar,%0\n"
" copy %%r0, %1\n"
"3: \n"
" .section .fixup,\"ax\"\n"
"4: ldi -2, %1\n"
FIXUP_BRANCH(3b)
" .previous\n"
ASM_EXCEPTIONTABLE_ENTRY(1b,4b)
ASM_EXCEPTIONTABLE_ENTRY(2b,4b)
: "=r" (val), "=r" (ret)
ASM_EXCEPTIONTABLE_ENTRY_EFAULT(1b, 3b)
ASM_EXCEPTIONTABLE_ENTRY_EFAULT(2b, 3b)
: "=r" (val), "+r" (ret)
: "0" (val), "r" (saddr), "r" (regs->isr)
: "r19", "r20", FIXUP_BRANCH_CLOBBER );
: "r19", "r20" );
#else
{
unsigned long valh=0,vall=0;
Expand All @@ -239,18 +215,13 @@ static int emulate_ldd(struct pt_regs *regs, int toreg, int flop)
" mtsar %%r19\n"
" vshd %0,%1,%0\n"
" vshd %1,%%r20,%1\n"
" copy %%r0, %2\n"
"4: \n"
" .section .fixup,\"ax\"\n"
"5: ldi -2, %2\n"
FIXUP_BRANCH(4b)
" .previous\n"
ASM_EXCEPTIONTABLE_ENTRY(1b,5b)
ASM_EXCEPTIONTABLE_ENTRY(2b,5b)
ASM_EXCEPTIONTABLE_ENTRY(3b,5b)
: "=r" (valh), "=r" (vall), "=r" (ret)
ASM_EXCEPTIONTABLE_ENTRY_EFAULT(1b, 4b)
ASM_EXCEPTIONTABLE_ENTRY_EFAULT(2b, 4b)
ASM_EXCEPTIONTABLE_ENTRY_EFAULT(3b, 4b)
: "=r" (valh), "=r" (vall), "+r" (ret)
: "0" (valh), "1" (vall), "r" (saddr), "r" (regs->isr)
: "r19", "r20", FIXUP_BRANCH_CLOBBER );
: "r19", "r20" );
val=((__u64)valh<<32)|(__u64)vall;
}
#endif
Expand All @@ -268,7 +239,7 @@ static int emulate_ldd(struct pt_regs *regs, int toreg, int flop)
static int emulate_sth(struct pt_regs *regs, int frreg)
{
unsigned long val = regs->gr[frreg];
int ret;
ASM_EXCEPTIONTABLE_VAR(ret);

if (!frreg)
val = 0;
Expand All @@ -281,25 +252,20 @@ static int emulate_sth(struct pt_regs *regs, int frreg)
" extrw,u %1, 23, 8, %%r19\n"
"1: stb %1, 1(%%sr1, %2)\n"
"2: stb %%r19, 0(%%sr1, %2)\n"
" copy %%r0, %0\n"
"3: \n"
" .section .fixup,\"ax\"\n"
"4: ldi -2, %0\n"
FIXUP_BRANCH(3b)
" .previous\n"
ASM_EXCEPTIONTABLE_ENTRY(1b,4b)
ASM_EXCEPTIONTABLE_ENTRY(2b,4b)
: "=r" (ret)
ASM_EXCEPTIONTABLE_ENTRY_EFAULT(1b, 3b)
ASM_EXCEPTIONTABLE_ENTRY_EFAULT(2b, 3b)
: "+r" (ret)
: "r" (val), "r" (regs->ior), "r" (regs->isr)
: "r19", FIXUP_BRANCH_CLOBBER );
: "r19" );

return ret;
}

static int emulate_stw(struct pt_regs *regs, int frreg, int flop)
{
unsigned long val;
int ret;
ASM_EXCEPTIONTABLE_VAR(ret);

if (flop)
val = ((__u32*)(regs->fr))[frreg];
Expand Down Expand Up @@ -328,24 +294,19 @@ static int emulate_stw(struct pt_regs *regs, int frreg, int flop)
" or %%r1, %%r21, %%r21\n"
" stw %%r20,0(%%sr1,%2)\n"
" stw %%r21,4(%%sr1,%2)\n"
" copy %%r0, %0\n"
"3: \n"
" .section .fixup,\"ax\"\n"
"4: ldi -2, %0\n"
FIXUP_BRANCH(3b)
" .previous\n"
ASM_EXCEPTIONTABLE_ENTRY(1b,4b)
ASM_EXCEPTIONTABLE_ENTRY(2b,4b)
: "=r" (ret)
ASM_EXCEPTIONTABLE_ENTRY_EFAULT(1b, 3b)
ASM_EXCEPTIONTABLE_ENTRY_EFAULT(2b, 3b)
: "+r" (ret)
: "r" (val), "r" (regs->ior), "r" (regs->isr)
: "r19", "r20", "r21", "r22", "r1", FIXUP_BRANCH_CLOBBER );
: "r19", "r20", "r21", "r22", "r1" );

return ret;
}
static int emulate_std(struct pt_regs *regs, int frreg, int flop)
{
__u64 val;
int ret;
ASM_EXCEPTIONTABLE_VAR(ret);

if (flop)
val = regs->fr[frreg];
Expand All @@ -357,11 +318,10 @@ static int emulate_std(struct pt_regs *regs, int frreg, int flop)
DPRINTF("store r%d (0x%016llx) to " RFMT ":" RFMT " for 8 bytes\n", frreg,
val, regs->isr, regs->ior);

#ifdef CONFIG_PA20
#ifndef CONFIG_64BIT
if (!flop)
return -1;
#endif
if (!IS_ENABLED(CONFIG_64BIT) && !flop)
return ERR_NOTHANDLED;

#ifdef CONFIG_64BIT
__asm__ __volatile__ (
" mtsp %3, %%sr1\n"
" depd,z %2, 60, 3, %%r19\n"
Expand All @@ -378,19 +338,14 @@ static int emulate_std(struct pt_regs *regs, int frreg, int flop)
" or %%r1, %%r21, %%r21\n"
"3: std %%r20,0(%%sr1,%2)\n"
"4: std %%r21,8(%%sr1,%2)\n"
" copy %%r0, %0\n"
"5: \n"
" .section .fixup,\"ax\"\n"
"6: ldi -2, %0\n"
FIXUP_BRANCH(5b)
" .previous\n"
ASM_EXCEPTIONTABLE_ENTRY(1b,6b)
ASM_EXCEPTIONTABLE_ENTRY(2b,6b)
ASM_EXCEPTIONTABLE_ENTRY(3b,6b)
ASM_EXCEPTIONTABLE_ENTRY(4b,6b)
: "=r" (ret)
ASM_EXCEPTIONTABLE_ENTRY_EFAULT(1b, 5b)
ASM_EXCEPTIONTABLE_ENTRY_EFAULT(2b, 5b)
ASM_EXCEPTIONTABLE_ENTRY_EFAULT(3b, 5b)
ASM_EXCEPTIONTABLE_ENTRY_EFAULT(4b, 5b)
: "+r" (ret)
: "r" (val), "r" (regs->ior), "r" (regs->isr)
: "r19", "r20", "r21", "r22", "r1", FIXUP_BRANCH_CLOBBER );
: "r19", "r20", "r21", "r22", "r1" );
#else
{
unsigned long valh=(val>>32),vall=(val&0xffffffffl);
Expand All @@ -412,20 +367,15 @@ static int emulate_std(struct pt_regs *regs, int frreg, int flop)
"3: stw %1,0(%%sr1,%3)\n"
"4: stw %%r1,4(%%sr1,%3)\n"
"5: stw %2,8(%%sr1,%3)\n"
" copy %%r0, %0\n"
"6: \n"
" .section .fixup,\"ax\"\n"
"7: ldi -2, %0\n"
FIXUP_BRANCH(6b)
" .previous\n"
ASM_EXCEPTIONTABLE_ENTRY(1b,7b)
ASM_EXCEPTIONTABLE_ENTRY(2b,7b)
ASM_EXCEPTIONTABLE_ENTRY(3b,7b)
ASM_EXCEPTIONTABLE_ENTRY(4b,7b)
ASM_EXCEPTIONTABLE_ENTRY(5b,7b)
: "=r" (ret)
ASM_EXCEPTIONTABLE_ENTRY_EFAULT(1b, 6b)
ASM_EXCEPTIONTABLE_ENTRY_EFAULT(2b, 6b)
ASM_EXCEPTIONTABLE_ENTRY_EFAULT(3b, 6b)
ASM_EXCEPTIONTABLE_ENTRY_EFAULT(4b, 6b)
ASM_EXCEPTIONTABLE_ENTRY_EFAULT(5b, 6b)
: "+r" (ret)
: "r" (valh), "r" (vall), "r" (regs->ior), "r" (regs->isr)
: "r19", "r20", "r21", "r1", FIXUP_BRANCH_CLOBBER );
: "r19", "r20", "r21", "r1" );
}
#endif

Expand Down Expand Up @@ -547,7 +497,7 @@ void handle_unaligned(struct pt_regs *regs)
ret = emulate_stw(regs, R2(regs->iir),0);
break;

#ifdef CONFIG_PA20
#ifdef CONFIG_64BIT
case OPCODE_LDD_I:
case OPCODE_LDDA_I:
case OPCODE_LDD_S:
Expand Down Expand Up @@ -606,7 +556,7 @@ void handle_unaligned(struct pt_regs *regs)
flop=1;
ret = emulate_std(regs, R2(regs->iir),1);
break;
#ifdef CONFIG_PA20
#ifdef CONFIG_64BIT
case OPCODE_LDD_L:
ret = emulate_ldd(regs, R2(regs->iir),0);
break;
Expand Down Expand Up @@ -673,7 +623,7 @@ void handle_unaligned(struct pt_regs *regs)
printk(KERN_CRIT "Unaligned handler failed, ret = %d\n", ret);
die_if_kernel("Unaligned data reference", regs, 28);

if (ret == ERR_PAGEFAULT)
if (ret == -EFAULT)
{
force_sig_fault(SIGSEGV, SEGV_MAPERR,
(void __user *)regs->ior);
Expand Down

0 comments on commit d1434e0

Please sign in to comment.