]> git.itanic.dy.fi Git - linux-stable/commitdiff
powerpc/tm: Abort on emulation and alignment faults
authorMichael Neuling <mikey@neuling.org>
Sun, 26 May 2013 18:09:39 +0000 (18:09 +0000)
committerGreg Kroah-Hartman <gregkh@linuxfoundation.org>
Fri, 7 Jun 2013 19:53:20 +0000 (12:53 -0700)
commit 6ce6c629fd8254b3177650de99699682ff7f6707 upstream.

If we are emulating an instruction inside an active user transaction that
touches memory, the kernel can't emulate it as it operates in transactional
suspend context.  We need to abort these transactions and send them back to
userspace for the hardware to rollback.

We can service these if the user transaction is in suspend mode, since the
kernel will operate in the same suspend context.

This adds a check to all alignment faults and to specific instruction
emulations (only string instructions for now).  If the user process is in an
active (non-suspended) transaction, we abort the transaction go back to
userspace allowing the HW to roll back the transaction and tell the user of the
failure.  This also adds new tm abort cause codes to report the reason of the
persistent error to the user.

Crappy test case here http://neuling.org/devel/junkcode/aligntm.c

Signed-off-by: Michael Neuling <mikey@neuling.org>
Signed-off-by: Benjamin Herrenschmidt <benh@kernel.crashing.org>
Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
Documentation/powerpc/transactional_memory.txt
arch/powerpc/include/asm/reg.h
arch/powerpc/kernel/traps.c

index 26c3beb8bcc3d703e1fb0bf95165d55036ee1195..dc23e58ae2641a0ae876d2a1840530ae7e4ec59d 100644 (file)
@@ -180,9 +180,12 @@ kernel aborted a transaction:
                         transactions for consistency will use this.
  TM_CAUSE_SIGNAL        Signal delivered.
  TM_CAUSE_MISC          Currently unused.
+ TM_CAUSE_ALIGNMENT     Alignment fault.
+ TM_CAUSE_EMULATE       Emulation that touched memory.
 
-These can be checked by the user program's abort handler as TEXASR[0:7].
-
+These can be checked by the user program's abort handler as TEXASR[0:7].  If
+bit 7 is set, it indicates that the error is consider persistent.  For example
+a TM_CAUSE_ALIGNMENT will be persistent while a TM_CAUSE_RESCHED will not.q
 
 GDB
 ===
index 7c5bce0da5789faa136d129f1f8dc9277f1b74dd..2fe88600add610d9a735bc49a605b076aab12a12 100644 (file)
 #define TM_CAUSE_SYSCALL       0xd8  /* future use */
 #define TM_CAUSE_MISC          0xd6  /* future use */
 #define TM_CAUSE_SIGNAL                0xd4
+#define TM_CAUSE_ALIGNMENT     0xd2
+#define TM_CAUSE_EMULATE       0xd0
 
 #if defined(CONFIG_PPC_BOOK3S_64)
 #define MSR_64BIT      MSR_SF
index 83efa2f7d9266ced97726aa6b26c1739076a6ec1..1c22b2d580b55a68aedfdf35a62e8bbf67689d67 100644 (file)
@@ -52,6 +52,7 @@
 #ifdef CONFIG_PPC64
 #include <asm/firmware.h>
 #include <asm/processor.h>
+#include <asm/tm.h>
 #endif
 #include <asm/kexec.h>
 #include <asm/ppc-opcode.h>
@@ -913,6 +914,28 @@ static int emulate_isel(struct pt_regs *regs, u32 instword)
        return 0;
 }
 
+#ifdef CONFIG_PPC_TRANSACTIONAL_MEM
+static inline bool tm_abort_check(struct pt_regs *regs, int cause)
+{
+        /* If we're emulating a load/store in an active transaction, we cannot
+         * emulate it as the kernel operates in transaction suspended context.
+         * We need to abort the transaction.  This creates a persistent TM
+         * abort so tell the user what caused it with a new code.
+        */
+       if (MSR_TM_TRANSACTIONAL(regs->msr)) {
+               tm_enable();
+               tm_abort(cause);
+               return true;
+       }
+       return false;
+}
+#else
+static inline bool tm_abort_check(struct pt_regs *regs, int reason)
+{
+       return false;
+}
+#endif
+
 static int emulate_instruction(struct pt_regs *regs)
 {
        u32 instword;
@@ -952,6 +975,9 @@ static int emulate_instruction(struct pt_regs *regs)
 
        /* Emulate load/store string insn. */
        if ((instword & PPC_INST_STRING_GEN_MASK) == PPC_INST_STRING) {
+               if (tm_abort_check(regs,
+                                  TM_CAUSE_EMULATE | TM_CAUSE_PERSISTENT))
+                       return -EINVAL;
                PPC_WARN_EMULATED(string, regs);
                return emulate_string_inst(regs, instword);
        }
@@ -1124,6 +1150,9 @@ void alignment_exception(struct pt_regs *regs)
        if (!arch_irq_disabled_regs(regs))
                local_irq_enable();
 
+       if (tm_abort_check(regs, TM_CAUSE_ALIGNMENT | TM_CAUSE_PERSISTENT))
+               goto bail;
+
        /* we don't implement logging of alignment exceptions */
        if (!(current->thread.align_ctl & PR_UNALIGN_SIGBUS))
                fixed = fix_alignment(regs);