summaryrefslogtreecommitdiffstats
path: root/arch/tile/kernel/traps.c
diff options
context:
space:
mode:
authorChris Metcalf2010-06-25 23:04:17 +0200
committerChris Metcalf2010-07-06 19:41:51 +0200
commit0707ad30d10110aebc01a5a64fb63f4b32d20b73 (patch)
tree64d8ba73e605ac26e56808d1d77701b3f83cf8b2 /arch/tile/kernel/traps.c
parentarch/tile: Split the icache flush code off to a generic <arch> header. (diff)
downloadkernel-qcow2-linux-0707ad30d10110aebc01a5a64fb63f4b32d20b73.tar.gz
kernel-qcow2-linux-0707ad30d10110aebc01a5a64fb63f4b32d20b73.tar.xz
kernel-qcow2-linux-0707ad30d10110aebc01a5a64fb63f4b32d20b73.zip
arch/tile: Miscellaneous cleanup changes.
This commit is primarily changes caused by reviewing "sparse" and "checkpatch" output on our sources, so is somewhat noisy, since things like "printk() -> pr_err()" (or whatever) throughout the codebase tend to get tedious to read. Rather than trying to tease apart precisely which things changed due to which type of code review, this commit includes various cleanups in the code: - sparse: Add declarations in headers for globals. - sparse: Fix __user annotations. - sparse: Using gfp_t consistently instead of int. - sparse: removing functions not actually used. - checkpatch: Clean up printk() warnings by using pr_info(), etc.; also avoid partial-line printks except in bootup code. - checkpatch: Use exposed structs rather than typedefs. - checkpatch: Change some C99 comments to C89 comments. In addition, a couple of minor other changes are rolled in to this commit: - Add support for a "raise" instruction to cause SIGFPE, etc., to be raised. - Remove some compat code that is unnecessary when we fully eliminate some of the deprecated syscalls from the generic syscall ABI. - Update the tile_defconfig to reflect current config contents. Signed-off-by: Chris Metcalf <cmetcalf@tilera.com> Acked-by: Arnd Bergmann <arnd@arndb.de>
Diffstat (limited to 'arch/tile/kernel/traps.c')
-rw-r--r--arch/tile/kernel/traps.c130
1 files changed, 105 insertions, 25 deletions
diff --git a/arch/tile/kernel/traps.c b/arch/tile/kernel/traps.c
index 12cb10f38527..3870abbeeaa2 100644
--- a/arch/tile/kernel/traps.c
+++ b/arch/tile/kernel/traps.c
@@ -20,6 +20,9 @@
#include <linux/uaccess.h>
#include <linux/ptrace.h>
#include <asm/opcode-tile.h>
+#include <asm/opcode_constants.h>
+#include <asm/stack.h>
+#include <asm/traps.h>
#include <arch/interrupts.h>
#include <arch/spr_def.h>
@@ -42,7 +45,7 @@ static int __init setup_unaligned_fixup(char *str)
if (strict_strtol(str, 0, &val) != 0)
return 0;
unaligned_fixup = val;
- printk("Fixups for unaligned data accesses are %s\n",
+ pr_info("Fixups for unaligned data accesses are %s\n",
unaligned_fixup >= 0 ?
(unaligned_fixup ? "enabled" : "disabled") :
"completely disabled");
@@ -56,7 +59,7 @@ static int dma_disabled;
static int __init nodma(char *str)
{
- printk("User-space DMA is disabled\n");
+ pr_info("User-space DMA is disabled\n");
dma_disabled = 1;
return 1;
}
@@ -97,20 +100,106 @@ static int retry_gpv(unsigned int gpv_reason)
#endif /* CHIP_HAS_TILE_DMA() */
-/* Defined inside do_trap(), below. */
#ifdef __tilegx__
-extern tilegx_bundle_bits bpt_code;
+#define bundle_bits tilegx_bundle_bits
#else
-extern tile_bundle_bits bpt_code;
+#define bundle_bits tile_bundle_bits
#endif
+extern bundle_bits bpt_code;
+
+asm(".pushsection .rodata.bpt_code,\"a\";"
+ ".align 8;"
+ "bpt_code: bpt;"
+ ".size bpt_code,.-bpt_code;"
+ ".popsection");
+
+static int special_ill(bundle_bits bundle, int *sigp, int *codep)
+{
+ int sig, code, maxcode;
+
+ if (bundle == bpt_code) {
+ *sigp = SIGTRAP;
+ *codep = TRAP_BRKPT;
+ return 1;
+ }
+
+ /* If it's a "raise" bundle, then "ill" must be in pipe X1. */
+#ifdef __tilegx__
+ if ((bundle & TILEGX_BUNDLE_MODE_MASK) != 0)
+ return 0;
+ if (get_Opcode_X1(bundle) != UNARY_OPCODE_X1)
+ return 0;
+ if (get_UnaryOpcodeExtension_X1(bundle) != ILL_UNARY_OPCODE_X1)
+ return 0;
+#else
+ if (bundle & TILE_BUNDLE_Y_ENCODING_MASK)
+ return 0;
+ if (get_Opcode_X1(bundle) != SHUN_0_OPCODE_X1)
+ return 0;
+ if (get_UnShOpcodeExtension_X1(bundle) != UN_0_SHUN_0_OPCODE_X1)
+ return 0;
+ if (get_UnOpcodeExtension_X1(bundle) != ILL_UN_0_SHUN_0_OPCODE_X1)
+ return 0;
+#endif
+
+ /* Check that the magic distinguishers are set to mean "raise". */
+ if (get_Dest_X1(bundle) != 29 || get_SrcA_X1(bundle) != 37)
+ return 0;
+
+ /* There must be an "addli zero, zero, VAL" in X0. */
+ if (get_Opcode_X0(bundle) != ADDLI_OPCODE_X0)
+ return 0;
+ if (get_Dest_X0(bundle) != TREG_ZERO)
+ return 0;
+ if (get_SrcA_X0(bundle) != TREG_ZERO)
+ return 0;
+
+ /*
+ * Validate the proposed signal number and si_code value.
+ * Note that we embed these in the static instruction itself
+ * so that we perturb the register state as little as possible
+ * at the time of the actual fault; it's unlikely you'd ever
+ * need to dynamically choose which kind of fault to raise
+ * from user space.
+ */
+ sig = get_Imm16_X0(bundle) & 0x3f;
+ switch (sig) {
+ case SIGILL:
+ maxcode = NSIGILL;
+ break;
+ case SIGFPE:
+ maxcode = NSIGFPE;
+ break;
+ case SIGSEGV:
+ maxcode = NSIGSEGV;
+ break;
+ case SIGBUS:
+ maxcode = NSIGBUS;
+ break;
+ case SIGTRAP:
+ maxcode = NSIGTRAP;
+ break;
+ default:
+ return 0;
+ }
+ code = (get_Imm16_X0(bundle) >> 6) & 0xf;
+ if (code <= 0 || code > maxcode)
+ return 0;
+
+ /* Make it the requested signal. */
+ *sigp = sig;
+ *codep = code | __SI_FAULT;
+ return 1;
+}
+
void __kprobes do_trap(struct pt_regs *regs, int fault_num,
unsigned long reason)
{
siginfo_t info = { 0 };
int signo, code;
unsigned long address;
- __typeof__(bpt_code) instr;
+ bundle_bits instr;
/* Re-enable interrupts. */
local_irq_enable();
@@ -122,10 +211,10 @@ void __kprobes do_trap(struct pt_regs *regs, int fault_num,
if (!user_mode(regs)) {
if (fixup_exception(regs)) /* only UNALIGN_DATA in practice */
return;
- printk(KERN_ALERT "Kernel took bad trap %d at PC %#lx\n",
+ pr_alert("Kernel took bad trap %d at PC %#lx\n",
fault_num, regs->pc);
if (fault_num == INT_GPV)
- printk(KERN_ALERT "GPV_REASON is %#lx\n", reason);
+ pr_alert("GPV_REASON is %#lx\n", reason);
show_regs(regs);
do_exit(SIGKILL); /* FIXME: implement i386 die() */
return;
@@ -133,22 +222,14 @@ void __kprobes do_trap(struct pt_regs *regs, int fault_num,
switch (fault_num) {
case INT_ILL:
- asm(".pushsection .rodata.bpt_code,\"a\";"
- ".align 8;"
- "bpt_code: bpt;"
- ".size bpt_code,.-bpt_code;"
- ".popsection");
-
- if (copy_from_user(&instr, (void *)regs->pc, sizeof(instr))) {
- printk(KERN_ERR "Unreadable instruction for INT_ILL:"
+ if (copy_from_user(&instr, (void __user *)regs->pc,
+ sizeof(instr))) {
+ pr_err("Unreadable instruction for INT_ILL:"
" %#lx\n", regs->pc);
do_exit(SIGKILL);
return;
}
- if (instr == bpt_code) {
- signo = SIGTRAP;
- code = TRAP_BRKPT;
- } else {
+ if (!special_ill(instr, &signo, &code)) {
signo = SIGILL;
code = ILL_ILLOPC;
}
@@ -181,7 +262,8 @@ void __kprobes do_trap(struct pt_regs *regs, int fault_num,
if (unaligned_fixup >= 0) {
struct single_step_state *state =
current_thread_info()->step_state;
- if (!state || (void *)(regs->pc) != state->buffer) {
+ if (!state ||
+ (void __user *)(regs->pc) != state->buffer) {
single_step_once(regs);
return;
}
@@ -221,17 +303,15 @@ void __kprobes do_trap(struct pt_regs *regs, int fault_num,
info.si_signo = signo;
info.si_code = code;
- info.si_addr = (void *)address;
+ info.si_addr = (void __user *)address;
if (signo == SIGILL)
info.si_trapno = fault_num;
force_sig_info(signo, &info, current);
}
-extern void _dump_stack(int dummy, ulong pc, ulong lr, ulong sp, ulong r52);
-
void kernel_double_fault(int dummy, ulong pc, ulong lr, ulong sp, ulong r52)
{
_dump_stack(dummy, pc, lr, sp, r52);
- printk("Double fault: exiting\n");
+ pr_emerg("Double fault: exiting\n");
machine_halt();
}