Skip to content
Snippets Groups Projects
qdss.py 18.81 KiB
# Copyright (c) 2012, 2014 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
import itertools
from print_out import print_out_str

tmc_registers = {
    'RSZ': (0x004, 'RAM Size'),
    'STS': (0x00C, 'Status Register'),
    'RRD': (0x010, 'RAM Read Data Register'),
    'RRP': (0x014, 'RAM Read Pointer Register'),
    'RWP': (0x018, 'RAM Write Pointer Register'),
    'TRG': (0x01C, 'Trigger Counter Register'),
    'CTL': (0x020, 'Control Register'),
    'RWD': (0x024, 'RAM Write Data Register'),
    'MODE': (0x028, 'Mode Register'),
    'LBUFLEVEL': (0x02C, 'Latched Buffer Fill Level'),
    'CBUFLEVEL': (0x030, 'Current Buffer Fill Level'),
    'BUFWM': (0x034, 'Buffer Level Water Mark'),
    'RRPHI': (0x038, 'RAM Read Pointer High Register'),
    'RWPHI': (0x03C, 'RAM Write Pointer High Register'),
    'AXICTL': (0x110, 'AXI Control Register'),
    'DBALO': (0x118, 'Data Buffer Address Low Register'),
    'DBAHI': (0x11C, 'Data Buffer Address High Register'),
    'FFSR': (0x300, 'Formatter and Flush Status Register'),
    'FFCR': (0x304, 'Formatter and Flush Control Register'),
    'PSCR': (0x308, 'Periodic Synchronization Counter Register'),
    'ITATBMDATA0': (0xED0, 'Integration Test ATB Master Data Register 0'),
    'ITATBMCTR2': (0xED4, 'Integration Test ATB Master Interface Control 2 Register'),
    'ITATBMCTR1': (0xED8, 'Integration Test ATB Master Control Register 1'),
    'ITATBMCTR0': (0xEDC, 'Integration Test ATB Master Interface Control 0 Register'),
    'ITMISCOP0': (0xEE0, 'Integration Test Miscellaneous Output Register 0'),
    'ITTRFLIN': (0xEE8, 'Integration Test Trigger In and Flush In Register'),
    'ITATBDATA0': (0xEEC, 'Integration Test ATB Data Register 0'),
    'ITATBCTR2': (0xEF0, 'Integration Test ATB Control 2 Register'),
    'ITATBCTR1': (0xEF4, 'Integration Test ATB Control 1 Register'),
    'ITATBCTR0': (0xEF8, 'Integration Test ATB Control 0 Register'),
    'ITCTRL': (0xF00, 'Integration Mode Control Register'),
    'CLAIMSET': (0xFA0, 'Claim Tag Set Register'),
    'CLAIMCLR': (0xFA4, 'Claim Tag Clear Register'),
    'LAR': (0xFB0, 'Lock Access Register'),
    'LSR': (0xFB4, 'Lock Status Register'),
    'AUTHSTATUS': (0xFB8, 'Authentication Status Register'),
    'DEVID': (0xFC8, 'Device Configuration Register'),
    'DEVTYPE': (0xFCC, 'Device Type Identifier Register'),
    'PERIPHID4': (0xFD0, 'Peripheral ID4 Register'),
    'PERIPHID5': (0xFD4, 'Peripheral ID5 Register'),
    'PERIPHID6': (0xFD8, 'Peripheral ID6 Register'),
    'PERIPHID7': (0xFDC, 'Peripheral ID7 Register'),
    'PERIPHID0': (0xFE0, 'Peripheral ID0 Register'),
    'PERIPHID1': (0xFE4, 'Peripheral ID1 Register'),
    'PERIPHID2': (0xFE8, 'Peripheral ID2 Register'),
    'PERIPHID3': (0xFEC, 'Peripheral ID3 Register'),
    'COMPID0': (0xFF0, 'Component ID0 Register'),
    'COMPID1': (0xFF4, 'Component ID1 Register'),
    'COMPID2': (0xFF8, 'Component ID2 Register'),
    'COMPID3': (0xFFC, 'Component ID3 Register'),
}

