diff options
Diffstat (limited to 'arch/powerpc/kernel/signal.c')
-rw-r--r-- | arch/powerpc/kernel/signal.c | 47 |
1 files changed, 44 insertions, 3 deletions
diff --git a/arch/powerpc/kernel/signal.c b/arch/powerpc/kernel/signal.c index cf12eae02de5..457e97aa2945 100644 --- a/arch/powerpc/kernel/signal.c +++ b/arch/powerpc/kernel/signal.c | |||
@@ -13,10 +13,12 @@ | |||
13 | #include <linux/signal.h> | 13 | #include <linux/signal.h> |
14 | #include <linux/uprobes.h> | 14 | #include <linux/uprobes.h> |
15 | #include <linux/key.h> | 15 | #include <linux/key.h> |
16 | #include <linux/context_tracking.h> | ||
16 | #include <asm/hw_breakpoint.h> | 17 | #include <asm/hw_breakpoint.h> |
17 | #include <asm/uaccess.h> | 18 | #include <asm/uaccess.h> |
18 | #include <asm/unistd.h> | 19 | #include <asm/unistd.h> |
19 | #include <asm/debug.h> | 20 | #include <asm/debug.h> |
21 | #include <asm/tm.h> | ||
20 | 22 | ||
21 | #include "signal.h" | 23 | #include "signal.h" |
22 | 24 | ||
@@ -24,18 +26,18 @@ | |||
24 | * through debug.exception-trace sysctl. | 26 | * through debug.exception-trace sysctl. |
25 | */ | 27 | */ |
26 | 28 | ||
27 | int show_unhandled_signals = 0; | 29 | int show_unhandled_signals = 1; |
28 | 30 | ||
29 | /* | 31 | /* |
30 | * Allocate space for the signal frame | 32 | * Allocate space for the signal frame |
31 | */ | 33 | */ |
32 | void __user * get_sigframe(struct k_sigaction *ka, struct pt_regs *regs, | 34 | void __user * get_sigframe(struct k_sigaction *ka, unsigned long sp, |
33 | size_t frame_size, int is_32) | 35 | size_t frame_size, int is_32) |
34 | { | 36 | { |
35 | unsigned long oldsp, newsp; | 37 | unsigned long oldsp, newsp; |
36 | 38 | ||
37 | /* Default to using normal stack */ | 39 | /* Default to using normal stack */ |
38 | oldsp = get_clean_sp(regs, is_32); | 40 | oldsp = get_clean_sp(sp, is_32); |
39 | 41 | ||
40 | /* Check for alt stack */ | 42 | /* Check for alt stack */ |
41 | if ((ka->sa.sa_flags & SA_ONSTACK) && | 43 | if ((ka->sa.sa_flags & SA_ONSTACK) && |
@@ -159,6 +161,8 @@ static int do_signal(struct pt_regs *regs) | |||
159 | 161 | ||
160 | void do_notify_resume(struct pt_regs *regs, unsigned long thread_info_flags) | 162 | void do_notify_resume(struct pt_regs *regs, unsigned long thread_info_flags) |
161 | { | 163 | { |
164 | user_exit(); | ||
165 | |||
162 | if (thread_info_flags & _TIF_UPROBE) | 166 | if (thread_info_flags & _TIF_UPROBE) |
163 | uprobe_notify_resume(regs); | 167 | uprobe_notify_resume(regs); |
164 | 168 | ||
@@ -169,4 +173,41 @@ void do_notify_resume(struct pt_regs *regs, unsigned long thread_info_flags) | |||
169 | clear_thread_flag(TIF_NOTIFY_RESUME); | 173 | clear_thread_flag(TIF_NOTIFY_RESUME); |
170 | tracehook_notify_resume(regs); | 174 | tracehook_notify_resume(regs); |
171 | } | 175 | } |
176 | |||
177 | user_enter(); | ||
178 | } | ||
179 | |||
180 | unsigned long get_tm_stackpointer(struct pt_regs *regs) | ||
181 | { | ||
182 | /* When in an active transaction that takes a signal, we need to be | ||
183 | * careful with the stack. It's possible that the stack has moved back | ||
184 | * up after the tbegin. The obvious case here is when the tbegin is | ||
185 | * called inside a function that returns before a tend. In this case, | ||
186 | * the stack is part of the checkpointed transactional memory state. | ||
187 | * If we write over this non transactionally or in suspend, we are in | ||
188 | * trouble because if we get a tm abort, the program counter and stack | ||
189 | * pointer will be back at the tbegin but our in memory stack won't be | ||
190 | * valid anymore. | ||
191 | * | ||
192 | * To avoid this, when taking a signal in an active transaction, we | ||
193 | * need to use the stack pointer from the checkpointed state, rather | ||
194 | * than the speculated state. This ensures that the signal context | ||
195 | * (written tm suspended) will be written below the stack required for | ||
196 | * the rollback. The transaction is aborted becuase of the treclaim, | ||
197 | * so any memory written between the tbegin and the signal will be | ||
198 | * rolled back anyway. | ||
199 | * | ||
200 | * For signals taken in non-TM or suspended mode, we use the | ||
201 | * normal/non-checkpointed stack pointer. | ||
202 | */ | ||
203 | |||
204 | #ifdef CONFIG_PPC_TRANSACTIONAL_MEM | ||
205 | if (MSR_TM_ACTIVE(regs->msr)) { | ||
206 | tm_enable(); | ||
207 | tm_reclaim(¤t->thread, regs->msr, TM_CAUSE_SIGNAL); | ||
208 | if (MSR_TM_TRANSACTIONAL(regs->msr)) | ||
209 | return current->thread.ckpt_regs.gpr[1]; | ||
210 | } | ||
211 | #endif | ||
212 | return regs->gpr[1]; | ||
172 | } | 213 | } |