예제 #1
0
inline void aee_print_regs(struct pt_regs *regs)
{
    aee_nested_printf("[r0-r15,cpsr]%08lx %08lx %08lx %08lx %08lx %08lx %08lx "
                      "%08lx %08lx %08lx %08lx %08lx %08lx %08lx %08lx %08lx %08lx\n",
                      regs->ARM_r0, regs->ARM_r1, regs->ARM_r2,
                      regs->ARM_r3, regs->ARM_r4, regs->ARM_r5,
                      regs->ARM_r6, regs->ARM_r7, regs->ARM_r8,
                      regs->ARM_r9, regs->ARM_r10,
                      regs->ARM_fp, regs->ARM_ip, regs->ARM_sp,
                      regs->ARM_lr, regs->ARM_pc, regs->ARM_cpsr);
}
예제 #2
0
inline void aee_print_bt(struct pt_regs *regs)
{
    int i;
    unsigned long high, bottom, fp;
    struct stackframe cur_frame;
    struct pt_regs *exp_regs;
    bottom = regs->ARM_sp;
    if (!virt_addr_valid(bottom)) {
        aee_nested_printf("invalid sp[%x]\n", regs);
        return;
    }
    high = ALIGN(bottom, THREAD_SIZE);
    cur_frame.lr = regs->ARM_lr;
    cur_frame.fp = regs->ARM_fp;
    cur_frame.pc = regs->ARM_pc;
    for (i = 0; i < AEE_MAX_EXCP_FRAME; i++) {
        fp = cur_frame.fp;
        if ((fp < (bottom + 12)) || ((fp + 4) >= (high + 8192))) {
            if (fp != 0)
                aee_nested_printf("fp(%x)", fp);
            break;
        }
        cur_frame.fp = *(unsigned long *)(fp - 12);
        cur_frame.lr = *(unsigned long *)(fp - 4);
        cur_frame.pc = *(unsigned long *)fp;
        if (!
                ((cur_frame.lr >= (PAGE_OFFSET + THREAD_SIZE))
                 && virt_addr_valid(cur_frame.lr)))
            break;
        if (in_exception_text(cur_frame.pc)) {
            exp_regs = (struct pt_regs *)(fp + 4);
            cur_frame.lr = exp_regs->ARM_pc;
        }
        aee_nested_printf("%08lx, ", cur_frame.lr);
    }
    aee_nested_printf("\n");
    return;
}
struct ipanic_header *ipanic_header(void)
{
	int i;
	struct ipanic_data_header *dheader;
	int next_offset;
	if (iheader)
		return iheader;
	iheader = &ipanic_hdr;
	iheader->magic = AEE_IPANIC_MAGIC;
	iheader->version = AEE_IPANIC_PHDR_VERSION;
	if (ipanic_msdc_info(iheader)) {
		LOGE("ipanic initialize msdc fail.");
		aee_nested_printf("$");
		return NULL;
	}
	iheader->size = sizeof(struct ipanic_header);
	iheader->datas = 0;
#if 1
	iheader->dhblk = ALIGN(sizeof(struct ipanic_data_header), iheader->blksize);
#else
	iheader->dhblk = 0;
#endif
	next_offset = ALIGN(sizeof(struct ipanic_header), iheader->blksize);
	for (i = IPANIC_DT_HEADER + 1; i < IPANIC_DT_RESERVED31; i++) {
		dheader = &iheader->data_hdr[i];
		dheader->type = i;
		dheader->valid = 0;
		dheader->used = 0;
		strncpy(dheader->name, ipanic_dt_ops[i].string, 32);
		if (ipanic_dt_active(i) && ipanic_dt_ops[i].size) {
			dheader->encrypt = ipanic_dt_encrypt(i);
			dheader->offset = next_offset + iheader->dhblk;
			dheader->total = ALIGN(ipanic_dt_ops[i].size, iheader->blksize);
			if (iheader->partsize < (dheader->offset + dheader->total)) {
				LOGW("skip %s[%x@%x>%x]\n", dheader->name, dheader->total,
				     dheader->offset, iheader->partsize);
				dheader->offset = INT_MAX;
				dheader->total = 0;
				continue;
			}
			next_offset += dheader->total + iheader->dhblk;
		} else {
			dheader->offset = INT_MAX;
			dheader->total = 0;
		}
	}
	ipanic_header_to_sd(0);
	return iheader;
}
예제 #4
0
inline int aee_nested_save_stack(struct pt_regs *regs)
{
    int len = 0;
    if (!virt_addr_valid(regs->ARM_sp))
        return -1;
    aee_nested_printf("[%08lx %08lx]\n", regs->ARM_sp, regs->ARM_sp + 256);

    len = aee_dump_stack_top_binary(nested_panic_buf, sizeof(nested_panic_buf),
                                    regs->ARM_sp, regs->ARM_sp + 256);
    if (len > 0)
        aee_sram_fiq_save_bin(nested_panic_buf, len);
    else
        print_error_msg(len);
    return len;
}
예제 #5
0
struct ipanic_header *ipanic_header_from_sd(unsigned int offset, unsigned int magic)
{
	struct ipanic_data_header *dheader;
	int dt;
	char str[256];
	size_t size = 0;
	struct ipanic_header *header;
	struct ipanic_data_header dheader_header = {
		.type = IPANIC_DT_HEADER,
		.offset = offset,
		.used = sizeof(struct ipanic_header),
	};
	header = (struct ipanic_header *)ipanic_data_from_sd(&dheader_header, 0);
	if (IS_ERR_OR_NULL((void *)header)) {
		LOGD("read header failed[%ld]\n", PTR_ERR((void *)header));
		header = NULL;
	} else if (header->magic != magic) {
		LOGD("no ipanic data[%x]\n", header->magic);
		kfree(header);
		header = NULL;
		ipanic_erase();
	} else {
		for (dt = IPANIC_DT_HEADER + 1; dt < IPANIC_DT_RESERVED31; dt++) {
			dheader = &header->data_hdr[dt];
			if (dheader->valid) {
				size += snprintf(str + size, 256 - size, "%s[%x@%x],",
						 dheader->name, dheader->used, dheader->offset);
			}
		}
		LOGD("ipanic data available^v^%s^v^\n", str);
	}
	return header;
}

