parisc/unaligned: Fix fldd and fstd unaligned handlers on 32-bit kernel
authorHelge Deller <deller@gmx.de>
Fri, 18 Feb 2022 08:25:20 +0000 (09:25 +0100)
committerGreg Kroah-Hartman <gregkh@linuxfoundation.org>
Wed, 2 Mar 2022 10:33:52 +0000 (11:33 +0100)
commit dd2288f4a020d693360e3e8d72f8b9d9c25f5ef6 upstream.

Usually the kernel provides fixup routines to emulate the fldd and fstd
floating-point instructions if they load or store 8-byte from/to a not
natuarally aligned memory location.

On a 32-bit kernel I noticed that those unaligned handlers didn't worked and
instead the application got a SEGV.
While checking the code I found two problems:

First, the OPCODE_FLDD_L and OPCODE_FSTD_L cases were ifdef'ed out by the
CONFIG_PA20 option, and as such those weren't built on a pure 32-bit kernel.
This is now fixed by moving the CONFIG_PA20 #ifdef to prevent the compilation
of OPCODE_LDD_L and OPCODE_FSTD_L only, and handling the fldd and fstd
instructions.

The second problem are two bugs in the 32-bit inline assembly code, where the
wrong registers where used. The calculation of the natural alignment used %2
(vall) instead of %3 (ior), and the first word was stored back to address %1
(valh) instead of %3 (ior).

Signed-off-by: Helge Deller <deller@gmx.de>
Cc: stable@vger.kernel.org
Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
arch/parisc/kernel/unaligned.c

index e36f7b75ab07b3275a5af086cb4ab22dd6102119..681585e30d4e58efc365baecc75a9cbe3f976d89 100644 (file)
@@ -411,7 +411,7 @@ static int emulate_std(struct pt_regs *regs, int frreg, int flop)
        __asm__ __volatile__ (
 "      mtsp    %4, %%sr1\n"
 "      zdep    %2, 29, 2, %%r19\n"
-"      dep     %%r0, 31, 2, %2\n"
+"      dep     %%r0, 31, 2, %3\n"
 "      mtsar   %%r19\n"
 "      zvdepi  -2, 32, %%r19\n"
 "1:    ldw     0(%%sr1,%3),%%r20\n"
@@ -423,7 +423,7 @@ static int emulate_std(struct pt_regs *regs, int frreg, int flop)
 "      andcm   %%r21, %%r19, %%r21\n"
 "      or      %1, %%r20, %1\n"
 "      or      %2, %%r21, %2\n"
-"3:    stw     %1,0(%%sr1,%1)\n"
+"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"
@@ -611,7 +611,6 @@ void handle_unaligned(struct pt_regs *regs)
                ret = ERR_NOTHANDLED;   /* "undefined", but lets kill them. */
                break;
        }
-#ifdef CONFIG_PA20
        switch (regs->iir & OPCODE2_MASK)
        {
        case OPCODE_FLDD_L:
@@ -622,14 +621,15 @@ void handle_unaligned(struct pt_regs *regs)
                flop=1;
                ret = emulate_std(regs, R2(regs->iir),1);
                break;
+#ifdef CONFIG_PA20
        case OPCODE_LDD_L:
                ret = emulate_ldd(regs, R2(regs->iir),0);
                break;
        case OPCODE_STD_L:
                ret = emulate_std(regs, R2(regs->iir),0);
                break;
-       }
 #endif
+       }
        switch (regs->iir & OPCODE3_MASK)
        {
        case OPCODE_FLDW_L: