From 16b5d462f73eb29d1f67fa01cc1ea66afdc72569 Mon Sep 17 00:00:00 2001 From: Ralf Baechle Date: Thu, 23 Mar 2000 02:25:38 +0000 Subject: Merge with Linux 2.3.99-pre2. --- arch/sparc/kernel/unaligned.c | 40 ++++++++++++++++++++++++++++++++++++++-- 1 file changed, 38 insertions(+), 2 deletions(-) (limited to 'arch/sparc/kernel/unaligned.c') diff --git a/arch/sparc/kernel/unaligned.c b/arch/sparc/kernel/unaligned.c index 592a2a4c0..2f051a6aa 100644 --- a/arch/sparc/kernel/unaligned.c +++ b/arch/sparc/kernel/unaligned.c @@ -1,4 +1,4 @@ -/* $Id: unaligned.c,v 1.20 2000/01/21 11:38:42 jj Exp $ +/* $Id: unaligned.c,v 1.21 2000/03/15 08:50:16 anton Exp $ * unaligned.c: Unaligned load/store trap handling with special * cases for the kernel to do them more quickly. * @@ -106,6 +106,26 @@ static inline unsigned long fetch_reg(unsigned int reg, struct pt_regs *regs) return win->locals[reg - 16]; /* yes, I know what this does... */ } +static inline unsigned long safe_fetch_reg(unsigned int reg, struct pt_regs *regs) +{ + struct reg_window *win; + unsigned long ret; + + if(reg < 16) + return (!reg ? 0 : regs->u_regs[reg]); + + /* Ho hum, the slightly complicated case. */ + win = (struct reg_window *) regs->u_regs[UREG_FP]; + + if ((unsigned long)win & 3) + return -1; + + if (get_user(ret, &win->locals[reg - 16])) + return -1; + + return ret; +} + static inline unsigned long *fetch_reg_addr(unsigned int reg, struct pt_regs *regs) { struct reg_window *win; @@ -132,6 +152,22 @@ 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 int rs1 = (insn >> 14) & 0x1f; + unsigned int rs2 = insn & 0x1f; + unsigned int rd = (insn >> 25) & 0x1f; + + if(insn & 0x2000) { + maybe_flush_windows(rs1, 0, rd); + return (safe_fetch_reg(rs1, regs) + sign_extend_imm13(insn)); + } else { + maybe_flush_windows(rs1, rs2, rd); + return (safe_fetch_reg(rs1, regs) + safe_fetch_reg(rs2, regs)); + } +} + /* This is just to make gcc think panic does return... */ static void unaligned_panic(char *str) { @@ -427,7 +463,7 @@ void user_mna_trap_fault(struct pt_regs *regs, unsigned int insn) info.si_signo = SIGBUS; info.si_errno = 0; info.si_code = BUS_ADRALN; - info.si_addr = (void *)compute_effective_address(regs, insn); + info.si_addr = (void *)safe_compute_effective_address(regs, insn); info.si_trapno = 0; send_sig_info(SIGBUS, &info, current); } -- cgit v1.2.3