diff options
| author | Dongdong Deng <dongdong.deng@windriver.com> | 2010-10-27 22:47:00 -0400 |
|---|---|---|
| committer | Jason Wessel <jason.wessel@windriver.com> | 2010-10-29 14:14:42 -0400 |
| commit | ff10b88b5a05c8f1646dd15fb9f6093c1384ff6d (patch) | |
| tree | e620eda79f8062dc858a0429096ec7d0332ce760 | |
| parent | 4dacd5c073150cd78dfb6004cbfa71986f0258a4 (diff) | |
kgdb,ppc: Individual register get/set for ppc
commit 534af1082329392bc29f6badf815e69ae2ae0f4c(kgdb,kdb: individual
register set and and get API) introduce dbg_get_reg/dbg_set_reg API
for individual register get and set.
This patch implement those APIs for ppc.
Signed-off-by: Dongdong Deng <dongdong.deng@windriver.com>
Signed-off-by: Jason Wessel <jason.wessel@windriver.com>
| -rw-r--r-- | arch/powerpc/include/asm/kgdb.h | 1 | ||||
| -rw-r--r-- | arch/powerpc/kernel/kgdb.c | 188 |
2 files changed, 126 insertions, 63 deletions
diff --git a/arch/powerpc/include/asm/kgdb.h b/arch/powerpc/include/asm/kgdb.h index edd217006d27..9db24e77b9f4 100644 --- a/arch/powerpc/include/asm/kgdb.h +++ b/arch/powerpc/include/asm/kgdb.h | |||
| @@ -31,6 +31,7 @@ static inline void arch_kgdb_breakpoint(void) | |||
| 31 | asm(".long 0x7d821008"); /* twge r2, r2 */ | 31 | asm(".long 0x7d821008"); /* twge r2, r2 */ |
| 32 | } | 32 | } |
| 33 | #define CACHE_FLUSH_IS_SAFE 1 | 33 | #define CACHE_FLUSH_IS_SAFE 1 |
| 34 | #define DBG_MAX_REG_NUM 70 | ||
| 34 | 35 | ||
| 35 | /* The number bytes of registers we have to save depends on a few | 36 | /* The number bytes of registers we have to save depends on a few |
| 36 | * things. For 64bit we default to not including vector registers and | 37 | * things. For 64bit we default to not including vector registers and |
diff --git a/arch/powerpc/kernel/kgdb.c b/arch/powerpc/kernel/kgdb.c index 7f61a3ac787c..7a9db64f3f04 100644 --- a/arch/powerpc/kernel/kgdb.c +++ b/arch/powerpc/kernel/kgdb.c | |||
| @@ -194,40 +194,6 @@ static int kgdb_dabr_match(struct pt_regs *regs) | |||
| 194 | ptr = (unsigned long *)ptr32; \ | 194 | ptr = (unsigned long *)ptr32; \ |
| 195 | } while (0) | 195 | } while (0) |
| 196 | 196 | ||
| 197 | |||
| 198 | void pt_regs_to_gdb_regs(unsigned long *gdb_regs, struct pt_regs *regs) | ||
| 199 | { | ||
| 200 | unsigned long *ptr = gdb_regs; | ||
| 201 | int reg; | ||
| 202 | |||
| 203 | memset(gdb_regs, 0, NUMREGBYTES); | ||
| 204 | |||
| 205 | for (reg = 0; reg < 32; reg++) | ||
| 206 | PACK64(ptr, regs->gpr[reg]); | ||
| 207 | |||
| 208 | #ifdef CONFIG_FSL_BOOKE | ||
| 209 | #ifdef CONFIG_SPE | ||
| 210 | for (reg = 0; reg < 32; reg++) | ||
| 211 | PACK64(ptr, current->thread.evr[reg]); | ||
| 212 | #else | ||
| 213 | ptr += 32; | ||
| 214 | #endif | ||
| 215 | #else | ||
| 216 | /* fp registers not used by kernel, leave zero */ | ||
| 217 | ptr += 32 * 8 / sizeof(long); | ||
| 218 | #endif | ||
| 219 | |||
| 220 | PACK64(ptr, regs->nip); | ||
| 221 | PACK64(ptr, regs->msr); | ||
| 222 | PACK32(ptr, regs->ccr); | ||
| 223 | PACK64(ptr, regs->link); | ||
| 224 | PACK64(ptr, regs->ctr); | ||
| 225 | PACK32(ptr, regs->xer); | ||
| 226 | |||
| 227 | BUG_ON((unsigned long)ptr > | ||
| 228 | (unsigned long)(((void *)gdb_regs) + NUMREGBYTES)); | ||
| 229 | } | ||
| 230 | |||
| 231 | void sleeping_thread_to_gdb_regs(unsigned long *gdb_regs, struct task_struct *p) | 197 | void sleeping_thread_to_gdb_regs(unsigned long *gdb_regs, struct task_struct *p) |
| 232 | { | 198 | { |
| 233 | struct pt_regs *regs = (struct pt_regs *)(p->thread.ksp + | 199 | struct pt_regs *regs = (struct pt_regs *)(p->thread.ksp + |
| @@ -271,44 +237,140 @@ void sleeping_thread_to_gdb_regs(unsigned long *gdb_regs, struct task_struct *p) | |||
| 271 | (unsigned long)(((void *)gdb_regs) + NUMREGBYTES)); | 237 | (unsigned long)(((void *)gdb_regs) + NUMREGBYTES)); |
| 272 | } | 238 | } |
| 273 | 239 | ||
| 274 | #define UNPACK64(dest, ptr) do { dest = *(ptr++); } while (0) | 240 | #define GDB_SIZEOF_REG sizeof(unsigned long) |
| 241 | #define GDB_SIZEOF_REG_U32 sizeof(u32) | ||
| 275 | 242 | ||
| 276 | #define UNPACK32(dest, ptr) do { \ | 243 | #ifdef CONFIG_FSL_BOOKE |
| 277 | u32 *ptr32; \ | 244 | #define GDB_SIZEOF_FLOAT_REG sizeof(unsigned long) |
| 278 | ptr32 = (u32 *)ptr; \ | 245 | #else |
| 279 | dest = *(ptr32++); \ | 246 | #define GDB_SIZEOF_FLOAT_REG sizeof(u64) |
| 280 | ptr = (unsigned long *)ptr32; \ | 247 | #endif |
| 281 | } while (0) | ||
| 282 | 248 | ||
| 283 | void gdb_regs_to_pt_regs(unsigned long *gdb_regs, struct pt_regs *regs) | 249 | struct dbg_reg_def_t dbg_reg_def[DBG_MAX_REG_NUM] = |
| 284 | { | 250 | { |
| 285 | unsigned long *ptr = gdb_regs; | 251 | { "r0", GDB_SIZEOF_REG, offsetof(struct pt_regs, gpr[0]) }, |
| 286 | int reg; | 252 | { "r1", GDB_SIZEOF_REG, offsetof(struct pt_regs, gpr[1]) }, |
| 287 | 253 | { "r2", GDB_SIZEOF_REG, offsetof(struct pt_regs, gpr[2]) }, | |
| 288 | for (reg = 0; reg < 32; reg++) | 254 | { "r3", GDB_SIZEOF_REG, offsetof(struct pt_regs, gpr[3]) }, |
| 289 | UNPACK64(regs->gpr[reg], ptr); | 255 | { "r4", GDB_SIZEOF_REG, offsetof(struct pt_regs, gpr[4]) }, |
| 256 | { "r5", GDB_SIZEOF_REG, offsetof(struct pt_regs, gpr[5]) }, | ||
| 257 | { "r6", GDB_SIZEOF_REG, offsetof(struct pt_regs, gpr[6]) }, | ||
| 258 | { "r7", GDB_SIZEOF_REG, offsetof(struct pt_regs, gpr[7]) }, | ||
| 259 | { "r8", GDB_SIZEOF_REG, offsetof(struct pt_regs, gpr[8]) }, | ||
| 260 | { "r9", GDB_SIZEOF_REG, offsetof(struct pt_regs, gpr[9]) }, | ||
| 261 | { "r10", GDB_SIZEOF_REG, offsetof(struct pt_regs, gpr[10]) }, | ||
| 262 | { "r11", GDB_SIZEOF_REG, offsetof(struct pt_regs, gpr[11]) }, | ||
| 263 | { "r12", GDB_SIZEOF_REG, offsetof(struct pt_regs, gpr[12]) }, | ||
| 264 | { "r13", GDB_SIZEOF_REG, offsetof(struct pt_regs, gpr[13]) }, | ||
| 265 | { "r14", GDB_SIZEOF_REG, offsetof(struct pt_regs, gpr[14]) }, | ||
| 266 | { "r15", GDB_SIZEOF_REG, offsetof(struct pt_regs, gpr[15]) }, | ||
| 267 | { "r16", GDB_SIZEOF_REG, offsetof(struct pt_regs, gpr[16]) }, | ||
| 268 | { "r17", GDB_SIZEOF_REG, offsetof(struct pt_regs, gpr[17]) }, | ||
| 269 | { "r18", GDB_SIZEOF_REG, offsetof(struct pt_regs, gpr[18]) }, | ||
| 270 | { "r19", GDB_SIZEOF_REG, offsetof(struct pt_regs, gpr[19]) }, | ||
| 271 | { "r20", GDB_SIZEOF_REG, offsetof(struct pt_regs, gpr[20]) }, | ||
| 272 | { "r21", GDB_SIZEOF_REG, offsetof(struct pt_regs, gpr[21]) }, | ||
| 273 | { "r22", GDB_SIZEOF_REG, offsetof(struct pt_regs, gpr[22]) }, | ||
| 274 | { "r23", GDB_SIZEOF_REG, offsetof(struct pt_regs, gpr[23]) }, | ||
| 275 | { "r24", GDB_SIZEOF_REG, offsetof(struct pt_regs, gpr[24]) }, | ||
| 276 | { "r25", GDB_SIZEOF_REG, offsetof(struct pt_regs, gpr[25]) }, | ||
| 277 | { "r26", GDB_SIZEOF_REG, offsetof(struct pt_regs, gpr[26]) }, | ||
| 278 | { "r27", GDB_SIZEOF_REG, offsetof(struct pt_regs, gpr[27]) }, | ||
| 279 | { "r28", GDB_SIZEOF_REG, offsetof(struct pt_regs, gpr[28]) }, | ||
| 280 | { "r29", GDB_SIZEOF_REG, offsetof(struct pt_regs, gpr[29]) }, | ||
| 281 | { "r30", GDB_SIZEOF_REG, offsetof(struct pt_regs, gpr[30]) }, | ||
| 282 | { "r31", GDB_SIZEOF_REG, offsetof(struct pt_regs, gpr[31]) }, | ||
| 283 | |||
| 284 | { "f0", GDB_SIZEOF_FLOAT_REG, 0 }, | ||
| 285 | { "f1", GDB_SIZEOF_FLOAT_REG, 1 }, | ||
| 286 | { "f2", GDB_SIZEOF_FLOAT_REG, 2 }, | ||
| 287 | { "f3", GDB_SIZEOF_FLOAT_REG, 3 }, | ||
| 288 | { "f4", GDB_SIZEOF_FLOAT_REG, 4 }, | ||
| 289 | { "f5", GDB_SIZEOF_FLOAT_REG, 5 }, | ||
| 290 | { "f6", GDB_SIZEOF_FLOAT_REG, 6 }, | ||
| 291 | { "f7", GDB_SIZEOF_FLOAT_REG, 7 }, | ||
| 292 | { "f8", GDB_SIZEOF_FLOAT_REG, 8 }, | ||
| 293 | { "f9", GDB_SIZEOF_FLOAT_REG, 9 }, | ||
| 294 | { "f10", GDB_SIZEOF_FLOAT_REG, 10 }, | ||
| 295 | { "f11", GDB_SIZEOF_FLOAT_REG, 11 }, | ||
| 296 | { "f12", GDB_SIZEOF_FLOAT_REG, 12 }, | ||
| 297 | { "f13", GDB_SIZEOF_FLOAT_REG, 13 }, | ||
| 298 | { "f14", GDB_SIZEOF_FLOAT_REG, 14 }, | ||
| 299 | { "f15", GDB_SIZEOF_FLOAT_REG, 15 }, | ||
| 300 | { "f16", GDB_SIZEOF_FLOAT_REG, 16 }, | ||
| 301 | { "f17", GDB_SIZEOF_FLOAT_REG, 17 }, | ||
| 302 | { "f18", GDB_SIZEOF_FLOAT_REG, 18 }, | ||
| 303 | { "f19", GDB_SIZEOF_FLOAT_REG, 19 }, | ||
| 304 | { "f20", GDB_SIZEOF_FLOAT_REG, 20 }, | ||
| 305 | { "f21", GDB_SIZEOF_FLOAT_REG, 21 }, | ||
| 306 | { "f22", GDB_SIZEOF_FLOAT_REG, 22 }, | ||
| 307 | { "f23", GDB_SIZEOF_FLOAT_REG, 23 }, | ||
| 308 | { "f24", GDB_SIZEOF_FLOAT_REG, 24 }, | ||
| 309 | { "f25", GDB_SIZEOF_FLOAT_REG, 25 }, | ||
| 310 | { "f26", GDB_SIZEOF_FLOAT_REG, 26 }, | ||
| 311 | { "f27", GDB_SIZEOF_FLOAT_REG, 27 }, | ||
| 312 | { "f28", GDB_SIZEOF_FLOAT_REG, 28 }, | ||
| 313 | { "f29", GDB_SIZEOF_FLOAT_REG, 29 }, | ||
| 314 | { "f30", GDB_SIZEOF_FLOAT_REG, 30 }, | ||
| 315 | { "f31", GDB_SIZEOF_FLOAT_REG, 31 }, | ||
| 316 | |||
| 317 | { "pc", GDB_SIZEOF_REG, offsetof(struct pt_regs, nip) }, | ||
| 318 | { "msr", GDB_SIZEOF_REG, offsetof(struct pt_regs, msr) }, | ||
| 319 | { "cr", GDB_SIZEOF_REG_U32, offsetof(struct pt_regs, ccr) }, | ||
| 320 | { "lr", GDB_SIZEOF_REG, offsetof(struct pt_regs, link) }, | ||
| 321 | { "ctr", GDB_SIZEOF_REG_U32, offsetof(struct pt_regs, ctr) }, | ||
| 322 | { "xer", GDB_SIZEOF_REG, offsetof(struct pt_regs, xer) }, | ||
| 323 | }; | ||
| 290 | 324 | ||
| 291 | #ifdef CONFIG_FSL_BOOKE | 325 | char *dbg_get_reg(int regno, void *mem, struct pt_regs *regs) |
| 292 | #ifdef CONFIG_SPE | 326 | { |
| 293 | for (reg = 0; reg < 32; reg++) | 327 | if (regno >= DBG_MAX_REG_NUM || regno < 0) |
| 294 | UNPACK64(current->thread.evr[reg], ptr); | 328 | return NULL; |
| 329 | |||
| 330 | if (regno < 32 || regno >= 64) | ||
| 331 | /* First 0 -> 31 gpr registers*/ | ||
| 332 | /* pc, msr, ls... registers 64 -> 69 */ | ||
| 333 | memcpy(mem, (void *)regs + dbg_reg_def[regno].offset, | ||
| 334 | dbg_reg_def[regno].size); | ||
| 335 | |||
| 336 | if (regno >= 32 && regno < 64) { | ||
| 337 | /* FP registers 32 -> 63 */ | ||
| 338 | #if defined(CONFIG_FSL_BOOKE) && defined(CONFIG_SPE) | ||
| 339 | if (current) | ||
| 340 | memcpy(mem, current->thread.evr[regno-32], | ||
| 341 | dbg_reg_def[regno].size); | ||
| 295 | #else | 342 | #else |
| 296 | ptr += 32; | 343 | /* fp registers not used by kernel, leave zero */ |
| 344 | memset(mem, 0, dbg_reg_def[regno].size); | ||
| 297 | #endif | 345 | #endif |
| 346 | } | ||
| 347 | |||
| 348 | return dbg_reg_def[regno].name; | ||
| 349 | } | ||
| 350 | |||
| 351 | int dbg_set_reg(int regno, void *mem, struct pt_regs *regs) | ||
| 352 | { | ||
| 353 | if (regno >= DBG_MAX_REG_NUM || regno < 0) | ||
| 354 | return -EINVAL; | ||
| 355 | |||
| 356 | if (regno < 32 || regno >= 64) | ||
| 357 | /* First 0 -> 31 gpr registers*/ | ||
| 358 | /* pc, msr, ls... registers 64 -> 69 */ | ||
| 359 | memcpy((void *)regs + dbg_reg_def[regno].offset, mem, | ||
| 360 | dbg_reg_def[regno].size); | ||
| 361 | |||
| 362 | if (regno >= 32 && regno < 64) { | ||
| 363 | /* FP registers 32 -> 63 */ | ||
| 364 | #if defined(CONFIG_FSL_BOOKE) && defined(CONFIG_SPE) | ||
| 365 | memcpy(current->thread.evr[regno-32], mem, | ||
| 366 | dbg_reg_def[regno].size); | ||
| 298 | #else | 367 | #else |
| 299 | /* fp registers not used by kernel, leave zero */ | 368 | /* fp registers not used by kernel, leave zero */ |
| 300 | ptr += 32 * 8 / sizeof(int); | 369 | return 0; |
| 301 | #endif | 370 | #endif |
| 371 | } | ||
| 302 | 372 | ||
| 303 | UNPACK64(regs->nip, ptr); | 373 | return 0; |
| 304 | UNPACK64(regs->msr, ptr); | ||
| 305 | UNPACK32(regs->ccr, ptr); | ||
| 306 | UNPACK64(regs->link, ptr); | ||
| 307 | UNPACK64(regs->ctr, ptr); | ||
| 308 | UNPACK32(regs->xer, ptr); | ||
| 309 | |||
| 310 | BUG_ON((unsigned long)ptr > | ||
| 311 | (unsigned long)(((void *)gdb_regs) + NUMREGBYTES)); | ||
| 312 | } | 374 | } |
| 313 | 375 | ||
| 314 | void kgdb_arch_set_pc(struct pt_regs *regs, unsigned long pc) | 376 | void kgdb_arch_set_pc(struct pt_regs *regs, unsigned long pc) |
