Skip to content

Commit

Permalink
powerpc/tm: Abort on emulation and alignment faults
Browse files Browse the repository at this point in the history
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>
Cc: <stable@vger.kernel.org> # v3.9
Signed-off-by: Benjamin Herrenschmidt <benh@kernel.crashing.org>
  • Loading branch information
Michael Neuling authored and Benjamin Herrenschmidt committed May 31, 2013
1 parent 24b9237 commit 6ce6c62
Show file tree
Hide file tree
Showing 3 changed files with 36 additions and 2 deletions.
7 changes: 5 additions & 2 deletions Documentation/powerpc/transactional_memory.txt
Original file line number Diff line number Diff line change
Expand Up @@ -161,9 +161,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
===
Expand Down
2 changes: 2 additions & 0 deletions arch/powerpc/include/asm/reg.h
Original file line number Diff line number Diff line change
Expand Up @@ -122,6 +122,8 @@
#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
Expand Down
29 changes: 29 additions & 0 deletions arch/powerpc/kernel/traps.c
Original file line number Diff line number Diff line change
Expand Up @@ -53,6 +53,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>
Expand Down Expand Up @@ -932,6 +933,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;
Expand Down Expand Up @@ -971,6 +994,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);
}
Expand Down Expand Up @@ -1148,6 +1174,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);
Expand Down

0 comments on commit 6ce6c62

Please sign in to comment.