diff options
author | Ralf Baechle <ralf@linux-mips.org> | 2000-02-04 07:40:19 +0000 |
---|---|---|
committer | Ralf Baechle <ralf@linux-mips.org> | 2000-02-04 07:40:19 +0000 |
commit | 33263fc5f9ac8e8cb2b22d06af3ce5ac1dd815e4 (patch) | |
tree | 2d1b86a40bef0958a68cf1a2eafbeb0667a70543 /arch/ppc/kernel/align.c | |
parent | 216f5f51aa02f8b113aa620ebc14a9631a217a00 (diff) |
Merge with Linux 2.3.32.
Diffstat (limited to 'arch/ppc/kernel/align.c')
-rw-r--r-- | arch/ppc/kernel/align.c | 52 |
1 files changed, 47 insertions, 5 deletions
diff --git a/arch/ppc/kernel/align.c b/arch/ppc/kernel/align.c index 6a20863c5..7f6340261 100644 --- a/arch/ppc/kernel/align.c +++ b/arch/ppc/kernel/align.c @@ -1,9 +1,13 @@ /* * align.c - handle alignment exceptions for the Power PC. * - * Paul Mackerras August 1996. - * Copyright (C) 1996 Paul Mackerras (paulus@cs.anu.edu.au). + * Copyright (c) 1996 Paul Mackerras <paulus@cs.anu.edu.au> + * Copyright (c) 1998-1999 TiVo, Inc. + * PowerPC 403GCX modifications. + * Copyright (c) 1999 Grant Erickson <grant@lcse.umn.edu> + * PowerPC 403GCX/405GP modifications. */ +#include <linux/config.h> #include <linux/kernel.h> #include <linux/mm.h> #include <asm/ptrace.h> @@ -16,6 +20,13 @@ struct aligninfo { unsigned char flags; }; +#if defined(CONFIG_4xx) +#define OPCD(inst) (((inst) & 0xFC000000) >> 26) +#define RS(inst) (((inst) & 0x03E00000) >> 21) +#define RA(inst) (((inst) & 0x001F0000) >> 16) +#define IS_DFORM(code) ((code) >= 32 && (code) <= 47) +#endif + #define INVALID { 0, 0 } #define LD 1 /* load */ @@ -170,6 +181,9 @@ int fix_alignment(struct pt_regs *regs) { int instr, nb, flags; +#if defined(CONFIG_4xx) + int opcode, f1, f2, f3; +#endif int i, t; int reg, areg; unsigned char *addr; @@ -180,13 +194,42 @@ fix_alignment(struct pt_regs *regs) unsigned char v[8]; } data; +#if defined(CONFIG_4xx) + /* The 4xx-family processors have no DSISR register, + * so we emulate it. + */ + + instr = *((unsigned int *)regs->nip); + opcode = OPCD(instr); + reg = RS(instr); + areg = RA(instr); + + if (IS_DFORM(opcode)) { + f1 = 0; + f2 = (instr & 0x04000000) >> 26; + f3 = (instr & 0x78000000) >> 27; + } else { + f1 = (instr & 0x00000006) >> 1; + f2 = (instr & 0x00000040) >> 6; + f3 = (instr & 0x00000780) >> 7; + } + + instr = ((f1 << 5) | (f2 << 4) | f3); +#else + reg = (regs->dsisr >> 5) & 0x1f; /* source/dest register */ + areg = regs->dsisr & 0x1f; /* register to update */ instr = (regs->dsisr >> 10) & 0x7f; +#endif nb = aligninfo[instr].len; if (nb == 0) return 0; /* too hard or invalid instruction bits */ flags = aligninfo[instr].flags; - addr = (unsigned char *) regs->dar; - reg = (regs->dsisr >> 5) & 0x1f; /* source/dest register */ + + /* For the 4xx-family processors, the 'dar' field of the + * pt_regs structure is overloaded and is really from the DEAR. + */ + + addr = (unsigned char *)regs->dar; /* Verify the address of the operand */ if (user_mode(regs)) { @@ -280,7 +323,6 @@ fix_alignment(struct pt_regs *regs) } if (flags & U) { - areg = regs->dsisr & 0x1f; /* register to update */ regs->gpr[areg] = regs->dar; } |