diff --git a/linux-ramdump-parser-v2/iommulib.py b/linux-ramdump-parser-v2/iommulib.py index fc941e20e5bd4ab73aa84f19c62a300015b7991a..f7f80796242e3c52643485dc55669ba41708ecc7 100644 --- a/linux-ramdump-parser-v2/iommulib.py +++ b/linux-ramdump-parser-v2/iommulib.py @@ -20,6 +20,9 @@ class Domain(object): self.ctx_list = ctx_list self.client_name = client_name + def __repr__(self): + return "#%d: %s" % (self.domain_num, self.client_name) + class IommuLib(object): def __init__(self, ramdump): self.ramdump = ramdump diff --git a/linux-ramdump-parser-v2/lpaeiommulib.py b/linux-ramdump-parser-v2/lpaeiommulib.py new file mode 100644 index 0000000000000000000000000000000000000000..85edcd967338b4cb6745f748e863e52b6e5d29ca --- /dev/null +++ b/linux-ramdump-parser-v2/lpaeiommulib.py @@ -0,0 +1,187 @@ +# 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. + +from collections 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) diff --git a/linux-ramdump-parser-v2/mmu.py b/linux-ramdump-parser-v2/mmu.py index 5b41a9f2b90b5fafb144e6fcd21d0ae8bbb66bf6..fad2b3159791ccc8737e871f4e66836fbba8559d 100644 --- a/linux-ramdump-parser-v2/mmu.py +++ b/linux-ramdump-parser-v2/mmu.py @@ -11,6 +11,7 @@ from bitops import bm, bvalsel from register import Register +import sizes class MMU(object): @@ -154,11 +155,195 @@ class Armv7LPAEMMU(MMU): TL_DESCRIPTOR_RESERVED = 0x1 TL_DESCRIPTOR_PAGE = 0x3 + # Mapping classes + class MappingInfo(object): pass + + class LeafMapping(MappingInfo): + def __init__(self, virt_r, descriptor, page_size, n): + self.virt_r = virt_r + + self.descriptor = descriptor + self.attributes = Register( + descriptor.value, + software=(58, 55), + XN=(54, 54), + PXN=(53, 53), + contiguous_hint=(52, 52), + nG=(11, 11), + AF=(10, 10), + sh_10=(9, 8), + ap_21=(7, 6), + ns=(5, 5), + attr_index_20=(4, 2), + ) + + self.page_size = page_size + self.leaf = True + + p = Register(output_address=(39, n), page_offset=(n - 1, 0)) + p.output_address = self.descriptor.output_address + self.virt_r.add_field('rest', (n - 1, 0)) + p.page_offset |= self.virt_r.rest + self.phys = p.value + + def __repr__(self): + pstart, pend = self.phys_addr_range() + return '[{:x}-{:x}][{:}]'.format( + pstart, pend, + ','.join(self.get_attributes_strings()) + ) + + def phys_addr_range(self): + return (self.phys, self.phys + self.page_size) + + def get_attributes_strings(self): + attrs = [ + self.get_xn_string(), self.get_pxn_string(), + self.get_contiguous_hint_string(), + self.get_nG_string(), self.get_AF_string(), + self.get_sh_string(), self.get_ap_21_string(), + self.get_ns_string(), self.get_attr_index_20_string(), + ] + return [a for a in attrs if a != ''] + + def get_xn_string(self): + if self.attributes.XN == 1: + return 'XN' + return '' + + def get_pxn_string(self): + if self.attributes.PXN == 1: + return 'PXN' + return '' + + def get_contiguous_hint_string(self): + if self.attributes.contiguous_hint == 1: + return 'Contiguous' + return '' + + def get_nG_string(self): + if self.attributes.nG == 1: + return 'nG' + return '' + + def get_AF_string(self): + if self.attributes.AF == 1: + return 'AF' + return '' + + def get_sh_string(self): + if self.attributes.sh_10 == 0b00: + return 'Non-shareable' + elif self.attributes.sh_10 == 0b01: + return 'UNPREDICTABLE' + elif self.attributes.sh_10 == 0b10: + return 'Outer Shareable' + elif self.attributes.sh_10 == 0b11: + return 'Inner Shareable' + raise ValueError('Impossible sh[1:0]: 0x%x' % self.attributes.sh_10) + + def get_ap_21_string(self): + if self.attributes.ap_21 == 0b00: + return 'R/W@PL1' + elif self.attributes.ap_21 == 0b01: + return 'R/W' + elif self.attributes.ap_21 == 0b10: + return 'R/O@PL1' + elif self.attributes.ap_21 == 0b11: + return 'R/O' + raise ValueError('Impossible ap[2:1]: 0x%x' % self.attributes.ap_21) + + def get_ns_string(self): + if self.attributes.ns == 1: + return 'NS' + return '' + + def get_attr_index_20_string(self): + return 'AI=0x%x' % self.attributes.attr_index_20 + + class TableMapping(MappingInfo): + def __init__(self, next_table_addr): + self.next_table_addr = next_table_addr + self.leaf = False + + def __repr__(self): + return '[Next Table: 0x%x]' % ( + self.next_table_addr + ) + + class FLBlockMapping(LeafMapping): + def __init__(self, virt_r, desc): + super(Armv7LPAEMMU.FLBlockMapping, self).__init__( + virt_r, desc, sizes.SZ_1G, 30) + + class SLBlockMapping(LeafMapping): + def __init__(self, virt_r, desc): + super(Armv7LPAEMMU.SLBlockMapping, self).__init__( + virt_r, desc, sizes.SZ_2M, 21) + + class TLPageMapping(LeafMapping): + def __init__(self, virt_r, desc): + super(Armv7LPAEMMU.TLPageMapping, self).__init__( + virt_r, desc, sizes.SZ_4K, 12) + + class FLTableMapping(TableMapping): pass + class SLTableMapping(TableMapping): pass + + + # Exceptions + class LookupException(Exception): pass + class LookupExceptionFLSL(LookupException): pass + class LookupExceptionTL(LookupException): pass + + def __init__(self, ramdump, pgtbl, txsz, virt_for_fl=False): + """Constructor for Armv7LPAEMMU. + + - ramdump: RamDump instance + + - pgtbl: base address of page table + + - txsz: t0sz or t1sz (see ARM ARM B3.6.6 (rev 0406C.b)) + + - virt_for_fl: whether we should do a virtual address lookup + for the first-level page table. Note that it wouldn't make + any sense to pass `True' here if this is the "main" mmu + instance for a RamDump, because then the RamDump would try + to invoke this very object to do the lookup, and we would + recursively discover the higgs boson. This option is useful, + though, for parsing LPAE page tables whose first-level page + table is sitting in kernel address space (as is the case for + the IOMMU LPAE page tables). + + """ + super(Armv7LPAEMMU, self).__init__(ramdump) + self.pgtbl = pgtbl + self.txsz = txsz + self.virt_for_fl = virt_for_fl + + if (32 - txsz) > 30: + self.initial_lkup_level = 1 + self.initial_block_split = 12 + else: + self.initial_lkup_level = 2 + self.initial_block_split = 21 + + if self.initial_lkup_level == 1: + # see the ARMv7 ARM B3.6.6 (rev 0406C.b): + self.input_addr_split = 5 - self.txsz + if self.input_addr_split not in [4, 5]: + raise ValueError("Invalid stage 1 first-level `n' value: 0x%x. Please check txsz." + % self.input_addr_split) + else: + # see the ARMv7 ARM B3.6.6 (rev 0406C.b): + self.input_addr_split = 14 - self.txsz + if self.input_addr_split not in range(7, 13): + raise ValueError("Invalid stage 1 second-level (initial) `n' value: 0x%x. Please check txsz." + % self.input_addr_split) + def do_fl_sl_level_lookup(self, table_base_address, table_index, - input_addr_split, block_split): + block_split, virtual=False): descriptor, addr = self.do_level_lookup( - table_base_address, table_index, - input_addr_split) + table_base_address, table_index, virtual=virtual) if descriptor.dtype == Armv7LPAEMMU.DESCRIPTOR_BLOCK: descriptor.add_field('output_address', (39, block_split)) elif descriptor.dtype == Armv7LPAEMMU.DESCRIPTOR_TABLE: @@ -166,35 +351,25 @@ class Armv7LPAEMMU(MMU): # next_level_base_addr_upper descriptor.add_field('next_level_base_addr_upper', (39, 12)) else: - raise Exception( + raise Armv7LPAEMMU.LookupExceptionFLSL( 'Invalid stage 1 first- or second-level translation\ndescriptor: (%s)\naddr: (%s)' % (str(descriptor), str(addr)) ) return descriptor - def do_fl_level_lookup(self, table_base_address, table_index, - input_addr_split): - return self.do_fl_sl_level_lookup(table_base_address, table_index, - input_addr_split, 30) - - def do_sl_level_lookup(self, table_base_address, table_index): - return self.do_fl_sl_level_lookup(table_base_address, table_index, - 12, 21) - def do_tl_level_lookup(self, table_base_address, table_index): descriptor, addr = self.do_level_lookup( - table_base_address, table_index, 12) + table_base_address, table_index) if descriptor.dtype == Armv7LPAEMMU.TL_DESCRIPTOR_PAGE: descriptor.add_field('output_address', (39, 12)) else: - raise Exception( + raise Armv7LPAEMMU.LookupExceptionTL( 'Invalid stage 1 third-level translation\ndescriptor: (%s)\naddr: (%s)' % (str(descriptor), str(addr)) ) return descriptor - def do_level_lookup(self, table_base_address, table_index, - input_addr_split): + def do_level_lookup(self, table_base_address, table_index, virtual=False): """Does a base + index descriptor lookup. Returns a tuple with the Register object representing the found @@ -202,107 +377,102 @@ class Armv7LPAEMMU(MMU): descriptor address. """ - n = input_addr_split + n = self.input_addr_split # these Registers are overkill but nice documentation:). table_base = Register(table_base_address, base=(39, n)) - descriptor_addr = Register(base=(39, n), - offset=(n - 1, 3)) + descriptor_addr = Register(base=(39, n), offset=(n - 1, 3)) descriptor_addr.base = table_base.base descriptor_addr.offset = table_index - descriptor_val = self.read_phys_dword(descriptor_addr.value) - descriptor = Register(descriptor_val, - dtype=(1, 0)) + descriptor_val = self.ramdump.read_dword( + descriptor_addr.value, virtual=virtual) + descriptor = Register(descriptor_val, dtype=(1, 0)) return descriptor, descriptor_addr - def block_or_page_desc_2_phys(self, desc, virt_r, n): - phys = Register(output_address=(39, n), - page_offset=(n - 1, 0)) - phys.output_address = desc.output_address - virt_r.add_field('rest', (n - 1, 0)) - phys.page_offset |= virt_r.rest - return phys.value + def load_page_tables(self): + pass - def fl_block_desc_2_phys(self, desc, virt_r): - """Block descriptor to physical address.""" - return self.block_or_page_desc_2_phys(desc, virt_r, 30) + def page_table_walk(self, virt): + info = self.translate(virt) + return info.phys if info is not None else None - def sl_block_desc_2_phys(self, desc, virt_r): - """Block descriptor to physical address.""" - return self.block_or_page_desc_2_phys(desc, virt_r, 21) + def translate_first_level(self, virt_r): + try: + fl_desc = self.do_fl_sl_level_lookup(self.pgtbl, virt_r.fl_index, + 30, virtual=self.virt_for_fl) + except Armv7LPAEMMU.LookupExceptionFLSL: + return None - def tl_page_desc_2_phys(self, desc, virt_r): - """Page descriptor to physical address.""" - return self.block_or_page_desc_2_phys(desc, virt_r, 12) + # if we got a block descriptor we're done: + if fl_desc.dtype == Armv7LPAEMMU.DESCRIPTOR_BLOCK: + return Armv7LPAEMMU.FLBlockMapping(virt_r, fl_desc) - def read_phys_dword(self, physaddr): - return self.ramdump.read_dword(physaddr, virtual=False) + base = Register(base=(39, 12)) + base.base = fl_desc.next_level_base_addr_upper + return Armv7LPAEMMU.FLTableMapping(base.value) - def load_page_tables(self): - pass + def translate_second_level(self, virt_r, level2_table_addr, block_split=None): + if block_split is None: + block_split = self.initial_block_split + try: + sl_desc = self.do_fl_sl_level_lookup( + level2_table_addr, virt_r.sl_index, block_split) + # res.next_table_addr, virt_r.sl_index, 12, 21) + except Armv7LPAEMMU.LookupExceptionFLSL: + return None - def __init__(self, ramdump, pgtbl, t1sz, initial_lkup_level): - super(Armv7LPAEMMU, self).__init__(ramdump) - self.pgtbl = pgtbl - self.t1sz = t1sz - self.initial_lkup_level = initial_lkup_level + # if we got a block descriptor we're done: + if sl_desc.dtype == Armv7LPAEMMU.DESCRIPTOR_BLOCK: + return Armv7LPAEMMU.SLBlockMapping(virt_r, sl_desc) - def page_table_walk(self, virt): + base = Register(base=(39, 12)) + base.base = sl_desc.next_level_base_addr_upper + return Armv7LPAEMMU.SLTableMapping(base.value) + def translate_third_level(self, virt_r, level3_table_addr): + try: + tl_desc = self.do_tl_level_lookup( + level3_table_addr, virt_r.tl_index) + except Armv7LPAEMMU.LookupExceptionTL: + return None + + return Armv7LPAEMMU.TLPageMapping(virt_r, tl_desc) + + def translate(self, virt): + """Does a page table walk and returns a LeafMapping that describes the + mapping (including the physical address and mapping + attributes) + + """ if self.initial_lkup_level == 1: - # see the ARMv7 ARM B3.6.6 (rev 0406C.b): - input_addr_split = 5 - self.t1sz - if input_addr_split not in [4, 5]: - raise Exception("Invalid stage 1 first-level `n' value: 0x%x" - % input_addr_split) virt_r = Register(virt, - fl_index=(input_addr_split + 26, 30), + fl_index=(self.input_addr_split + 26, 30), sl_index=(29, 21), tl_index=(20, 12), page_index=(11, 0)) - fl_desc = self.do_fl_level_lookup( - self.pgtbl, virt_r.fl_index, input_addr_split) - # if we got a block descriptor we're done: - if fl_desc.dtype == Armv7LPAEMMU.DESCRIPTOR_BLOCK: - return self.fl_block_desc_2_phys(fl_desc, virt_r) + res = self.translate_first_level(virt_r) - base = Register(base=(39, 12)) - base.base = fl_desc.next_level_base_addr_upper - sl_desc = self.do_sl_level_lookup( - base.value, virt_r.sl_index) + if res is None or res.leaf: + return res + level2_table_addr = res.next_table_addr elif self.initial_lkup_level == 2: - # see the ARMv7 ARM B3.6.6 (rev 0406C.b): - input_addr_split = 14 - self.t1sz - if input_addr_split not in range(7, 13): - raise Exception("Invalid stage 1 second-level (initial) `n' value: 0x%x" - % input_addr_split) virt_r = Register(virt, - sl_index=(input_addr_split + 17, 21), + sl_index=(self.input_addr_split + 17, 21), tl_index=(20, 12), page_index=(11, 0)) - try: - sl_desc = self.do_fl_sl_level_lookup( - self.pgtbl, virt_r.sl_index, input_addr_split, 21) - except: - return None + level2_table_addr = self.pgtbl else: - raise Exception('Invalid initial lookup level (0x%x)' % + raise ValueError('Invalid initial lookup level (0x%x). Should be 1 or 2.' % self.initial_lkup_level) - # if we got a block descriptor we're done: - if sl_desc.dtype == Armv7LPAEMMU.DESCRIPTOR_BLOCK: - return self.sl_block_desc_2_phys(sl_desc, virt_r) + res = self.translate_second_level(virt_r, level2_table_addr) - base = Register(base=(39, 12)) - base.base = sl_desc.next_level_base_addr_upper - try: - tl_desc = self.do_tl_level_lookup( - base.value, virt_r.tl_index) - except: - return None + if res is None or res.leaf: + return res - return self.tl_page_desc_2_phys(tl_desc, virt_r) + level3_table_addr = res.next_table_addr + return self.translate_third_level(virt_r, level3_table_addr) def dump_page_tables(self, f): f.write( diff --git a/linux-ramdump-parser-v2/parsers/iommu.py b/linux-ramdump-parser-v2/parsers/iommu.py index 0216ee9a597c86e811da9aa8329a74566932c016..af4d59e7a8619ef2be6bbd535719dc04fb122306 100644 --- a/linux-ramdump-parser-v2/parsers/iommu.py +++ b/linux-ramdump-parser-v2/parsers/iommu.py @@ -15,6 +15,7 @@ from print_out import print_out_str from parser_util import register_parser, RamParser from sizes import SZ_4K, SZ_64K, SZ_1M, SZ_16M, get_order, order_size_strings from iommulib import IommuLib +from lpaeiommulib import parse_long_form_tables @register_parser('--print-iommu-pg-tables', 'Print IOMMU page tables') class IOMMU(RamParser): @@ -302,6 +303,34 @@ class IOMMU(RamParser): self.out_file.write('0x%08x--0x%08x [0x%08x] [UNMAPPED]\n' % (mapping.virt_start, mapping.virt_end, mapping.virt_size())) + def parse_short_form_tables(self, d): + self.out_file = self.ramdump.open_file( + 'msm_iommu_domain_%02d.txt' % (d.domain_num)) + redirect = 'OFF' + if d.redirect is None: + redirect = 'UNKNOWN' + elif d.redirect > 0: + redirect = 'ON' + iommu_context = 'None attached' + if len(d.ctx_list) > 0: + iommu_context = '' + for (num, name) in d.ctx_list: + iommu_context += '%s (%d) ' % (name, num) + iommu_context = iommu_context.strip() + + self.out_file.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)) + self.out_file.write( + '[VA Start -- VA End ] [Size ] [PA Start -- PA End ] [Size ] [Read/Write][Page Table Entry Size]\n') + if d.pg_table == 0: + self.out_file.write( + 'No Page Table Found. (Probably a secure domain)\n') + else: + self.print_page_table_pretty(d.pg_table) + self.out_file.write('\n-------------\nRAW Dump\n') + self.print_page_table(d.pg_table) + self.out_file.close() + def parse(self): ilib = IommuLib(self.ramdump) self.domain_list = ilib.domain_list @@ -311,29 +340,7 @@ class IOMMU(RamParser): return for d in self.domain_list: - self.out_file = self.ramdump.open_file( - 'msm_iommu_domain_%02d.txt' % (d.domain_num)) - redirect = 'OFF' - if d.redirect is None: - redirect = 'UNKNOWN' - elif d.redirect > 0: - redirect = 'ON' - iommu_context = 'None attached' - if len(d.ctx_list) > 0: - iommu_context = '' - for (num, name) in d.ctx_list: - iommu_context += '%s (%d) ' % (name, num) - iommu_context = iommu_context.strip() - - self.out_file.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)) - self.out_file.write( - '[VA Start -- VA End ] [Size ] [PA Start -- PA End ] [Size ] [Read/Write][Page Table Entry Size]\n') - if d.pg_table == 0: - self.out_file.write( - 'No Page Table Found. (Probably a secure domain)\n') + if self.ramdump.is_config_defined('CONFIG_IOMMU_LPAE'): + parse_long_form_tables(self.ramdump, d) else: - self.print_page_table_pretty(d.pg_table) - self.out_file.write('\n-------------\nRAW Dump\n') - self.print_page_table(d.pg_table) - self.out_file.close() + self.parse_short_form_tables(d) diff --git a/linux-ramdump-parser-v2/ramdump.py b/linux-ramdump-parser-v2/ramdump.py index 75d748507f0dd969996ce7872211ada368a0c5ae..e2b3bea7c9e63b8d1b1ba0757d75153352c68f06 100644 --- a/linux-ramdump-parser-v2/ramdump.py +++ b/linux-ramdump-parser-v2/ramdump.py @@ -513,10 +513,8 @@ class RamDump(): # * 0xc0000000: T0SZ = 0, T1SZ = 2 if self.page_offset == 0x40000000: t1sz = 0 - initial_lkup_level = 1 elif self.page_offset == 0x80000000: t1sz = 1 - initial_lkup_level = 1 elif self.page_offset == 0xc0000000: t1sz = 2 # need to fixup ttbr1 since we'll be skipping the @@ -525,13 +523,11 @@ class RamDump(): # add \ttbr1, \ttbr1, #4096 * (1 + 3) @ only L2 used, skip # pgd+3*pmd swapper_pg_dir_addr += (4096 * (1 + 3)) - initial_lkup_level = 2 else: raise Exception( 'Invalid phys_offset for page_table_walk: 0x%x' % self.page_offset) - self.mmu = Armv7LPAEMMU(self, swapper_pg_dir_addr, - t1sz, initial_lkup_level) + self.mmu = Armv7LPAEMMU(self, swapper_pg_dir_addr, t1sz) else: print_out_str( "!!! Couldn't determine whether or not we're using LPAE!")