diff options
author | Kumar Gala <galak@kernel.crashing.org> | 2011-04-06 01:18:48 -0400 |
---|---|---|
committer | Kumar Gala <galak@kernel.crashing.org> | 2011-05-19 01:36:42 -0400 |
commit | d36b4c4f3cc6caae6d4a12d9f995513e4c3acdd5 (patch) | |
tree | 410d9093b681689b5e74cd6cba4b44601efb8876 /arch/powerpc | |
parent | 134c428e5a31f2d5ed3a70ba20dac83895ec8b82 (diff) |
powerpc/fsl-booke64: Add support for Debug Level exception handler
Signed-off-by: Kumar Gala <galak@kernel.crashing.org>
Diffstat (limited to 'arch/powerpc')
-rw-r--r-- | arch/powerpc/include/asm/cputable.h | 4 | ||||
-rw-r--r-- | arch/powerpc/kernel/exceptions-64e.S | 65 | ||||
-rw-r--r-- | arch/powerpc/kernel/setup_64.c | 8 |
3 files changed, 73 insertions, 4 deletions
diff --git a/arch/powerpc/include/asm/cputable.h b/arch/powerpc/include/asm/cputable.h index 4efbfb3f3254..c0d842cfd012 100644 --- a/arch/powerpc/include/asm/cputable.h +++ b/arch/powerpc/include/asm/cputable.h | |||
@@ -157,6 +157,7 @@ extern const char *powerpc_base_platform; | |||
157 | #define CPU_FTR_476_DD2 ASM_CONST(0x0000000000010000) | 157 | #define CPU_FTR_476_DD2 ASM_CONST(0x0000000000010000) |
158 | #define CPU_FTR_NEED_COHERENT ASM_CONST(0x0000000000020000) | 158 | #define CPU_FTR_NEED_COHERENT ASM_CONST(0x0000000000020000) |
159 | #define CPU_FTR_NO_BTIC ASM_CONST(0x0000000000040000) | 159 | #define CPU_FTR_NO_BTIC ASM_CONST(0x0000000000040000) |
160 | #define CPU_FTR_DEBUG_LVL_EXC ASM_CONST(0x0000000000080000) | ||
160 | #define CPU_FTR_NODSISRALIGN ASM_CONST(0x0000000000100000) | 161 | #define CPU_FTR_NODSISRALIGN ASM_CONST(0x0000000000100000) |
161 | #define CPU_FTR_PPC_LE ASM_CONST(0x0000000000200000) | 162 | #define CPU_FTR_PPC_LE ASM_CONST(0x0000000000200000) |
162 | #define CPU_FTR_REAL_LE ASM_CONST(0x0000000000400000) | 163 | #define CPU_FTR_REAL_LE ASM_CONST(0x0000000000400000) |
@@ -385,7 +386,8 @@ extern const char *powerpc_base_platform; | |||
385 | CPU_FTR_DBELL) | 386 | CPU_FTR_DBELL) |
386 | #define CPU_FTRS_E5500 (CPU_FTR_USE_TB | CPU_FTR_NODSISRALIGN | \ | 387 | #define CPU_FTRS_E5500 (CPU_FTR_USE_TB | CPU_FTR_NODSISRALIGN | \ |
387 | CPU_FTR_L2CSR | CPU_FTR_LWSYNC | CPU_FTR_NOEXECUTE | \ | 388 | CPU_FTR_L2CSR | CPU_FTR_LWSYNC | CPU_FTR_NOEXECUTE | \ |
388 | CPU_FTR_DBELL | CPU_FTR_POPCNTB | CPU_FTR_POPCNTD) | 389 | CPU_FTR_DBELL | CPU_FTR_POPCNTB | CPU_FTR_POPCNTD | \ |
390 | CPU_FTR_DEBUG_LVL_EXC) | ||
389 | #define CPU_FTRS_GENERIC_32 (CPU_FTR_COMMON | CPU_FTR_NODSISRALIGN) | 391 | #define CPU_FTRS_GENERIC_32 (CPU_FTR_COMMON | CPU_FTR_NODSISRALIGN) |
390 | 392 | ||
391 | /* 64-bit CPUs */ | 393 | /* 64-bit CPUs */ |
diff --git a/arch/powerpc/kernel/exceptions-64e.S b/arch/powerpc/kernel/exceptions-64e.S index 4d0abb4930a1..cf27a8fa0d29 100644 --- a/arch/powerpc/kernel/exceptions-64e.S +++ b/arch/powerpc/kernel/exceptions-64e.S | |||
@@ -253,9 +253,6 @@ exception_marker: | |||
253 | .balign 0x1000 | 253 | .balign 0x1000 |
254 | .globl interrupt_base_book3e | 254 | .globl interrupt_base_book3e |
255 | interrupt_base_book3e: /* fake trap */ | 255 | interrupt_base_book3e: /* fake trap */ |
256 | /* Note: If real debug exceptions are supported by the HW, the vector | ||
257 | * below will have to be patched up to point to an appropriate handler | ||
258 | */ | ||
259 | EXCEPTION_STUB(0x000, machine_check) /* 0x0200 */ | 256 | EXCEPTION_STUB(0x000, machine_check) /* 0x0200 */ |
260 | EXCEPTION_STUB(0x020, critical_input) /* 0x0580 */ | 257 | EXCEPTION_STUB(0x020, critical_input) /* 0x0580 */ |
261 | EXCEPTION_STUB(0x040, debug_crit) /* 0x0d00 */ | 258 | EXCEPTION_STUB(0x040, debug_crit) /* 0x0d00 */ |
@@ -455,6 +452,68 @@ interrupt_end_book3e: | |||
455 | kernel_dbg_exc: | 452 | kernel_dbg_exc: |
456 | b . /* NYI */ | 453 | b . /* NYI */ |
457 | 454 | ||
455 | /* Debug exception as a debug interrupt*/ | ||
456 | START_EXCEPTION(debug_debug); | ||
457 | DBG_EXCEPTION_PROLOG(0xd00, PROLOG_ADDITION_2REGS) | ||
458 | |||
459 | /* | ||
460 | * If there is a single step or branch-taken exception in an | ||
461 | * exception entry sequence, it was probably meant to apply to | ||
462 | * the code where the exception occurred (since exception entry | ||
463 | * doesn't turn off DE automatically). We simulate the effect | ||
464 | * of turning off DE on entry to an exception handler by turning | ||
465 | * off DE in the DSRR1 value and clearing the debug status. | ||
466 | */ | ||
467 | |||
468 | mfspr r14,SPRN_DBSR /* check single-step/branch taken */ | ||
469 | andis. r15,r14,DBSR_IC@h | ||
470 | beq+ 1f | ||
471 | |||
472 | LOAD_REG_IMMEDIATE(r14,interrupt_base_book3e) | ||
473 | LOAD_REG_IMMEDIATE(r15,interrupt_end_book3e) | ||
474 | cmpld cr0,r10,r14 | ||
475 | cmpld cr1,r10,r15 | ||
476 | blt+ cr0,1f | ||
477 | bge+ cr1,1f | ||
478 | |||
479 | /* here it looks like we got an inappropriate debug exception. */ | ||
480 | lis r14,DBSR_IC@h /* clear the IC event */ | ||
481 | rlwinm r11,r11,0,~MSR_DE /* clear DE in the DSRR1 value */ | ||
482 | mtspr SPRN_DBSR,r14 | ||
483 | mtspr SPRN_DSRR1,r11 | ||
484 | lwz r10,PACA_EXDBG+EX_CR(r13) /* restore registers */ | ||
485 | ld r1,PACA_EXDBG+EX_R1(r13) | ||
486 | ld r14,PACA_EXDBG+EX_R14(r13) | ||
487 | ld r15,PACA_EXDBG+EX_R15(r13) | ||
488 | mtcr r10 | ||
489 | ld r10,PACA_EXDBG+EX_R10(r13) /* restore registers */ | ||
490 | ld r11,PACA_EXDBG+EX_R11(r13) | ||
491 | mfspr r13,SPRN_SPRG_DBG_SCRATCH | ||
492 | rfdi | ||
493 | |||
494 | /* Normal debug exception */ | ||
495 | /* XXX We only handle coming from userspace for now since we can't | ||
496 | * quite save properly an interrupted kernel state yet | ||
497 | */ | ||
498 | 1: andi. r14,r11,MSR_PR; /* check for userspace again */ | ||
499 | beq kernel_dbg_exc; /* if from kernel mode */ | ||
500 | |||
501 | /* Now we mash up things to make it look like we are coming on a | ||
502 | * normal exception | ||
503 | */ | ||
504 | mfspr r15,SPRN_SPRG_DBG_SCRATCH | ||
505 | mtspr SPRN_SPRG_GEN_SCRATCH,r15 | ||
506 | mfspr r14,SPRN_DBSR | ||
507 | EXCEPTION_COMMON(0xd00, PACA_EXDBG, INTS_DISABLE_ALL) | ||
508 | std r14,_DSISR(r1) | ||
509 | addi r3,r1,STACK_FRAME_OVERHEAD | ||
510 | mr r4,r14 | ||
511 | ld r14,PACA_EXDBG+EX_R14(r13) | ||
512 | ld r15,PACA_EXDBG+EX_R15(r13) | ||
513 | bl .save_nvgprs | ||
514 | bl .DebugException | ||
515 | b .ret_from_except | ||
516 | |||
458 | /* Doorbell interrupt */ | 517 | /* Doorbell interrupt */ |
459 | MASKABLE_EXCEPTION(0x2070, doorbell, .doorbell_exception, ACK_NONE) | 518 | MASKABLE_EXCEPTION(0x2070, doorbell, .doorbell_exception, ACK_NONE) |
460 | 519 | ||
diff --git a/arch/powerpc/kernel/setup_64.c b/arch/powerpc/kernel/setup_64.c index c2ec0a12e14f..a88bf2713d41 100644 --- a/arch/powerpc/kernel/setup_64.c +++ b/arch/powerpc/kernel/setup_64.c | |||
@@ -62,6 +62,7 @@ | |||
62 | #include <asm/udbg.h> | 62 | #include <asm/udbg.h> |
63 | #include <asm/kexec.h> | 63 | #include <asm/kexec.h> |
64 | #include <asm/mmu_context.h> | 64 | #include <asm/mmu_context.h> |
65 | #include <asm/code-patching.h> | ||
65 | 66 | ||
66 | #include "setup.h" | 67 | #include "setup.h" |
67 | 68 | ||
@@ -477,6 +478,9 @@ static void __init irqstack_early_init(void) | |||
477 | #ifdef CONFIG_PPC_BOOK3E | 478 | #ifdef CONFIG_PPC_BOOK3E |
478 | static void __init exc_lvl_early_init(void) | 479 | static void __init exc_lvl_early_init(void) |
479 | { | 480 | { |
481 | extern unsigned int interrupt_base_book3e; | ||
482 | extern unsigned int exc_debug_debug_book3e; | ||
483 | |||
480 | unsigned int i; | 484 | unsigned int i; |
481 | 485 | ||
482 | for_each_possible_cpu(i) { | 486 | for_each_possible_cpu(i) { |
@@ -487,6 +491,10 @@ static void __init exc_lvl_early_init(void) | |||
487 | mcheckirq_ctx[i] = (struct thread_info *) | 491 | mcheckirq_ctx[i] = (struct thread_info *) |
488 | __va(memblock_alloc(THREAD_SIZE, THREAD_SIZE)); | 492 | __va(memblock_alloc(THREAD_SIZE, THREAD_SIZE)); |
489 | } | 493 | } |
494 | |||
495 | if (cpu_has_feature(CPU_FTR_DEBUG_LVL_EXC)) | ||
496 | patch_branch(&interrupt_base_book3e + (0x040 / 4) + 1, | ||
497 | (unsigned long)&exc_debug_debug_book3e, 0); | ||
490 | } | 498 | } |
491 | #else | 499 | #else |
492 | #define exc_lvl_early_init() | 500 | #define exc_lvl_early_init() |