]> git.saurik.com Git - apple/xnu.git/blobdiff - tools/lldbmacros/pmap.py
xnu-6153.101.6.tar.gz
[apple/xnu.git] / tools / lldbmacros / pmap.py
old mode 100644 (file)
new mode 100755 (executable)
index 9b5638b..8bff268
@@ -118,7 +118,7 @@ def KDPWritePhysMEM(address, intval, bits):
     if not WriteInt32ToMemoryAddress(0, input_address):
         return False
 
     if not WriteInt32ToMemoryAddress(0, input_address):
         return False
 
-    kdp_pkt_size = GetType('kdp_writephysmem64_req_t').GetByteSize()
+    kdp_pkt_size = GetType('kdp_writephysmem64_req_t').GetByteSize() + (bits / 8)
     if not WriteInt32ToMemoryAddress(kdp_pkt_size, len_address):
         return False
 
     if not WriteInt32ToMemoryAddress(kdp_pkt_size, len_address):
         return False
 
@@ -381,12 +381,11 @@ def _PmapL4Walk(pmap_addr_val,vaddr, ept_pmap, verbose_level = vSCRIPT):
         params: pmap_addr_val - core.value representing kernel data of type pmap_addr_t
         vaddr : int - virtual address to walk
     """
         params: pmap_addr_val - core.value representing kernel data of type pmap_addr_t
         vaddr : int - virtual address to walk
     """
-    is_cpu64_bit = int(kern.globals.cpu_64bit)
     pt_paddr = unsigned(pmap_addr_val)
     pt_valid = (unsigned(pmap_addr_val) != 0)
     pt_large = 0
     pframe_offset = 0
     pt_paddr = unsigned(pmap_addr_val)
     pt_valid = (unsigned(pmap_addr_val) != 0)
     pt_large = 0
     pframe_offset = 0
-    if pt_valid and is_cpu64_bit:
+    if pt_valid:
         # Lookup bits 47:39 of linear address in PML4T
         pt_index = (vaddr >> 39) & 0x1ff
         pframe_offset = vaddr & 0x7fffffffff
         # Lookup bits 47:39 of linear address in PML4T
         pt_index = (vaddr >> 39) & 0x1ff
         pframe_offset = vaddr & 0x7fffffffff
@@ -887,7 +886,7 @@ def PmapWalk(pmap, vaddr, verbose_level = vHUMAN):
         return PmapWalkX86_64(pmap, vaddr, verbose_level)
     elif kern.arch == 'arm':
         return PmapWalkARM(pmap, vaddr, verbose_level)
         return PmapWalkX86_64(pmap, vaddr, verbose_level)
     elif kern.arch == 'arm':
         return PmapWalkARM(pmap, vaddr, verbose_level)
-    elif kern.arch == 'arm64':
+    elif kern.arch.startswith('arm64'):
         return PmapWalkARM64(pmap, vaddr, verbose_level)
     else:
         raise NotImplementedError("PmapWalk does not support {0}".format(kern.arch))
         return PmapWalkARM64(pmap, vaddr, verbose_level)
     else:
         raise NotImplementedError("PmapWalk does not support {0}".format(kern.arch))
@@ -915,11 +914,15 @@ def DecodeTTE(cmd_args=None):
         raise ArgumentError("Too few arguments to decode_tte.")
     if kern.arch == 'arm':
         PmapDecodeTTEARM(kern.GetValueFromAddress(cmd_args[0], "unsigned long"), ArgumentStringToInt(cmd_args[1]), vSCRIPT)
         raise ArgumentError("Too few arguments to decode_tte.")
     if kern.arch == 'arm':
         PmapDecodeTTEARM(kern.GetValueFromAddress(cmd_args[0], "unsigned long"), ArgumentStringToInt(cmd_args[1]), vSCRIPT)
-    elif kern.arch == 'arm64':
+    elif kern.arch.startswith('arm64'):
         PmapDecodeTTEARM64(long(kern.GetValueFromAddress(cmd_args[0], "unsigned long")), ArgumentStringToInt(cmd_args[1]))
     else:
         raise NotImplementedError("decode_tte does not support {0}".format(kern.arch))
 
         PmapDecodeTTEARM64(long(kern.GetValueFromAddress(cmd_args[0], "unsigned long")), ArgumentStringToInt(cmd_args[1]))
     else:
         raise NotImplementedError("decode_tte does not support {0}".format(kern.arch))
 
+
+PVH_HIGH_FLAGS_ARM64 = (1 << 62) | (1 << 61) | (1 << 60) | (1 << 59)
+PVH_HIGH_FLAGS_ARM32 = (1 << 31)
+
 def PVWalkARM(pa):
     """ Walk a physical-to-virtual reverse mapping list maintained by the arm pmap
         pa: physical address (NOT page number).  Does not need to be page-aligned 
 def PVWalkARM(pa):
     """ Walk a physical-to-virtual reverse mapping list maintained by the arm pmap
         pa: physical address (NOT page number).  Does not need to be page-aligned 
@@ -928,20 +931,37 @@ def PVWalkARM(pa):
     vm_last_phys = unsigned(kern.globals.vm_last_phys)
     if pa < vm_first_phys or pa >= vm_last_phys:
         raise ArgumentError("PA {:#x} is outside range of managed physical addresses: [{:#x}, {:#x})".format(pa, vm_first_phys, vm_last_phys))
     vm_last_phys = unsigned(kern.globals.vm_last_phys)
     if pa < vm_first_phys or pa >= vm_last_phys:
         raise ArgumentError("PA {:#x} is outside range of managed physical addresses: [{:#x}, {:#x})".format(pa, vm_first_phys, vm_last_phys))
-    page_size = kern.globals.arm_hardware_page_size
+    page_size = kern.globals.page_size
     pn = (pa - unsigned(kern.globals.vm_first_phys)) / page_size
     pvh = unsigned(kern.globals.pv_head_table[pn])
     pvh_type = pvh & 0x3
     pn = (pa - unsigned(kern.globals.vm_first_phys)) / page_size
     pvh = unsigned(kern.globals.pv_head_table[pn])
     pvh_type = pvh & 0x3
+    print "PVH raw value: ({:#x})".format(pvh)
+    if kern.arch.startswith('arm64'):
+        iommu_flag = 0x4
+        iommu_table_flag = 1 << 63
+        pvh = pvh | PVH_HIGH_FLAGS_ARM64
+    else:
+        iommu_flag = 0
+        iommu_table_flag = 0 
+        pvh = pvh | PVH_HIGH_FLAGS_ARM32
     if pvh_type == 0:
         print "PVH type: NULL"
         return
     elif pvh_type == 3:
     if pvh_type == 0:
         print "PVH type: NULL"
         return
     elif pvh_type == 3:
-        print "PVH type: page-table descriptor"
+        print "PVH type: page-table descriptor ({:#x})".format(pvh & ~0x3)
         return
     elif pvh_type == 2:
         ptep = pvh & ~0x3
         return
     elif pvh_type == 2:
         ptep = pvh & ~0x3
+        pte_str = ''
         print "PVH type: single PTE"
         print "PVH type: single PTE"
-        print "PTE {:#x}: {:#x}".format(ptep, dereference(kern.GetValueFromAddress(ptep, 'pt_entry_t *')))
+        if ptep & iommu_flag:
+            ptep = ptep & ~iommu_flag
+            if ptep & iommu_table_flag:
+                pte_str = ' (IOMMU table), entry'
+            else:
+                pte_str = ' (IOMMU state), descriptor'
+                ptep = ptep | iommu_table_flag
+        print "PTE {:#x}{:s}: {:#x}".format(ptep, pte_str, dereference(kern.GetValueFromAddress(ptep, 'pt_entry_t *')))
     elif pvh_type == 1:
         pvep = pvh & ~0x3
         print "PVH type: PTE list"
     elif pvh_type == 1:
         pvep = pvh & ~0x3
         print "PVH type: PTE list"
@@ -951,9 +971,17 @@ def PVWalkARM(pa):
                 pve_str = ' (alt acct) '
             else:
                 pve_str = ''
                 pve_str = ' (alt acct) '
             else:
                 pve_str = ''
+            current_pvep = pvep
             pvep = unsigned(pve.pve_next) & ~0x1
             ptep = unsigned(pve.pve_ptep) & ~0x3
             pvep = unsigned(pve.pve_next) & ~0x1
             ptep = unsigned(pve.pve_ptep) & ~0x3
-            print "PTE {:#x}{:s}: {:#x}".format(ptep, pve_str, dereference(kern.GetValueFromAddress(ptep, 'pt_entry_t *')))
+            if ptep & iommu_flag:
+                ptep = ptep & ~iommu_flag
+                if ptep & iommu_table_flag:
+                    pve_str = ' (IOMMU table), entry'
+                else:
+                    pve_str = ' (IOMMU state), descriptor'
+                    ptep = ptep | iommu_table_flag
+            print "PVE {:#x}, PTE {:#x}{:s}: {:#x}".format(current_pvep, ptep, pve_str, dereference(kern.GetValueFromAddress(ptep, 'pt_entry_t *')))
 
 @lldb_command('pv_walk')
 def PVWalk(cmd_args=None):
 
 @lldb_command('pv_walk')
 def PVWalk(cmd_args=None):
@@ -962,41 +990,76 @@ def PVWalk(cmd_args=None):
     """
     if cmd_args == None or len(cmd_args) < 1:
         raise ArgumentError("Too few arguments to pv_walk.")
     """
     if cmd_args == None or len(cmd_args) < 1:
         raise ArgumentError("Too few arguments to pv_walk.")
-    if kern.arch != 'arm' and kern.arch != 'arm64':
+    if not kern.arch.startswith('arm'):
         raise NotImplementedError("pv_walk does not support {0}".format(kern.arch))
     PVWalkARM(kern.GetValueFromAddress(cmd_args[0], 'unsigned long'))
 
         raise NotImplementedError("pv_walk does not support {0}".format(kern.arch))
     PVWalkARM(kern.GetValueFromAddress(cmd_args[0], 'unsigned long'))
 
+@lldb_command('kvtophys')
+def KVToPhys(cmd_args=None):
+    """ Translate a kernel virtual address to the corresponding physical address.
+        Assumes the virtual address falls within the kernel static region.
+        Syntax: (lldb) kvtophys <kernel virtual address>
+    """
+    if cmd_args == None or len(cmd_args) < 1:
+        raise ArgumentError("Too few arguments to kvtophys.")
+    if kern.arch.startswith('arm'):
+        print "{:#x}".format(KVToPhysARM(long(unsigned(kern.GetValueFromAddress(cmd_args[0], 'unsigned long')))))
+    elif kern.arch == 'x86_64':
+        print "{:#x}".format(long(unsigned(kern.GetValueFromAddress(cmd_args[0], 'unsigned long'))) - unsigned(kern.globals.physmap_base))
+
+@lldb_command('phystokv')
+def PhysToKV(cmd_args=None):
+    """ Translate a physical address to the corresponding static kernel virtual address.
+        Assumes the physical address corresponds to managed DRAM.
+        Syntax: (lldb) phystokv <physical address>
+    """
+    if cmd_args == None or len(cmd_args) < 1:
+        raise ArgumentError("Too few arguments to phystokv.")
+    print "{:#x}".format(kern.PhysToKernelVirt(long(unsigned(kern.GetValueFromAddress(cmd_args[0], 'unsigned long')))))
+
+def KVToPhysARM(addr):
+    if kern.arch.startswith('arm64'):
+        ptov_table = kern.globals.ptov_table
+        for i in range(0, kern.globals.ptov_index):
+            if (addr >= long(unsigned(ptov_table[i].va))) and (addr < (long(unsigned(ptov_table[i].va)) + long(unsigned(ptov_table[i].len)))):
+                return (addr - long(unsigned(ptov_table[i].va)) + long(unsigned(ptov_table[i].pa)))
+    return (addr - unsigned(kern.globals.gVirtBase) + unsigned(kern.globals.gPhysBase))
+
 def ShowPTEARM(pte):
     """ Display vital information about an ARM page table entry
         pte: kernel virtual address of the PTE.  Should be L3 PTE.  May also work with L2 TTEs for certain devices.
     """
     page_size = kern.globals.arm_hardware_page_size
 def ShowPTEARM(pte):
     """ Display vital information about an ARM page table entry
         pte: kernel virtual address of the PTE.  Should be L3 PTE.  May also work with L2 TTEs for certain devices.
     """
     page_size = kern.globals.arm_hardware_page_size
-    pn = (pte - unsigned(kern.globals.gVirtBase) + unsigned(kern.globals.gPhysBase) - unsigned(kern.globals.vm_first_phys)) / page_size
-    pvh = kern.globals.pv_head_table[pn]
+    pn = (KVToPhysARM(pte) - unsigned(kern.globals.vm_first_phys)) / page_size
+    pvh = unsigned(kern.globals.pv_head_table[pn])
+    if kern.arch.startswith('arm64'):
+        pvh = pvh | PVH_HIGH_FLAGS_ARM64
+    else:
+        pvh = pvh | PVH_HIGH_FLAGS_ARM32
     pvh_type = pvh & 0x3
     pvh_type = pvh & 0x3
-    if pvh_type != 0x3 and pvh_type != 0x0:
+    if pvh_type != 0x3:
         raise ValueError("PV head {:#x} does not correspond to a page-table descriptor".format(pvh))
     ptd = kern.GetValueFromAddress(pvh & ~0x3, 'pt_desc_t *')
     print "descriptor: {:#x}".format(ptd)
     print "pmap: {:#x}".format(ptd.pmap)
     pt_index = (pte % kern.globals.page_size) / page_size
     pte_pgoff = pte % page_size
         raise ValueError("PV head {:#x} does not correspond to a page-table descriptor".format(pvh))
     ptd = kern.GetValueFromAddress(pvh & ~0x3, 'pt_desc_t *')
     print "descriptor: {:#x}".format(ptd)
     print "pmap: {:#x}".format(ptd.pmap)
     pt_index = (pte % kern.globals.page_size) / page_size
     pte_pgoff = pte % page_size
-    if kern.arch == 'arm64':
+    if kern.arch.startswith('arm64'):
         pte_pgoff = pte_pgoff / 8
         nttes = page_size / 8
     else:
         pte_pgoff = pte_pgoff / 4
         nttes = page_size / 4
         pte_pgoff = pte_pgoff / 8
         nttes = page_size / 8
     else:
         pte_pgoff = pte_pgoff / 4
         nttes = page_size / 4
-    if ptd.pt_cnt[pt_index].refcnt == 0x8000:
+    if ptd.ptd_info[pt_index].refcnt == 0x4000:
         level = 2
         granule = nttes * page_size
     else:
         level = 3
         granule = page_size
         level = 2
         granule = nttes * page_size
     else:
         level = 3
         granule = page_size
-    print "maps VA: {:#x}".format(long(unsigned(ptd.pt_map[pt_index].va)) + (pte_pgoff * granule))
+    print "maps VA: {:#x}".format(long(unsigned(ptd.ptd_info[pt_index].va)) + (pte_pgoff * granule))
     pteval = long(unsigned(dereference(kern.GetValueFromAddress(unsigned(pte), 'pt_entry_t *'))))
     print "value: {:#x}".format(pteval)
     pteval = long(unsigned(dereference(kern.GetValueFromAddress(unsigned(pte), 'pt_entry_t *'))))
     print "value: {:#x}".format(pteval)
-    if kern.arch == 'arm64':
+    if kern.arch.startswith('arm64'):
         print "level: {:d}".format(level)
         PmapDecodeTTEARM64(pteval, level)
     elif kern.arch == 'arm':
         print "level: {:d}".format(level)
         PmapDecodeTTEARM64(pteval, level)
     elif kern.arch == 'arm':
@@ -1009,7 +1072,7 @@ def ShowPTE(cmd_args=None):
     """
     if cmd_args == None or len(cmd_args) < 1:
         raise ArgumentError("Too few arguments to showpte.")
     """
     if cmd_args == None or len(cmd_args) < 1:
         raise ArgumentError("Too few arguments to showpte.")
-    if kern.arch != 'arm' and kern.arch != 'arm64':
+    if not kern.arch.startswith('arm'):
         raise NotImplementedError("showpte does not support {0}".format(kern.arch))
     ShowPTEARM(kern.GetValueFromAddress(cmd_args[0], 'unsigned long'))
 
         raise NotImplementedError("showpte does not support {0}".format(kern.arch))
     ShowPTEARM(kern.GetValueFromAddress(cmd_args[0], 'unsigned long'))
 