struct aee_oops *ipanic_oops_from_sd(void)
{
	struct aee_oops *oops = NULL;
	struct ipanic_header *hdr = NULL;
	struct ipanic_data_header *dheader;
	char *data;
	int i;
	hdr = ipanic_header_from_sd(0, AEE_IPANIC_MAGIC);
	if (hdr == NULL) {
		return NULL;
	}

	oops = aee_oops_create(AE_DEFECT_FATAL, AE_KE, IPANIC_MODULE_TAG);
	if (oops == NULL) {
		LOGE("%s: can not allocate buffer\n", __func__);
		return NULL;
	}

	for (i = IPANIC_DT_HEADER + 1; i < IPANIC_DT_RESERVED31; i++) {
		dheader = &hdr->data_hdr[i];
		if (dheader->valid == 0) {
			continue;
		}
		data = ipanic_data_from_sd(dheader, 1);
		if (data) {
			switch (i) {
			case IPANIC_DT_KERNEL_LOG:
				oops->console = data;
				oops->console_len = dheader->used;
				break;
			case IPANIC_DT_MINI_RDUMP:
				oops->mini_rdump = data;
				oops->mini_rdump_len = dheader->used;
				break;
			case IPANIC_DT_MAIN_LOG:
				oops->android_main = data;
				oops->android_main_len = dheader->used;
				break;
			case IPANIC_DT_SYSTEM_LOG:
				oops->android_system = data;
				oops->android_system_len = dheader->used;
				break;
			case IPANIC_DT_EVENTS_LOG:
				/* Todo .. */
				break;
			case IPANIC_DT_RADIO_LOG:
				oops->android_radio = data;
				oops->android_radio_len = dheader->used;
				break;
			case IPANIC_DT_CURRENT_TSK:
				memcpy(oops->process_path, data, sizeof(struct aee_process_info));
				break;
			case IPANIC_DT_MMPROFILE:
				oops->mmprofile = data;
				oops->mmprofile_len = dheader->used;
				break;
			default:
				LOGI("%s: [%d] NOT USED.\n", __func__, i);
			}
		} else {
			LOGW("%s: read %s failed, %x@%x\n", __func__,
			     dheader->name, dheader->used, dheader->offset);
		}
	}
	return oops;
}

