diff options
-rw-r--r-- | Documentation/powerpc/transactional_memory.txt | 7 | ||||
-rw-r--r-- | arch/powerpc/include/asm/reg.h | 2 | ||||
-rw-r--r-- | arch/powerpc/kernel/traps.c | 29 |
3 files changed, 36 insertions, 2 deletions
diff --git a/Documentation/powerpc/transactional_memory.txt b/Documentation/powerpc/transactional_memory.txt index 84e04a0db0f8..c54bf3127651 100644 --- a/Documentation/powerpc/transactional_memory.txt +++ b/Documentation/powerpc/transactional_memory.txt | |||
@@ -161,9 +161,12 @@ kernel aborted a transaction: | |||
161 | transactions for consistency will use this. | 161 | transactions for consistency will use this. |
162 | TM_CAUSE_SIGNAL Signal delivered. | 162 | TM_CAUSE_SIGNAL Signal delivered. |
163 | TM_CAUSE_MISC Currently unused. | 163 | TM_CAUSE_MISC Currently unused. |
164 | TM_CAUSE_ALIGNMENT Alignment fault. | ||
165 | TM_CAUSE_EMULATE Emulation that touched memory. | ||
164 | 166 | ||
165 | These can be checked by the user program's abort handler as TEXASR[0:7]. | 167 | These can be checked by the user program's abort handler as TEXASR[0:7]. If |
166 | 168 | bit 7 is set, it indicates that the error is consider persistent. For example | |
169 | a TM_CAUSE_ALIGNMENT will be persistent while a TM_CAUSE_RESCHED will not.q | ||
167 | 170 | ||
168 | GDB | 171 | GDB |
169 | === | 172 | === |
diff --git a/arch/powerpc/include/asm/reg.h b/arch/powerpc/include/asm/reg.h index 8f6a94b2dc99..d0528e0d6db8 100644 --- a/arch/powerpc/include/asm/reg.h +++ b/arch/powerpc/include/asm/reg.h | |||
@@ -122,6 +122,8 @@ | |||
122 | #define TM_CAUSE_SYSCALL 0xd8 /* future use */ | 122 | #define TM_CAUSE_SYSCALL 0xd8 /* future use */ |
123 | #define TM_CAUSE_MISC 0xd6 /* future use */ | 123 | #define TM_CAUSE_MISC 0xd6 /* future use */ |
124 | #define TM_CAUSE_SIGNAL 0xd4 | 124 | #define TM_CAUSE_SIGNAL 0xd4 |
125 | #define TM_CAUSE_ALIGNMENT 0xd2 | ||
126 | #define TM_CAUSE_EMULATE 0xd0 | ||
125 | 127 | ||
126 | #if defined(CONFIG_PPC_BOOK3S_64) | 128 | #if defined(CONFIG_PPC_BOOK3S_64) |
127 | #define MSR_64BIT MSR_SF | 129 | #define MSR_64BIT MSR_SF |
diff --git a/arch/powerpc/kernel/traps.c b/arch/powerpc/kernel/traps.c index a7a648f6b750..f18c79c324ef 100644 --- a/arch/powerpc/kernel/traps.c +++ b/arch/powerpc/kernel/traps.c | |||
@@ -53,6 +53,7 @@ | |||
53 | #ifdef CONFIG_PPC64 | 53 | #ifdef CONFIG_PPC64 |
54 | #include <asm/firmware.h> | 54 | #include <asm/firmware.h> |
55 | #include <asm/processor.h> | 55 | #include <asm/processor.h> |
56 | #include <asm/tm.h> | ||
56 | #endif | 57 | #endif |
57 | #include <asm/kexec.h> | 58 | #include <asm/kexec.h> |
58 | #include <asm/ppc-opcode.h> | 59 | #include <asm/ppc-opcode.h> |
@@ -932,6 +933,28 @@ static int emulate_isel(struct pt_regs *regs, u32 instword) | |||
932 | return 0; | 933 | return 0; |
933 | } | 934 | } |
934 | 935 | ||
936 | #ifdef CONFIG_PPC_TRANSACTIONAL_MEM | ||
937 | static inline bool tm_abort_check(struct pt_regs *regs, int cause) | ||
938 | { | ||
939 | /* If we're emulating a load/store in an active transaction, we cannot | ||
940 | * emulate it as the kernel operates in transaction suspended context. | ||
941 | * We need to abort the transaction. This creates a persistent TM | ||
942 | * abort so tell the user what caused it with a new code. | ||
943 | */ | ||
944 | if (MSR_TM_TRANSACTIONAL(regs->msr)) { | ||
945 | tm_enable(); | ||
946 | tm_abort(cause); | ||
947 | return true; | ||
948 | } | ||
949 | return false; | ||
950 | } | ||
951 | #else | ||
952 | static inline bool tm_abort_check(struct pt_regs *regs, int reason) | ||
953 | { | ||
954 | return false; | ||
955 | } | ||
956 | #endif | ||
957 | |||
935 | static int emulate_instruction(struct pt_regs *regs) | 958 | static int emulate_instruction(struct pt_regs *regs) |
936 | { | 959 | { |
937 | u32 instword; | 960 | u32 instword; |
@@ -971,6 +994,9 @@ static int emulate_instruction(struct pt_regs *regs) | |||
971 | 994 | ||
972 | /* Emulate load/store string insn. */ | 995 | /* Emulate load/store string insn. */ |
973 | if ((instword & PPC_INST_STRING_GEN_MASK) == PPC_INST_STRING) { | 996 | if ((instword & PPC_INST_STRING_GEN_MASK) == PPC_INST_STRING) { |
997 | if (tm_abort_check(regs, | ||
998 | TM_CAUSE_EMULATE | TM_CAUSE_PERSISTENT)) | ||
999 | return -EINVAL; | ||
974 | PPC_WARN_EMULATED(string, regs); | 1000 | PPC_WARN_EMULATED(string, regs); |
975 | return emulate_string_inst(regs, instword); | 1001 | return emulate_string_inst(regs, instword); |
976 | } | 1002 | } |
@@ -1148,6 +1174,9 @@ void alignment_exception(struct pt_regs *regs) | |||
1148 | if (!arch_irq_disabled_regs(regs)) | 1174 | if (!arch_irq_disabled_regs(regs)) |
1149 | local_irq_enable(); | 1175 | local_irq_enable(); |
1150 | 1176 | ||
1177 | if (tm_abort_check(regs, TM_CAUSE_ALIGNMENT | TM_CAUSE_PERSISTENT)) | ||
1178 | goto bail; | ||
1179 | |||
1151 | /* we don't implement logging of alignment exceptions */ | 1180 | /* we don't implement logging of alignment exceptions */ |
1152 | if (!(current->thread.align_ctl & PR_UNALIGN_SIGBUS)) | 1181 | if (!(current->thread.align_ctl & PR_UNALIGN_SIGBUS)) |
1153 | fixed = fix_alignment(regs); | 1182 | fixed = fix_alignment(regs); |