@@ -1098,12 +1161,12 @@ def ScanPageTables(action, targetPmap=None):
     """
     print "Scanning all available translation tables.  This may take a long time..."
     def ScanPmap(pmap, action):
     """
     print "Scanning all available translation tables.  This may take a long time..."
     def ScanPmap(pmap, action):
-        if kern.arch == 'arm64':
+        if kern.arch.startswith('arm64'):
             granule = kern.globals.arm64_root_pgtable_num_ttes * 8
         elif kern.arch == 'arm':
             granule = pmap.tte_index_max * 4
         action(pmap, 1, 'root', pmap.tte, unsigned(pmap.ttep), granule)
             granule = kern.globals.arm64_root_pgtable_num_ttes * 8
         elif kern.arch == 'arm':
             granule = pmap.tte_index_max * 4
         action(pmap, 1, 'root', pmap.tte, unsigned(pmap.ttep), granule)
-        if kern.arch == 'arm64':
+        if kern.arch.startswith('arm64'):
             FindMappingAtLevelARM64(pmap, pmap.tte, kern.globals.arm64_root_pgtable_num_ttes, kern.globals.arm64_root_pgtable_level, action)
         elif kern.arch == 'arm':
             FindMappingAtLevelARM(pmap, pmap.tte, pmap.tte_index_max, 1, action)
             FindMappingAtLevelARM64(pmap, pmap.tte, kern.globals.arm64_root_pgtable_num_ttes, kern.globals.arm64_root_pgtable_level, action)
         elif kern.arch == 'arm':
             FindMappingAtLevelARM(pmap, pmap.tte, pmap.tte_index_max, 1, action)
@@ -1124,7 +1187,7 @@ def ShowAllMappings(cmd_args=None):
     """
     if cmd_args == None or len(cmd_args) < 1:
         raise ArgumentError("Too few arguments to showallmappings.")
     """
     if cmd_args == None or len(cmd_args) < 1:
         raise ArgumentError("Too few arguments to showallmappings.")
-    if kern.arch != 'arm' and kern.arch != 'arm64':
+    if not kern.arch.startswith('arm'):
         raise NotImplementedError("showallmappings does not support {0}".format(kern.arch))
     pa = kern.GetValueFromAddress(cmd_args[0], 'unsigned long')
     targetPmap = None
         raise NotImplementedError("showallmappings does not support {0}".format(kern.arch))
     pa = kern.GetValueFromAddress(cmd_args[0], 'unsigned long')
     targetPmap = None
@@ -1136,7 +1199,7 @@ def ShowAllMappings(cmd_args=None):
     ScanPageTables(printMatchedMapping, targetPmap)
 
 def checkPVList(pmap, level, type, tte, paddr, granule):
     ScanPageTables(printMatchedMapping, targetPmap)
 
 def checkPVList(pmap, level, type, tte, paddr, granule):
-    """ Checks an ARM physical-to-virtual mapping list for consistency error.
+    """ Checks an ARM physical-to-virtual mapping list for consistency errors.
         pmap: owner of the translation table
         level: translation table level.  PV lists will only be checked for L2 (arm32) or L3 (arm64) tables.
         type: unused
         pmap: owner of the translation table
         level: translation table level.  PV lists will only be checked for L2 (arm32) or L3 (arm64) tables.
         type: unused
@@ -1146,20 +1209,22 @@ def checkPVList(pmap, level, type, tte, paddr, granule):
     """
     vm_first_phys = unsigned(kern.globals.vm_first_phys)
     vm_last_phys = unsigned(kern.globals.vm_last_phys)
     """
     vm_first_phys = unsigned(kern.globals.vm_first_phys)
     vm_last_phys = unsigned(kern.globals.vm_last_phys)
-    page_size = kern.globals.arm_hardware_page_size
-    if kern.arch == 'arm64':
+    page_size = kern.globals.page_size
+    if kern.arch.startswith('arm64'):
         page_offset_mask = (page_size - 1)
         page_base_mask = ((1 << ARM64_VMADDR_BITS) - 1) & (~page_offset_mask)
         paddr = paddr & page_base_mask
         max_level = 3
         page_offset_mask = (page_size - 1)
         page_base_mask = ((1 << ARM64_VMADDR_BITS) - 1) & (~page_offset_mask)
         paddr = paddr & page_base_mask
         max_level = 3