etm_registers = {
    'ETMCR': (0x000, 'Main Control Register'),
    'ETMCCR': (0x001, 'Configuration Code Register'),
    'ETMTRIGGER': (0x002, 'Trigger Event Register'),
    'ETMSR': (0x004, 'Status Register'),
    'ETMCSR': (0x005, 'System Configuration Register'),
    'ETMTSSCR': (0x006, 'TraceEnable Start/Stop Control Register'),
    'ETMTEEVR': (0x008, 'TraceEnable Event Register'),
    'ETMTECR1': (0x009, 'TraceEnable Control Register'),
    'ETMFFLR': (0x00B, 'FIFOFULL Level Register'),
    'ETMACVR0': (0x10, 'Address Comparator Value Register 0'),
    'ETMACVR1': (0x11, 'Address Comparator Value Register 1'),
    'ETMACVR2': (0x12, 'Address Comparator Value Register 2'),
    'ETMACVR3': (0x13, 'Address Comparator Value Register 3'),
    'ETMACVR4': (0x14, 'Address Comparator Value Register 4'),
    'ETMACVR5': (0x15, 'Address Comparator Value Register 5'),
    'ETMACVR6': (0x16, 'Address Comparator Value Register 6'),
    'ETMACVR7': (0x17, 'Address Comparator Value Register 7'),
    'ETMACVR8': (0x18, 'Address Comparator Value Register 8'),
    'ETMACVR9': (0x19, 'Address Comparator Value Register 9'),
    'ETMACVRA': (0x1A, 'Address Comparator Value Register A'),
    'ETMACVRB': (0x1B, 'Address Comparator Value Register B'),
    'ETMACVRC': (0x1C, 'Address Comparator Value Register C'),
    'ETMACVRD': (0x1D, 'Address Comparator Value Register D'),
    'ETMACVRE': (0x1E, 'Address Comparator Value Register E'),
    'ETMACVRF': (0x1F, 'Address Comparator Value Register F'),

    'ETMACVT0': (0x20, 'Address Comparator Type Register 0'),
    'ETMACVT1': (0x21, 'Address Comparator Type Register 1'),
    'ETMACVT2': (0x22, 'Address Comparator Type Register 2'),
    'ETMACVT3': (0x23, 'Address Comparator Type Register 3'),
    'ETMACVT4': (0x24, 'Address Comparator Type Register 4'),
    'ETMACVT5': (0x25, 'Address Comparator Type Register 5'),
    'ETMACVT6': (0x26, 'Address Comparator Type Register 6'),
    'ETMACVT7': (0x27, 'Address Comparator Type Register 7'),
    'ETMACVT8': (0x28, 'Address Comparator Type Register 8'),
    'ETMACVT9': (0x29, 'Address Comparator Type Register 9'),
    'ETMACVTA': (0x2A, 'Address Comparator Type Register A'),
    'ETMACVTB': (0x2B, 'Address Comparator Type Register B'),
    'ETMACVTC': (0x2C, 'Address Comparator Type Register C'),
    'ETMACVTD': (0x2D, 'Address Comparator Type Register D'),
    'ETMACVTE': (0x2E, 'Address Comparator Type Register E'),
    'ETMACVTF': (0x2F, 'Address Comparator Type Register F'),

    'ETMCNTRLDVR0': (0x050, 'Counter Reload Value Register 0'),
    'ETMCNTRLDVR1': (0x051, 'Counter Reload Value Register 1'),
    'ETMCNTRLDVR2': (0x052, 'Counter Reload Value Register 2'),
    'ETMCNTRLDVR3': (0x053, 'Counter Reload Value Register 3'),

    'ETMCNTRENR0': (0x054, 'Counter Enable Event Register 0'),
    'ETMCNTRENR1': (0x055, 'Counter Enable Event Register 1'),
    'ETMCNTRENR2': (0x056, 'Counter Enable Event Register 2'),
    'ETMCNTRENR3': (0x057, 'Counter Enable Event Register 3'),

    'ETMCNTRLDEVR0': (0x058, 'Counter Reload Event Registers 0'),
    'ETMCNTRLDEVR1': (0x059, 'Counter Reload Event Registers 1'),
    'ETMCNTRLDEVR2': (0x05A, 'Counter Reload Event Registers 2'),
    'ETMCNTRLDEVR3': (0x05B, 'Counter Reload Event Registers 3'),

    'ETMCNTVR0': (0x05C, 'Counter Value Register 0'),
    'ETMCNTVR1': (0x05D, 'Counter Value Register 1'),
    'ETMCNTVR2': (0x05E, 'Counter Value Register 2'),
    'ETMCNTVR3': (0x05F, 'Counter Value Register 3'),

    'ETMSQabEVR0': (0x060, 'Sequencer State Transition Event Register 0'),
    'ETMSQabEVR1': (0x061, 'Sequencer State Transition Event Register 1'),
    'ETMSQabEVR2': (0x062, 'Sequencer State Transition Event Register 2'),
    'ETMSQabEVR3': (0x063, 'Sequencer State Transition Event Register 3'),
    'ETMSQabEVR4': (0x064, 'Sequencer State Transition Event Register 4'),
    'ETMSQabEVR5': (0x065, 'Sequencer State Transition Event Register 5'),

    'ETMSQR': (0x067, 'Current Sequencer State Register'),

    'ETMEXTOUTEVR0': (0x068, 'External Output Event Registers 0'),
    'ETMEXTOUTEVR1': (0x069, 'External Output Event Registers 1'),
    'ETMEXTOUTEVR2': (0x06A, 'External Output Event Registers 2'),
    'ETMEXTOUTEVR3': (0x06B, 'External Output Event Registers 3'),

    'ETMCIDCVR0': (0x06C, 'Context ID Comparator Value Register 0'),
    'ETMCIDCVR1': (0x06D, 'Context ID Comparator Value Register 1'),
    'ETMCIDCVR2': (0x06E, 'Context ID Comparator Value Register 2'),

    'ETMCIDCMR0': (0x06F, 'Context ID Mask Register'),

    'ETMIMPSPEC0': (0x070, 'Implementation Specific Register 0'),
    'ETMIMPSPEC1': (0x071, 'Implementation Specific Register 1'),
    'ETMIMPSPEC2': (0x072, 'Implementation Specific Register 2'),
    'ETMIMPSPEC3': (0x073, 'Implementation Specific Register 3'),
    'ETMIMPSPEC4': (0x074, 'Implementation Specific Register 4'),
    'ETMIMPSPEC5': (0x075, 'Implementation Specific Register 5'),
    'ETMIMPSPEC6': (0x076, 'Implementation Specific Register 6'),
    'ETMIMPSPEC7': (0x077, 'Implementation Specific Register 7'),

    'ETMSYNCFR': (0x078, 'Synchronization Frequency Register'),
    'ETMIDR': (0x079, 'ID register'),
    'ETMCCER': (0x07A, 'Configuration Code Extension Register'),
    'ETMEXTINSELR': (0x07B, 'Extended External Input Selection Register'),
    'ETMTESSEICR': (0x07C, 'TraceEnable Start/Stop EmbeddedICE Control Register'),
    'ETMEIBCR': (0x07D, 'EmbeddedICE Behavior COntrol Register'),
    'ETMTSEVR': (0x07E, 'Timestamp Event Register'),
    'ETMAUXCR': (0x07F, 'Auxilary Control Register'),
    'ETMTRACEIDR': (0x080, 'CoreSight Trace ID Register'),
    'ETMVMIDCVR': (0x090, 'VMID Comparator Value Register'),

    'ETMOSLAR': (0x0C0, 'OS Lock Access Register'),
    'ETMOSLSR': (0x0C1, 'OS Lock Status Register'),
    'ETMPDCR': (0x0C4, 'Device Power-DOwn Control Register'),
    'ETMPDSR': (0x0C5, 'Device Power Down Status Register'),

    'ETMITCTRL': (0x3C0, 'Integration Mode Control Register'),
    'ETMCLAIMSET': (0x3E8, 'Claim Tag Set Register'),
    'ETMCLAIMCLR': (0x3E9, 'Claim Tag Clear Register'),
    'ETMLAR': (0x3Ec, 'Lock Access Register'),
    'ETMLSR': (0x3ED, 'Lock Status Register'),
    'ETMAUTHSTATUS': (0x3EE, 'Authentication Status Register'),
    'ETMDEVID': (0x3F2, 'Device Configuration Register'),
    'ETMDEVTYPE': (0x3F3, 'Device Type Register'),
    'ETMPIDR4': (0x3F4, 'Peripheral ID4 Register'),
    'ETMPIDR0': (0x3F8, 'Peripheral ID0 Register'),
    'ETMPIDR1': (0x3F9, 'Peripheral ID1 Register'),
    'ETMPIDR2': (0x3FA, 'Peripheral ID2 Register'),
    'ETMPIDR3': (0x3FB, 'Peripheral ID3 Register'),
    'ETMCIDR0': (0x3FC, 'Component ID0 Register'),
    'ETMCIDR1': (0x3FD, 'Component ID1 Register'),
    'ETMCIDR2': (0x3FE, 'Component ID2 Register'),
}


