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!")