|
@@ -929,3 +929,159 @@ do_entUnaUser(void __user * va, unsigned long opcode,
|
|
|
__asm__ __volatile__(
|
|
|
"1: ldq_u %2,1(%5)\n"
|
|
|
"2: ldq_u %1,0(%5)\n"
|
|
|
+ " inswh %6,%5,%4\n"
|
|
|
+ " inswl %6,%5,%3\n"
|
|
|
+ " mskwh %2,%5,%2\n"
|
|
|
+ " mskwl %1,%5,%1\n"
|
|
|
+ " or %2,%4,%2\n"
|
|
|
+ " or %1,%3,%1\n"
|
|
|
+ "3: stq_u %2,1(%5)\n"
|
|
|
+ "4: stq_u %1,0(%5)\n"
|
|
|
+ "5:\n"
|
|
|
+ ".section __ex_table,\"a\"\n"
|
|
|
+ " .long 1b - .\n"
|
|
|
+ " lda %2,5b-1b(%0)\n"
|
|
|
+ " .long 2b - .\n"
|
|
|
+ " lda %1,5b-2b(%0)\n"
|
|
|
+ " .long 3b - .\n"
|
|
|
+ " lda $31,5b-3b(%0)\n"
|
|
|
+ " .long 4b - .\n"
|
|
|
+ " lda $31,5b-4b(%0)\n"
|
|
|
+ ".previous"
|
|
|
+ : "=r"(error), "=&r"(tmp1), "=&r"(tmp2),
|
|
|
+ "=&r"(tmp3), "=&r"(tmp4)
|
|
|
+ : "r"(va), "r"(*reg_addr), "0"(0));
|
|
|
+ if (error)
|
|
|
+ goto give_sigsegv;
|
|
|
+ return;
|
|
|
+
|
|
|
+ case 0x26: /* sts */
|
|
|
+ fake_reg = s_reg_to_mem(alpha_read_fp_reg(reg));
|
|
|
+ /* FALLTHRU */
|
|
|
+
|
|
|
+ case 0x2c: /* stl */
|
|
|
+ __asm__ __volatile__(
|
|
|
+ "1: ldq_u %2,3(%5)\n"
|
|
|
+ "2: ldq_u %1,0(%5)\n"
|
|
|
+ " inslh %6,%5,%4\n"
|
|
|
+ " insll %6,%5,%3\n"
|
|
|
+ " msklh %2,%5,%2\n"
|
|
|
+ " mskll %1,%5,%1\n"
|
|
|
+ " or %2,%4,%2\n"
|
|
|
+ " or %1,%3,%1\n"
|
|
|
+ "3: stq_u %2,3(%5)\n"
|
|
|
+ "4: stq_u %1,0(%5)\n"
|
|
|
+ "5:\n"
|
|
|
+ ".section __ex_table,\"a\"\n"
|
|
|
+ " .long 1b - .\n"
|
|
|
+ " lda %2,5b-1b(%0)\n"
|
|
|
+ " .long 2b - .\n"
|
|
|
+ " lda %1,5b-2b(%0)\n"
|
|
|
+ " .long 3b - .\n"
|
|
|
+ " lda $31,5b-3b(%0)\n"
|
|
|
+ " .long 4b - .\n"
|
|
|
+ " lda $31,5b-4b(%0)\n"
|
|
|
+ ".previous"
|
|
|
+ : "=r"(error), "=&r"(tmp1), "=&r"(tmp2),
|
|
|
+ "=&r"(tmp3), "=&r"(tmp4)
|
|
|
+ : "r"(va), "r"(*reg_addr), "0"(0));
|
|
|
+ if (error)
|
|
|
+ goto give_sigsegv;
|
|
|
+ return;
|
|
|
+
|
|
|
+ case 0x27: /* stt */
|
|
|
+ fake_reg = alpha_read_fp_reg(reg);
|
|
|
+ /* FALLTHRU */
|
|
|
+
|
|
|
+ case 0x2d: /* stq */
|
|
|
+ __asm__ __volatile__(
|
|
|
+ "1: ldq_u %2,7(%5)\n"
|
|
|
+ "2: ldq_u %1,0(%5)\n"
|
|
|
+ " insqh %6,%5,%4\n"
|
|
|
+ " insql %6,%5,%3\n"
|
|
|
+ " mskqh %2,%5,%2\n"
|
|
|
+ " mskql %1,%5,%1\n"
|
|
|
+ " or %2,%4,%2\n"
|
|
|
+ " or %1,%3,%1\n"
|
|
|
+ "3: stq_u %2,7(%5)\n"
|
|
|
+ "4: stq_u %1,0(%5)\n"
|
|
|
+ "5:\n"
|
|
|
+ ".section __ex_table,\"a\"\n\t"
|
|
|
+ " .long 1b - .\n"
|
|
|
+ " lda %2,5b-1b(%0)\n"
|
|
|
+ " .long 2b - .\n"
|
|
|
+ " lda %1,5b-2b(%0)\n"
|
|
|
+ " .long 3b - .\n"
|
|
|
+ " lda $31,5b-3b(%0)\n"
|
|
|
+ " .long 4b - .\n"
|
|
|
+ " lda $31,5b-4b(%0)\n"
|
|
|
+ ".previous"
|
|
|
+ : "=r"(error), "=&r"(tmp1), "=&r"(tmp2),
|
|
|
+ "=&r"(tmp3), "=&r"(tmp4)
|
|
|
+ : "r"(va), "r"(*reg_addr), "0"(0));
|
|
|
+ if (error)
|
|
|
+ goto give_sigsegv;
|
|
|
+ return;
|
|
|
+
|
|
|
+ default:
|
|
|
+ /* What instruction were you trying to use, exactly? */
|
|
|
+ goto give_sigbus;
|
|
|
+ }
|
|
|
+
|
|
|
+ /* Only integer loads should get here; everyone else returns early. */
|
|
|
+ if (reg == 30)
|
|
|
+ wrusp(fake_reg);
|
|
|
+ return;
|
|
|
+
|
|
|
+give_sigsegv:
|
|
|
+ regs->pc -= 4; /* make pc point to faulting insn */
|
|
|
+ info.si_signo = SIGSEGV;
|
|
|
+ info.si_errno = 0;
|
|
|
+
|
|
|
+ /* We need to replicate some of the logic in mm/fault.c,
|
|
|
+ since we don't have access to the fault code in the
|
|
|
+ exception handling return path. */
|
|
|
+ if (!__access_ok((unsigned long)va, 0, USER_DS))
|
|
|
+ info.si_code = SEGV_ACCERR;
|
|
|
+ else {
|
|
|
+ struct mm_struct *mm = current->mm;
|
|
|
+ down_read(&mm->mmap_sem);
|
|
|
+ if (find_vma(mm, (unsigned long)va))
|
|
|
+ info.si_code = SEGV_ACCERR;
|
|
|
+ else
|
|
|
+ info.si_code = SEGV_MAPERR;
|
|
|
+ up_read(&mm->mmap_sem);
|
|
|
+ }
|
|
|
+ info.si_addr = va;
|
|
|
+ send_sig_info(SIGSEGV, &info, current);
|
|
|
+ return;
|
|
|
+
|
|
|
+give_sigbus:
|
|
|
+ regs->pc -= 4;
|
|
|
+ info.si_signo = SIGBUS;
|
|
|
+ info.si_errno = 0;
|
|
|
+ info.si_code = BUS_ADRALN;
|
|
|
+ info.si_addr = va;
|
|
|
+ send_sig_info(SIGBUS, &info, current);
|
|
|
+ return;
|
|
|
+}
|
|
|
+
|
|
|
+void __cpuinit
|
|
|
+trap_init(void)
|
|
|
+{
|
|
|
+ /* Tell PAL-code what global pointer we want in the kernel. */
|
|
|
+ register unsigned long gptr __asm__("$29");
|
|
|
+ wrkgp(gptr);
|
|
|
+
|
|
|
+ /* Hack for Multia (UDB) and JENSEN: some of their SRMs have
|
|
|
+ a bug in the handling of the opDEC fault. Fix it up if so. */
|
|
|
+ if (implver() == IMPLVER_EV4)
|
|
|
+ opDEC_check();
|
|
|
+
|
|
|
+ wrent(entArith, 1);
|
|
|
+ wrent(entMM, 2);
|
|
|
+ wrent(entIF, 3);
|
|
|
+ wrent(entUna, 4);
|
|
|
+ wrent(entSys, 5);
|
|
|
+ wrent(entDbg, 6);
|
|
|
+}
|