]> git.karo-electronics.de Git - karo-tx-linux.git/commitdiff
ARM: 7208/1: Add condition code checking to SWP emulation handler.
authorLeif Lindholm <leif.lindholm@arm.com>
Mon, 12 Dec 2011 18:45:24 +0000 (19:45 +0100)
committerRussell King <rmk+kernel@arm.linux.org.uk>
Tue, 13 Dec 2011 08:52:03 +0000 (08:52 +0000)
This patch fixes two separate issues with the SWP emulation handler:
1: Certain processors implementing ARMv7-A can (legally) take an
   undef exception even when the condition code would have meant that
   the instruction should not have been executed.
2: Opcodes with all flags set (condition code = 0xf) have been reused
   in recent, and not-so-recent, versions of the ARM architecture to
   implement unconditional extensions to the instruction set. The
   existing code would still have processed any undefs triggered by
   executing an opcode with such a value.

This patch uses the new generic ARM instruction set condition code
checks to implement proper handling of these situations.

Signed-off-by: Leif Lindholm <leif.lindholm@arm.com>
Reviewed-by: Will Deacon <will.deacon@arm.com>
Signed-off-by: Russell King <rmk+kernel@arm.linux.org.uk>
arch/arm/kernel/swp_emulate.c

index 5f452f8fde0569d140e0d6055220f29be08396f1..df745188f5de4abdf3bd04faaa5d31b653b0f210 100644 (file)
@@ -25,6 +25,7 @@
 #include <linux/syscalls.h>
 #include <linux/perf_event.h>
 
+#include <asm/opcodes.h>
 #include <asm/traps.h>
 #include <asm/uaccess.h>
 
@@ -185,6 +186,21 @@ static int swp_handler(struct pt_regs *regs, unsigned int instr)
 
        perf_sw_event(PERF_COUNT_SW_EMULATION_FAULTS, 1, regs, regs->ARM_pc);
 
+       res = arm_check_condition(instr, regs->ARM_cpsr);
+       switch (res) {
+       case ARM_OPCODE_CONDTEST_PASS:
+               break;
+       case ARM_OPCODE_CONDTEST_FAIL:
+               /* Condition failed - return to next instruction */
+               regs->ARM_pc += 4;
+               return 0;
+       case ARM_OPCODE_CONDTEST_UNCOND:
+               /* If unconditional encoding - not a SWP, undef */
+               return -EFAULT;
+       default:
+               return -EINVAL;
+       }
+
        if (current->pid != previous_pid) {
                pr_debug("\"%s\" (%ld) uses deprecated SWP{B} instruction\n",
                         current->comm, (unsigned long)current->pid);