linux/arch/parisc/kernel/unaligned.c
<<
>>
Prefs
   1// SPDX-License-Identifier: GPL-2.0-or-later
   2/*
   3 *    Unaligned memory access handler
   4 *
   5 *    Copyright (C) 2001 Randolph Chung <tausq@debian.org>
   6 *    Significantly tweaked by LaMont Jones <lamont@debian.org>
   7 */
   8
   9#include <linux/jiffies.h>
  10#include <linux/kernel.h>
  11#include <linux/module.h>
  12#include <linux/sched/signal.h>
  13#include <linux/sched/debug.h>
  14#include <linux/signal.h>
  15#include <linux/ratelimit.h>
  16#include <linux/uaccess.h>
  17#include <asm/hardirq.h>
  18#include <asm/traps.h>
  19
  20/* #define DEBUG_UNALIGNED 1 */
  21
  22#ifdef DEBUG_UNALIGNED
  23#define DPRINTF(fmt, args...) do { printk(KERN_DEBUG "%s:%d:%s ", __FILE__, __LINE__, __func__ ); printk(KERN_DEBUG fmt, ##args ); } while (0)
  24#else
  25#define DPRINTF(fmt, args...)
  26#endif
  27
  28#ifdef CONFIG_64BIT
  29#define RFMT "%016lx"
  30#else
  31#define RFMT "%08lx"
  32#endif
  33
  34#define FIXUP_BRANCH(lbl) \
  35        "\tldil L%%" #lbl ", %%r1\n"                    \
  36        "\tldo R%%" #lbl "(%%r1), %%r1\n"               \
  37        "\tbv,n %%r0(%%r1)\n"
  38/* If you use FIXUP_BRANCH, then you must list this clobber */
  39#define FIXUP_BRANCH_CLOBBER "r1"
  40
  41/* 1111 1100 0000 0000 0001 0011 1100 0000 */
  42#define OPCODE1(a,b,c)  ((a)<<26|(b)<<12|(c)<<6) 
  43#define OPCODE2(a,b)    ((a)<<26|(b)<<1)
  44#define OPCODE3(a,b)    ((a)<<26|(b)<<2)
  45#define OPCODE4(a)      ((a)<<26)
  46#define OPCODE1_MASK    OPCODE1(0x3f,1,0xf)
  47#define OPCODE2_MASK    OPCODE2(0x3f,1)
  48#define OPCODE3_MASK    OPCODE3(0x3f,1)
  49#define OPCODE4_MASK    OPCODE4(0x3f)
  50
  51/* skip LDB - never unaligned (index) */
  52#define OPCODE_LDH_I    OPCODE1(0x03,0,0x1)
  53#define OPCODE_LDW_I    OPCODE1(0x03,0,0x2)
  54#define OPCODE_LDD_I    OPCODE1(0x03,0,0x3)
  55#define OPCODE_LDDA_I   OPCODE1(0x03,0,0x4)
  56#define OPCODE_LDCD_I   OPCODE1(0x03,0,0x5)
  57#define OPCODE_LDWA_I   OPCODE1(0x03,0,0x6)
  58#define OPCODE_LDCW_I   OPCODE1(0x03,0,0x7)
  59/* skip LDB - never unaligned (short) */
  60#define OPCODE_LDH_S    OPCODE1(0x03,1,0x1)
  61#define OPCODE_LDW_S    OPCODE1(0x03,1,0x2)
  62#define OPCODE_LDD_S    OPCODE1(0x03,1,0x3)
  63#define OPCODE_LDDA_S   OPCODE1(0x03,1,0x4)
  64#define OPCODE_LDCD_S   OPCODE1(0x03,1,0x5)
  65#define OPCODE_LDWA_S   OPCODE1(0x03,1,0x6)
  66#define OPCODE_LDCW_S   OPCODE1(0x03,1,0x7)
  67/* skip STB - never unaligned */
  68#define OPCODE_STH      OPCODE1(0x03,1,0x9)
  69#define OPCODE_STW      OPCODE1(0x03,1,0xa)
  70#define OPCODE_STD      OPCODE1(0x03,1,0xb)
  71/* skip STBY - never unaligned */
  72/* skip STDBY - never unaligned */
  73#define OPCODE_STWA     OPCODE1(0x03,1,0xe)
  74#define OPCODE_STDA     OPCODE1(0x03,1,0xf)
  75
  76#define OPCODE_FLDWX    OPCODE1(0x09,0,0x0)
  77#define OPCODE_FLDWXR   OPCODE1(0x09,0,0x1)
  78#define OPCODE_FSTWX    OPCODE1(0x09,0,0x8)
  79#define OPCODE_FSTWXR   OPCODE1(0x09,0,0x9)
  80#define OPCODE_FLDWS    OPCODE1(0x09,1,0x0)
  81#define OPCODE_FLDWSR   OPCODE1(0x09,1,0x1)
  82#define OPCODE_FSTWS    OPCODE1(0x09,1,0x8)
  83#define OPCODE_FSTWSR   OPCODE1(0x09,1,0x9)
  84#define OPCODE_FLDDX    OPCODE1(0x0b,0,0x0)
  85#define OPCODE_FSTDX    OPCODE1(0x0b,0,0x8)
  86#define OPCODE_FLDDS    OPCODE1(0x0b,1,0x0)
  87#define OPCODE_FSTDS    OPCODE1(0x0b,1,0x8)
  88
  89#define OPCODE_LDD_L    OPCODE2(0x14,0)
  90#define OPCODE_FLDD_L   OPCODE2(0x14,1)
  91#define OPCODE_STD_L    OPCODE2(0x1c,0)
  92#define OPCODE_FSTD_L   OPCODE2(0x1c,1)
  93
  94#define OPCODE_LDW_M    OPCODE3(0x17,1)
  95#define OPCODE_FLDW_L   OPCODE3(0x17,0)
  96#define OPCODE_FSTW_L   OPCODE3(0x1f,0)
  97#define OPCODE_STW_M    OPCODE3(0x1f,1)
  98
  99#define OPCODE_LDH_L    OPCODE4(0x11)
 100#define OPCODE_LDW_L    OPCODE4(0x12)
 101#define OPCODE_LDWM     OPCODE4(0x13)
 102#define OPCODE_STH_L    OPCODE4(0x19)
 103#define OPCODE_STW_L    OPCODE4(0x1A)
 104#define OPCODE_STWM     OPCODE4(0x1B)
 105
 106#define MAJOR_OP(i) (((i)>>26)&0x3f)
 107#define R1(i) (((i)>>21)&0x1f)
 108#define R2(i) (((i)>>16)&0x1f)
 109#define R3(i) ((i)&0x1f)
 110#define FR3(i) ((((i)<<1)&0x1f)|(((i)>>6)&1))
 111#define IM(i,n) (((i)>>1&((1<<(n-1))-1))|((i)&1?((0-1L)<<(n-1)):0))
 112#define IM5_2(i) IM((i)>>16,5)
 113#define IM5_3(i) IM((i),5)
 114#define IM14(i) IM((i),14)
 115
 116#define ERR_NOTHANDLED  -1
 117#define ERR_PAGEFAULT   -2
 118
 119int unaligned_enabled __read_mostly = 1;
 120
 121static int emulate_ldh(struct pt_regs *regs, int toreg)
 122{
 123        unsigned long saddr = regs->ior;
 124        unsigned long val = 0;
 125        int ret;
 126
 127        DPRINTF("load " RFMT ":" RFMT " to r%d for 2 bytes\n", 
 128                regs->isr, regs->ior, toreg);
 129
 130        __asm__ __volatile__  (
 131"       mtsp    %4, %%sr1\n"
 132"1:     ldbs    0(%%sr1,%3), %%r20\n"
 133"2:     ldbs    1(%%sr1,%3), %0\n"
 134"       depw    %%r20, 23, 24, %0\n"
 135"       copy    %%r0, %1\n"
 136"3:     \n"
 137"       .section .fixup,\"ax\"\n"
 138"4:     ldi     -2, %1\n"
 139        FIXUP_BRANCH(3b)
 140"       .previous\n"
 141        ASM_EXCEPTIONTABLE_ENTRY(1b, 4b)
 142        ASM_EXCEPTIONTABLE_ENTRY(2b, 4b)
 143        : "=r" (val), "=r" (ret)
 144        : "0" (val), "r" (saddr), "r" (regs->isr)
 145        : "r20", FIXUP_BRANCH_CLOBBER );
 146
 147        DPRINTF("val = 0x" RFMT "\n", val);
 148
 149        if (toreg)
 150                regs->gr[toreg] = val;
 151
 152        return ret;
 153}
 154
 155static int emulate_ldw(struct pt_regs *regs, int toreg, int flop)
 156{
 157        unsigned long saddr = regs->ior;
 158        unsigned long val = 0;
 159        int ret;
 160
 161        DPRINTF("load " RFMT ":" RFMT " to r%d for 4 bytes\n", 
 162                regs->isr, regs->ior, toreg);
 163
 164        __asm__ __volatile__  (
 165"       zdep    %3,28,2,%%r19\n"                /* r19=(ofs&3)*8 */
 166"       mtsp    %4, %%sr1\n"
 167"       depw    %%r0,31,2,%3\n"
 168"1:     ldw     0(%%sr1,%3),%0\n"
 169"2:     ldw     4(%%sr1,%3),%%r20\n"
 170"       subi    32,%%r19,%%r19\n"
 171"       mtctl   %%r19,11\n"
 172"       vshd    %0,%%r20,%0\n"
 173"       copy    %%r0, %1\n"
 174"3:     \n"
 175"       .section .fixup,\"ax\"\n"
 176"4:     ldi     -2, %1\n"
 177        FIXUP_BRANCH(3b)
 178"       .previous\n"
 179        ASM_EXCEPTIONTABLE_ENTRY(1b, 4b)
 180        ASM_EXCEPTIONTABLE_ENTRY(2b, 4b)
 181        : "=r" (val), "=r" (ret)
 182        : "0" (val), "r" (saddr), "r" (regs->isr)
 183        : "r19", "r20", FIXUP_BRANCH_CLOBBER );
 184
 185        DPRINTF("val = 0x" RFMT "\n", val);
 186
 187        if (flop)
 188                ((__u32*)(regs->fr))[toreg] = val;
 189        else if (toreg)
 190                regs->gr[toreg] = val;
 191
 192        return ret;
 193}
 194static int emulate_ldd(struct pt_regs *regs, int toreg, int flop)
 195{
 196        unsigned long saddr = regs->ior;
 197        __u64 val = 0;
 198        int ret;
 199
 200        DPRINTF("load " RFMT ":" RFMT " to r%d for 8 bytes\n", 
 201                regs->isr, regs->ior, toreg);
 202#ifdef CONFIG_PA20
 203
 204#ifndef CONFIG_64BIT
 205        if (!flop)
 206                return -1;
 207#endif
 208        __asm__ __volatile__  (
 209"       depd,z  %3,60,3,%%r19\n"                /* r19=(ofs&7)*8 */
 210"       mtsp    %4, %%sr1\n"
 211"       depd    %%r0,63,3,%3\n"
 212"1:     ldd     0(%%sr1,%3),%0\n"
 213"2:     ldd     8(%%sr1,%3),%%r20\n"
 214"       subi    64,%%r19,%%r19\n"
 215"       mtsar   %%r19\n"
 216"       shrpd   %0,%%r20,%%sar,%0\n"
 217"       copy    %%r0, %1\n"
 218"3:     \n"
 219"       .section .fixup,\"ax\"\n"
 220"4:     ldi     -2, %1\n"
 221        FIXUP_BRANCH(3b)
 222"       .previous\n"
 223        ASM_EXCEPTIONTABLE_ENTRY(1b,4b)
 224        ASM_EXCEPTIONTABLE_ENTRY(2b,4b)
 225        : "=r" (val), "=r" (ret)
 226        : "0" (val), "r" (saddr), "r" (regs->isr)
 227        : "r19", "r20", FIXUP_BRANCH_CLOBBER );
 228#else
 229    {
 230        unsigned long valh=0,vall=0;
 231        __asm__ __volatile__  (
 232"       zdep    %5,29,2,%%r19\n"                /* r19=(ofs&3)*8 */
 233"       mtsp    %6, %%sr1\n"
 234"       dep     %%r0,31,2,%5\n"
 235"1:     ldw     0(%%sr1,%5),%0\n"
 236"2:     ldw     4(%%sr1,%5),%1\n"
 237"3:     ldw     8(%%sr1,%5),%%r20\n"
 238"       subi    32,%%r19,%%r19\n"
 239"       mtsar   %%r19\n"
 240"       vshd    %0,%1,%0\n"
 241"       vshd    %1,%%r20,%1\n"
 242"       copy    %%r0, %2\n"
 243"4:     \n"
 244"       .section .fixup,\"ax\"\n"
 245"5:     ldi     -2, %2\n"
 246        FIXUP_BRANCH(4b)
 247"       .previous\n"
 248        ASM_EXCEPTIONTABLE_ENTRY(1b,5b)
 249        ASM_EXCEPTIONTABLE_ENTRY(2b,5b)
 250        ASM_EXCEPTIONTABLE_ENTRY(3b,5b)
 251        : "=r" (valh), "=r" (vall), "=r" (ret)
 252        : "0" (valh), "1" (vall), "r" (saddr), "r" (regs->isr)
 253        : "r19", "r20", FIXUP_BRANCH_CLOBBER );
 254        val=((__u64)valh<<32)|(__u64)vall;
 255    }
 256#endif
 257
 258        DPRINTF("val = 0x%llx\n", val);
 259
 260        if (flop)
 261                regs->fr[toreg] = val;
 262        else if (toreg)
 263                regs->gr[toreg] = val;
 264
 265        return ret;
 266}
 267
 268static int emulate_sth(struct pt_regs *regs, int frreg)
 269{
 270        unsigned long val = regs->gr[frreg];
 271        int ret;
 272
 273        if (!frreg)
 274                val = 0;
 275
 276        DPRINTF("store r%d (0x" RFMT ") to " RFMT ":" RFMT " for 2 bytes\n", frreg, 
 277                val, regs->isr, regs->ior);
 278
 279        __asm__ __volatile__ (
 280"       mtsp %3, %%sr1\n"
 281"       extrw,u %1, 23, 8, %%r19\n"
 282"1:     stb %1, 1(%%sr1, %2)\n"
 283"2:     stb %%r19, 0(%%sr1, %2)\n"
 284"       copy    %%r0, %0\n"
 285"3:     \n"
 286"       .section .fixup,\"ax\"\n"
 287"4:     ldi     -2, %0\n"
 288        FIXUP_BRANCH(3b)
 289"       .previous\n"
 290        ASM_EXCEPTIONTABLE_ENTRY(1b,4b)
 291        ASM_EXCEPTIONTABLE_ENTRY(2b,4b)
 292        : "=r" (ret)
 293        : "r" (val), "r" (regs->ior), "r" (regs->isr)
 294        : "r19", FIXUP_BRANCH_CLOBBER );
 295
 296        return ret;
 297}
 298
 299static int emulate_stw(struct pt_regs *regs, int frreg, int flop)
 300{
 301        unsigned long val;
 302        int ret;
 303
 304        if (flop)
 305                val = ((__u32*)(regs->fr))[frreg];
 306        else if (frreg)
 307                val = regs->gr[frreg];
 308        else
 309                val = 0;
 310
 311        DPRINTF("store r%d (0x" RFMT ") to " RFMT ":" RFMT " for 4 bytes\n", frreg, 
 312                val, regs->isr, regs->ior);
 313
 314
 315        __asm__ __volatile__ (
 316"       mtsp %3, %%sr1\n"
 317"       zdep    %2, 28, 2, %%r19\n"
 318"       dep     %%r0, 31, 2, %2\n"
 319"       mtsar   %%r19\n"
 320"       depwi,z -2, %%sar, 32, %%r19\n"
 321"1:     ldw     0(%%sr1,%2),%%r20\n"
 322"2:     ldw     4(%%sr1,%2),%%r21\n"
 323"       vshd    %%r0, %1, %%r22\n"
 324"       vshd    %1, %%r0, %%r1\n"
 325"       and     %%r20, %%r19, %%r20\n"
 326"       andcm   %%r21, %%r19, %%r21\n"
 327"       or      %%r22, %%r20, %%r20\n"
 328"       or      %%r1, %%r21, %%r21\n"
 329"       stw     %%r20,0(%%sr1,%2)\n"
 330"       stw     %%r21,4(%%sr1,%2)\n"
 331"       copy    %%r0, %0\n"
 332"3:     \n"
 333"       .section .fixup,\"ax\"\n"
 334"4:     ldi     -2, %0\n"
 335        FIXUP_BRANCH(3b)
 336"       .previous\n"
 337        ASM_EXCEPTIONTABLE_ENTRY(1b,4b)
 338        ASM_EXCEPTIONTABLE_ENTRY(2b,4b)
 339        : "=r" (ret)
 340        : "r" (val), "r" (regs->ior), "r" (regs->isr)
 341        : "r19", "r20", "r21", "r22", "r1", FIXUP_BRANCH_CLOBBER );
 342
 343        return 0;
 344}
 345static int emulate_std(struct pt_regs *regs, int frreg, int flop)
 346{
 347        __u64 val;
 348        int ret;
 349
 350        if (flop)
 351                val = regs->fr[frreg];
 352        else if (frreg)
 353                val = regs->gr[frreg];
 354        else
 355                val = 0;
 356
 357        DPRINTF("store r%d (0x%016llx) to " RFMT ":" RFMT " for 8 bytes\n", frreg, 
 358                val,  regs->isr, regs->ior);
 359
 360#ifdef CONFIG_PA20
 361#ifndef CONFIG_64BIT
 362        if (!flop)
 363                return -1;
 364#endif
 365        __asm__ __volatile__ (
 366"       mtsp %3, %%sr1\n"
 367"       depd,z  %2, 60, 3, %%r19\n"
 368"       depd    %%r0, 63, 3, %2\n"
 369"       mtsar   %%r19\n"
 370"       depdi,z -2, %%sar, 64, %%r19\n"
 371"1:     ldd     0(%%sr1,%2),%%r20\n"
 372"2:     ldd     8(%%sr1,%2),%%r21\n"
 373"       shrpd   %%r0, %1, %%sar, %%r22\n"
 374"       shrpd   %1, %%r0, %%sar, %%r1\n"
 375"       and     %%r20, %%r19, %%r20\n"
 376"       andcm   %%r21, %%r19, %%r21\n"
 377"       or      %%r22, %%r20, %%r20\n"
 378"       or      %%r1, %%r21, %%r21\n"
 379"3:     std     %%r20,0(%%sr1,%2)\n"
 380"4:     std     %%r21,8(%%sr1,%2)\n"
 381"       copy    %%r0, %0\n"
 382"5:     \n"
 383"       .section .fixup,\"ax\"\n"
 384"6:     ldi     -2, %0\n"
 385        FIXUP_BRANCH(5b)
 386"       .previous\n"
 387        ASM_EXCEPTIONTABLE_ENTRY(1b,6b)
 388        ASM_EXCEPTIONTABLE_ENTRY(2b,6b)
 389        ASM_EXCEPTIONTABLE_ENTRY(3b,6b)
 390        ASM_EXCEPTIONTABLE_ENTRY(4b,6b)
 391        : "=r" (ret)
 392        : "r" (val), "r" (regs->ior), "r" (regs->isr)
 393        : "r19", "r20", "r21", "r22", "r1", FIXUP_BRANCH_CLOBBER );
 394#else
 395    {
 396        unsigned long valh=(val>>32),vall=(val&0xffffffffl);
 397        __asm__ __volatile__ (
 398"       mtsp    %4, %%sr1\n"
 399"       zdep    %2, 29, 2, %%r19\n"
 400"       dep     %%r0, 31, 2, %2\n"
 401"       mtsar   %%r19\n"
 402"       zvdepi  -2, 32, %%r19\n"
 403"1:     ldw     0(%%sr1,%3),%%r20\n"
 404"2:     ldw     8(%%sr1,%3),%%r21\n"
 405"       vshd    %1, %2, %%r1\n"
 406"       vshd    %%r0, %1, %1\n"
 407"       vshd    %2, %%r0, %2\n"
 408"       and     %%r20, %%r19, %%r20\n"
 409"       andcm   %%r21, %%r19, %%r21\n"
 410"       or      %1, %%r20, %1\n"
 411"       or      %2, %%r21, %2\n"
 412"3:     stw     %1,0(%%sr1,%1)\n"
 413"4:     stw     %%r1,4(%%sr1,%3)\n"
 414"5:     stw     %2,8(%%sr1,%3)\n"
 415"       copy    %%r0, %0\n"
 416"6:     \n"
 417"       .section .fixup,\"ax\"\n"
 418"7:     ldi     -2, %0\n"
 419        FIXUP_BRANCH(6b)
 420"       .previous\n"
 421        ASM_EXCEPTIONTABLE_ENTRY(1b,7b)
 422        ASM_EXCEPTIONTABLE_ENTRY(2b,7b)
 423        ASM_EXCEPTIONTABLE_ENTRY(3b,7b)
 424        ASM_EXCEPTIONTABLE_ENTRY(4b,7b)
 425        ASM_EXCEPTIONTABLE_ENTRY(5b,7b)
 426        : "=r" (ret)
 427        : "r" (valh), "r" (vall), "r" (regs->ior), "r" (regs->isr)
 428        : "r19", "r20", "r21", "r1", FIXUP_BRANCH_CLOBBER );
 429    }
 430#endif
 431
 432        return ret;
 433}
 434
 435void handle_unaligned(struct pt_regs *regs)
 436{
 437        static DEFINE_RATELIMIT_STATE(ratelimit, 5 * HZ, 5);
 438        unsigned long newbase = R1(regs->iir)?regs->gr[R1(regs->iir)]:0;
 439        int modify = 0;
 440        int ret = ERR_NOTHANDLED;
 441        register int flop=0;    /* true if this is a flop */
 442
 443        __inc_irq_stat(irq_unaligned_count);
 444
 445        /* log a message with pacing */
 446        if (user_mode(regs)) {
 447                if (current->thread.flags & PARISC_UAC_SIGBUS) {
 448                        goto force_sigbus;
 449                }
 450
 451                if (!(current->thread.flags & PARISC_UAC_NOPRINT) &&
 452                        __ratelimit(&ratelimit)) {
 453                        char buf[256];
 454                        sprintf(buf, "%s(%d): unaligned access to 0x" RFMT " at ip=0x" RFMT "\n",
 455                                current->comm, task_pid_nr(current), regs->ior, regs->iaoq[0]);
 456                        printk(KERN_WARNING "%s", buf);
 457#ifdef DEBUG_UNALIGNED
 458                        show_regs(regs);
 459#endif          
 460                }
 461
 462                if (!unaligned_enabled)
 463                        goto force_sigbus;
 464        }
 465
 466        /* handle modification - OK, it's ugly, see the instruction manual */
 467        switch (MAJOR_OP(regs->iir))
 468        {
 469        case 0x03:
 470        case 0x09:
 471        case 0x0b:
 472                if (regs->iir&0x20)
 473                {
 474                        modify = 1;
 475                        if (regs->iir&0x1000)           /* short loads */
 476                                if (regs->iir&0x200)
 477                                        newbase += IM5_3(regs->iir);
 478                                else
 479                                        newbase += IM5_2(regs->iir);
 480                        else if (regs->iir&0x2000)      /* scaled indexed */
 481                        {
 482                                int shift=0;
 483                                switch (regs->iir & OPCODE1_MASK)
 484                                {
 485                                case OPCODE_LDH_I:
 486                                        shift= 1; break;
 487                                case OPCODE_LDW_I:
 488                                        shift= 2; break;
 489                                case OPCODE_LDD_I:
 490                                case OPCODE_LDDA_I:
 491                                        shift= 3; break;
 492                                }
 493                                newbase += (R2(regs->iir)?regs->gr[R2(regs->iir)]:0)<<shift;
 494                        } else                          /* simple indexed */
 495                                newbase += (R2(regs->iir)?regs->gr[R2(regs->iir)]:0);
 496                }
 497                break;
 498        case 0x13:
 499        case 0x1b:
 500                modify = 1;
 501                newbase += IM14(regs->iir);
 502                break;
 503        case 0x14:
 504        case 0x1c:
 505                if (regs->iir&8)
 506                {
 507                        modify = 1;
 508                        newbase += IM14(regs->iir&~0xe);
 509                }
 510                break;
 511        case 0x16:
 512        case 0x1e:
 513                modify = 1;
 514                newbase += IM14(regs->iir&6);
 515                break;
 516        case 0x17:
 517        case 0x1f:
 518                if (regs->iir&4)
 519                {
 520                        modify = 1;
 521                        newbase += IM14(regs->iir&~4);
 522                }
 523                break;
 524        }
 525
 526        /* TODO: make this cleaner... */
 527        switch (regs->iir & OPCODE1_MASK)
 528        {
 529        case OPCODE_LDH_I:
 530        case OPCODE_LDH_S:
 531                ret = emulate_ldh(regs, R3(regs->iir));
 532                break;
 533
 534        case OPCODE_LDW_I:
 535        case OPCODE_LDWA_I:
 536        case OPCODE_LDW_S:
 537        case OPCODE_LDWA_S:
 538                ret = emulate_ldw(regs, R3(regs->iir),0);
 539                break;
 540
 541        case OPCODE_STH:
 542                ret = emulate_sth(regs, R2(regs->iir));
 543                break;
 544
 545        case OPCODE_STW:
 546        case OPCODE_STWA:
 547                ret = emulate_stw(regs, R2(regs->iir),0);
 548                break;
 549
 550#ifdef CONFIG_PA20
 551        case OPCODE_LDD_I:
 552        case OPCODE_LDDA_I:
 553        case OPCODE_LDD_S:
 554        case OPCODE_LDDA_S:
 555                ret = emulate_ldd(regs, R3(regs->iir),0);
 556                break;
 557
 558        case OPCODE_STD:
 559        case OPCODE_STDA:
 560                ret = emulate_std(regs, R2(regs->iir),0);
 561                break;
 562#endif
 563
 564        case OPCODE_FLDWX:
 565        case OPCODE_FLDWS:
 566        case OPCODE_FLDWXR:
 567        case OPCODE_FLDWSR:
 568                flop=1;
 569                ret = emulate_ldw(regs,FR3(regs->iir),1);
 570                break;
 571
 572        case OPCODE_FLDDX:
 573        case OPCODE_FLDDS:
 574                flop=1;
 575                ret = emulate_ldd(regs,R3(regs->iir),1);
 576                break;
 577
 578        case OPCODE_FSTWX:
 579        case OPCODE_FSTWS:
 580        case OPCODE_FSTWXR:
 581        case OPCODE_FSTWSR:
 582                flop=1;
 583                ret = emulate_stw(regs,FR3(regs->iir),1);
 584                break;
 585
 586        case OPCODE_FSTDX:
 587        case OPCODE_FSTDS:
 588                flop=1;
 589                ret = emulate_std(regs,R3(regs->iir),1);
 590                break;
 591
 592        case OPCODE_LDCD_I:
 593        case OPCODE_LDCW_I:
 594        case OPCODE_LDCD_S:
 595        case OPCODE_LDCW_S:
 596                ret = ERR_NOTHANDLED;   /* "undefined", but lets kill them. */
 597                break;
 598        }
 599#ifdef CONFIG_PA20
 600        switch (regs->iir & OPCODE2_MASK)
 601        {
 602        case OPCODE_FLDD_L:
 603                flop=1;
 604                ret = emulate_ldd(regs,R2(regs->iir),1);
 605                break;
 606        case OPCODE_FSTD_L:
 607                flop=1;
 608                ret = emulate_std(regs, R2(regs->iir),1);
 609                break;
 610        case OPCODE_LDD_L:
 611                ret = emulate_ldd(regs, R2(regs->iir),0);
 612                break;
 613        case OPCODE_STD_L:
 614                ret = emulate_std(regs, R2(regs->iir),0);
 615                break;
 616        }
 617#endif
 618        switch (regs->iir & OPCODE3_MASK)
 619        {
 620        case OPCODE_FLDW_L:
 621                flop=1;
 622                ret = emulate_ldw(regs, R2(regs->iir),0);
 623                break;
 624        case OPCODE_LDW_M:
 625                ret = emulate_ldw(regs, R2(regs->iir),1);
 626                break;
 627
 628        case OPCODE_FSTW_L:
 629                flop=1;
 630                ret = emulate_stw(regs, R2(regs->iir),1);
 631                break;
 632        case OPCODE_STW_M:
 633                ret = emulate_stw(regs, R2(regs->iir),0);
 634                break;
 635        }
 636        switch (regs->iir & OPCODE4_MASK)
 637        {
 638        case OPCODE_LDH_L:
 639                ret = emulate_ldh(regs, R2(regs->iir));
 640                break;
 641        case OPCODE_LDW_L:
 642        case OPCODE_LDWM:
 643                ret = emulate_ldw(regs, R2(regs->iir),0);
 644                break;
 645        case OPCODE_STH_L:
 646                ret = emulate_sth(regs, R2(regs->iir));
 647                break;
 648        case OPCODE_STW_L:
 649        case OPCODE_STWM:
 650                ret = emulate_stw(regs, R2(regs->iir),0);
 651                break;
 652        }
 653
 654        if (ret == 0 && modify && R1(regs->iir))
 655                regs->gr[R1(regs->iir)] = newbase;
 656
 657
 658        if (ret == ERR_NOTHANDLED)
 659                printk(KERN_CRIT "Not-handled unaligned insn 0x%08lx\n", regs->iir);
 660
 661        DPRINTF("ret = %d\n", ret);
 662
 663        if (ret)
 664        {
 665                /*
 666                 * The unaligned handler failed.
 667                 * If we were called by __get_user() or __put_user() jump
 668                 * to it's exception fixup handler instead of crashing.
 669                 */
 670                if (!user_mode(regs) && fixup_exception(regs))
 671                        return;
 672
 673                printk(KERN_CRIT "Unaligned handler failed, ret = %d\n", ret);
 674                die_if_kernel("Unaligned data reference", regs, 28);
 675
 676                if (ret == ERR_PAGEFAULT)
 677                {
 678                        force_sig_fault(SIGSEGV, SEGV_MAPERR,
 679                                        (void __user *)regs->ior);
 680                }
 681                else
 682                {
 683force_sigbus:
 684                        /* couldn't handle it ... */
 685                        force_sig_fault(SIGBUS, BUS_ADRALN,
 686                                        (void __user *)regs->ior);
 687                }
 688                
 689                return;
 690        }
 691
 692        /* else we handled it, let life go on. */
 693        regs->gr[0]|=PSW_N;
 694}
 695
 696/*
 697 * NB: check_unaligned() is only used for PCXS processors right
 698 * now, so we only check for PA1.1 encodings at this point.
 699 */
 700
 701int
 702check_unaligned(struct pt_regs *regs)
 703{
 704        unsigned long align_mask;
 705
 706        /* Get alignment mask */
 707
 708        align_mask = 0UL;
 709        switch (regs->iir & OPCODE1_MASK) {
 710
 711        case OPCODE_LDH_I:
 712        case OPCODE_LDH_S:
 713        case OPCODE_STH:
 714                align_mask = 1UL;
 715                break;
 716
 717        case OPCODE_LDW_I:
 718        case OPCODE_LDWA_I:
 719        case OPCODE_LDW_S:
 720        case OPCODE_LDWA_S:
 721        case OPCODE_STW:
 722        case OPCODE_STWA:
 723                align_mask = 3UL;
 724                break;
 725
 726        default:
 727                switch (regs->iir & OPCODE4_MASK) {
 728                case OPCODE_LDH_L:
 729                case OPCODE_STH_L:
 730                        align_mask = 1UL;
 731                        break;
 732                case OPCODE_LDW_L:
 733                case OPCODE_LDWM:
 734                case OPCODE_STW_L:
 735                case OPCODE_STWM:
 736                        align_mask = 3UL;
 737                        break;
 738                }
 739                break;
 740        }
 741
 742        return (int)(regs->ior & align_mask);
 743}
 744
 745