in kernel/traps.c [776:956]
__asm__ __volatile__(
"1: ldq_u %1,0(%3)\n"
"2: ldq_u %2,1(%3)\n"
" extwl %1,%3,%1\n"
" extwh %2,%3,%2\n"
"3:\n"
EXC(1b,3b,%1,%0)
EXC(2b,3b,%2,%0)
: "=r"(error), "=&r"(tmp1), "=&r"(tmp2)
: "r"(va), "0"(0));
if (error)
goto give_sigsegv;
*reg_addr = tmp1|tmp2;
break;
case 0x22: /* lds */
__asm__ __volatile__(
"1: ldq_u %1,0(%3)\n"
"2: ldq_u %2,3(%3)\n"
" extll %1,%3,%1\n"
" extlh %2,%3,%2\n"
"3:\n"
EXC(1b,3b,%1,%0)
EXC(2b,3b,%2,%0)
: "=r"(error), "=&r"(tmp1), "=&r"(tmp2)
: "r"(va), "0"(0));
if (error)
goto give_sigsegv;
alpha_write_fp_reg(reg, s_mem_to_reg((int)(tmp1|tmp2)));
return;
case 0x23: /* ldt */
__asm__ __volatile__(
"1: ldq_u %1,0(%3)\n"
"2: ldq_u %2,7(%3)\n"
" extql %1,%3,%1\n"
" extqh %2,%3,%2\n"
"3:\n"
EXC(1b,3b,%1,%0)
EXC(2b,3b,%2,%0)
: "=r"(error), "=&r"(tmp1), "=&r"(tmp2)
: "r"(va), "0"(0));
if (error)
goto give_sigsegv;
alpha_write_fp_reg(reg, tmp1|tmp2);
return;
case 0x28: /* ldl */
__asm__ __volatile__(
"1: ldq_u %1,0(%3)\n"
"2: ldq_u %2,3(%3)\n"
" extll %1,%3,%1\n"
" extlh %2,%3,%2\n"
"3:\n"
EXC(1b,3b,%1,%0)
EXC(2b,3b,%2,%0)
: "=r"(error), "=&r"(tmp1), "=&r"(tmp2)
: "r"(va), "0"(0));
if (error)
goto give_sigsegv;
*reg_addr = (int)(tmp1|tmp2);
break;
case 0x29: /* ldq */
__asm__ __volatile__(
"1: ldq_u %1,0(%3)\n"
"2: ldq_u %2,7(%3)\n"
" extql %1,%3,%1\n"
" extqh %2,%3,%2\n"
"3:\n"
EXC(1b,3b,%1,%0)
EXC(2b,3b,%2,%0)
: "=r"(error), "=&r"(tmp1), "=&r"(tmp2)
: "r"(va), "0"(0));
if (error)
goto give_sigsegv;
*reg_addr = tmp1|tmp2;
break;
/* Note that the store sequences do not indicate that they change
memory because it _should_ be affecting nothing in this context.
(Otherwise we have other, much larger, problems.) */
case 0x0d: /* stw */
__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"
EXC(1b,5b,%2,%0)
EXC(2b,5b,%1,%0)
EXC(3b,5b,$31,%0)
EXC(4b,5b,$31,%0)
: "=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));
fallthrough;
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"
EXC(1b,5b,%2,%0)
EXC(2b,5b,%1,%0)
EXC(3b,5b,$31,%0)
EXC(4b,5b,$31,%0)
: "=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);
fallthrough;
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"
EXC(1b,5b,%2,%0)
EXC(2b,5b,%1,%0)
EXC(3b,5b,$31,%0)
EXC(4b,5b,$31,%0)
: "=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 */
/* 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 ((unsigned long)va >= TASK_SIZE)
si_code = SEGV_ACCERR;
else {