Skip to content
Snippets Groups Projects
Select Git revision
  • f3dbb5dceb5b9be42df137ea7aa8c3b310e4fee5
  • test default
2 results

lpaeiommulib.py

Blame
  • lpaeiommulib.py 7.32 KiB
    # Copyright (c) 2013-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.
    
    try:
        from collections import OrderedDict
    except ImportError:
        from ordereddict import OrderedDict
    
    from print_out import print_out_str
    from register import Register
    from mmu import Armv7LPAEMMU
    import sizes
    
    NUM_FL_PTE = 4
    NUM_SL_PTE = 512
    NUM_TL_PTE = 512
    
    def print_lpae_mappings(mappings, outfile):
        """Dump some page tables. `mappings' should already be sorted."""
        fmt = '[0x{vstart:08x}--0x{vend:08x}] [0x{size:08x}] [A:0x{pstart:08x}--0x{pend:08x}] [{attrs}][{sizestring}]\n'
        fmt_unmapped = '[0x{vstart:08x}--0x{vend:08x}] [0x{size:08x}] [UNMAPPED]\n'
        for ((virt_start, virt_end), info) in mappings.iteritems():
            if info is None:
                outfile.write(fmt_unmapped.format(
                    vstart=virt_start,
                    vend=virt_end,
                    size=virt_end - virt_start,
                ))
            else:
                outfile.write(fmt.format(
                    vstart=virt_start,
                    vend=virt_end,
                    size=info.page_size,
                    pstart=info.phys,
                    pend=info.phys + info.page_size,
                    attrs=','.join(info.get_attributes_strings()),
                    sizestring=sizes.get_size_string(info.page_size)
                ))
    
    def get_flat_mappings(domain, mmu):
        """Walk some LPAE IOMMU page tables by iterating over all possible
        page table entries at each level. Returns a dictionary of the
        form: {(virt_start, virt_end): LeafMapping object, ...}
    
        """
        mappings = {}
        n = mmu.input_addr_split
        virt_r = Register(fl_index=(n + 26, 30),
                          sl_index=(29, 21),
                          tl_index=(20, 12),
                          page_index=(11, 0))
        for fl_index in range(0, NUM_FL_PTE):
            virt_r.zero()
            virt_r.fl_index = fl_index
            info1 = mmu.translate_first_level(virt_r)
            if info1 is None:
                continue
            if info1.leaf:
                virt = virt_r.value
                mappings[virt, virt + info1.page_size] = info1
                continue
    
            # this is a table. do the second-level lookup:
            for sl_index in range(0, NUM_SL_PTE):
                virt_r.sl_index = sl_index
                info2 = mmu.translate_second_level(virt_r, info1.next_table_addr)
                if info2 is None:
                    continue
                if info2.leaf:
                    virt = virt_r.value
                    mappings[virt, virt + info2.page_size] = info2
                    continue
    
                # this is a table. do the third-level lookup:
                for tl_index in range(0, NUM_TL_PTE):
                    virt_r.tl_index = tl_index
                    info3 = mmu.translate_third_level(virt_r, info2.next_table_addr)
                    if info3 is None:
                        continue
                    if not info3.leaf:
                        raise Exception('Non-leaf third-level PTE???')
                    virt = virt_r.value
                    mappings[virt, virt + info3.page_size] = info3
    
        return OrderedDict(sorted(mappings.items()))
    
    def get_coalesced_mappings(flat_mappings):
        """Convert some "flat" mappings (from `get_flat_mappings') to a more
        compact representation where contiguous ranges are coalesced.
    
        """
        # fair warning: things are about to get a little hairy. have fun.
    
        flat_items = flat_mappings.items()
        # samers maps indices into flat_items to coalesced virtual
        # starting addresses for those items.
        samers = {}
        # mark adjacent equivalent mappings
        for i, (virt_range, info) in enumerate(flat_items):
            virt_start, virt_end = virt_range
            if i == 0:
                cur_virt = virt_start
                continue
            prev_range, prev_info = flat_items[i - 1]
            prev_start, prev_end = prev_range
            if virt_start == prev_end and \
               info.attributes == prev_info.attributes:
                samers[i] = cur_virt
            else:
                cur_virt = virt_start
    
        # merge adjacent equivalent mappings. coalesced_mappings will be
        # keyed by starting virtual address alone.
        coalesced_mappings = {}
        for i, (virt_range, info) in enumerate(flat_items):
            virt_start, virt_end = virt_range
            page_size = virt_end - virt_start
            if i in samers:
                coalesced_mappings[samers[i]].page_size += page_size
                continue
            if virt_start not in coalesced_mappings:
                coalesced_mappings[virt_start] = info
                continue
            else:
                raise ValueError('We should have either gotten a samer or something not in coalesced_mappings...')
    
        # convert coalesced_mappings to cc, which is keyed by a 2-tuple of
        # the form: (virt_start, virt_end). Still mapping to the same
        # LeafMapping objects.
        cc = dict(((virt_start, virt_start + info.page_size), info)
                  for virt_start,info in coalesced_mappings.iteritems())
        # maintain order to facilitate finding unmapped gaps
        cc = OrderedDict(sorted(cc.items()))
    
        # fill in the unmapped gaps by adding mappings to `None':
        if len(cc) > 0:
            (first_vstart, first_vend), info = cc.items()[0]
            (last_vstart, last_vend), info = cc.items()[-1]
            if first_vstart != 0:
                cc[0, first_vstart] = None
            if last_vend != 0xffffffff:
                cc[last_vend, 0xffffffff] = None
            cc = OrderedDict(sorted(cc.items()))
            keys = cc.keys()
            for i, ((vstart, vend), info) in enumerate(cc.items()[1:-1]):
                prev_start, prev_end = keys[i] # no need for -1 since we're iterating starting at 1
                if prev_end != vstart:
                    cc[prev_end, vstart] = None
        cc = OrderedDict(sorted(cc.items()))
        return cc
    
    def parse_long_form_tables(dump, d):
        fname = 'msm_iommu_domain_%02d.txt' % (d.domain_num)
        with dump.open_file(fname) as outfile:
    
            print_out_str('LPAE Iommu page tables: ' + fname)
    
            t0sz = 0
            mmu = Armv7LPAEMMU(dump, d.pg_table, t0sz, virt_for_fl=True)
    
            redirect = 'OFF'
            if d.redirect is None:
                redirect = 'UNKNOWN'
            elif d.redirect > 0:
                redirect = 'ON'
            iommu_context = ' '.join('%s (%s)' % (name, num)
                                     for (name, num) in d.ctx_list)
            iommu_context = iommu_context or 'None attached'
    
            outfile.write('IOMMU Context: %s. Domain: %s (%d) [L2 cache redirect for page tables is %s]\n' % (
                iommu_context, d.client_name, d.domain_num, redirect))
            outfile.write(
                '[VA Start -- VA End  ] [Size      ] [PA Start   -- PA End  ] [Attributes][Page Table Entry Size]\n')
            if d.pg_table == 0:
                outfile.write(
                    'No Page Table Found. (Probably a secure domain)\n')
            else:
                mappings = get_flat_mappings(d, mmu)
                print_lpae_mappings(get_coalesced_mappings(mappings), outfile)
                outfile.write('\n-------------\nRAW Dump\n')
                outfile.write('Raw: ' + str(d) + '\n')
                print_lpae_mappings(mappings, outfile)