Skip to content
Snippets Groups Projects
Commit fb473f25 authored by Linux Build Service Account's avatar Linux Build Service Account Committed by Gerrit - the friendly Code Review server
Browse files

Merge "lrdp-v2: refactor Iommu domain parsing code"

parents 54748268 29d3f2ed
No related branches found
No related tags found
No related merge requests found
# Copyright (c) 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 rb_tree
import linux_list as llist
class Domain(object):
def __init__(self, domain_num, pg_table, redirect, ctx_list, client_name):
self.domain_num = domain_num
self.pg_table = pg_table
self.redirect = redirect
self.ctx_list = ctx_list
self.client_name = client_name
class IommuLib(object):
def __init__(self, ramdump):
self.ramdump = ramdump
self.domain_list = []
root = self.ramdump.read_word('domain_root')
if root is None:
return
rb_walker = rb_tree.RbTreeWalker(self.ramdump)
rb_walker.walk(root, self._iommu_domain_func, self.domain_list)
def _iommu_list_func(self, node, ctx_list):
ctx_drvdata_name_ptr = self.ramdump.read_word(
node + self.ramdump.field_offset('struct msm_iommu_ctx_drvdata', 'name'))
ctxdrvdata_num_offset = self.ramdump.field_offset(
'struct msm_iommu_ctx_drvdata', 'num')
num = self.ramdump.read_word(node + ctxdrvdata_num_offset)
if ctx_drvdata_name_ptr != 0:
name = self.ramdump.read_cstring(ctx_drvdata_name_ptr, 100)
ctx_list.append((num, name))
def _iommu_domain_func(self, node, domain_list):
domain_num = self.ramdump.read_word(self.ramdump.sibling_field_addr(
node, 'struct msm_iova_data', 'node', 'domain_num'))
domain = self.ramdump.read_word(self.ramdump.sibling_field_addr(
node, 'struct msm_iova_data', 'node', 'domain'))
priv_ptr = self.ramdump.read_word(
domain + self.ramdump.field_offset('struct iommu_domain', 'priv'))
client_name_offset = self.ramdump.field_offset(
'struct msm_iommu_priv', 'client_name')
if client_name_offset is not None:
client_name_ptr = self.ramdump.read_word(
priv_ptr + self.ramdump.field_offset(
'struct msm_iommu_priv', 'client_name'))
if client_name_ptr != 0:
client_name = self.ramdump.read_cstring(client_name_ptr, 100)
else:
client_name = '(null)'
else:
client_name = 'unknown'
list_attached_offset = self.ramdump.field_offset(
'struct msm_iommu_priv', 'list_attached')
if list_attached_offset is not None:
list_attached = self.ramdump.read_word(priv_ptr + list_attached_offset)
else:
list_attached = None
priv_pt_offset = self.ramdump.field_offset('struct msm_iommu_priv', 'pt')
pgtable_offset = self.ramdump.field_offset('struct msm_iommu_pt', 'fl_table')
redirect_offset = self.ramdump.field_offset('struct msm_iommu_pt', 'redirect')
if priv_pt_offset is not None:
pg_table = self.ramdump.read_word(
priv_ptr + priv_pt_offset + pgtable_offset)
redirect = self.ramdump.read_word(
priv_ptr + priv_pt_offset + redirect_offset)
else:
# On some builds we are unable to look up the offsets so hardcode
# the offsets.
pg_table = self.ramdump.read_word(priv_ptr + 0)
redirect = self.ramdump.read_word(priv_ptr + self.ramdump.sizeof('void *'))
# Note: On some code bases we don't have this pg_table and redirect in the priv structure (see msm_iommu_sec.c). It only
# contains list_attached. If this is the case we can detect that by checking whether
# pg_table == redirect (prev == next pointers of the attached
# list).
if pg_table == redirect:
# This is a secure domain. We don't have access to the page
# tables.
pg_table = 0
redirect = None
ctx_list = []
if list_attached is not None and list_attached != 0:
list_walker = llist.ListWalker(
self.ramdump, list_attached,
self.ramdump.field_offset('struct msm_iommu_ctx_drvdata', 'attached_elm'))
list_walker.walk(list_attached, self._iommu_list_func, extra=ctx_list)
domain_list.append(
Domain(domain_num, pg_table, redirect, ctx_list, client_name))
# Copyright (c) 2013, The Linux Foundation. All rights reserved.
# 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
......@@ -17,50 +17,32 @@ struct list_head {
};
'''
def get_list_offsets(ram_dump):
next_offset = ram_dump.field_offset('struct list_head', 'next')
prev_offset = ram_dump.field_offset('struct list_head', 'prev')
return next_offset, prev_offset
class ListWalker(object):
'''
ram_dump: Reference to the ram dump
node_addr: The address of the first element of the list
list_elem_offset: The offset of the list_head in the structure that this list is container for.
next_offset: The offset for the next pointer in the list
prev_offset: The offset for the prev pointer in the list
'''
def __init__(self, ram_dump, node_addr, list_elem_offset, next_offset, prev_offset):
self.LIST_OFFSETS = [
('((struct list_head *)0x0)', 'next', 0, 0),
('((struct list_head *)0x0)', 'prev', 0, 0),
]
self.LIST_NEXT_IDX = 0
self.LIST_PREV_IDX = 1
def __init__(self, ram_dump, node_addr, list_elem_offset):
self.ram_dump = ram_dump
self.next_offset = next_offset
self.prev_offset = prev_offset
self.list_elem_offset = list_elem_offset
self.last_node = node_addr
self.seen_nodes = []
def walk(self, node_addr, func):
def walk(self, node_addr, func, extra=None):
if node_addr != 0:
func(node_addr - self.list_elem_offset)
func(node_addr - self.list_elem_offset, extra)
next_node_addr = node_addr + self.next_offset
next_node_addr = node_addr + self.ram_dump.field_offset('struct list_head', 'next')
next_node = self.ram_dump.read_word(next_node_addr)
if next_node != self.last_node:
if next_node in self.seen_nodes:
print_out_str(
'[!] WARNING: Cycle found in attach list for IOMMU domain. List is corrupted!')
'[!] WARNING: Cycle found in list. List is corrupted!')
else:
self.seen_nodes.append(node_addr)
self.walk(next_node, func)
self.walk(next_node, func, extra)
......@@ -11,27 +11,14 @@
import math
import rb_tree
import linux_list as llist
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
IOMMU_DOMAIN_VAR = 'domain_root'
from iommulib import IommuLib
@register_parser('--print-iommu-pg-tables', 'Print IOMMU page tables')
class IOMMU(RamParser):
class Domain(object):
def __init__(self):
self.domain_num = -1
self.pg_table = 0
self.redirect = 0
self.ctx_name = ''
self.client_name = ''
class FlatMapping(object):
def __init__(self, virt, phys=-1, type='[]', size=SZ_4K, mapped=False):
......@@ -61,7 +48,6 @@ class IOMMU(RamParser):
def __init__(self, *args):
super(IOMMU, self).__init__(*args)
self.out_file = None
self.domain_list = []
self.NUM_FL_PTE = 4096
self.NUM_SL_PTE = 256
......@@ -90,37 +76,9 @@ class IOMMU(RamParser):
self.SL_CACHEABLE = (1 << 3)
self.SL_TEX0 = (1 << 6)
self.SL_NG = (1 << 11)
self.ctxdrvdata_name_offset = 0
self.ctxdrvdata_num_offset = 0
self.ctx_list = []
self.node_offset = self.ramdump.field_offset(
'struct msm_iova_data', 'node')
self.domain_num_offset = self.ramdump.field_offset(
'struct msm_iova_data', 'domain_num')
self.domain_offset = self.ramdump.field_offset(
'struct msm_iova_data', 'domain')
self.priv_offset = self.ramdump.field_offset(
'struct iommu_domain', 'priv')
self.ctxdrvdata_attached_offset = self.ramdump.field_offset(
'struct msm_iommu_ctx_drvdata', 'attached_elm')
self.ctxdrvdata_name_offset = self.ramdump.field_offset(
'struct msm_iommu_ctx_drvdata', 'name')
self.ctxdrvdata_num_offset = self.ramdump.field_offset(
'struct msm_iommu_ctx_drvdata', 'num')
self.priv_pt_offset = self.ramdump.field_offset(
'struct msm_iommu_priv', 'pt')
self.list_attached_offset = self.ramdump.field_offset(
'struct msm_iommu_priv', 'list_attached')
self.client_name_offset = self.ramdump.field_offset(
'struct msm_iommu_priv', 'client_name')
self.pgtable_offset = self.ramdump.field_offset(
'struct msm_iommu_pt', 'fl_table')
self.redirect_offset = self.ramdump.field_offset(
'struct msm_iommu_pt', 'redirect')
self.list_next_offset, self.list_prev_offset = llist.get_list_offsets(
self.ramdump)
def fl_offset(va):
return (((va) & 0xFFF00000) >> 20)
......@@ -128,76 +86,6 @@ class IOMMU(RamParser):
def sl_offset(va):
return (((va) & 0xFF000) >> 12)
def list_func(self, node):
ctx_drvdata_name_ptr = self.ramdump.read_word(
node + self.ctxdrvdata_name_offset)
num = self.ramdump.read_word(node + self.ctxdrvdata_num_offset)
if ctx_drvdata_name_ptr != 0:
name = self.ramdump.read_cstring(ctx_drvdata_name_ptr, 100)
self.ctx_list.append((num, name))
def iommu_domain_func(self, node):
domain_num_addr = (node - self.node_offset) + self.domain_num_offset
domain_num = self.ramdump.read_word(domain_num_addr)
domain_addr = (node - self.node_offset) + self.domain_offset
domain = self.ramdump.read_word(domain_addr)
priv_ptr = self.ramdump.read_word(domain + self.priv_offset)
if self.client_name_offset is not None:
client_name_ptr = self.ramdump.read_word(
priv_ptr + self.client_name_offset)
if client_name_ptr != 0:
client_name = self.ramdump.read_cstring(client_name_ptr, 100)
else:
client_name = '(null)'
else:
client_name = 'unknown'
if self.list_attached_offset is not None:
list_attached = self.ramdump.read_word(
priv_ptr + self.list_attached_offset)
else:
list_attached = None
if self.priv_pt_offset is not None:
pg_table = self.ramdump.read_word(
priv_ptr + self.priv_pt_offset + self.pgtable_offset)
redirect = self.ramdump.read_word(
priv_ptr + self.priv_pt_offset + self.redirect_offset)
else:
# On some builds we are unable to look up the offsets so hardcode
# the offsets.
pg_table = self.ramdump.read_word(priv_ptr + 0)
redirect = self.ramdump.read_word(priv_ptr + 4)
# Note: On some code bases we don't have this pg_table and redirect in the priv structure (see msm_iommu_sec.c). It only
# contains list_attached. If this is the case we can detect that by checking whether
# pg_table == redirect (prev == next pointers of the attached
# list).
if pg_table == redirect:
# This is a secure domain. We don't have access to the page
# tables.
pg_table = 0
redirect = None
if list_attached is not None and list_attached != 0:
list_walker = llist.ListWalker(
self.ramdump, list_attached, self.ctxdrvdata_attached_offset, self.list_next_offset, self.list_prev_offset)
list_walker.walk(list_attached, self.list_func)
dom = self.Domain()
dom.domain_num = domain_num
dom.pg_table = pg_table
dom.redirect = redirect
dom.ctx_list = self.ctx_list
dom.client_name = client_name
self.ctx_list = []
self.domain_list.append(dom)
def print_sl_page_table(self, pg_table):
sl_pte = pg_table
for i in range(0, self.NUM_SL_PTE):
......@@ -415,17 +303,13 @@ class IOMMU(RamParser):
(mapping.virt_start, mapping.virt_end, mapping.virt_size()))
def parse(self):
iommu_domains_rb_root = self.ramdump.addr_lookup(IOMMU_DOMAIN_VAR)
if iommu_domains_rb_root is None:
ilib = IommuLib(self.ramdump)
self.domain_list = ilib.domain_list
if self.domain_list is None:
print_out_str(
'[!] WARNING: IOMMU domains was not found in this build. No IOMMU page tables will be generated')
return
iommu_domains_rb_root_addr = self.ramdump.read_word(
iommu_domains_rb_root)
rb_walker = rb_tree.RbTreeWalker(self.ramdump)
rb_walker.walk(iommu_domains_rb_root_addr, self.iommu_domain_func)
for d in self.domain_list:
self.out_file = self.ramdump.open_file(
'msm_iommu_domain_%02d.txt' % (d.domain_num))
......
......@@ -30,21 +30,25 @@ class RbTreeWalker(object):
self.left_offset = self.ram_dump.field_offset(
'struct rb_node', 'rb_left')
def _walk(self, node, func, seen):
def _walk(self, node, func, seen, extra):
if node != 0:
left_node_addr = node + self.left_offset
left_node = self.ram_dump.read_word(left_node_addr)
if left_node not in seen:
seen.append(left_node)
self._walk(left_node, func, seen)
self._walk(left_node, func, seen, extra)
func(node)
func(node, extra)
right_node_addr = node + self.right_offset
right_node = self.ram_dump.read_word(right_node_addr)
if right_node not in seen:
seen.append(right_node)
self._walk(right_node, func, seen)
self._walk(right_node, func, seen, extra)
def walk(self, node, func):
self._walk(node, func, [])
def walk(self, node, func, extra=None):
"""Walks the RbTree, calling `func' on each iteration. `func' receives
two arguments: the current `struct rb_node', and `extra'.
"""
self._walk(node, func, [], extra)
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment