一、问题现象
高低温测试中出现两例死机问题,问题的指向于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
- 初始值:cyclecount = 65281, j = 0
- 第一次检查:65281 >= 0,成立,j++ 后 j = 1
- 第二次检查:65281 >= 100,成立,j++ 后 j = 2
- 第三次检查:65281 >= 300,成立,j++ 后 j = 3
- 第四次检查:65281 >= 800,成立,j++ 后 j = 4
- 第五次检查:65281 >= cc_cv_cycle_count[4],此时数组越界。
从dmesg中的BRK的前夕日志可以看到:
对比正常的日志:
cyclecount的值不可能一下子从1变成了0xFF01,故怀疑发生了Bitflip
虽然bitflip的问题比较难以修复,但是这里可以增加一下兼容性代码来屏蔽数组越界问题。
判断这个cyclecount的值是否大于0 且小于800 ,不符合的认为是异常值 做特别处理
三、解决方案
- 怀疑为bitflip问题
- 兼容性方案:判断这个cyclecount的值是否大于0 且小于800 ,不符合的认为是异常值 做特别处理