一、问题现象

高低温测试中出现两例死机问题,问题的指向于charger模块

二、问题分析

2.1 dmesg_TZ.txt

125008.185224:   Unexpected kernel BRK exception at EL1
125008.185232:   Internal error: BRK handler: fffffffff2005512 [#1] PREEMPT SMP
125008.185333:   Skip md ftrace buffer dump for: 0x1609e0

125008.186235:   CPU: 1 PID: 25688 Comm: kworker/1:3 Tainted: G        WC OE     5.15.153 #1
125008.186242:   Hardware name: Qualcomm Technologies, Inc. KHAJE IDP nopmi creek (DT)
125008.186246:   Workqueue: events status_change_work.c319aeb9914bc6f89784e640f4933ac6.cfi_jt [main_chg]
125008.186297:   pstate: 20400005 (nzCv daif +PAN -UAO -TCO -DIT -SSBS BTYPE=--)
125008.186303:   pc : status_change_work+0x8f4/0x8fc [main_chg]
125008.186338:   lr : status_change_work+0x478/0x8fc [main_chg]
125008.186372:   sp : ffffffc029293d00
125008.186376:   x29: ffffffc029293d20 x28: ffffff809ccab528 x27: ffffff8121655350
125008.186388:   x26: ffffff80d8f8c110 x25: 0000000000000000 x24: 0000000000448ae0
125008.186398:   x23: ffffff8178f45405 x22: ffffff805a426480 x21: 000000000000ff01
125008.186409:   x20: ffffffe8a7912000 x19: 0000000000000000 x18: ffffffc01f72d020
125008.186419:   x17: 000000000005bf68 x16: 0000000000000000 x15: 0000000000000001
125008.186429:   x14: ffffff805fbb2600 x13: 0000000000007ff3 x12: 0000000000003fb1
125008.186439:   x11: 000000000000ffff x10: 0000000000003fb1 x9 : ffffffe8a7912000
125008.186449:   x8 : 0000000000000320 x7 : ffffff81405cd400 x6 : ffffffc0292937ac
125008.186460:   x5 : 0000000000000000 x4 : 0000000000000000 x3 : ffffffc0292939b0
125008.186469:   x2 : ffffffe8a7229050 x1 : ffffffc029293d0c x0 : 0000000000000000
125008.186480:   Call trace:
125008.186483:    status_change_work+0x8f4/0x8fc [main_chg]
125008.186517:    process_one_work+0x1a4/0x4b4
125008.186528:    worker_thread+0x29c/0x500
125008.186534:    kthread+0x164/0x1c8
125008.186541:    ret_from_fork+0x10/0x20
125008.186552:   Code: 0b130104 97143304 17fffe27 9754fcd4 (d42aa240) 
125008.186558:   ---[ end trace dbc7e2b75e341aef ]---

关键点:

  • 问题模块:main_chg
  • 问题代码行:status_change_work+0x8f4
  • 问题cpu: CPU: 1

2.2 trace32分析

正常恢复堆栈后发现异常点

可以看出代码是跳转到0xffffffdaeebad754处执行了brk的动作

我们朝前看代码,可以找到有一处b.ge 0xffffffdaeebad754,有且仅有一处,故问题点就在此处

这段的逻辑代码如下:

    ret = power_supply_get_property(chip->batt_psy, POWER_SUPPLY_PROP_CYCLE_COUNT, &pval);
	if (ret < 0) {
		lc_err("Couldn't read batt voltage_now, ret=%d\n", ret);
	}
	cyclecount =  pval.intval;   // handle_jeita中获取cyclecount


	while (cyclecount >= cc_cv_cycle_count[j])   //循环与cc_cv_cyle_count的值比较
		j++;

而cc_cv_cycle_count的定义如下:

#define CC_CV_CYCLE_COUNT_MAX 4
int cc_cv_cycle_count[CC_CV_CYCLE_COUNT_MAX] = {0,100,300,800};

其实这段逻辑的意思就是判断cyclecount的值的区间,来设置j值。到这里我们其实就能够想到有可能的问题:数组越界!!!!

一旦cyclecount的值大于了800,就会出现数组越界问题

下面我们来证实一下:

从这张图我们可以看到while循环,循环了3次,在第四次的时候发生brk。而比较的双方就是w21和w8,查看汇编我们就可以得知,cyclecount的值就是w21寄存器的值。

查看w21寄存器的赋值到这个while循环以及后续发生brk时刻,w21寄存器并未再次赋值,故此时W21寄存器里的值就是cyclecount的值

而这个值很明显就是异常的,大于了800

  1. 初始值:cyclecount = 65281, j = 0
  2. 第一次检查:65281 >= 0,成立,j++ 后 j = 1
  3. 第二次检查:65281 >= 100,成立,j++ 后 j = 2
  4. 第三次检查:65281 >= 300,成立,j++ 后 j = 3
  5. 第四次检查:65281 >= 800,成立,j++ 后 j = 4
  6. 第五次检查:65281 >= cc_cv_cycle_count[4],此时数组越界。

从dmesg中的BRK的前夕日志可以看到:

对比正常的日志:

cyclecount的值不可能一下子从1变成了0xFF01,故怀疑发生了Bitflip

虽然bitflip的问题比较难以修复,但是这里可以增加一下兼容性代码来屏蔽数组越界问题。

判断这个cyclecount的值是否大于0 且小于800 ,不符合的认为是异常值 做特别处理

三、解决方案

  1. 怀疑为bitflip问题
  2. 兼容性方案:判断这个cyclecount的值是否大于0 且小于800 ,不符合的认为是异常值 做特别处理