Skip to content
Snippets Groups Projects
Commit 29d3f2ed authored by Mitchel Humpherys's avatar Mitchel Humpherys
Browse files

lrdp-v2: refactor Iommu domain parsing code

The Iommu domain parsing code is common across different Iommu page
table types (normal vs LPAE). Pull this code out so that it can be
easily re-used later when LPAE page table support is added.

Change-Id: Ifc39c12428a9c090f8197d997ddd293e0ae1f0b1
parent 87538b00
Branches
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.
Please register or to comment