+        pvh_set_bits = PVH_HIGH_FLAGS_ARM64
     elif kern.arch == 'arm':
         page_base_mask = 0xFFFFF000
         paddr = paddr & page_base_mask
         max_level = 2
     elif kern.arch == 'arm':
         page_base_mask = 0xFFFFF000
         paddr = paddr & page_base_mask
         max_level = 2
+        pvh_set_bits = PVH_HIGH_FLAGS_ARM32
     if level < max_level or paddr < vm_first_phys or paddr >= vm_last_phys:
         return
     pn = (paddr - vm_first_phys) / page_size
     if level < max_level or paddr < vm_first_phys or paddr >= vm_last_phys:
         return
     pn = (paddr - vm_first_phys) / page_size
-    pvh = unsigned(kern.globals.pv_head_table[pn])
+    pvh = unsigned(kern.globals.pv_head_table[pn]) | pvh_set_bits
     pvh_type = pvh & 0x3
     if pmap is not None:
         pmap_str = "pmap: {:#x}: ".format(pmap)
     pvh_type = pvh & 0x3
     if pmap is not None:
         pmap_str = "pmap: {:#x}: ".format(pmap)
@@ -1206,10 +1271,10 @@ def PVCheck(cmd_args=None, cmd_options={}):
             -P        : Interpret <addr> as a physical address rather than a PTE
     """
     if cmd_args == None or len(cmd_args) < 1:
             -P        : Interpret <addr> as a physical address rather than a PTE
     """
     if cmd_args == None or len(cmd_args) < 1:
-        raise ArgumentError("Too few arguments to showallmappings.")
+        raise ArgumentError("Too few arguments to pv_check.")
     if kern.arch == 'arm':
         level = 2
     if kern.arch == 'arm':
         level = 2
-    elif kern.arch == 'arm64':
+    elif kern.arch.startswith('arm64'):
         level = 3
     else:
         raise NotImplementedError("showallmappings does not support {0}".format(kern.arch))
         level = 3
     else:
         raise NotImplementedError("showallmappings does not support {0}".format(kern.arch))
@@ -1231,7 +1296,7 @@ def CheckPmapIntegrity(cmd_args=None):
         for kernel_pmap, as we do not create PV entries for static kernel mappings on ARM.
         Use of this macro without the [<pmap>] argument is heavily discouraged.
     """
         for kernel_pmap, as we do not create PV entries for static kernel mappings on ARM.
         Use of this macro without the [<pmap>] argument is heavily discouraged.
     """
-    if kern.arch != 'arm' and kern.arch != 'arm64':
+    if not kern.arch.startswith('arm'):
         raise NotImplementedError("showallmappings does not support {0}".format(kern.arch))
     targetPmap = None
     if len(cmd_args) > 0:
         raise NotImplementedError("showallmappings does not support {0}".format(kern.arch))
     targetPmap = None
     if len(cmd_args) > 0:
@@ -1245,7 +1310,7 @@ def PmapsForLedger(cmd_args=None):
     """
     if cmd_args == None or len(cmd_args) < 1:
         raise ArgumentError("Too few arguments to pmapsforledger.")
     """
     if cmd_args == None or len(cmd_args) < 1:
         raise ArgumentError("Too few arguments to pmapsforledger.")
-    if kern.arch != 'arm' and kern.arch != 'arm64':
+    if not kern.arch.startswith('arm'):
         raise NotImplementedError("pmapsforledger does not support {0}".format(kern.arch))
     ledger = kern.GetValueFromAddress(cmd_args[0], 'ledger_t')
     for pmap in IterateQueue(kern.globals.map_pmap_list, 'pmap_t', 'pmaps'):
         raise NotImplementedError("pmapsforledger does not support {0}".format(kern.arch))
     ledger = kern.GetValueFromAddress(cmd_args[0], 'ledger_t')
     for pmap in IterateQueue(kern.globals.map_pmap_list, 'pmap_t', 'pmaps'):