-
Susheel Khiani authored
Some clients can generate 48/49 bit virtual address. Enhance ramdump parser to add support for this page table format. Change-Id: I46d803e7fcecadc73e0ccca3422d586c00ecc610
5162ebea
lpaeiommulib.py 7.33 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, domain_num):
fname = 'msm_iommu_domain_%02d.txt' % (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)