This patch adds support for debugging early (such as in setup_arch or before slab initialization) on ia64. Signed-off-by: Bob Picco Index: linux-2.6.18-rc7/arch/ia64/kernel/entry.S =================================================================== --- linux-2.6.18-rc7.orig/arch/ia64/kernel/entry.S 2006-10-13 16:57:00.000000000 +0100 +++ linux-2.6.18-rc7/arch/ia64/kernel/entry.S 2006-10-13 17:09:56.000000000 +0100 @@ -953,9 +953,9 @@ GLOBAL_ENTRY(ia64_leave_kernel) shr.u r18=r19,16 // get byte size of existing "dirty" partition ;; mov r16=ar.bsp // get existing backing store pointer - addl r17=THIS_CPU(ia64_phys_stacked_size_p8),r0 +(pUStk) addl r17=THIS_CPU(ia64_phys_stacked_size_p8),r0 ;; - ld4 r17=[r17] // r17 = cpu_data->phys_stacked_size_p8 +(pUStk) ld4 r17=[r17] // r17 = cpu_data->phys_stacked_size_p8 (pKStk) br.cond.dpnt skip_rbs_switch /* Index: linux-2.6.18-rc7/arch/ia64/kernel/ivt.S =================================================================== --- linux-2.6.18-rc7.orig/arch/ia64/kernel/ivt.S 2006-10-13 16:56:36.000000000 +0100 +++ linux-2.6.18-rc7/arch/ia64/kernel/ivt.S 2006-10-13 17:09:56.000000000 +0100 @@ -52,6 +52,14 @@ #include #include +#ifdef CONFIG_KGDB +#define KGDB_ENABLE_PSR_DB mov r31=psr;; movl r30=IA64_PSR_DB;; \ + or r31=r31,r30;; \ + mov psr.l=r31;; srlz.i;; +#else +#define KGDB_ENABLE_PSR_DB +#endif + #if 1 # define PSR_DEFAULT_BITS psr.ac #else @@ -519,6 +527,7 @@ ENTRY(page_fault) movl r14=ia64_leave_kernel ;; SAVE_REST + KGDB_ENABLE_PSR_DB mov rp=r14 ;; adds out2=16,r12 // out2 = pointer to pt_regs @@ -863,6 +872,7 @@ ENTRY(interrupt) srlz.i // ensure everybody knows psr.ic is back on ;; SAVE_REST + KGDB_ENABLE_PSR_DB ;; MCA_RECOVER_RANGE(interrupt) alloc r14=ar.pfs,0,0,2,0 // must be first in an insn group @@ -1110,6 +1120,7 @@ ENTRY(non_syscall) movl r15=ia64_leave_kernel ;; SAVE_REST + KGDB_ENABLE_PSR_DB mov rp=r15 ;; br.call.sptk.many b6=ia64_bad_break // avoid WAW on CFM and ignore return addr @@ -1143,6 +1154,7 @@ ENTRY(dispatch_unaligned_handler) adds r3=8,r2 // set up second base pointer ;; SAVE_REST + KGDB_ENABLE_PSR_DB movl r14=ia64_leave_kernel ;; mov rp=r14 @@ -1185,6 +1197,10 @@ ENTRY(dispatch_to_fault_handler) adds r3=8,r2 // set up second base pointer for SAVE_REST ;; SAVE_REST + cmp.eq p6,p0=29,out0 +(p6) br.cond.spnt 1f;; // debug_vector + KGDB_ENABLE_PSR_DB +1: movl r14=ia64_leave_kernel ;; mov rp=r14 Index: linux-2.6.18-rc7/arch/ia64/kernel/process.c =================================================================== --- linux-2.6.18-rc7.orig/arch/ia64/kernel/process.c 2006-10-13 16:56:36.000000000 +0100 +++ linux-2.6.18-rc7/arch/ia64/kernel/process.c 2006-10-13 17:09:56.000000000 +0100 @@ -458,6 +458,9 @@ copy_thread (int nr, unsigned long clone */ child_ptregs->cr_ipsr = ((child_ptregs->cr_ipsr | IA64_PSR_BITS_TO_SET) & ~(IA64_PSR_BITS_TO_CLEAR | IA64_PSR_PP | IA64_PSR_UP)); +#ifdef CONFIG_KGDB + child_ptregs->cr_ipsr |= IA64_PSR_DB; +#endif /* * NOTE: The calling convention considers all floating point @@ -686,6 +689,9 @@ kernel_thread (int (*fn)(void *), void * regs.pt.r11 = (unsigned long) arg; /* 2nd argument */ /* Preserve PSR bits, except for bits 32-34 and 37-45, which we can't read. */ regs.pt.cr_ipsr = ia64_getreg(_IA64_REG_PSR) | IA64_PSR_BN; +#ifdef CONFIG_KGDB + regs.pt.cr_ipsr |= IA64_PSR_DB; +#endif regs.pt.cr_ifs = 1UL << 63; /* mark as valid, empty frame */ regs.sw.ar_fpsr = regs.pt.ar_fpsr = ia64_getreg(_IA64_REG_AR_FPSR); regs.sw.ar_bspstore = (unsigned long) current + IA64_RBS_OFFSET; Index: linux-2.6.18-rc7/arch/ia64/kernel/unwind.c =================================================================== --- linux-2.6.18-rc7.orig/arch/ia64/kernel/unwind.c 2006-10-13 16:56:36.000000000 +0100 +++ linux-2.6.18-rc7/arch/ia64/kernel/unwind.c 2006-10-13 17:09:56.000000000 +0100 @@ -72,10 +72,68 @@ # define STAT(x...) #endif +#ifdef CONFIG_KGDB +#define KGDB_EARLY_SIZE 100 +static struct unw_reg_state __initdata kgdb_reg_state[KGDB_EARLY_SIZE]; +static struct unw_labeled_state __initdata kgdb_labeled_state[KGDB_EARLY_SIZE]; +void __initdata *kgdb_reg_state_free, __initdata *kgdb_labeled_state_free; + +static void __init +kgdb_malloc_init(void) +{ + int i; + + kgdb_reg_state_free = kgdb_reg_state; + for (i = 1; i < KGDB_EARLY_SIZE; i++) { + *((unsigned long *) &kgdb_reg_state[i]) = (unsigned long) kgdb_reg_state_free; + kgdb_reg_state_free = &kgdb_reg_state[i]; + } + + kgdb_labeled_state_free = kgdb_labeled_state; + for (i = 1; i < KGDB_EARLY_SIZE; i++) { + *((unsigned long *) &kgdb_labeled_state[i]) = + (unsigned long) kgdb_labeled_state_free; + kgdb_labeled_state_free = &kgdb_labeled_state[i]; + } + +} + +static void * __init +kgdb_malloc(void **mem) +{ + void *p; + + p = *mem; + *mem = *((void **) p); + return p; +} + +static void __init +kgdb_free(void **mem, void *p) +{ + *((void **)p) = *mem; + *mem = p; +} + +#define alloc_reg_state() (!malloc_sizes[0].cs_cachep ? \ + kgdb_malloc(&kgdb_reg_state_free) : \ + kmalloc(sizeof(struct unw_reg_state), GFP_ATOMIC)) +#define free_reg_state(usr) (!malloc_sizes[0].cs_cachep ? \ + kgdb_free(&kgdb_reg_state_free, usr) : \ + kfree(usr)) +#define alloc_labeled_state() (!malloc_sizes[0].cs_cachep ? \ + kgdb_malloc(&kgdb_labeled_state_free) : \ + kmalloc(sizeof(struct unw_labeled_state), GFP_ATOMIC)) +#define free_labeled_state(usr) (!malloc_sizes[0].cs_cachep ? \ + kgdb_free(&kgdb_labeled_state_free, usr) : \ + kfree(usr)) + +#else #define alloc_reg_state() kmalloc(sizeof(struct unw_reg_state), GFP_ATOMIC) #define free_reg_state(usr) kfree(usr) #define alloc_labeled_state() kmalloc(sizeof(struct unw_labeled_state), GFP_ATOMIC) #define free_labeled_state(usr) kfree(usr) +#endif typedef unsigned long unw_word; typedef unsigned char unw_hash_index_t; @@ -238,6 +296,24 @@ static struct { #endif }; +#ifdef CONFIG_KGDB +/* + * This makes it safe to call breakpoint() very early + * in setup_arch providing: + * 1) breakpoint isn't called between lines in cpu_init + * where init_mm.mm_count is incremented and ia64_mmu_init + * is called. Otherwise the test below is invalid. + * 2) the memory examined doesn't result in tlbmiss. + */ +static unsigned long inline kgdb_unimpl_va_mask(void) +{ + if (atomic_read(&init_mm.mm_count) > 1) + return local_cpu_data->unimpl_va_mask; + else + return 0UL; +} +#endif + static inline int read_only (void *addr) { @@ -1786,7 +1862,11 @@ run_script (struct unw_script *script, s case UNW_INSN_LOAD: #ifdef UNW_DEBUG +#ifdef CONFIG_KGDB + if ((s[val] & (kgdb_unimpl_va_mask() | 0x7)) != 0 +#else if ((s[val] & (local_cpu_data->unimpl_va_mask | 0x7)) != 0 +#endif || s[val] < TASK_SIZE) { UNW_DPRINT(0, "unwind.%s: rejecting bad psp=0x%lx\n", @@ -1821,7 +1901,11 @@ find_save_locs (struct unw_frame_info *i struct unw_script *scr; unsigned long flags = 0; +#ifdef CONFIG_KGDB + if ((info->ip & (kgdb_unimpl_va_mask() | 0xf)) || info->ip < TASK_SIZE) { +#else if ((info->ip & (local_cpu_data->unimpl_va_mask | 0xf)) || info->ip < TASK_SIZE) { +#endif /* don't let obviously bad addresses pollute the cache */ /* FIXME: should really be level 0 but it occurs too often. KAO */ UNW_DPRINT(1, "unwind.%s: rejecting bad ip=0x%lx\n", __FUNCTION__, info->ip); @@ -2249,6 +2333,9 @@ unw_init (void) init_unwind_table(&unw.kernel_table, "kernel", KERNEL_START, (unsigned long) __gp, __start_unwind, __end_unwind); +#ifdef CONFIG_KGDB + kgdb_malloc_init(); +#endif } /*