Skip to content
Snippets Groups Projects
Commit a025f637 authored by Sarangdhar Joshi's avatar Sarangdhar Joshi
Browse files

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
parent 32820ffe
No related branches found
No related tags found
No related merge requests found
# 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
# 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
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment