diff --git a/dcc_parser/.gitignore b/dcc_parser/.gitignore new file mode 100644 index 0000000000000000000000000000000000000000..0d20b6487c61e7d1bde93acf4a14b7a89083a16d --- /dev/null +++ b/dcc_parser/.gitignore @@ -0,0 +1 @@ +*.pyc diff --git a/dcc_parser/dcc_parser.py b/dcc_parser/dcc_parser.py new file mode 100644 index 0000000000000000000000000000000000000000..b296cd52acdda87c0b95a3a1d95065e86e4a6264 --- /dev/null +++ b/dcc_parser/dcc_parser.py @@ -0,0 +1,220 @@ +# Copyright (c) 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 +# only version 2 as published by the Free Software Foundation. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. + +import datetime +import logging +import logging.handlers +import os +import struct +import sys + +from optparse import OptionParser + +count = 0 +address = [] +data = [] + + +def log_init(name, path, filename): + # Set up logger + logger = logging.getLogger(name) + logger.setLevel(logging.INFO) + + # Add the log message handler to the logger + if filename is not None: + handler = logging.FileHandler(path + '/' + filename, mode='w') + else: + handler = logging.StreamHandler(sys.stdout) + + logger.addHandler(handler) + return logger + + +def add_addr(base, offset, length): + for i in range(0, length): + addr = base + offset + (i * 4) + address.append(addr) + + +def read_data(data_pt): + nr = count + while nr > 0: + word = data_pt.read(4) + if len(word) != 4: + break + + val = struct.unpack('<L', word)[0] + data.append(val) + nr = nr - 1 + + return nr + + +def read_config(config_pt): + nr = 0 + offset = 0 + base = 0 + while True: + word = config_pt.read(4) + if len(word) != 4: + break + + val = struct.unpack('<L', word)[0] + + if val == 0: + break + + if val & (1 << 31): + base = ((val & 0x0FFFFFFF) << 4) + offset = 0 + else: + for i in range(0, 2): + offset = offset + (val & 0xFF) * 4 + val = val >> 8 + + length = (val & 0x7f) + val = val >> 8 + + if length != 0: + nr += length + add_addr(base, offset, length) + else: + if (i == 0): + log.error("Error! Found zero length!") + return 0 + else: + offset = 0 + return nr + + +def dump_regs_json(options): + log.info("Dumping regs in JSON format in \'{0}\' file.".format(options.outfile)) + parsed_data.info("{") + parsed_data.info("\t\"version\": 1,") + parsed_data.info("\t\"timestamp\": \"{0}\",".format(datetime.date.today().strftime('%m/%d/%y'))) + parsed_data.info("\t\"generator\": \"Linux DCC Parser\",") + parsed_data.info("\t\"chip\": {") + parsed_data.info("\t\t\"name\": \"{0}\",".format(options.chipname)) + parsed_data.info("\t\t\"version\": \"{0}\"".format(options.chipversion)) + parsed_data.info("\t},") + parsed_data.info("\t\"registers\": [") + for addr, val in zip(address, data): + parsed_data.info("\t\t{{ \"address\": \"0x{0:08x}\", \"value\": \"0x{1:08x}\" }},".format(addr, val)) + parsed_data.info("\t]") + parsed_data.info("}") + return + + +def dump_regs_xml(options): + log.info("Dumping regs in XML format in \'{0}\' file.".format(options.outfile)) + parsed_data.info("<?xml version=\"1.0\" encoding=\"utf-8\"?>") + parsed_data.info("<hwioDump version=\"1\"") + parsed_data.info("\t<timestamp>{0}</timestamp>".format(datetime.date.today().strftime('%m/%d/%y'))) + parsed_data.info("\t<generator>Linux DCC Parser</generator>") + parsed_data.info("\t<chip name=\"{0}\" version=\"{1}\">".format(options.chipname, options.chipversion)) + for addr, val in zip(address, data): + parsed_data.info("\t\t<register address=\"0x{0:08x}\" value=\"0x{1:08x}\" />".format(addr, val)) + parsed_data.info("\t</chip>") + parsed_data.info("</hwioDump>") + return + + +def dump_regs(options): + if options.json is True: + dump_regs_json(options) + else: + dump_regs_xml(options) + +if __name__ == '__main__': + usage = 'usage: %prog [options to print]. Run with --help for more details' + parser = OptionParser(usage) + parser.add_option('-s', '--sram-file', dest='sramfile', + help='sram image path') + parser.add_option('-a', '--atb-file', dest='atbfile', help='atb image path') + parser.add_option('-j', '--json', action='store_true', + help='output in JSON format') + parser.add_option('-o', '--out-dir', dest='outdir', help='output dir path') + parser.add_option('-f', '--output-file', dest='outfile', + help='output filename') + parser.add_option('-l', '--log-file', dest='logfile', help='Log filename') + parser.add_option('', '--chip-name', dest='chipname', help='chip name') + parser.add_option('', '--chip-version', dest='chipversion', + help='chip version') + + (options, args) = parser.parse_args() + + args = '' + for arg in sys.argv: + args = args + arg + ' ' + + if options.outdir: + if not os.path.exists(options.outdir): + print ('!!! Out directory does not exist. Creating...') + try: + os.makedirs(options.outdir) + except: + print ("Failed to create %s. You probably don't have permissions there. Bailing." % options.outdir) + sys.exit(1) + else: + options.outdir = '.' + + if options.json: + ext = '.json' + else: + ext = '.xml' + + if options.outfile is None: + options.outfile = 'dcc_captured_data{0}'.format(ext) + + log = log_init('LOG', options.outdir, options.logfile) + + log.info("Data Capture and Compare(DCC) parser.") + + if options.sramfile is None: + log.error("No SRAM image file given! Exiting...") + parser.print_usage() + sys.exit(1) + + try: + sram_file = open(options.sramfile, 'rb') + except: + log.error("could not open path {0}".format(options.sramfile)) + log.error("Do you have read permissions on the path?") + sys.exit(1) + + if options.atbfile is not None: + try: + atb_file = open(options.atbfile, 'rb') + except: + log.error("could not open path {0}".format(options.atbfile)) + log.error("Do you have read permissions on the path?") + sys.exit(1) + + count = 0 + count = read_config(sram_file) + if options.atbfile is None: + atb_file = sram_file + if count == 0: + log.error('No configuration found in SRAM!!') + sys.exit(1) + + if read_data(atb_file): + log.error('Couldn\'t read complete data.') + else: + parsed_data = log_init('PARSED_DATA', options.outdir, options.outfile) + dump_regs(options) + + sram_file.close() + + if options.atbfile is not None: + atb_file.close() + + sys.stderr.flush() diff --git a/linux-ramdump-parser-v2/dcc.py b/linux-ramdump-parser-v2/dcc.py new file mode 100644 index 0000000000000000000000000000000000000000..79bd6c91718b05e9b34eb84b46aee0a717da228a --- /dev/null +++ b/linux-ramdump-parser-v2/dcc.py @@ -0,0 +1,89 @@ +# Copyright (c) 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 +# only version 2 as published by the Free Software Foundation. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. + +import struct +from print_out import print_out_str +from ramparse import VERSION + +dcc_register_list = [ + 'DCC_HW_VERSION', + 'DCC_HW_INFO', + 'DCC_CGC_CFG', + 'DCC_LL', + 'DCC_RAM_CFG', + 'DCC_CFG', + 'DCC_SW_CTL', + 'DCC_STATUS', + 'DCC_FETCH_ADDR', + 'DCC_SRAM_ADDR', + 'DCC_INT_ENABLE', + 'DCC_INT_STATUS', + 'DCC_QSB_CFG' + ] + +# DCC regs hash table +dcc_regs = {} + +class DccRegDump(): + + def __init__(self, start, end): + self.start_addr = start + self.end_addr = end + + def parse_all_regs(self, ram_dump): + num_reg = len(dcc_register_list) + if (self.start_addr + 4 * num_reg) > self.end_addr: + return False + + for reg in dcc_register_list: + dcc_regs[reg] = ram_dump.read_u32(self.start_addr, False) + self.start_addr += 4 + return True + + def dump_all_regs(self, ram_dump): + outfile = ram_dump.open_file('dcc_regs.txt') + outfile.write('DCC registers:\n') + for reg in dcc_register_list: + outfile.write('{0} : 0x{1:08x}\n'.format(reg, dcc_regs[reg])) + outfile.close() + +class DccSramDump(): + def __init__(self, start, end): + self.start_addr = start + self.end_addr = end + + def dump_sram_img(self, ram_dump): + if self.start_addr >= self.end_addr: + return False + + rsz = self.end_addr - self.start_addr + + if dcc_regs.has_key('DCC_HW_INFO') == False \ + or dcc_regs['DCC_HW_INFO'] == 0: + print_out_str('DCC HW Info missing! Skipping sram dump...') + return False + + if dcc_regs['DCC_CFG'] & 0x1: + print_out_str('DCC is configured in CRC mode. Skipping sram dump ...') + return False + + if dcc_regs['DCC_RAM_CFG'] == 0: + print_out_str('No config found in DCC SRAM. Skipping sram dump ...') + return False + + sramfile = ram_dump.open_file('sram.bin') + for i in range(0, rsz): + val = ram_dump.read_byte(self.start_addr + i, False) + sramfile.write(struct.pack('<B', val)) + + sramfile.close() + + return True diff --git a/linux-ramdump-parser-v2/debug_image_v2.py b/linux-ramdump-parser-v2/debug_image_v2.py index 436c1ba367bca75e01c8d6e890f29e0141ff65a1..87638fc14aec9c3542afa04031119f086b539b92 100755 --- a/linux-ramdump-parser-v2/debug_image_v2.py +++ b/linux-ramdump-parser-v2/debug_image_v2.py @@ -16,7 +16,9 @@ import shutil import os import platform import subprocess +import sys +from dcc import DccRegDump, DccSramDump from pmic import PmicRegDump from print_out import print_out_str, print_out_exception from qdss import QDSSDump @@ -57,6 +59,8 @@ client_table = { 'MSM_DUMP_DATA_OCMEM': 'parse_ocmem', 'MSM_DUMP_DATA_DBGUI_REG' : 'parse_qdss_common', 'MSM_DUMP_DATA_PMIC': 'parse_pmic', + 'MSM_DUMP_DATA_DCC_REG':'parse_dcc_reg', + 'MSM_DUMP_DATA_DCC_SRAM':'parse_dcc_sram', 'MSM_DUMP_DATA_TMC_ETF': 'parse_qdss_common', 'MSM_DUMP_DATA_TMC_REG': 'parse_qdss_common', 'MSM_DUMP_DATA_L2_TLB': 'parse_l2_tlb', @@ -102,6 +106,33 @@ class DebugImage_v2(): regs.dump_all_regs(ram_dump) + def parse_dcc_reg(self, version, start, end, client_id, ram_dump): + client_name = self.dump_data_id_lookup_table[client_id] + + print_out_str( + 'Parsing {0} context start {1:x} end {2:x}'.format(client_name, start, end)) + + regs = DccRegDump(start, end) + if regs.parse_all_regs(ram_dump) is False: + print_out_str('!!! Could not get registers from DCC register dump') + return + + regs.dump_all_regs(ram_dump) + return + + def parse_dcc_sram(self, version, start, end, client_id, ram_dump): + client_name = self.dump_data_id_lookup_table[client_id] + + print_out_str( + 'Parsing {0} context start {1:x} end {2:x}'.format(client_name, start, end)) + + regs = DccSramDump(start, end) + if regs.dump_sram_img(ram_dump) is False: + print_out_str('!!! Could not dump SRAM') + else: + ram_dump.dcc = True + return + def parse_qdss_common(self, version, start, end, client_id, ram_dump): client_name = self.dump_data_id_lookup_table[client_id] @@ -250,6 +281,30 @@ class DebugImage_v2(): subprocess.call('{0} -c {1} exit'.format(qtf_path, port)) p.communicate('quit') + def parse_dcc(self, ram_dump): + out_dir = ram_dump.outdir + + dcc_parser_path = os.path.join(os.path.dirname(__file__), '..', 'dcc_parser', 'dcc_parser.py') + + if dcc_parser_path is None: + print_out_str("!!! Incorrect path for DCC specified.") + return + + if not os.path.exists(dcc_parser_path): + print_out_str("!!! dcc_parser_path {0} does not exist! Check your settings!".format(dcc_parser_path)) + return + + if os.path.getsize(os.path.join(out_dir, 'sram.bin')) > 0: + sram_file = os.path.join(out_dir, 'sram.bin') + else: + return + + p = subprocess.Popen([sys.executable, dcc_parser_path, '-s', sram_file, '--out-dir', out_dir], + stdout=subprocess.PIPE, stderr=subprocess.STDOUT) + + print_out_str('--------') + print_out_str(p.communicate()[0]) + def parse_dump_v2(self, ram_dump): self.dump_type_lookup_table = ram_dump.gdbmi.get_enum_lookup_table( 'msm_dump_type', 2) @@ -418,3 +473,5 @@ class DebugImage_v2(): self.qdss.dump_all(ram_dump) if ram_dump.qtf: self.parse_qtf(ram_dump) + if ram_dump.dcc: + self.parse_dcc(ram_dump) diff --git a/linux-ramdump-parser-v2/ramdump.py b/linux-ramdump-parser-v2/ramdump.py index 8c77aba53fef2ec17a8264642c40c6126ec9cb93..d452fbc0b73705098bf675c3bfe7dfa36c0bb3c2 100644 --- a/linux-ramdump-parser-v2/ramdump.py +++ b/linux-ramdump-parser-v2/ramdump.py @@ -460,6 +460,7 @@ class RamDump(): self.thread_size = 8192 self.qtf_path = options.qtf_path self.qtf = options.qtf + self.dcc = False self.t32_host_system = options.t32_host_system or None self.ipc_log_test = options.ipc_test self.ipc_log_skip = options.ipc_skip