Home Home > GIT Browse
summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorDavid S. Miller <davem@kernel.bkbits.net>2004-06-15 08:04:05 -0700
committerDavid S. Miller <davem@kernel.bkbits.net>2004-06-15 08:04:05 -0700
commit0e662d3aa5a29ac3943e35652e8ed9dfff33cf20 (patch)
tree45a69dd6776a7cc3afb12f2ee0bbf78f3dcfb86c
parentd860a0ad215965ab03fe497889fe2e1a4ede3765 (diff)
parentf344ba4994aac4c6789131f447b7892830cfdf6f (diff)
Merge davem@nuts.davemloft.net:/disk1/BK/sparc-2.6
into kernel.bkbits.net:/home/davem/sparc-2.6
-rw-r--r--arch/sparc/kernel/unaligned.c8
-rw-r--r--arch/sparc/mm/fault.c27
-rw-r--r--arch/sparc64/kernel/unaligned.c4
-rw-r--r--arch/sparc64/mm/fault.c15
4 files changed, 40 insertions, 14 deletions
diff --git a/arch/sparc/kernel/unaligned.c b/arch/sparc/kernel/unaligned.c
index 3a1ccaccb0a9..a9a9e0c73ae4 100644
--- a/arch/sparc/kernel/unaligned.c
+++ b/arch/sparc/kernel/unaligned.c
@@ -137,8 +137,8 @@ static inline unsigned long *fetch_reg_addr(unsigned int reg, struct pt_regs *re
return &win->locals[reg - 16];
}
-static inline unsigned long compute_effective_address(struct pt_regs *regs,
- unsigned int insn)
+static unsigned long compute_effective_address(struct pt_regs *regs,
+ unsigned int insn)
{
unsigned int rs1 = (insn >> 14) & 0x1f;
unsigned int rs2 = insn & 0x1f;
@@ -153,8 +153,8 @@ static inline unsigned long compute_effective_address(struct pt_regs *regs,
}
}
-static inline unsigned long safe_compute_effective_address(struct pt_regs *regs,
- unsigned int insn)
+unsigned long safe_compute_effective_address(struct pt_regs *regs,
+ unsigned int insn)
{
unsigned int rs1 = (insn >> 14) & 0x1f;
unsigned int rs2 = insn & 0x1f;
diff --git a/arch/sparc/mm/fault.c b/arch/sparc/mm/fault.c
index 44db3351691e..cc857f681d97 100644
--- a/arch/sparc/mm/fault.c
+++ b/arch/sparc/mm/fault.c
@@ -201,6 +201,25 @@ asmlinkage int lookup_fault(unsigned long pc, unsigned long ret_pc,
return 0;
}
+extern unsigned long safe_compute_effective_address(struct pt_regs *,
+ unsigned int);
+
+static unsigned long compute_si_addr(struct pt_regs *regs, int text_fault)
+{
+ unsigned int insn;
+
+ if (text_fault)
+ return regs->pc;
+
+ if (regs->psr & PSR_PS) {
+ insn = *(unsigned int *) regs->pc;
+ } else {
+ __get_user(insn, (unsigned int *) regs->pc);
+ }
+
+ return safe_compute_effective_address(regs, insn);
+}
+
asmlinkage void do_sparc_fault(struct pt_regs *regs, int text_fault, int write,
unsigned long address)
{
@@ -307,7 +326,7 @@ bad_area_nosemaphore:
info.si_errno = 0;
/* info.si_code set above to make clear whether
this was a SEGV_MAPERR or SEGV_ACCERR fault. */
- info.si_addr = (void *)address;
+ info.si_addr = (void *) compute_si_addr(regs, text_fault);
info.si_trapno = 0;
force_sig_info (SIGSEGV, &info, tsk);
return;
@@ -361,7 +380,7 @@ do_sigbus:
info.si_signo = SIGBUS;
info.si_errno = 0;
info.si_code = BUS_ADRERR;
- info.si_addr = (void *)address;
+ info.si_addr = (void *) compute_si_addr(regs, text_fault);
info.si_trapno = 0;
force_sig_info (SIGBUS, &info, tsk);
if (!from_user)
@@ -530,7 +549,7 @@ bad_area:
info.si_errno = 0;
/* info.si_code set above to make clear whether
this was a SEGV_MAPERR or SEGV_ACCERR fault. */
- info.si_addr = (void *)address;
+ info.si_addr = (void *) address;
info.si_trapno = 0;
force_sig_info (SIGSEGV, &info, tsk);
return;
@@ -540,7 +559,7 @@ do_sigbus:
info.si_signo = SIGBUS;
info.si_errno = 0;
info.si_code = BUS_ADRERR;
- info.si_addr = (void *)address;
+ info.si_addr = (void *) address;
info.si_trapno = 0;
force_sig_info (SIGBUS, &info, tsk);
}
diff --git a/arch/sparc64/kernel/unaligned.c b/arch/sparc64/kernel/unaligned.c
index 5b664354e73b..646a788fa9d2 100644
--- a/arch/sparc64/kernel/unaligned.c
+++ b/arch/sparc64/kernel/unaligned.c
@@ -158,8 +158,8 @@ static unsigned long *fetch_reg_addr(unsigned int reg, struct pt_regs *regs)
}
}
-static unsigned long compute_effective_address(struct pt_regs *regs,
- unsigned int insn, unsigned int rd)
+unsigned long compute_effective_address(struct pt_regs *regs,
+ unsigned int insn, unsigned int rd)
{
unsigned int rs1 = (insn >> 14) & 0x1f;
unsigned int rs2 = insn & 0x1f;
diff --git a/arch/sparc64/mm/fault.c b/arch/sparc64/mm/fault.c
index 348f206f0663..5fc4644aad99 100644
--- a/arch/sparc64/mm/fault.c
+++ b/arch/sparc64/mm/fault.c
@@ -207,14 +207,21 @@ outret:
return insn;
}
-static void do_fault_siginfo(int code, int sig, unsigned long address)
+extern unsigned long compute_effective_address(struct pt_regs *, unsigned int, unsigned int);
+
+static void do_fault_siginfo(int code, int sig, struct pt_regs *regs,
+ unsigned int insn, int fault_code)
{
siginfo_t info;
info.si_code = code;
info.si_signo = sig;
info.si_errno = 0;
- info.si_addr = (void *) address;
+ if (fault_code & FAULT_CODE_ITLB)
+ info.si_addr = (void *) regs->tpc;
+ else
+ info.si_addr = (void *)
+ compute_effective_address(regs, insn, 0);
info.si_trapno = 0;
force_sig_info(sig, &info, current);
}
@@ -295,7 +302,7 @@ static void do_kernel_fault(struct pt_regs *regs, int si_code, int fault_code,
/* The si_code was set to make clear whether
* this was a SEGV_MAPERR or SEGV_ACCERR fault.
*/
- do_fault_siginfo(si_code, SIGSEGV, address);
+ do_fault_siginfo(si_code, SIGSEGV, regs, insn, fault_code);
return;
}
@@ -471,7 +478,7 @@ do_sigbus:
* Send a sigbus, regardless of whether we were in kernel
* or user mode.
*/
- do_fault_siginfo(BUS_ADRERR, SIGBUS, address);
+ do_fault_siginfo(BUS_ADRERR, SIGBUS, regs, insn, fault_code);
/* Kernel mode? Handle exceptions or die */
if (regs->tstate & TSTATE_PRIV)