int ipanic(struct notifier_block *this, unsigned long event, void *ptr)
{
	struct ipanic_data_header *dheader;
	struct kmsg_dumper dumper;
	ipanic_atf_log_rec_t atf_log = {ATF_LOG_SIZE, 0, 0};
	int dt;
	int errno;
	struct ipanic_header *ipanic_hdr;
	aee_rr_rec_fiq_step(AEE_FIQ_STEP_KE_IPANIC_START);
	aee_rr_rec_exp_type(2);
	bust_spinlocks(1);
	spin_lock_irq(&ipanic_lock);
	aee_disable_api();
	mrdump_mini_ke_cpu_regs(NULL);
	ipanic_mrdump_mini(AEE_REBOOT_MODE_KERNEL_PANIC, "kernel PANIC");
	if (!ipanic_data_is_valid(IPANIC_DT_KERNEL_LOG)) {
		ipanic_klog_region(&dumper);
		errno = ipanic_data_to_sd(IPANIC_DT_KERNEL_LOG, &dumper);
		if (errno == -1)
			aee_nested_printf("$");
	}
	ipanic_klog_region(&dumper);
	errno = ipanic_data_to_sd(IPANIC_DT_OOPS_LOG, &dumper);
	if (errno == -1)
		aee_nested_printf("$");
	ipanic_data_to_sd(IPANIC_DT_CURRENT_TSK, 0);
	/* kick wdt after save the most critical infos */
	ipanic_kick_wdt();
	ipanic_data_to_sd(IPANIC_DT_MAIN_LOG, (void *)1);
	ipanic_data_to_sd(IPANIC_DT_SYSTEM_LOG, (void *)4);
	ipanic_data_to_sd(IPANIC_DT_EVENTS_LOG, (void *)2);
	ipanic_data_to_sd(IPANIC_DT_RADIO_LOG, (void *)3);
	aee_wdt_dump_info();
	ipanic_klog_region(&dumper);
	ipanic_data_to_sd(IPANIC_DT_WDT_LOG, &dumper);
#ifdef CONFIG_MTK_WQ_DEBUG
	mt_dump_wq_debugger();
#endif
	ipanic_klog_region(&dumper);
	ipanic_data_to_sd(IPANIC_DT_WQ_LOG, &dumper);
	ipanic_data_to_sd(IPANIC_DT_MMPROFILE, 0);
	ipanic_data_to_sd(IPANIC_DT_ATF_LOG, &atf_log);
	errno = ipanic_header_to_sd(0);
	if (!IS_ERR(ERR_PTR(errno)))
		mrdump_mini_ipanic_done();
	ipanic_klog_region(&dumper);
	ipanic_data_to_sd(IPANIC_DT_LAST_LOG, &dumper);
	LOGD("ipanic done^_^");
	ipanic_hdr = ipanic_header();
	for (dt = IPANIC_DT_HEADER + 1; dt < IPANIC_DT_RESERVED31; dt++) {
		dheader = &ipanic_hdr->data_hdr[dt];
		if (dheader->valid) {
			LOGD("%s[%x@%x],", dheader->name, dheader->used, dheader->offset);
		}
	}
	LOGD("^_^\n");
	aee_rr_rec_fiq_step(AEE_FIQ_STEP_KE_IPANIC_DONE);

	return NOTIFY_DONE;
}

