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
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
- 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
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))
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))
+
+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
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
+ 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:
- print "PVH type: page-table descriptor"
+ print "PVH type: page-table descriptor ({:#x})".format(pvh & ~0x3)
return
elif pvh_type == 2:
ptep = pvh & ~0x3
+ pte_str = ''
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"
pve_str = ' (alt acct) '
else:
pve_str = ''
+ current_pvep = pvep
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):
"""
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'))
+@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
- 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
- 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
- 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
- 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
- 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)
- if kern.arch == 'arm64':
+ if kern.arch.startswith('arm64'):
print "level: {:d}".format(level)
PmapDecodeTTEARM64(pteval, level)
elif kern.arch == 'arm':
"""
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'))
"""
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)
- 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)
"""
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
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
"""
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
+ pvh_set_bits = PVH_HIGH_FLAGS_ARM64
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
- 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)
-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
- elif kern.arch == 'arm64':
+ elif kern.arch.startswith('arm64'):
level = 3
else:
raise NotImplementedError("showallmappings does not support {0}".format(kern.arch))
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:
"""
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'):