summaryrefslogtreecommitdiffstats
path: root/arch/alpha/kernel/traps.c
diff options
context:
space:
mode:
Diffstat (limited to 'arch/alpha/kernel/traps.c')
-rw-r--r--arch/alpha/kernel/traps.c455
1 files changed, 341 insertions, 114 deletions
diff --git a/arch/alpha/kernel/traps.c b/arch/alpha/kernel/traps.c
index a9e0c6cf2..02fa5a35d 100644
--- a/arch/alpha/kernel/traps.c
+++ b/arch/alpha/kernel/traps.c
@@ -16,34 +16,54 @@
#include <asm/gentrap.h>
#include <asm/uaccess.h>
#include <asm/unaligned.h>
+#include <asm/sysinfo.h>
+#include <asm/smp_lock.h>
-void die_if_kernel(char * str, struct pt_regs * regs, long err)
+
+void die_if_kernel(char * str, struct pt_regs * regs, long err,
+ unsigned long *r9_15)
{
long i;
- unsigned long sp;
+ unsigned long sp, ra;
unsigned int * pc;
if (regs->ps & 8)
return;
printk("%s(%d): %s %ld\n", current->comm, current->pid, str, err);
sp = (unsigned long) (regs+1);
- printk("pc = [<%lx>] ps = %04lx\n", regs->pc, regs->ps);
- printk("rp = [<%lx>] sp = %lx\n", regs->r26, sp);
- printk("r0=%lx r1=%lx r2=%lx r3=%lx\n",
- regs->r0, regs->r1, regs->r2, regs->r3);
- printk("r8=%lx\n", regs->r8);
- printk("r16=%lx r17=%lx r18=%lx r19=%lx\n",
- regs->r16, regs->r17, regs->r18, regs->r19);
- printk("r20=%lx r21=%lx r22=%lx r23=%lx\n",
- regs->r20, regs->r21, regs->r22, regs->r23);
- printk("r24=%lx r25=%lx r26=%lx r27=%lx\n",
- regs->r24, regs->r25, regs->r26, regs->r27);
- printk("r28=%lx r29=%lx r30=%lx\n",
- regs->r28, regs->gp, sp);
+ __get_user(ra, (unsigned long *)sp);
+ printk("pc = [<%016lx>] ps = %04lx\n", regs->pc, regs->ps);
+ printk("rp = [<%016lx>] ra = [<%016lx>]\n", regs->r26, ra);
+ printk("r0 = %016lx r1 = %016lx\n", regs->r0, regs->r1);
+ printk("r2 = %016lx r3 = %016lx\n", regs->r2, regs->r3);
+ printk("r4 = %016lx r5 = %016lx\n", regs->r4, regs->r5);
+ printk("r6 = %016lx r7 = %016lx\n", regs->r6, regs->r7);
+
+ if (r9_15) {
+ printk("r8 = %016lx r9 = %016lx\n", regs->r8, r9_15[9]);
+ printk("r10= %016lx r11= %016lx\n", r9_15[10], r9_15[11]);
+ printk("r12= %016lx r13= %016lx\n", r9_15[12], r9_15[13]);
+ printk("r14= %016lx r15= %016lx\n", r9_15[14], r9_15[15]);
+ } else {
+ printk("r8 = %016lx\n", regs->r8);
+ }
+
+ printk("r16= %016lx r17= %016lx\n", regs->r16, regs->r17);
+ printk("r18= %016lx r19= %016lx\n", regs->r18, regs->r19);
+ printk("r20= %016lx r21= %016lx\n", regs->r20, regs->r21);
+ printk("r22= %016lx r23= %016lx\n", regs->r22, regs->r23);
+ printk("r24= %016lx r25= %016lx\n", regs->r24, regs->r25);
+ printk("r27= %016lx r28= %016lx\n", regs->r27, regs->r28);
+ printk("gp = %016lx sp = %016lx\n", regs->gp, sp);
+
printk("Code:");
pc = (unsigned int *) regs->pc;
- for (i = -3; i < 6; i++)
- printk("%c%08x%c",i?' ':'<',pc[i],i?' ':'>');
+ for (i = -3; i < 6; i++) {
+ unsigned int insn;
+ if (__get_user(insn, pc+i))
+ break;
+ printk("%c%08x%c",i?' ':'<',insn,i?' ':'>');
+ }
printk("\n");
do_exit(SIGSEGV);
}
@@ -64,10 +84,13 @@ asmlinkage void do_entArith(unsigned long summary, unsigned long write_mask,
return; /* emulation was successful */
}
}
+
+ lock_kernel();
printk("%s: arithmetic trap at %016lx: %02lx %016lx\n",
current->comm, regs.pc, summary, write_mask);
- die_if_kernel("Arithmetic fault", &regs, 0);
+ die_if_kernel("Arithmetic fault", &regs, 0, 0);
force_sig(SIGFPE, current);
+ unlock_kernel();
}
asmlinkage void do_entIF(unsigned long type, unsigned long a1,
@@ -76,7 +99,8 @@ asmlinkage void do_entIF(unsigned long type, unsigned long a1,
{
extern int ptrace_cancel_bpt (struct task_struct *who);
- die_if_kernel("Instruction fault", &regs, type);
+ lock_kernel();
+ die_if_kernel("Instruction fault", &regs, type, 0);
switch (type) {
case 0: /* breakpoint */
if (ptrace_cancel_bpt(current)) {
@@ -154,6 +178,7 @@ asmlinkage void do_entIF(unsigned long type, unsigned long a1,
default:
panic("do_entIF: unexpected instruction-fault type");
}
+ unlock_kernel();
}
/*
@@ -187,21 +212,10 @@ asmlinkage void do_entUna(void * va, unsigned long opcode, unsigned long reg,
unsigned long a3, unsigned long a4, unsigned long a5,
struct allregs regs)
{
- static int cnt = 0;
- static long last_time = 0;
long error, tmp1, tmp2, tmp3, tmp4;
unsigned long pc = regs.pc - 4;
unsigned fixup;
- if (cnt >= 5 && jiffies - last_time > 5*HZ) {
- cnt = 0;
- }
- if (++cnt < 5) {
- printk("kernel: unaligned trap at %016lx: %p %lx %ld\n",
- pc, va, opcode, reg);
- }
- last_time = jiffies;
-
unaligned[0].count++;
unaligned[0].va = (unsigned long) va;
unaligned[0].pc = pc;
@@ -211,7 +225,6 @@ asmlinkage void do_entUna(void * va, unsigned long opcode, unsigned long reg,
exception will we decide whether we should have caught it. */
switch (opcode) {
-#ifdef __HAVE_CPU_BWX
case 0x0c: /* ldwu */
__asm__ __volatile__(
"1: ldq_u %1,0(%3)\n"
@@ -224,14 +237,13 @@ asmlinkage void do_entUna(void * va, unsigned long opcode, unsigned long reg,
" lda %1,3b-1b(%0)\n"
" .gprel32 2b\n"
" lda %2,3b-2b(%0)\n"
- ".text"
+ ".previous"
: "=r"(error), "=&r"(tmp1), "=&r"(tmp2)
: "r"(va), "0"(0));
if (error)
goto got_exception;
una_reg(reg) = tmp1|tmp2;
return;
-#endif
case 0x28: /* ldl */
__asm__ __volatile__(
@@ -245,7 +257,7 @@ asmlinkage void do_entUna(void * va, unsigned long opcode, unsigned long reg,
" lda %1,3b-1b(%0)\n"
" .gprel32 2b\n"
" lda %2,3b-2b(%0)\n"
- ".text"
+ ".previous"
: "=r"(error), "=&r"(tmp1), "=&r"(tmp2)
: "r"(va), "0"(0));
if (error)
@@ -265,7 +277,7 @@ asmlinkage void do_entUna(void * va, unsigned long opcode, unsigned long reg,
" lda %1,3b-1b(%0)\n"
" .gprel32 2b\n"
" lda %2,3b-2b(%0)\n"
- ".text"
+ ".previous"
: "=r"(error), "=&r"(tmp1), "=&r"(tmp2)
: "r"(va), "0"(0));
if (error)
@@ -276,7 +288,6 @@ asmlinkage void do_entUna(void * va, unsigned long opcode, unsigned long reg,
/* 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.) */
-#ifdef __HAVE_CPU_BWX
case 0x0d: /* stw */
__asm__ __volatile__(
"1: ldq_u %2,1(%5)\n"
@@ -299,14 +310,13 @@ asmlinkage void do_entUna(void * va, unsigned long opcode, unsigned long reg,
" lda $31,5b-3b(%0)\n"
" .gprel32 4b\n"
" lda $31,5b-4b(%0)\n"
- ".text"
+ ".previous"
: "=r"(error), "=&r"(tmp1), "=&r"(tmp2),
"=&r"(tmp3), "=&r"(tmp4)
: "r"(va), "r"(una_reg(reg)), "0"(0));
if (error)
goto got_exception;
return;
-#endif
case 0x2c: /* stl */
__asm__ __volatile__(
@@ -330,7 +340,7 @@ asmlinkage void do_entUna(void * va, unsigned long opcode, unsigned long reg,
" lda $31,5b-3b(%0)\n"
" .gprel32 4b\n"
" lda $31,5b-4b(%0)\n"
- ".text"
+ ".previous"
: "=r"(error), "=&r"(tmp1), "=&r"(tmp2),
"=&r"(tmp3), "=&r"(tmp4)
: "r"(va), "r"(una_reg(reg)), "0"(0));
@@ -360,7 +370,7 @@ asmlinkage void do_entUna(void * va, unsigned long opcode, unsigned long reg,
" lda $31,5b-3b(%0)\n"
" .gprel32 4b\n"
" lda $31,5b-4b(%0)\n"
- ".text"
+ ".previous"
: "=r"(error), "=&r"(tmp1), "=&r"(tmp2),
"=&r"(tmp3), "=&r"(tmp4)
: "r"(va), "r"(una_reg(reg)), "0"(0));
@@ -368,9 +378,12 @@ asmlinkage void do_entUna(void * va, unsigned long opcode, unsigned long reg,
goto got_exception;
return;
}
+
+ lock_kernel();
printk("Bad unaligned kernel access at %016lx: %p %lx %ld\n",
pc, va, opcode, reg);
do_exit(SIGSEGV);
+ unlock_kernel();
return;
got_exception:
@@ -379,17 +392,23 @@ got_exception:
if ((fixup = search_exception_table(pc)) != 0) {
unsigned long newpc;
newpc = fixup_exception(una_reg, fixup, pc);
+
+ lock_kernel();
printk("Forwarding unaligned exception at %lx (%lx)\n",
pc, newpc);
+ unlock_kernel();
+
(&regs)->pc = newpc;
return;
}
/* Yikes! No one to forward the exception to. */
+ lock_kernel();
printk("%s: unhandled unaligned exception at pc=%lx ra=%lx"
" (bad address = %p)\n", current->comm,
pc, una_reg(26), va);
do_exit(SIGSEGV);
+ unlock_kernel();
}
/*
@@ -409,13 +428,13 @@ static inline unsigned long s_mem_to_reg (unsigned long s_mem)
exp = (exp_msb << 10) | exp_low; /* common case */
if (exp_msb) {
if (exp_low == 0x7f) {
- exp = 0x3ff;
+ exp = 0x7ff;
}
} else {
if (exp_low == 0x00) {
exp = 0x000;
} else {
- exp |= (0x7 << 8);
+ exp |= (0x7 << 7);
}
}
return (sign << 63) | (exp << 52) | (frac << 29);
@@ -449,50 +468,68 @@ static inline unsigned long s_reg_to_mem (unsigned long s_reg)
* uses them as temporary storage for integer memory to memory copies.
* However, we need to deal with stt/ldt and sts/lds only.
*/
-asmlinkage void do_entUnaUser(void * va, unsigned long opcode, unsigned long reg,
- unsigned long * frame)
+
+#define OP_INT_MASK ( 1L << 0x28 | 1L << 0x2c /* ldl stl */ \
+ | 1L << 0x29 | 1L << 0x2d /* ldq stq */ \
+ | 1L << 0x0c | 1L << 0x0d ) /* ldwu stw */
+
+#define OP_WRITE_MASK ( 1L << 0x26 | 1L << 0x27 /* sts stt */ \
+ | 1L << 0x2c | 1L << 0x2d /* stl stq */ \
+ | 1L << 0xd ) /* stw */
+
+asmlinkage void do_entUnaUser(void * va, unsigned long opcode,
+ unsigned long reg, unsigned long * frame)
{
- long dir, size;
- unsigned long *reg_addr, *pc_addr, usp, zero = 0;
- static int cnt = 0;
- static long last_time = 0;
extern void alpha_write_fp_reg (unsigned long reg, unsigned long val);
extern unsigned long alpha_read_fp_reg (unsigned long reg);
- pc_addr = frame + 7 + 20 + 1; /* pc in PAL frame */
+ static int cnt = 0;
+ static long last_time = 0;
- if (cnt >= 5 && jiffies - last_time > 5*HZ) {
- cnt = 0;
- }
- if (++cnt < 5) {
- printk("%s(%d): unaligned trap at %016lx: %p %lx %ld\n",
- current->comm, current->pid,
- *pc_addr - 4, va, opcode, reg);
- }
- last_time = jiffies;
+ unsigned long tmp1, tmp2, tmp3, tmp4;
+ unsigned long *reg_addr, *pc_addr, fake_reg;
+ unsigned long uac_bits;
+ long error;
- ++unaligned[1].count;
- unaligned[1].va = (unsigned long) va - 4;
- unaligned[1].pc = *pc_addr;
+ pc_addr = frame + 7 + 20 + 1; /* pc in PAL frame */
+
+ /* Check the UAC bits to decide what the user wants us to do
+ with the unaliged access. */
- dir = VERIFY_READ;
- if (opcode & 0x4) {
- /* it's a stl, stq, stt, or sts */
- dir = VERIFY_WRITE;
+ uac_bits = (current->tss.flags >> UAC_SHIFT) & UAC_BITMASK;
+ if (!(uac_bits & UAC_NOPRINT)) {
+ if (cnt >= 5 && jiffies - last_time > 5*HZ) {
+ cnt = 0;
+ }
+ if (++cnt < 5) {
+ lock_kernel();
+ printk("%s(%d): unaligned trap at %016lx: %p %lx %ld\n",
+ current->comm, current->pid,
+ *pc_addr - 4, va, opcode, reg);
+ unlock_kernel();
+ }
+ last_time = jiffies;
}
- size = 4;
- if (opcode & 0x1) {
- /* it's a quadword op */
- size = 8;
+ if (uac_bits & UAC_SIGBUS) {
+ goto give_sigbus;
}
- if (verify_area(dir, va, size)) {
- *pc_addr -= 4; /* make pc point to faulting insn */
- force_sig(SIGSEGV, current);
+ if (uac_bits & UAC_NOFIX) {
+ /* Not sure why you'd want to use this, but... */
return;
}
+ /* Don't bother reading ds in the access check since we already
+ know that this came from the user. Also rely on the fact that
+ the page at TASK_SIZE is unmapped and so can't be touched anyway. */
+ if (!__access_ok((unsigned long)va, 0, USER_DS))
+ goto give_sigsegv;
+
+ ++unaligned[1].count;
+ unaligned[1].va = (unsigned long)va;
+ unaligned[1].pc = *pc_addr - 4;
+
reg_addr = frame;
- if (opcode >= 0x28) {
+ if ((1L << opcode) & OP_INT_MASK) {
/* it's an integer load/store */
switch (reg) {
case 0: case 1: case 2: case 3: case 4:
@@ -525,57 +562,249 @@ asmlinkage void do_entUnaUser(void * va, unsigned long opcode, unsigned long reg
case 30:
/* usp in PAL regs */
- usp = rdusp();
- reg_addr = &usp;
+ fake_reg = rdusp();
+ reg_addr = &fake_reg;
break;
case 31:
/* zero "register" */
- reg_addr = &zero;
+ fake_reg = 0;
+ reg_addr = &fake_reg;
break;
}
}
+ /* We don't want to use the generic get/put unaligned macros as
+ we want to trap exceptions. Only if we actually get an
+ exception will we decide whether we should have caught it. */
+
switch (opcode) {
- case 0x22: /* lds */
- alpha_write_fp_reg(reg, s_mem_to_reg(
- get_unaligned((unsigned int *)va)));
- break;
- case 0x26: /* sts */
- put_unaligned(s_reg_to_mem(alpha_read_fp_reg(reg)),
- (unsigned int *)va);
+ case 0x0c: /* ldwu */
+ __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"
+ ".section __ex_table,\"a\"\n"
+ " .gprel32 1b\n"
+ " lda %1,3b-1b(%0)\n"
+ " .gprel32 2b\n"
+ " lda %2,3b-2b(%0)\n"
+ ".previous"
+ : "=r"(error), "=&r"(tmp1), "=&r"(tmp2)
+ : "r"(va), "0"(0));
+ if (error)
+ goto give_sigsegv;
+ *reg_addr = tmp1|tmp2;
break;
- case 0x23: /* ldt */
- alpha_write_fp_reg(reg, get_unaligned((unsigned long *)va));
- break;
- case 0x27: /* stt */
- put_unaligned(alpha_read_fp_reg(reg), (unsigned long *)va);
- 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"
+ ".section __ex_table,\"a\"\n"
+ " .gprel32 1b\n"
+ " lda %1,3b-1b(%0)\n"
+ " .gprel32 2b\n"
+ " lda %2,3b-2b(%0)\n"
+ ".previous"
+ : "=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 0x28: /* ldl */
- *reg_addr = get_unaligned((int *)va);
- break;
- case 0x2c: /* stl */
- put_unaligned(*reg_addr, (int *)va);
- break;
+ 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"
+ ".section __ex_table,\"a\"\n"
+ " .gprel32 1b\n"
+ " lda %1,3b-1b(%0)\n"
+ " .gprel32 2b\n"
+ " lda %2,3b-2b(%0)\n"
+ ".previous"
+ : "=r"(error), "=&r"(tmp1), "=&r"(tmp2)
+ : "r"(va), "0"(0));
+ if (error)
+ goto give_sigsegv;
+ alpha_write_fp_reg(reg, tmp1|tmp2);
+ return;
- case 0x29: /* ldq */
- *reg_addr = get_unaligned((long *)va);
+ 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"
+ ".section __ex_table,\"a\"\n"
+ " .gprel32 1b\n"
+ " lda %1,3b-1b(%0)\n"
+ " .gprel32 2b\n"
+ " lda %2,3b-2b(%0)\n"
+ ".previous"
+ : "=r"(error), "=&r"(tmp1), "=&r"(tmp2)
+ : "r"(va), "0"(0));
+ if (error)
+ goto give_sigsegv;
+ *reg_addr = (int)(tmp1|tmp2);
break;
- case 0x2d: /* stq */
- put_unaligned(*reg_addr, (long *)va);
+
+ 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"
+ ".section __ex_table,\"a\"\n"
+ " .gprel32 1b\n"
+ " lda %1,3b-1b(%0)\n"
+ " .gprel32 2b\n"
+ " lda %2,3b-2b(%0)\n"
+ ".previous"
+ : "=r"(error), "=&r"(tmp1), "=&r"(tmp2)
+ : "r"(va), "0"(0));
+ if (error)
+ goto give_sigsegv;
+ *reg_addr = tmp1|tmp2;
break;
- default:
- *pc_addr -= 4; /* make pc point to faulting insn */
- force_sig(SIGBUS, current);
+ /* 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"
+ ".section __ex_table,\"a\"\n"
+ " .gprel32 1b\n"
+ " lda %2,5b-1b(%0)\n"
+ " .gprel32 2b\n"
+ " lda %1,5b-2b(%0)\n"
+ " .gprel32 3b\n"
+ " lda $31,5b-3b(%0)\n"
+ " .gprel32 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;
- }
- if (opcode >= 0x28 && reg == 30 && dir == VERIFY_WRITE) {
- wrusp(usp);
+ case 0x26: /* sts */
+ fake_reg = s_reg_to_mem(alpha_read_fp_reg(reg));
+ reg_addr = &fake_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"
+ " .gprel32 1b\n"
+ " lda %2,5b-1b(%0)\n"
+ " .gprel32 2b\n"
+ " lda %1,5b-2b(%0)\n"
+ " .gprel32 3b\n"
+ " lda $31,5b-3b(%0)\n"
+ " .gprel32 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);
+ reg_addr = &fake_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"
+ " .gprel32 1b\n"
+ " lda %2,5b-1b(%0)\n"
+ " .gprel32 2b\n"
+ " lda %1,5b-2b(%0)\n"
+ " .gprel32 3b\n"
+ " lda $31,5b-3b(%0)\n"
+ " .gprel32 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:
+ *pc_addr -= 4; /* make pc point to faulting insn */
+ lock_kernel();
+ force_sig(SIGSEGV, current);
+ unlock_kernel();
+ return;
+
+give_sigbus:
+ *pc_addr -= 4;
+ lock_kernel();
+ force_sig(SIGBUS, current);
+ unlock_kernel();
+ return;
}
/*
@@ -593,8 +822,11 @@ asmlinkage long do_entSys(unsigned long a0, unsigned long a1, unsigned long a2,
unsigned long a3, unsigned long a4, unsigned long a5,
struct pt_regs regs)
{
- if (regs.r0 != 112)
+ lock_kernel();
+ /* Only report OSF system calls. */
+ if (regs.r0 != 112 && regs.r0 < 300)
printk("<sc %ld(%lx,%lx,%lx)>", regs.r0, a0, a1, a2);
+ unlock_kernel();
return -1;
}
@@ -604,16 +836,11 @@ extern asmlinkage void entArith(void);
extern asmlinkage void entUna(void);
extern asmlinkage void entSys(void);
+register unsigned long gptr __asm__("$29");
+
void trap_init(void)
{
- unsigned long gptr;
-
- /*
- * Tell PAL-code what global pointer we want in the kernel..
- */
- __asm__("br %0,___tmp\n"
- "___tmp:\tldgp %0,0(%0)"
- : "=r" (gptr));
+ /* Tell PAL-code what global pointer we want in the kernel. */
wrkgp(gptr);
wrent(entArith, 1);