void ipanic_recursive_ke(struct pt_regs *regs, struct pt_regs *excp_regs, int cpu)
{
	int errno;
	struct kmsg_dumper dumper;
	aee_nested_printf("minidump\n");
	aee_rr_rec_exp_type(3);
	bust_spinlocks(1);
	flush_cache_all();
#ifdef __aarch64__
	cpu_cache_off();
#else
	cpu_proc_fin();
#endif
	mrdump_mini_ke_cpu_regs(excp_regs);
	mrdump_mini_per_cpu_regs(cpu, regs);
	flush_cache_all();
	ipanic_mrdump_mini(AEE_REBOOT_MODE_NESTED_EXCEPTION, "Nested Panic");

	ipanic_data_to_sd(IPANIC_DT_CURRENT_TSK, 0);
	ipanic_kick_wdt();
	ipanic_klog_region(&dumper);
	ipanic_data_to_sd(IPANIC_DT_KERNEL_LOG, &dumper);
	errno = ipanic_header_to_sd(0);
	if (!IS_ERR(ERR_PTR(errno)))
		mrdump_mini_ipanic_done();
	if (ipanic_dt_active(IPANIC_DT_RAM_DUMP)) {
		aee_nested_printf("RAMDUMP.\n");
		__mrdump_create_oops_dump(AEE_REBOOT_MODE_NESTED_EXCEPTION, excp_regs,
					  "Nested Panic");
	}
	bust_spinlocks(0);
}
예제 #6
0
void aee_stop_nested_panic(struct pt_regs *regs)
{
    struct thread_info *thread = current_thread_info();
    int len = 0;
    int timeout = 1000000;
    int res = 0, cpu = 0;
    struct wd_api *wd_api = NULL;
    struct pt_regs *excp_regs = NULL;
    int prev_fiq_step = aee_rr_curr_fiq_step();
    /* everytime enter nested_panic flow, add 8 */
    static int step_base = -8;
    step_base = step_base < 48 ? step_base + 8 : 56;

    aee_rec_step_nested_panic(step_base);
    local_irq_disable();
    preempt_disable();

    aee_rec_step_nested_panic(step_base + 1);
    cpu = get_HW_cpuid();
    aee_rec_step_nested_panic(step_base + 2);
    /*nested panic may happens more than once on many/single cpus */
    if (atomic_read(&nested_panic_time) < 3)
        aee_nested_printf("\nCPU%dpanic%d@%d\n", cpu, nested_panic_time, prev_fiq_step);
    atomic_inc(&nested_panic_time);

    switch (atomic_read(&nested_panic_time)) {
    case 2:
        aee_print_regs(regs);
        aee_nested_printf("backtrace:");
        aee_print_bt(regs);
        break;

    /* must guarantee Only one cpu can run here */
    /* first check if thread valid */
    case 1:
        if (virt_addr_valid(thread) && virt_addr_valid(thread->regs_on_excp)) {
            excp_regs = thread->regs_on_excp;
        } else {
            /* if thread invalid, which means wrong sp or thread_info corrupted,
               check global aee_excp_regs instead */
            aee_nested_printf("invalid thread [%x], excp_regs [%x]\n", thread,
                              aee_excp_regs);
            excp_regs = aee_excp_regs;
        }

        aee_nested_printf("Nested panic\n");
        if (excp_regs) {
            aee_nested_printf("Previous\n");
            aee_print_regs(excp_regs);
        }
        aee_nested_printf("Current\n");
        aee_print_regs(regs);

        /*should not print stack info. this may overwhelms ram console used by fiq */
        if (0 != in_fiq_handler()) {
            aee_nested_printf("in fiq hander\n");
        } else {
            /*Dump first panic stack */
            aee_nested_printf("Previous\n");
            if (excp_regs) {
                len = aee_nested_save_stack(excp_regs);
                aee_nested_printf("\nbacktrace:");
                aee_print_bt(excp_regs);
            }

            /*Dump second panic stack */
            aee_nested_printf("Current\n");
            if (virt_addr_valid(regs)) {
                len = aee_nested_save_stack(regs);
                aee_nested_printf("\nbacktrace:");
                aee_print_bt(regs);
            }
        }
        aee_rec_step_nested_panic(step_base + 5);
        ipanic_recursive_ke(regs, excp_regs, cpu);

        aee_rec_step_nested_panic(step_base + 6);
        /* we donot want a FIQ after this, so disable hwt */
        res = get_wd_api(&wd_api);
        if (res) {
            aee_nested_printf("get_wd_api error\n");
        } else {
            wd_api->wd_aee_confirm_hwreboot();
        }
        aee_rec_step_nested_panic(step_base + 7);
        break;
    default:
        break;
    }
    /* waiting for the WDT timeout */
    while (1) {
        /* output to UART directly to avoid printk nested panic */
        /* mt_fiq_printf("%s hang here%d\t", __func__, i++); */
        while (timeout--) {
            udelay(1);
        }
        timeout = 1000000;
    }
}
예제 #7
0
void aee_stop_nested_panic(struct pt_regs *regs)
{
	struct thread_info *thread = current_thread_info();
    int i = 0;
    int len = 0;
    int timeout = 1000000;
   
    local_irq_disable();
    preempt_disable();


    /*Data abort handler data abort again on many cpu.
      Since ram console api is lockless, this should be prevented*/
    if(atomic_xchg(&nested_panic_time, 1) != 0) {
        aee_nested_printf("multicore enters nested panic\n");
        goto out; 
    }

    mtk_wdt_restart(WK_WDT_LOC_TYPE_NOLOCK);
    hw_reboot_mode(); 

    /*must guarantee Only one cpu can run here*/
	aee_nested_printf("Nested panic\n");
	aee_nested_printf("Log for the previous panic:\n");
    aee_nested_printf("pc: %08lx lr: %08lx psr: %08lx\n",
			((struct pt_regs *)thread->regs_on_excp)->ARM_pc, 
			((struct pt_regs *)thread->regs_on_excp)->ARM_lr, 
			((struct pt_regs *)thread->regs_on_excp)->ARM_cpsr);
    aee_nested_printf("sp: %08lx ip: %08lx fp: %08lx\n",
			((struct pt_regs *)thread->regs_on_excp)->ARM_sp, 
			((struct pt_regs *)thread->regs_on_excp)->ARM_ip, 
			((struct pt_regs *)thread->regs_on_excp)->ARM_fp);
	aee_nested_printf("r10: %08lx r9: %08lx r8: %08lx\n",
			((struct pt_regs *)thread->regs_on_excp)->ARM_r10, 
			((struct pt_regs *)thread->regs_on_excp)->ARM_r9, 
			((struct pt_regs *)thread->regs_on_excp)->ARM_r8);
	aee_nested_printf("r7: %08lx r6: %08lx r5: %08lx r4: %08lx\n",
			((struct pt_regs *)thread->regs_on_excp)->ARM_r7, 
			((struct pt_regs *)thread->regs_on_excp)->ARM_r6, 
			((struct pt_regs *)thread->regs_on_excp)->ARM_r5, 
			((struct pt_regs *)thread->regs_on_excp)->ARM_r4);
	aee_nested_printf("r3: %08lx r2: %08lx r1: %08lx r0: %08lx\n",
			((struct pt_regs *)thread->regs_on_excp)->ARM_r3, 
			((struct pt_regs *)thread->regs_on_excp)->ARM_r2, 
			((struct pt_regs *)thread->regs_on_excp)->ARM_r1, 
			((struct pt_regs *)thread->regs_on_excp)->ARM_r0);

	aee_nested_printf("Log for the current panic:\n");
	aee_nested_printf("pc: %08lx lr: %08lx psr: %08lx\n",
			regs->ARM_pc, 
			regs->ARM_lr, 
			regs->ARM_cpsr);
	aee_nested_printf("sp: %08lx ip: %08lx fp: %08lx\n",
			regs->ARM_sp, 
			regs->ARM_ip, 
			regs->ARM_fp);
	aee_nested_printf("r10: %08lx r9: %08lx r8: %08lx\n",
			regs->ARM_r10, 
			regs->ARM_r9, 
			regs->ARM_r8);
	aee_nested_printf("r7: %08lx r6: %08lx r5: %08lx r4: %08lx\n",
			regs->ARM_r7, 
			regs->ARM_r6, 
			regs->ARM_r5, 
			regs->ARM_r4);
	len = aee_nested_printf("r3: %08lx r2: %08lx r1: %08lx r0: %08lx\n",
			regs->ARM_r3, 
			regs->ARM_r2, 
			regs->ARM_r1, 
			regs->ARM_r0);

    /*should not print stack info. this may overwhelms ram console used by fiq*/
    if(0!= in_fiq_handler()) {
            goto out;        
    }

    aee_nested_printf("stack [%08lx %08lx]", 
                      ((struct pt_regs *)thread->regs_on_excp)->ARM_sp,
                      ((struct pt_regs *)thread->regs_on_excp)->ARM_sp + 512);

    /*Dump first panic stack*/
    len = aee_dump_stack_top_binary(nested_panic_buf,
                             sizeof(nested_panic_buf), 
                             ((struct pt_regs *)thread->regs_on_excp)->ARM_sp,
                             ((struct pt_regs *)thread->regs_on_excp)->ARM_sp + 512
                            );
    

    if(len > 0) {
        aee_sram_fiq_save_bin(nested_panic_buf, len);
    }else{
        print_error_msg(len);
    }
    
    aee_nested_printf("stack [%08lx %08lx]", regs->ARM_sp,
                        regs->ARM_sp + 256);

    /*Dump second panic stack*/
    len  = aee_dump_stack_top_binary(nested_panic_buf, 
                            sizeof(nested_panic_buf), 
                            regs->ARM_sp, 
                            regs->ARM_sp + 256);


    if(len > 0) {
        aee_sram_fiq_save_bin(nested_panic_buf, len);
    }else {
        print_error_msg(len);
    }

out:
   /* waiting for the WDT timeout */
	while (1)
    {
        printk("%s hang here%d\t", __func__, i++);
        while(timeout--)
        {
            udelay(1);
        }
        timeout = 1000000;
    }

}