class QDSSDump():

    def __init__(self):
        self.tmc_etr_start = None
        self.etf_start = None
        self.tmc_etf_start = None
        self.etm_regs0 = None
        self.etm_regs1 = None
        self.etm_regs2 = None
        self.etm_regs3 = None

    # Assumptions: Any address given here has been checked for correct magic
    def print_tmc_etf(self, ram_dump):
        if self.tmc_etf_start is None:
            print_out_str(
                "!!! TMC-ETF address has not been set! I can't continue!")
            return

        print_out_str('Now printing TMC-ETF registers to file')
        tmc_etf_out = ram_dump.open_file('tmc_etf.txt')
        for a, b in tmc_registers.iteritems():
            offset, name = b
            tmc_etf_out.write('{0} ({1}): {2:x}\n'.format(
                a, name, ram_dump.read_u32(self.tmc_etf_start + offset, False)))
        tmc_etf_out.close()

    def print_tmc_etr(self, ram_dump):
        if self.tmc_etr_start is None:
            print_out_str(
                "!!! TMC-ETR address has not been set! I can't continue!")
            return

        print_out_str('Now printing TMC-ETR registers to file')
        tmc_etf_out = ram_dump.open_file('tmc_etr.txt')
        for a, b in tmc_registers.iteritems():
            offset, name = b
            tmc_etf_out.write('{0} ({1}): {2:x}\n'.format(
                a, name, ram_dump.read_u32(self.tmc_etr_start + offset, False)))
        tmc_etf_out.close()

    def print_etm_registers(self, ram_dump, base, fname):
        etm_out = ram_dump.open_file(fname)
        for a, b in etm_registers.iteritems():
            offset, name = b
            etm_out.write('{0} ({1}): {2:x})\n'.format(
                a, name, ram_dump.read_u32(base + offset * 4, False)))
        etm_out.close()

    def print_all_etm_register(self, ram_dump):
        if self.etm_regs0 is None:
            print_out_str(
                '!!! ETM REGS 0 address was not set! Nothing will be parsed')
        else:
            self.print_etm_registers(ram_dump, self.etm_regs0, 'etm_regs0')

        if self.etm_regs1 is None:
            print_out_str(
                '!!! ETM REGS 1 address was not set! Nothing will be parsed')
        else:
            self.print_etm_registers(ram_dump, self.etm_regs1, 'etm_regs1')

        if self.etm_regs2 is None:
            print_out_str(
                '!!! ETM REGS 2 address was not set! Nothing will be parsed')
        else:
            self.print_etm_registers(ram_dump, self.etm_regs2, 'etm_regs2')

        if self.etm_regs3 is None:
            print_out_str(
                '!!! ETM REGS 3 address was not set! Nothing will be parsed')
        else:
            self.print_etm_registers(ram_dump, self.etm_regs3, 'etm_regs3')

    def save_etf_bin(self, ram_dump):
        tmc_etf = ram_dump.open_file('tmc-etf.bin')
        if self.tmc_etf_start is None or self.etf_start is None:
            print_out_str('!!! ETF was not the current sink!')
            tmc_etf.close()
            return

        ctl_offset, ctl_desc = tmc_registers['CTL']
        mode_offset, mode_desc = tmc_registers['MODE']
        rsz_offset, rsz_desc = tmc_registers['RSZ']

        ctl = ram_dump.read_u32(self.tmc_etf_start + ctl_offset, False)
        mode = ram_dump.read_u32(self.tmc_etf_start + mode_offset, False)
        rsz = ram_dump.read_u32(self.tmc_etf_start + rsz_offset, False)
        # rsz is given in words so convert to bytes
        rsz = 4 * rsz

        if (ctl & 0x1) == 1 and (mode == 0):
            for i in range(0, rsz):
                val = ram_dump.read_byte(self.etf_start + i, False)
                tmc_etf.write(struct.pack('<B', val))
        else:
            print_out_str('!!! ETF was not the current sink!')

        tmc_etf.close()

    def read_sg_data(self, dbaddr, sts, rwpval, ram_dump, tmc_etr):
        start = dbaddr
        continue_looping = True
        if (sts & 0x1) == 1:
            bottom_delta_read = False
            while continue_looping:
                entry = ram_dump.read_u32(start, False)
                blk = (entry >> 4) << 12
                if (entry & 0x3) == 3:
                    start = blk
                    continue
                elif (entry & 0x2) == 2:
                    if blk < rwpval and rwpval < (blk + 4096):
                        if not bottom_delta_read:
                            it = range(rwpval, blk + 4096)
                            bottom_delta_read = True
                        else:
                            it = range(blk, blk + (rwpval - blk))
                            continue_looping = False
                    elif bottom_delta_read:
                        it = range(blk, blk + 4096)
                    else:
                        start += 4
                        continue
                    start += 4
                elif (entry & 0x1) == 1:
                    if blk < rwpval and rwpval < (blk + 4096):
                        if not bottom_delta_read:
                            it = range(rwpval, blk + 4096)
                            bottom_delta_read = True
                        else:
                            it = range(blk, blk + (rwpval - blk))
                            continue_looping = False
                    elif bottom_delta_read:
                        it = range(blk, blk + 4096)
                    else:
                        start = dbaddr
                        continue
                    start = dbaddr
                else:
                    break

                for i in it:
                    val = ram_dump.read_byte(i, False)
                    tmc_etr.write(struct.pack("<B",val))
        else:
            while continue_looping:
                entry = ram_dump.read_u32(start, False)
                blk = (entry >> 4) << 12
                if (entry & 0x3) == 3:
                    start = blk
                    continue
                elif (entry & 0x2) == 2:
                    it = range(blk, blk + 4096)
                    start += 4
                elif (entry & 0x1) == 1:
                    it = range(blk, blk + 4096)
                    continue_looping = False
                else:
                    break

                for i in it:
                    val = ram_dump.read_byte(i, False)
                    tmc_etr.write(struct.pack("<B",val))

    def save_etr_bin(self, ram_dump):
        tmc_etr = ram_dump.open_file('tmc-etr.bin')
        if self.tmc_etr_start is None:
            print_out_str('!!! ETR was not enabled!')
            tmc_etr.close()
            return

        ctl_offset, ctl_desc = tmc_registers['CTL']
        mode_offset, mode_desc = tmc_registers['MODE']

        ctl = ram_dump.read_u32(self.tmc_etr_start + ctl_offset, False)
        mode = ram_dump.read_u32(self.tmc_etr_start + mode_offset, False)

        if (ctl & 0x1) == 1 and (mode == 0):
            sts_offset, sts_desc = tmc_registers['STS']
            sts = ram_dump.read_u32(self.tmc_etr_start + sts_offset, False)

            dbalo_offset, dbalo_desc = tmc_registers['DBALO']
            dbalo = ram_dump.read_u32(
                self.tmc_etr_start + dbalo_offset, False)
            dbahi_offset, dbahi_desc = tmc_registers['DBAHI']
            dbahi = ram_dump.read_u32(
                self.tmc_etr_start + dbahi_offset, False)
            dbaddr = (dbahi << 32) + dbalo

            rsz_offset, rsz_desc = tmc_registers['RSZ']
            rsz = ram_dump.read_u32(self.tmc_etr_start + rsz_offset, False)
            # rsz is given in words so convert to bytes
            rsz = 4 * rsz

            rwp_offset, rwp_desc = tmc_registers['RWP']
            rwp = ram_dump.read_u32(self.tmc_etr_start + rwp_offset, False)
            rwphi_offset, rwphi_desc = tmc_registers['RWPHI']
            rwphi = ram_dump.read_u32(self.tmc_etr_start + rwphi_offset, False)
            rwpval = (rwphi << 32) + rwp

            axictl_offset, axictl_desc = tmc_registers["AXICTL"]
            axictl = ram_dump.read_u32(self.tmc_etr_start + axictl_offset, False)

            if ((axictl >> 7) & 0x1) == 1:
                print_out_str('Scatter gather memory type was selected for TMC ETR')
                self.read_sg_data(dbaddr, sts, rwpval, ram_dump, tmc_etr)
            else:
                print_out_str('Contiguous memory type was selected for TMC ETR')
                if (sts & 0x1) == 1:
                    it = itertools.chain(range(rwpval, dbaddr+rsz), range(dbaddr, rwpval))
                else:
                    it = range(dbaddr, dbaddr+rsz)

                for i in it:
                    val = ram_dump.read_byte(i, False)
                    tmc_etr.write(struct.pack("<B",val))
        else:
            print_out_str ('!!! ETR was not the current sink!')

        tmc_etr.close()

    def dump_all(self, ram_dump):
        self.print_tmc_etf(ram_dump)
        self.print_tmc_etr(ram_dump)
        self.print_all_etm_register(ram_dump)
        self.save_etf_bin(ram_dump)
        self.save_etr_bin(ram_dump)