Newer
Older
# Copyright (c) 2013-2017, 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.
def page_buddy(ramdump, page):
mapcount_offset = ramdump.field_offset('struct page', '_mapcount')
val = ramdump.read_int(page + mapcount_offset)
# -128 is the magic for in the buddy allocator
return val == 0xffffff80
def get_debug_flags(ramdump, page):
debug_flag_offset = ramdump.field_offset('struct page', 'debug_flags')
flagval = ramdump.read_word(page + debug_flag_offset)
return flagval
def page_zonenum(page_flags):
# save this in a variable somewhere...
return (page_flags >> 26) & 3
def page_to_nid(page_flags):
return 0
def page_zone(ramdump, page):
contig_page_data = ramdump.address_of('contig_page_data')
node_zones_offset = ramdump.field_offset(
'struct pglist_data', 'node_zones')
page_flags_offset = ramdump.field_offset('struct page', 'flags')
zone_size = ramdump.sizeof('struct zone')
page_flags = ramdump.read_word(page + page_flags_offset)
if page_flags is None:
return None
zone = contig_page_data + node_zones_offset + \
(page_zonenum(page_flags) * zone_size)
return zone
def zone_is_highmem(ramdump, zone):
if not ramdump.is_config_defined('CONFIG_HIGHMEM'):
return False
if zone is None:
return False
# not at all how linux does it but it works for our purposes...
zone_name_offset = ramdump.field_offset('struct zone', 'name')
zone_name_addr = ramdump.read_word(zone + zone_name_offset)
if zone_name_addr is None:
return False
zone_name = ramdump.read_cstring(zone_name_addr, 48)
if zone_name is None:
# XXX do something?
return False
if zone_name == 'HighMem':
return True
else:
return False
def hash32(val, bits):
chash = c_uint(val * 0x9e370001).value
return chash >> (32 - bits)
def page_slot(ramdump, page):
hashed = hash32(page, 7)
htable = ramdump.address_of('page_address_htable')
htable_size = ramdump.sizeof('page_address_htable[0]')
return htable + htable_size * hashed
def page_to_section(page_flags):
# again savefn8n variable
return (page_flags >> 28) & 0xF
def nr_to_section(ramdump, sec_num):
memsection_struct_size = ramdump.sizeof('struct mem_section')
sections_per_root = 4096 / memsection_struct_size
sect_nr_to_root = sec_num / sections_per_root
masked = sec_num & (sections_per_root - 1)
mem_section_addr = ramdump.address_of('mem_section')
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
mem_section = ramdump.read_word(mem_section_addr)
if mem_section is None:
return None
return mem_section + memsection_struct_size * (sect_nr_to_root * sections_per_root + masked)
def section_mem_map_addr(ramdump, section):
map_offset = ramdump.field_offset('struct mem_section', 'section_mem_map')
result = ramdump.read_word(section + map_offset)
return result & ~((1 << 2) - 1)
def pfn_to_section_nr(pfn):
return pfn >> (28 - 12)
def pfn_to_section(ramdump, pfn):
return nr_to_section(ramdump, pfn_to_section_nr(pfn))
def pfn_to_page_sparse(ramdump, pfn):
sec = pfn_to_section(ramdump, pfn)
sizeof_page = ramdump.sizeof('struct page')
return section_mem_map_addr(ramdump, sec) + pfn * sizeof_page
def page_to_pfn_sparse(ramdump, page):
page_flags_offset = ramdump.field_offset('struct page', 'flags')
sizeof_page = ramdump.sizeof('struct page')
flags = ramdump.read_word(page + page_flags_offset)
if flags is None:
return 0
section = page_to_section(flags)
nr = nr_to_section(ramdump, section)
addr = section_mem_map_addr(ramdump, nr)
# divide by struct page size for division fun
return (page - addr) / sizeof_page
def get_vmemmap(ramdump):
# See: include/asm-generic/pgtable-nopud.h,
# arch/arm64/include/asm/pgtable-hwdef.h,
# arch/arm64/include/asm/pgtable.h
# kernel/arch/arm64/include/asm/memory.h
if (ramdump.kernel_version < (3, 18, 0)):
nlevels = int(ramdump.get_config_val("CONFIG_ARM64_PGTABLE_LEVELS"))
else:
nlevels = int(ramdump.get_config_val("CONFIG_PGTABLE_LEVELS"))
if ramdump.is_config_defined("CONFIG_ARM64_64K_PAGES"):
page_shift = 16
else:
page_shift = 12
pgdir_shift = ((page_shift - 3) * nlevels) + 3
pud_shift = pgdir_shift
pud_size = 1 << pud_shift
va_bits = int(ramdump.get_config_val("CONFIG_ARM64_VA_BITS"))
spsize = ramdump.sizeof('struct page')
vmemmap_size = bitops.align((1 << (va_bits - page_shift)) * spsize,
pud_size)
pfn_offset = (ramdump.phys_offset >> page_shift)
offset = pfn_offset * spsize
if (ramdump.kernel_version < (3, 18, 31)):
vmalloc_end = ramdump.page_offset - pud_size - vmemmap_size
# vmalloc_end = 0xFFFFFFBC00000000
elif (ramdump.kernel_version < (4, 9, 0)):
# for version >= 3.18.31,
# vmemmap is shifted to base addr (0x80000000) pfn.
vmalloc_end = ramdump.page_offset - pud_size - vmemmap_size - offset
else:
# for version >= 4.9.0,
struct_page_max_shift = 6
#vmemmap_size = ( 1 << (39 - 12 - 1 + 6))
vmemmap_size = ( 1 << (va_bits - page_shift - 1 + struct_page_max_shift))
vmalloc_end = ramdump.page_offset - vmemmap_size - offset
return vmalloc_end
def page_to_pfn_vmemmap(ramdump, page):
vmemmap = get_vmemmap(ramdump)
page_size = ramdump.sizeof('struct page')
return ((page - vmemmap) / page_size)
def pfn_to_page_vmemmap(ramdump, pfn):
vmemmap = get_vmemmap(ramdump)
page_size = ramdump.sizeof('struct page')
return vmemmap + (pfn * page_size)
def page_to_pfn_flat(ramdump, page):
mem_map_addr = ramdump.address_of('mem_map')
mem_map = ramdump.read_word(mem_map_addr)
page_size = ramdump.sizeof('struct page')
# XXX Needs to change for LPAE
pfn_offset = ramdump.phys_offset >> 12
return ((page - mem_map) / page_size) + pfn_offset
def pfn_to_page_flat(ramdump, pfn):
mem_map_addr = ramdump.address_of('mem_map')
mem_map = ramdump.read_word(mem_map_addr)
page_size = ramdump.sizeof('struct page')
# XXX Needs to change for LPAE
pfn_offset = ramdump.phys_offset >> 12
return mem_map + ((pfn - pfn_offset) * page_size)
def page_to_pfn(ramdump, page):
if ramdump.arm64:
return page_to_pfn_vmemmap(ramdump, page)
if ramdump.is_config_defined('CONFIG_SPARSEMEM'):
return page_to_pfn_sparse(ramdump, page)
else:
return page_to_pfn_flat(ramdump, page)
def pfn_to_page(ramdump, pfn):
if ramdump.arm64:
return pfn_to_page_vmemmap(ramdump, pfn)
if ramdump.is_config_defined('CONFIG_SPARSEMEM'):
return pfn_to_page_sparse(ramdump, pfn)
else:
return pfn_to_page_flat(ramdump, pfn)
def sparsemem_lowmem_page_address(ramdump, page):
membank1_start = ramdump.read_word(ramdump.address_of('membank1_start'))
membank0_size = ramdump.read_word(ramdump.address_of('membank0_size'))
# XXX currently magic
membank0_phys_offset = ramdump.phys_offset
membank0_page_offset = ramdump.page_offset
membank1_phys_offset = membank1_start
membank1_page_offset = membank0_page_offset + membank0_size
phys = page_to_pfn(ramdump, page) << 12
if phys >= membank1_start:
return phys - membank1_phys_offset + membank1_page_offset
else:
return phys - membank0_phys_offset + membank0_page_offset
def dont_map_hole_lowmem_page_address(ramdump, page):
phys = page_to_pfn(ramdump, page) << 12
hole_end_addr = ramdump.address_of('memory_hole_end')
if hole_end_addr is None:
hole_end_addr = ramdump.address_of('membank1_start')
hole_offset_addr = ramdump.address_of('memory_hole_offset')
if hole_offset_addr is None:
hole_offset_addr = ramdump.address_of('membank0_size')
hole_end = ramdump.read_word(hole_end_addr)
hole_offset = ramdump.read_word(hole_offset_addr)
if hole_end != 0 and phys >= hole_end:
return phys - hole_end + hole_offset + ramdump.page_offset
return phys - ramdump.phys_offset + ramdump.page_offset
def normal_lowmem_page_address(ramdump, page):
phys = page_to_pfn(ramdump, page) << 12
return phys - ramdump.phys_offset + ramdump.page_offset
def lowmem_page_address(ramdump, page):
if ramdump.is_config_defined('CONFIG_SPARSEMEM') and not ramdump.arm64:
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
return sparsemem_lowmem_page_address(ramdump, page)
elif ramdump.is_config_defined('CONFIG_DONT_MAP_HOLE_AFTER_MEMBANK0'):
return dont_map_hole_lowmem_page_address(ramdump, page)
else:
return normal_lowmem_page_address(ramdump, page)
def page_address(ramdump, page):
if not zone_is_highmem(ramdump, page_zone(ramdump, page)):
return lowmem_page_address(ramdump, page)
pas = page_slot(ramdump, page)
lh_offset = ramdump.field_offset('struct page_address_slot', 'lh')
start = pas + lh_offset
pam = start
while True:
pam = pam - lh_offset
pam_page_offset = ramdump.field_offset(
'struct page_address_map', 'page')
pam_virtual_offset = ramdump.field_offset(
'struct page_address_map', 'virtual')
pam_page = ramdump.read_word(pam + pam_page_offset)
if pam_page == page:
ret = ramdump.read_word(pam + pam_virtual_offset)
return ret
pam = ramdump.read_word(pam + lh_offset)
if pam == start:
return None