--- zzzz-none-000/linux-2.6.32.61/arch/mips/kernel/process.c 2013-06-10 09:43:48.000000000 +0000 +++ virian-300e-630/linux-2.6.32.61/arch/mips/kernel/process.c 2014-03-28 16:50:08.000000000 +0000 @@ -42,7 +42,13 @@ #include #include #include - +#ifdef CONFIG_AVM_POWER +#include +#endif/*--- #ifdef CONFIG_AVM_POWER ---*/ + +extern void r4k_wait_irqoff(void); +/*--- #define STACK_TRC(args...) printk(KERN_INFO args) ---*/ +#define STACK_TRC(args...) /* * The idle thread. There's no useful work to be done, so just try to conserve * power and have a low exit latency (ie sit in a loop waiting for somebody to @@ -59,13 +65,28 @@ while (1) { tick_nohz_stop_sched_tick(1); while (!need_resched() && cpu_online(cpu)) { + if(cpu_wait != r4k_wait_irqoff) { + /*--- in r4k_wait_irqoff ---*/ +#if defined(CONFIG_AVM_POWER) + avm_cpu_wait_start(); +#endif/*--- #if defined(CONFIG_AVM_POWER) ---*/ + } +#if defined(CONFIG_AVM_POWERMETER) && defined(DECTSYNC_PATCH) + PowerManagmentRessourceInfo(powerdevice_dectsync, 0); +#endif/*--- #if defined(CONFIG_AVM_POWERMETER) && defined(DECTSYNC_PATCH) ---*/ #ifdef CONFIG_MIPS_MT_SMTC - extern void smtc_idle_loop_hook(void); - - smtc_idle_loop_hook(); + { + extern void smtc_idle_loop_hook(void); + smtc_idle_loop_hook(); + } #endif if (cpu_wait) (*cpu_wait)(); + if(cpu_wait != r4k_wait_irqoff) { +#if defined(CONFIG_AVM_POWER) + avm_cpu_wait_end(); +#endif/*--- #if defined(CONFIG_AVM_POWER) ---*/ + } } #ifdef CONFIG_HOTPLUG_CPU if (!cpu_online(cpu) && !cpu_isset(cpu, cpu_callin_map) && @@ -73,6 +94,9 @@ system_state == SYSTEM_BOOTING)) play_dead(); #endif +#if defined(CONFIG_AVM_POWER) + avm_cpu_wait_info(); +#endif/*--- #if defined(CONFIG_AVM_POWER) ---*/ tick_nohz_restart_sched_tick(); preempt_enable_no_resched(); schedule(); @@ -285,42 +309,135 @@ return 1; return 0; } +static inline int is_sp_addiu_ins(union mips_instruction *ip) +{ + /* addiu/daddiu sp,sp,-imm */ + if (ip->i_format.rs != 29 || ip->i_format.rt != 29) + return 0; + if (ip->i_format.opcode == addiu_op || ip->i_format.opcode == daddiu_op) + return 1; + return 0; +} +static inline int is_sp_save_ins(union mips_instruction *ip) +{ + /* move reg, sp */ + if (ip->r_format.opcode != spec_op) { + return 0; + } + if (ip->r_format.func != addu_op) { + return 0; + } + if ((ip->r_format.rt == 29) && (ip->r_format.rs == 0)) { + return ip->r_format.rd; + } + if ((ip->r_format.rt == 0) && (ip->r_format.rs == 29)) { + return ip->r_format.rd; + } + return 0; +} +static inline int is_sp_restore_ins(union mips_instruction *ip) +{ + /* move reg, sp */ + if (ip->r_format.opcode != spec_op) { + return 0; + } + if (ip->r_format.rd != 29) + return 0; + if (ip->r_format.func == addu_op) { + return ip->r_format.rt; + } + return 0; +} +/*--------------------------------------------------------------------------------*\ + * mbahr@avm.de: special handling for "again-modify-stackpointer-code" (e.g. if CONFIG_FTRACE=y) + * + 80008614: 27bdffe8 addiu sp,sp,-24 + 80008618: afbe0010 sw s8,16(sp) + 8000861c: 03a0f021 move s8,sp <--- sp saved in local register !!! + 80008620: afbf0014 sw ra,20(sp) + 80008624: 03e00821 move at,ra + 80008628: 0c0078f8 jal 8001e3e0 + 8000862c: 27bdfff8 addiu sp,sp,-8 <--- modified stackpointer again !!! + + + .... + + + 80008664: 03c0e821 move sp,s8 <--- restore sp form local register + 80008668: 8fbf0014 lw ra,20(sp) + 8000866c: 24020001 li v0,1 + 80008670: 8fbe0010 lw s8,16(sp) + 80008674: 03e00008 jr ra + 80008678: 27bd0018 addiu sp,sp,24 +\*--------------------------------------------------------------------------------*/ static int get_frame_info(struct mips_frame_info *info) { union mips_instruction *ip = info->func; unsigned max_insns = info->func_size / sizeof(union mips_instruction); unsigned i; + unsigned int saved_sp = 0, extra_sp_offset = 0; info->pc_offset = -1; info->frame_size = 0; - if (!ip) - goto err; + if (!ip) { + STACK_TRC("%s: err: %d\n", __func__, __LINE__); + goto err; + } if (max_insns == 0) max_insns = 128U; /* unknown function size */ max_insns = min(128U, max_insns); for (i = 0; i < max_insns; i++, ip++) { - - if (is_jal_jalr_jr_ins(ip)) + STACK_TRC("%s: instruction %lx: %08lx\n", __func__, (unsigned long)ip, *((unsigned long *)ip)); + if (is_jal_jalr_jr_ins(ip)) { + STACK_TRC("%s: %d\n", __func__, __LINE__); break; + } if (!info->frame_size) { - if (is_sp_move_ins(ip)) + if (is_sp_addiu_ins(ip)) { info->frame_size = - ip->i_format.simmediate; + STACK_TRC("%s: set framsize=%d (simmediate=%d)\n", __func__, info->frame_size, ip->i_format.simmediate); + } continue; } - if (info->pc_offset == -1 && is_ra_save_ins(ip)) { - info->pc_offset = - ip->i_format.simmediate / sizeof(long); - break; + if(info->frame_size && (saved_sp == 0) && (saved_sp = is_sp_save_ins(ip))) { + /*--- if FTRACE configured arrrgh: stackpointer saved in local register, following code will again modify stack ... ---*/ + STACK_TRC("%s: %p:instruction=%08lx arrgh stackpointer saved in local register $%d\n", __func__, ip, *((unsigned long *)ip), saved_sp); + continue; + } + if ((info->pc_offset == -1) && is_ra_save_ins(ip)) { + info->pc_offset = ip->i_format.simmediate / sizeof(long); + STACK_TRC("%s: pc_offset %d simmediate=%d\n", __func__, info->pc_offset, ip->i_format.simmediate); + if(saved_sp == 0) { + break; + } + continue; } + if(saved_sp && is_sp_addiu_ins(ip)) { + extra_sp_offset += -ip->i_format.simmediate; + STACK_TRC("%s: stackpointer post-add : %d extra_sp_offset=%d\n", __func__, -ip->i_format.simmediate, extra_sp_offset); + continue; + } + if(saved_sp && (saved_sp == is_sp_restore_ins(ip))) { + STACK_TRC("%s: stackpointer restored\n", __func__); + /*--- stackpointer restored ---*/ + extra_sp_offset = 0; + saved_sp = 0; + } } - if (info->frame_size && info->pc_offset >= 0) /* nested */ + info->pc_offset += extra_sp_offset / sizeof(long); + info->frame_size += extra_sp_offset; + if (info->frame_size && info->pc_offset >= 0) {/* nested */ + STACK_TRC("%s: nested: size %d offset %d extra_sp_offset %d\n", __func__, info->frame_size, info->pc_offset, extra_sp_offset); return 0; - if (info->pc_offset < 0) /* leaf */ + } + if (info->pc_offset < 0) {/* leaf */ + STACK_TRC("%s: offset %d\n", __func__, info->pc_offset); return 1; + } /* prologue seems boggus... */ err: return -1; @@ -346,7 +463,7 @@ * thread_saved_pc() and get_wchan() are not reliable. */ if (schedule_mfi.pc_offset < 0) - printk("Can't analyze schedule() prologue at %p\n", schedule); + printk(KERN_WARNING"Can't analyze schedule() prologue at %p\n", schedule); return 0; } @@ -381,10 +498,16 @@ extern void ret_from_irq(void); extern void ret_from_exception(void); - stack_page = (unsigned long)task_stack_page(task); - if (!stack_page) + STACK_TRC("%s %d: %p sp=%lx pc=%lx ra=%lx\n", __FUNCTION__, __LINE__, task, *sp, pc, *ra); + if(task == NULL) { + stack_page = *sp; /*--- lazy safety ... ---*/ + } else { + stack_page = (unsigned long)task_stack_page(task); + } + if (!stack_page) { + STACK_TRC("%s %d: %p\n", __FUNCTION__, __LINE__, task); return 0; - + } /* * If we reached the bottom of interrupt context, * return saved pc in pt_regs. @@ -399,33 +522,41 @@ if (__kernel_text_address(pc)) { *sp = regs->regs[29]; *ra = regs->regs[31]; + STACK_TRC("%s %d: %p sp=%lx pc=%lx ra=%lx\n", __FUNCTION__, __LINE__, task, *sp, pc, *ra); return pc; } } + STACK_TRC("%s %d: %lx %d\n", __FUNCTION__, __LINE__, pc, __kernel_text_address(pc)); return 0; } - if (!kallsyms_lookup_size_offset(pc, &size, &ofs)) + if (!kallsyms_lookup_size_offset(pc, &size, &ofs)) { + STACK_TRC("%s %d:\n", __FUNCTION__, __LINE__); return 0; + } /* * Return ra if an exception occured at the first instruction */ if (unlikely(ofs == 0)) { pc = *ra; *ra = 0; + STACK_TRC("%s %d:\n", __FUNCTION__, __LINE__); return pc; } + STACK_TRC("%s %d: pc=%lx ofs=%lx\n", __FUNCTION__, __LINE__, pc, ofs); info.func = (void *)(pc - ofs); info.func_size = ofs; /* analyze from start to ofs */ leaf = get_frame_info(&info); - if (leaf < 0) + if (leaf < 0) { + STACK_TRC("%s %d:\n", __FUNCTION__, __LINE__); return 0; - + } if (*sp < stack_page || - *sp + info.frame_size > stack_page + THREAD_SIZE - 32) + *sp + info.frame_size > stack_page + THREAD_SIZE - 32) { + STACK_TRC("%s %d:\n", __FUNCTION__, __LINE__); return 0; - - if (leaf) + } + if (leaf) { /* * For some extreme cases, get_frame_info() can * consider wrongly a nested function as a leaf @@ -433,11 +564,13 @@ * same value. */ pc = pc != *ra ? *ra : 0; - else + } else { pc = ((unsigned long *)(*sp))[info.pc_offset]; - + STACK_TRC("%s %d: pc %lx pc_offset = %d\n", __FUNCTION__, __LINE__, pc, info.pc_offset); + } *sp += info.frame_size; *ra = 0; + STACK_TRC("%s %d: %lx %d\n", __FUNCTION__, __LINE__, pc, __kernel_text_address(pc)); return __kernel_text_address(pc) ? pc : 0; } #endif