diff options
author | Russell King <rmk+kernel@arm.linux.org.uk> | 2010-08-09 09:09:29 -0400 |
---|---|---|
committer | Russell King <rmk+kernel@arm.linux.org.uk> | 2010-08-09 09:09:29 -0400 |
commit | 054d5c9238f3c577ad51195c3ee7803613f322cc (patch) | |
tree | ff7d9f5c0e0ddf14230ba28f28ef69a2c0a0debf /arch/arm/kernel | |
parent | 11e4afb49b7fa1fc8e1ffd850c1806dd86a08204 (diff) | |
parent | 2192482ee5ce5d5d4a6cec0c351b2d3a744606eb (diff) |
Merge branch 'devel-stable' into devel
Diffstat (limited to 'arch/arm/kernel')
-rw-r--r-- | arch/arm/kernel/kgdb.c | 124 |
1 files changed, 81 insertions, 43 deletions
diff --git a/arch/arm/kernel/kgdb.c b/arch/arm/kernel/kgdb.c index c868a8864117..778c2f7024ff 100644 --- a/arch/arm/kernel/kgdb.c +++ b/arch/arm/kernel/kgdb.c | |||
@@ -10,57 +10,62 @@ | |||
10 | * Deepak Saxena <dsaxena@plexity.net> | 10 | * Deepak Saxena <dsaxena@plexity.net> |
11 | */ | 11 | */ |
12 | #include <linux/irq.h> | 12 | #include <linux/irq.h> |
13 | #include <linux/kdebug.h> | ||
13 | #include <linux/kgdb.h> | 14 | #include <linux/kgdb.h> |
14 | #include <asm/traps.h> | 15 | #include <asm/traps.h> |
15 | 16 | ||
16 | /* Make a local copy of the registers passed into the handler (bletch) */ | 17 | struct dbg_reg_def_t dbg_reg_def[DBG_MAX_REG_NUM] = |
17 | void pt_regs_to_gdb_regs(unsigned long *gdb_regs, struct pt_regs *kernel_regs) | ||
18 | { | 18 | { |
19 | int regno; | 19 | { "r0", 4, offsetof(struct pt_regs, ARM_r0)}, |
20 | 20 | { "r1", 4, offsetof(struct pt_regs, ARM_r1)}, | |
21 | /* Initialize all to zero. */ | 21 | { "r2", 4, offsetof(struct pt_regs, ARM_r2)}, |
22 | for (regno = 0; regno < GDB_MAX_REGS; regno++) | 22 | { "r3", 4, offsetof(struct pt_regs, ARM_r3)}, |
23 | gdb_regs[regno] = 0; | 23 | { "r4", 4, offsetof(struct pt_regs, ARM_r4)}, |
24 | { "r5", 4, offsetof(struct pt_regs, ARM_r5)}, | ||
25 | { "r6", 4, offsetof(struct pt_regs, ARM_r6)}, | ||
26 | { "r7", 4, offsetof(struct pt_regs, ARM_r7)}, | ||
27 | { "r8", 4, offsetof(struct pt_regs, ARM_r8)}, | ||
28 | { "r9", 4, offsetof(struct pt_regs, ARM_r9)}, | ||
29 | { "r10", 4, offsetof(struct pt_regs, ARM_r10)}, | ||
30 | { "fp", 4, offsetof(struct pt_regs, ARM_fp)}, | ||
31 | { "ip", 4, offsetof(struct pt_regs, ARM_ip)}, | ||
32 | { "sp", 4, offsetof(struct pt_regs, ARM_sp)}, | ||
33 | { "lr", 4, offsetof(struct pt_regs, ARM_lr)}, | ||
34 | { "pc", 4, offsetof(struct pt_regs, ARM_pc)}, | ||
35 | { "f0", 12, -1 }, | ||
36 | { "f1", 12, -1 }, | ||
37 | { "f2", 12, -1 }, | ||
38 | { "f3", 12, -1 }, | ||
39 | { "f4", 12, -1 }, | ||
40 | { "f5", 12, -1 }, | ||
41 | { "f6", 12, -1 }, | ||
42 | { "f7", 12, -1 }, | ||
43 | { "fps", 4, -1 }, | ||
44 | { "cpsr", 4, offsetof(struct pt_regs, ARM_cpsr)}, | ||
45 | }; | ||
24 | 46 | ||
25 | gdb_regs[_R0] = kernel_regs->ARM_r0; | 47 | char *dbg_get_reg(int regno, void *mem, struct pt_regs *regs) |
26 | gdb_regs[_R1] = kernel_regs->ARM_r1; | 48 | { |
27 | gdb_regs[_R2] = kernel_regs->ARM_r2; | 49 | if (regno >= DBG_MAX_REG_NUM || regno < 0) |
28 | gdb_regs[_R3] = kernel_regs->ARM_r3; | 50 | return NULL; |
29 | gdb_regs[_R4] = kernel_regs->ARM_r4; | 51 | |
30 | gdb_regs[_R5] = kernel_regs->ARM_r5; | 52 | if (dbg_reg_def[regno].offset != -1) |
31 | gdb_regs[_R6] = kernel_regs->ARM_r6; | 53 | memcpy(mem, (void *)regs + dbg_reg_def[regno].offset, |
32 | gdb_regs[_R7] = kernel_regs->ARM_r7; | 54 | dbg_reg_def[regno].size); |
33 | gdb_regs[_R8] = kernel_regs->ARM_r8; | 55 | else |
34 | gdb_regs[_R9] = kernel_regs->ARM_r9; | 56 | memset(mem, 0, dbg_reg_def[regno].size); |
35 | gdb_regs[_R10] = kernel_regs->ARM_r10; | 57 | return dbg_reg_def[regno].name; |
36 | gdb_regs[_FP] = kernel_regs->ARM_fp; | ||
37 | gdb_regs[_IP] = kernel_regs->ARM_ip; | ||
38 | gdb_regs[_SPT] = kernel_regs->ARM_sp; | ||
39 | gdb_regs[_LR] = kernel_regs->ARM_lr; | ||
40 | gdb_regs[_PC] = kernel_regs->ARM_pc; | ||
41 | gdb_regs[_CPSR] = kernel_regs->ARM_cpsr; | ||
42 | } | 58 | } |
43 | 59 | ||
44 | /* Copy local gdb registers back to kgdb regs, for later copy to kernel */ | 60 | int dbg_set_reg(int regno, void *mem, struct pt_regs *regs) |
45 | void gdb_regs_to_pt_regs(unsigned long *gdb_regs, struct pt_regs *kernel_regs) | ||
46 | { | 61 | { |
47 | kernel_regs->ARM_r0 = gdb_regs[_R0]; | 62 | if (regno >= DBG_MAX_REG_NUM || regno < 0) |
48 | kernel_regs->ARM_r1 = gdb_regs[_R1]; | 63 | return -EINVAL; |
49 | kernel_regs->ARM_r2 = gdb_regs[_R2]; | 64 | |
50 | kernel_regs->ARM_r3 = gdb_regs[_R3]; | 65 | if (dbg_reg_def[regno].offset != -1) |
51 | kernel_regs->ARM_r4 = gdb_regs[_R4]; | 66 | memcpy((void *)regs + dbg_reg_def[regno].offset, mem, |
52 | kernel_regs->ARM_r5 = gdb_regs[_R5]; | 67 | dbg_reg_def[regno].size); |
53 | kernel_regs->ARM_r6 = gdb_regs[_R6]; | 68 | return 0; |
54 | kernel_regs->ARM_r7 = gdb_regs[_R7]; | ||
55 | kernel_regs->ARM_r8 = gdb_regs[_R8]; | ||
56 | kernel_regs->ARM_r9 = gdb_regs[_R9]; | ||
57 | kernel_regs->ARM_r10 = gdb_regs[_R10]; | ||
58 | kernel_regs->ARM_fp = gdb_regs[_FP]; | ||
59 | kernel_regs->ARM_ip = gdb_regs[_IP]; | ||
60 | kernel_regs->ARM_sp = gdb_regs[_SPT]; | ||
61 | kernel_regs->ARM_lr = gdb_regs[_LR]; | ||
62 | kernel_regs->ARM_pc = gdb_regs[_PC]; | ||
63 | kernel_regs->ARM_cpsr = gdb_regs[_CPSR]; | ||
64 | } | 69 | } |
65 | 70 | ||
66 | void | 71 | void |
@@ -176,6 +181,33 @@ void kgdb_roundup_cpus(unsigned long flags) | |||
176 | local_irq_disable(); | 181 | local_irq_disable(); |
177 | } | 182 | } |
178 | 183 | ||
184 | static int __kgdb_notify(struct die_args *args, unsigned long cmd) | ||
185 | { | ||
186 | struct pt_regs *regs = args->regs; | ||
187 | |||
188 | if (kgdb_handle_exception(1, args->signr, cmd, regs)) | ||
189 | return NOTIFY_DONE; | ||
190 | return NOTIFY_STOP; | ||
191 | } | ||
192 | static int | ||
193 | kgdb_notify(struct notifier_block *self, unsigned long cmd, void *ptr) | ||
194 | { | ||
195 | unsigned long flags; | ||
196 | int ret; | ||
197 | |||
198 | local_irq_save(flags); | ||
199 | ret = __kgdb_notify(ptr, cmd); | ||
200 | local_irq_restore(flags); | ||
201 | |||
202 | return ret; | ||
203 | } | ||
204 | |||
205 | static struct notifier_block kgdb_notifier = { | ||
206 | .notifier_call = kgdb_notify, | ||
207 | .priority = -INT_MAX, | ||
208 | }; | ||
209 | |||
210 | |||
179 | /** | 211 | /** |
180 | * kgdb_arch_init - Perform any architecture specific initalization. | 212 | * kgdb_arch_init - Perform any architecture specific initalization. |
181 | * | 213 | * |
@@ -184,6 +216,11 @@ void kgdb_roundup_cpus(unsigned long flags) | |||
184 | */ | 216 | */ |
185 | int kgdb_arch_init(void) | 217 | int kgdb_arch_init(void) |
186 | { | 218 | { |
219 | int ret = register_die_notifier(&kgdb_notifier); | ||
220 | |||
221 | if (ret != 0) | ||
222 | return ret; | ||
223 | |||
187 | register_undef_hook(&kgdb_brkpt_hook); | 224 | register_undef_hook(&kgdb_brkpt_hook); |
188 | register_undef_hook(&kgdb_compiled_brkpt_hook); | 225 | register_undef_hook(&kgdb_compiled_brkpt_hook); |
189 | 226 | ||
@@ -200,6 +237,7 @@ void kgdb_arch_exit(void) | |||
200 | { | 237 | { |
201 | unregister_undef_hook(&kgdb_brkpt_hook); | 238 | unregister_undef_hook(&kgdb_brkpt_hook); |
202 | unregister_undef_hook(&kgdb_compiled_brkpt_hook); | 239 | unregister_undef_hook(&kgdb_compiled_brkpt_hook); |
240 | unregister_die_notifier(&kgdb_notifier); | ||
203 | } | 241 | } |
204 | 242 | ||
205 | /* | 243 | /* |