From a025f637c3cdd32b378737fab3bf0d570ec08090 Mon Sep 17 00:00:00 2001 From: Sarangdhar Joshi <spjoshi@codeaurora.org> Date: Tue, 22 Sep 2015 12:10:09 -0700 Subject: [PATCH] lrdpv2: Compute program counter based on other GPRs for msm8996 In certain reset scenarios, Program Counter value is not retained across reset. Implement logic to approximate Program Counter based on other General Purpose Registers. This should help get the CPU context from crash dumps when original Program Counter value is NULL or invalid. Change-Id: Iacffc4103df1d482682bc7c1e6b83a55981ca78d --- linux-ramdump-parser-v2/bitops.py | 9 +- linux-ramdump-parser-v2/watchdog_v2.py | 396 +++++++++++++++++++++++-- 2 files changed, 385 insertions(+), 20 deletions(-) diff --git a/linux-ramdump-parser-v2/bitops.py b/linux-ramdump-parser-v2/bitops.py index dc2d310..4f9da69 100644 --- a/linux-ramdump-parser-v2/bitops.py +++ b/linux-ramdump-parser-v2/bitops.py @@ -1,4 +1,4 @@ -# Copyright (c) 2013, The Linux Foundation. All rights reserved. +# Copyright (c) 2013-2015, The Linux Foundation. All rights reserved. # # This program is free software; you can redistribute it and/or modify # it under the terms of the GNU General Public License version 2 and @@ -18,3 +18,10 @@ def bm(msb, lsb): def bvalsel(msb, lsb, val): 'Masks and returns the bits from msb to lsb in val' return ((val & bm(msb, lsb)) >> lsb) + + +def is_set(val, bit): + 'Checks whether particular bit is set in val' + if (val >> bit) & 0x1: + return True + return False diff --git a/linux-ramdump-parser-v2/watchdog_v2.py b/linux-ramdump-parser-v2/watchdog_v2.py index 659663e..e01636d 100644 --- a/linux-ramdump-parser-v2/watchdog_v2.py +++ b/linux-ramdump-parser-v2/watchdog_v2.py @@ -1,4 +1,4 @@ -# Copyright (c) 2012-2014, The Linux Foundation. All rights reserved. +# Copyright (c) 2012-2015, The Linux Foundation. All rights reserved. # # This program is free software; you can redistribute it and/or modify # it under the terms of the GNU General Public License version 2 and @@ -12,8 +12,10 @@ import struct import re from print_out import print_out_str +from bitops import is_set -# (name from tz dump, corresponding T32 register, whether or not to print_out_str (the function name)) +# name from tz dump, corresponding T32 register, whether or not to +# print_out_str (the function name) sysdbg_cpu64_register_names_default = [ ('x0', 'x0', False), ('x1', 'x1', False), @@ -302,6 +304,250 @@ sysdbg_cpu64_ctxt_regs_type_v1_3 = ''.join([ 'Q', # __reserved2 ]) +sysdbg_cpu64_register_names_v1_4 = [ + ('x0', 'x0', False), + ('x1', 'x1', False), + ('x2', 'x2', False), + ('x3', 'x3', False), + ('x4', 'x4', False), + ('x5', 'x5', False), + ('x6', 'x6', False), + ('x7', 'x7', False), + ('x8', 'x8', False), + ('x9', 'x9', False), + ('x10', 'x10', False), + ('x11', 'x11', False), + ('x12', 'x12', False), + ('x13', 'x13', False), + ('x14', 'x14', False), + ('x15', 'x15', False), + ('x16', 'x16', False), + ('x17', 'x17', False), + ('x18', 'x18', False), + ('x19', 'x19', False), + ('x20', 'x20', False), + ('x21', 'x21', False), + ('x22', 'x22', False), + ('x23', 'x23', False), + ('x24', 'x24', False), + ('x25', 'x25', False), + ('x26', 'x26', False), + ('x27', 'x27', False), + ('x28', 'x28', False), + ('x29', 'x29', False), + ('x30', 'x30', True), + ('pc', 'pc', True), + ('currentEL', None, False), + ('sp_el3', 'sp_el3', False), + ('elr_el3', 'elr_el3', True), + ('spsr_el3', 'spsr_el3', False), + ('sp_el2', 'sp_el2', False), + ('elr_el2', 'elr_el2', True), + ('spsr_el2', 'spsr_el2', False), + ('sp_el1', 'sp_el1', False), + ('elr_el1', 'elr_el1', True), + ('spsr_el1', 'spsr_el1', False), + ('sp_el0', 'sp_el0', False), + ('dirty_flag', 'dirty_flag', False), + ('PStateMisc', 'PStateMisc', False), + ('trust0', 'trust0', False), + ('trust1', 'trust1', False), + ('trust2', 'trust2', False), + ('__reserved1', '__reserved1', False), + ('__reserved2', '__reserved2', False), + ('__reserved3', '__reserved3', False), + ('__reserved4', '__reserved4', False), +] + +sysdbg_cpu64_ctxt_regs_type_v1_4 = ''.join([ + 'Q', # x0 + 'Q', # x1 + 'Q', # x2 + 'Q', # x3 + 'Q', # x4 + 'Q', # x5 + 'Q', # x6 + 'Q', # x7 + 'Q', # x8 + 'Q', # x9 + 'Q', # x10 + 'Q', # x11 + 'Q', # x12 + 'Q', # x13 + 'Q', # x14 + 'Q', # x15 + 'Q', # x16 + 'Q', # x17 + 'Q', # x18 + 'Q', # x19 + 'Q', # x20 + 'Q', # x21 + 'Q', # x22 + 'Q', # x23 + 'Q', # x24 + 'Q', # x25 + 'Q', # x26 + 'Q', # x27 + 'Q', # x28 + 'Q', # x29 + 'Q', # x30 + 'Q', # pc + 'Q', # currentEL + 'Q', # sp_el3 + 'Q', # elr_el3 + 'Q', # spsr_el3 + 'Q', # sp_el2 + 'Q', # elr_el2 + 'Q', # spsr_el2 + 'Q', # sp_el1 + 'Q', # elr_el1 + 'Q', # spsr_el1 + 'Q', # sp_el0 + 'Q', # dirty_flag + 'Q', # PStateMisc + 'Q', # trust0 + 'Q', # trust1 + 'Q', # trust2 + 'Q', # __reserved1 + 'Q', # __reserved2 + 'Q', # __reserved3 + 'Q', # __reserved4 +]) + +sysdbg_neon128_register_names_v1_4 = [ + ('q0-lower', 'v0-lower', False), + ('q0-upper', 'v0-upper', False), + ('q1-lower', 'v1-lower', False), + ('q1-upper', 'v1-upper', False), + ('q2-lower', 'v2-lower', False), + ('q2-upper', 'v2-upper', False), + ('q3-lower', 'v3-lower', False), + ('q3-upper', 'v3-upper', False), + ('q4-lower', 'v4-lower', False), + ('q4-upper', 'v4-upper', False), + ('q5-lower', 'v5-lower', False), + ('q5-upper', 'v5-upper', False), + ('q6-lower', 'v6-lower', False), + ('q6-upper', 'v6-upper', False), + ('q7-lower', 'v7-lower', False), + ('q7-upper', 'v7-upper', False), + ('q8-lower', 'v8-lower', False), + ('q8-upper', 'v8-upper', False), + ('q9-lower', 'v9-lower', False), + ('q9-upper', 'v9-upper', False), + ('q10-lower', 'v10-lower', False), + ('q10-upper', 'v10-upper', False), + ('q11-lower', 'v11-lower', False), + ('q11-upper', 'v11-upper', False), + ('q12-lower', 'v12-lower', False), + ('q12-upper', 'v12-upper', False), + ('q13-lower', 'v13-lower', False), + ('q13-upper', 'v13-upper', False), + ('q14-lower', 'v14-lower', False), + ('q14-upper', 'v14-upper', False), + ('q15-lower', 'v15-lower', False), + ('q15-upper', 'v15-upper', False), + ('q16-lower', 'v16-lower', False), + ('q16-upper', 'v16-upper', False), + ('q17-lower', 'v17-lower', False), + ('q17-upper', 'v17-upper', False), + ('q18-lower', 'v18-lower', False), + ('q18-upper', 'v18-upper', False), + ('q19-lower', 'v19-lower', False), + ('q19-upper', 'v19-upper', False), + ('q20-lower', 'v20-lower', False), + ('q20-upper', 'v20-upper', False), + ('q21-lower', 'v21-lower', False), + ('q21-upper', 'v21-upper', False), + ('q22-lower', 'v22-lower', False), + ('q22-upper', 'v22-upper', False), + ('q23-lower', 'v23-lower', False), + ('q23-upper', 'v23-upper', False), + ('q24-lower', 'v24-lower', False), + ('q24-upper', 'v24-upper', False), + ('q25-lower', 'v25-lower', False), + ('q25-upper', 'v25-upper', False), + ('q26-lower', 'v26-lower', False), + ('q26-upper', 'v26-upper', False), + ('q27-lower', 'v27-lower', False), + ('q27-upper', 'v27-upper', False), + ('q28-lower', 'v28-lower', False), + ('q28-upper', 'v28-upper', False), + ('q29-lower', 'v29-lower', False), + ('q29-upper', 'v29-upper', False), + ('q30-lower', 'v30-lower', False), + ('q30-upper', 'v30-upper', False), + ('q31-lower', 'v31-lower', False), + ('q31-upper', 'v31-upper', False), +] + +sysdbg_neon128_register_type_v1_4 = ''.join([ + 'Q', # q0-lower + 'Q', # q0-upper + 'Q', # q1-lower + 'Q', # q1-upper + 'Q', # q2-lower + 'Q', # q2-upper + 'Q', # q3-lower + 'Q', # q3-upper + 'Q', # q4-lower + 'Q', # q4-upper + 'Q', # q5-lower + 'Q', # q5-upper + 'Q', # q6-lower + 'Q', # q6-upper + 'Q', # q7-lower + 'Q', # q7-upper + 'Q', # q8-lower + 'Q', # q8-upper + 'Q', # q9-lower + 'Q', # q9-upper + 'Q', # q10-lower + 'Q', # q10-upper + 'Q', # q11-lower + 'Q', # q11-upper + 'Q', # q12-lower + 'Q', # q12-upper + 'Q', # q13-lower + 'Q', # q13-upper + 'Q', # q14-lower + 'Q', # q14-upper + 'Q', # q15-lower + 'Q', # q15-upper + 'Q', # q16-lower + 'Q', # q16-upper + 'Q', # q17-lower + 'Q', # q17-upper + 'Q', # q18-lower + 'Q', # q18-upper + 'Q', # q19-lower + 'Q', # q19-upper + 'Q', # q20-lower + 'Q', # q20-upper + 'Q', # q21-lower + 'Q', # q21-upper + 'Q', # q22-lower + 'Q', # q22-upper + 'Q', # q23-lower + 'Q', # q23-upper + 'Q', # q24-lower + 'Q', # q24-upper + 'Q', # q25-lower + 'Q', # q25-upper + 'Q', # q26-lower + 'Q', # q26-upper + 'Q', # q27-lower + 'Q', # q27-upper + 'Q', # q28-lower + 'Q', # q28-upper + 'Q', # q29-lower + 'Q', # q29-upper + 'Q', # q30-lower + 'Q', # q30-upper + 'Q', # q31-lower + 'Q', # q31-upper +]) + cpu_name = ( 'Invalid', 'A53', @@ -323,9 +569,80 @@ sysdbg_cpu32_ctxt_regs_type['default'] = sysdbg_cpu32_ctxt_regs_type_default sysdbg_cpu64_register_names['1.3'] = sysdbg_cpu64_register_names_v1_3 sysdbg_cpu64_ctxt_regs_type['1.3'] = sysdbg_cpu64_ctxt_regs_type_v1_3 +# Version 1.4 +sysdbg_cpu64_register_names['1.4'] = sysdbg_cpu64_register_names_v1_4 +sysdbg_cpu64_ctxt_regs_type['1.4'] = sysdbg_cpu64_ctxt_regs_type_v1_4 + + +class NeonCtxType(): + + def __init__(self, regs_t, ramdump): + i = 0 + self.regs = {} + + if ramdump.arm64 is None: + return + + register_name = sysdbg_neon128_register_names_v1_4 + for r in regs_t: + self.regs[register_name[i][0]] = r + i += 1 + + class TZCpuCtx_v2(): - def __init__(self, version, regs_t, ramdump): + def compute_pc(self, neon_regs): + pstate = self.regs['PStateMisc'] + trust0 = self.regs['trust0'] + trust2 = self.regs['trust2'] + pc = self.regs['pc'] + + # AArch32 Mode + if is_set(pstate, 4): + val = pstate & 0xF + if val == 0x0 and is_set(trust0, 14): + self.regs['pc'] = self.regs['x14'] + elif val == 0x1 and is_set(trust0, 30): + self.regs['pc'] = self.regs['x30'] + elif val == 0x2 and is_set(trust0, 16): + self.regs['pc'] = self.regs['x16'] + elif val == 0x3 and is_set(trust0, 18): + self.regs['pc'] = self.regs['x18'] + elif val == 0x7 and is_set(trust0, 20): + self.regs['pc'] = self.regs['x20'] + elif val == 0xB and is_set(trust0, 22): + self.regs['pc'] = self.regs['x22'] + elif val == 0x6 and is_set(trust2, 31): + self.regs['pc'] = neon_regs['q31-upper'] + elif val == 0xA: + self.regs['pc'] = self.regs['elr_el2'] + elif val == 0xF and is_set(trust0, 14): + self.regs['pc'] = self.regs['x14'] + else: + print_out_str('!!! AArch32 PC Approximation Logic Failed!') + # AArch64 Mode + else: + if is_set(trust0, 30): + self.regs['pc'] = self.regs['x30'] + else: + val = (pstate >> 2) & 0x3 + if val == 0x0: + self.regs['pc'] = self.regs['elr_el1'] + elif val == 0x1: + self.regs['pc'] = self.regs['elr_el1'] + elif val == 0x2: + self.regs['pc'] = self.regs['elr_el2'] + elif val == 0x3: + self.regs['pc'] = self.regs['elr_el3'] + else: + print_out_str('!!! AArch64 PC Approximation Logic Failed!') + + if pc and pc != self.regs['pc']: + print_out_str( + '!!! PC computed by SDI {0} and Parser {1} are different!' + .format(hex(pc), hex(self.regs['pc']))) + + def __init__(self, version, regs_t, neon_regs, ramdump): i = 0 self.regs = {} self.version = version @@ -338,6 +655,11 @@ class TZCpuCtx_v2(): self.regs[register_name[i][0]] = r i += 1 + if self.version == '1.4' and self.regs['dirty_flag'] == 0x1: + print_out_str( + '!!! PC is invalid, applying "PC Approximation Logic"!') + self.compute_pc(neon_regs) + def print_regs(self, outfile, ramdump): if ramdump.arm64: register_names = sysdbg_cpu64_register_names[self.version] @@ -358,24 +680,27 @@ class TZCpuCtx_v2(): pc_string = None if pc_string is not None: print_out_str(' {0:8} = 0x{1:016x} {2}'.format( - reg_name, self.regs[reg_name], pc_string)) + reg_name, self.regs[reg_name], pc_string)) else: print_out_str(' {0:8} = 0x{1:016x}'.format( - reg_name, self.regs[reg_name])) + reg_name, self.regs[reg_name])) if t32_name is not None: outfile.write( 'r.s {0} 0x{1:x}\n'.format(t32_name, self.regs[reg_name])) + class TZRegDump_v2(): def __init__(self): self.core_regs = None self.sec_regs = None + self.neon_regs = {} self.version = 0 self.start_addr = 0 self.end_addr = 0 self.core = 0 - self.status = [] + self.status = [] + self.neon_fields = [] def dump_all_regs(self, ram_dump): coren_regs = ram_dump.open_file('core{0}_regs.cmm'.format(self.core)) @@ -384,7 +709,8 @@ class TZRegDump_v2(): self.core_regs.print_regs(coren_regs, ram_dump) coren_regs.close() - secure_regs = ram_dump.open_file('secure_world_core{0}_regs.cmm'.format(self.core)) + secure_regs = ram_dump.open_file( + 'secure_world_core{0}_regs.cmm'.format(self.core)) print_out_str('\n=============== secure contex ===========') self.sec_regs.print_regs(secure_regs, ram_dump) print_out_str('============ end secure context ===========') @@ -408,7 +734,8 @@ class TZRegDump_v2(): symname = 'UNKNOWN' offset = 0 print_out_str( - 'Core {3} PC: {0}+{1:x} <{2:x}>'.format(symname, offset, pc, self.core)) + 'Core {3} PC: {0}+{1:x} <{2:x}>'.format(symname, offset, + pc, self.core)) a = ram_dump.unwind_lookup(lr) if a is not None: symname, offset = a @@ -416,7 +743,8 @@ class TZRegDump_v2(): symname = 'UNKNOWN' offset = 0 print_out_str( - 'Core {3} LR: {0}+{1:x} <{2:x}>'.format(symname, offset, lr, self.core)) + 'Core {3} LR: {0}+{1:x} <{2:x}>'.format(symname, offset, + lr, self.core)) print_out_str('') ram_dump.unwind.unwind_backtrace(bt, fp, pc, lr, '') print_out_str('') @@ -444,19 +772,49 @@ class TZRegDump_v2(): if ram_dump.arm64: sc_regs = ram_dump.read_string( - self.start_addr, sysdbg_cpu64_ctxt_regs_type[self.version], False) - self.start_addr += struct.calcsize(sysdbg_cpu64_ctxt_regs_type[self.version]) + self.start_addr, + sysdbg_cpu64_ctxt_regs_type[self.version], + False) + self.start_addr += struct.calcsize( + sysdbg_cpu64_ctxt_regs_type[self.version]) sc_secure = ram_dump.read_string( - self.start_addr, sysdbg_cpu64_ctxt_regs_type[self.version] , False) - self.start_addr += struct.calcsize(sysdbg_cpu64_ctxt_regs_type[self.version]) + self.start_addr, + sysdbg_cpu64_ctxt_regs_type[self.version], + False) + self.start_addr += struct.calcsize( + sysdbg_cpu64_ctxt_regs_type[self.version]) + + if self.version == '1.4': + for i in range(0, 3): + self.neon_fields.append(ram_dump.read_u32( + self.start_addr, False)) + self.start_addr += 4 + + neon_ctx_regs = ram_dump.read_string( + self.start_addr, + sysdbg_neon128_register_type_v1_4, + False) + self.start_addr += struct.calcsize( + sysdbg_neon128_register_type_v1_4) + + neon = NeonCtxType(neon_ctx_regs, ram_dump) + self.neon_regs = neon.regs else: sc_regs = ram_dump.read_string( - self.start_addr, sysdbg_cpu32_ctxt_regs_type[self.version], False) - self.start_addr += struct.calcsize(sysdbg_cpu32_ctxt_regs_type[self.version]) + self.start_addr, + sysdbg_cpu32_ctxt_regs_type[self.version], + False) + self.start_addr += struct.calcsize( + sysdbg_cpu32_ctxt_regs_type[self.version]) sc_secure = ram_dump.read_string( - self.start_addr, sysdbg_cpu32_ctxt_regs_type[self.version] , False) - self.start_addr += struct.calcsize(sysdbg_cpu32_ctxt_regs_type[self.version]) + self.start_addr, + sysdbg_cpu32_ctxt_regs_type[self.version], + False) + self.start_addr += struct.calcsize( + sysdbg_cpu32_ctxt_regs_type[self.version]) - self.core_regs = TZCpuCtx_v2(self.version, sc_regs, ram_dump) - self.sec_regs = TZCpuCtx_v2(self.version, sc_secure, ram_dump) + self.core_regs = TZCpuCtx_v2(self.version, sc_regs, + self.neon_regs, ram_dump) + self.sec_regs = TZCpuCtx_v2(self.version, sc_secure, + self.neon_regs, ram_dump) return True -- GitLab