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