diff options
author | Tiejun Chen <tiejun.chen@windriver.com> | 2012-08-22 12:10:20 -0400 |
---|---|---|
committer | Benjamin Herrenschmidt <benh@kernel.crashing.org> | 2012-08-24 06:26:06 -0400 |
commit | 5f630401f9e98bd062733b5bbef096dbf2158066 (patch) | |
tree | 4d4d1d6fe382982119028473a14f9021d931684b /arch/powerpc/kernel | |
parent | 949616cf2d3095d1bb6b3d155c1cc963abd98b5c (diff) |
powerpc/kgdb: Restore current_thread_info properly
For powerpc BooKE and e200, singlestep is handled on the critical/dbg
exception stack. This causes current_thread_info() to fail for kgdb
internal, so previously We work around this issue by copying
the thread_info from the kernel stack before calling kgdb_handle_exception,
and copying it back afterwards.
But actually we don't do this properly. We should backup current_thread_info
then restore that when exit.
Signed-off-by: Tiejun Chen <tiejun.chen@windriver.com>
Signed-off-by: Benjamin Herrenschmidt <benh@kernel.crashing.org>
Diffstat (limited to 'arch/powerpc/kernel')
-rw-r--r-- | arch/powerpc/kernel/kgdb.c | 11 |
1 files changed, 9 insertions, 2 deletions
diff --git a/arch/powerpc/kernel/kgdb.c b/arch/powerpc/kernel/kgdb.c index 05adb69febf..c470a40b29f 100644 --- a/arch/powerpc/kernel/kgdb.c +++ b/arch/powerpc/kernel/kgdb.c | |||
@@ -25,6 +25,7 @@ | |||
25 | #include <asm/processor.h> | 25 | #include <asm/processor.h> |
26 | #include <asm/machdep.h> | 26 | #include <asm/machdep.h> |
27 | #include <asm/debug.h> | 27 | #include <asm/debug.h> |
28 | #include <linux/slab.h> | ||
28 | 29 | ||
29 | /* | 30 | /* |
30 | * This table contains the mapping between PowerPC hardware trap types, and | 31 | * This table contains the mapping between PowerPC hardware trap types, and |
@@ -153,6 +154,8 @@ static int kgdb_handle_breakpoint(struct pt_regs *regs) | |||
153 | static int kgdb_singlestep(struct pt_regs *regs) | 154 | static int kgdb_singlestep(struct pt_regs *regs) |
154 | { | 155 | { |
155 | struct thread_info *thread_info, *exception_thread_info; | 156 | struct thread_info *thread_info, *exception_thread_info; |
157 | struct thread_info *backup_current_thread_info = \ | ||
158 | (struct thread_info *)kmalloc(sizeof(struct thread_info), GFP_KERNEL); | ||
156 | 159 | ||
157 | if (user_mode(regs)) | 160 | if (user_mode(regs)) |
158 | return 0; | 161 | return 0; |
@@ -170,13 +173,17 @@ static int kgdb_singlestep(struct pt_regs *regs) | |||
170 | thread_info = (struct thread_info *)(regs->gpr[1] & ~(THREAD_SIZE-1)); | 173 | thread_info = (struct thread_info *)(regs->gpr[1] & ~(THREAD_SIZE-1)); |
171 | exception_thread_info = current_thread_info(); | 174 | exception_thread_info = current_thread_info(); |
172 | 175 | ||
173 | if (thread_info != exception_thread_info) | 176 | if (thread_info != exception_thread_info) { |
177 | /* Save the original current_thread_info. */ | ||
178 | memcpy(backup_current_thread_info, exception_thread_info, sizeof *thread_info); | ||
174 | memcpy(exception_thread_info, thread_info, sizeof *thread_info); | 179 | memcpy(exception_thread_info, thread_info, sizeof *thread_info); |
180 | } | ||
175 | 181 | ||
176 | kgdb_handle_exception(0, SIGTRAP, 0, regs); | 182 | kgdb_handle_exception(0, SIGTRAP, 0, regs); |
177 | 183 | ||
178 | if (thread_info != exception_thread_info) | 184 | if (thread_info != exception_thread_info) |
179 | memcpy(thread_info, exception_thread_info, sizeof *thread_info); | 185 | /* Restore current_thread_info lastly. */ |
186 | memcpy(exception_thread_info, backup_current_thread_info, sizeof *thread_info); | ||
180 | 187 | ||
181 | return 1; | 188 | return 1; |
182 | } | 189 | } |