diff --git a/arch/x86/Makefile.mmu b/arch/x86/Makefile.mmu index adb7dbd0b94..3c4611b8aa3 100644 --- a/arch/x86/Makefile.mmu +++ b/arch/x86/Makefile.mmu @@ -13,7 +13,8 @@ quiet_cmd_gen_mmu = GMMU $@ cmd_gen_mmu = \ ( \ $(OBJCOPY) -I $(OUTPUT_FORMAT) -O binary -j mmulist $< mmulist.bin && \ - $(GENMMU) -i mmulist.bin -o mmu_tables.bin $(GENMMU_EXTRA_ARGS)\ + $(GENMMU) -i mmulist.bin -k $(PREBUILT_KERNEL) \ + -o mmu_tables.bin $(GENMMU_EXTRA_ARGS) \ ) diff --git a/scripts/gen_mmu.py b/scripts/gen_mmu.py index a97a2de4a01..6fb2701380e 100755 --- a/scripts/gen_mmu.py +++ b/scripts/gen_mmu.py @@ -7,66 +7,1001 @@ import parser from collections import namedtuple import ctypes import argparse +import re +from elftools.elf.elffile import ELFFile +from elftools.elf.sections import SymbolTableSection -############# global variables +# global variables pd_complete = '' inputfile = '' outputfile = '' list_of_pde = {} num_of_regions = 0 -read_buff='' +read_buff = '' +raw_info = [] -struct_mmu_regions_tuple = {"start_addr","size","permissions"} -mmu_region_details = namedtuple("mmu_region_details", "pde_index page_entries_info") +struct_mmu_regions_tuple = {"start_addr", "size", "permissions"} +mmu_region_details = namedtuple("mmu_region_details", + "pde_index page_entries_info") -valid_pages_inside_pde = namedtuple("valid_pages_inside_pde","start_addr size \ +valid_pages_inside_pde = namedtuple("valid_pages_inside_pde", "start_addr size \ pte_valid_addr_start \ pte_valid_addr_end \ permissions") +mmu_region_details_pdpt = namedtuple("mmu_region_details_pdpt", + "pdpte_index pd_entries") + page_tables_list = [] +pd_tables_list = [] pd_start_addr = 0 validation_issue_memory_overlap = [False, 0, -1] output_offset = 0 print_string_pde_list = '' pde_pte_string = {} -FourMB = (1024*4096) #In Bytes +FourMB = (1024 * 4096) # In Bytes + +# Constants +PAGE_ENTRY_PRESENT = 1 +PAGE_ENTRY_READ_WRITE = 1 << 1 +PAGE_ENTRY_USER_SUPERVISOR = 1 << 2 +PAGE_ENTRY_PWT = 0 << 3 +PAGE_ENTRY_PCD = 0 << 4 +PAGE_ENTRY_ACCESSED = 0 << 5 # this is a read only field +PAGE_ENTRY_DIRTY = 0 << 6 # this is a read only field +PAGE_ENTRY_PAT = 0 << 7 +PAGE_ENTRY_GLOBAL = 0 << 8 +PAGE_ENTRY_ALLOC = 1 << 9 +PAGE_ENTRY_CUSTOM = 0 << 10 ############# -#return the page directory number for the give address -def get_pde_number(value): - return( (value >> 22 ) & 0x3FF) - -#return the page table number for the given address -def get_pte_number(value): - return( (value >> 12 ) & 0x3FF) +#*****************************************************************************# +# class for 4Kb Mode -# update the tuple values for the memory regions needed -def set_pde_pte_values(pde_index, address, mem_size, - pte_valid_addr_start, pte_valid_addr_end, perm): +class PageMode_4kb: + total_pages = 1023 + write_page_entry_bin = "I" + size_addressed_per_pde = (1024 * 4096) # 4MB In Bytes - pages_tuple = valid_pages_inside_pde( - start_addr = address, - size = mem_size, - pte_valid_addr_start = pte_valid_addr_start, - pte_valid_addr_end = pte_valid_addr_end, - permissions = perm) + # return the page directory number for the give address + def get_pde_number(self, value): + return (value >> 22) & 0x3FF - mem_region_values = mmu_region_details(pde_index = pde_index, - page_entries_info = []) + # return the page table number for the given address + def get_pte_number(self, value): + return (value >> 12) & 0x3FF - mem_region_values.page_entries_info.append(pages_tuple) + # get the total number of pd available + def get_number_of_pd(self): + return len(list_of_pde.keys()) + + # the return value will have the page address and it is assumed + # to be a 4096 boundary + # hence the output of this API will be a 20bit address of the page table + def address_of_page_table(self, page_table_number): + global pd_start_addr + + # location from where the Page tables will be written + PT_start_addr = pd_start_addr + 4096 + return ((PT_start_addr + + (page_tables_list.index(page_table_number) * 4096) >> 12)) + + # union x86_mmu_pde_pt { + # u32_t value; + # struct { + # u32_t p:1; + # u32_t rw:1; + # u32_t us:1; + # u32_t pwt:1; + # u32_t pcd:1; + # u32_t a:1; + # u32_t ignored1:1; + # u32_t ps:1; + # u32_t ignored2:4; + # u32_t page_table:20; + # }; + # }; + def get_binary_pde_value(self, value): + perms = value.page_entries_info[0].permissions + + present = PAGE_ENTRY_PRESENT + read_write = check_bits(perms, [1, 29]) << 1 + user_mode = check_bits(perms, [2, 28]) << 2 + + pwt = PAGE_ENTRY_PWT + pcd = PAGE_ENTRY_PCD + a = PAGE_ENTRY_ACCESSED + ps = 0 << 7 # this is a read only field + page_table = self.address_of_page_table(value.pde_index) << 12 + return (present | + read_write | + user_mode | + pwt | + pcd | + a | + ps | + page_table) + + # union x86_mmu_pte { + # u32_t value; + # struct { + # u32_t p:1; + # u32_t rw:1; + # u32_t us:1; + # u32_t pwt:1; + # u32_t pcd:1; + # u32_t a:1; + # u32_t d:1; + # u32_t pat:1; + # u32_t g:1; + # u32_t alloc:1; + # u32_t custom:2; + # u32_t page:20; + # }; + # }; + def get_binary_pte_value(self, value, pte, perm_for_pte): + present = PAGE_ENTRY_PRESENT + read_write = ((perm_for_pte >> 1) & 0x1) << 1 + user_mode = ((perm_for_pte >> 2) & 0x1) << 2 + pwt = PAGE_ENTRY_PWT + pcd = PAGE_ENTRY_PCD + a = PAGE_ENTRY_ACCESSED + d = PAGE_ENTRY_DIRTY + pat = PAGE_ENTRY_PAT + g = PAGE_ENTRY_GLOBAL + alloc = PAGE_ENTRY_ALLOC + custom = PAGE_ENTRY_CUSTOM + + # This points to the actual memory in the HW + # totally 20 bits to rep the phy address + # first 10 is the number got from pde and next 10 is pte + page_table = ((value.pde_index << 10) | pte) << 12 + + binary_value = (present | read_write | user_mode | + pwt | pcd | a | d | pat | g | alloc | custom | + page_table) + return binary_value + + def populate_required_structs(self): + for region in raw_info: + pde_index = self.get_pde_number(region[0]) + pte_valid_addr_start = self.get_pte_number(region[0]) + + # Get the end of the page table entries + # Since a memory region can take up only a few entries in the Page + # table, this helps us get the last valid PTE. + pte_valid_addr_end = self.get_pte_number(region[0] + + region[1] - 1) + + mem_size = region[1] + + # In-case the start address aligns with a page table entry other + # than zero and the mem_size is greater than (1024*4096) i.e 4MB + # in case where it overflows the currenty PDE's range then limit the + # PTE to 1024 and so make the mem_size reflect the actual size taken + # up in the current PDE + if (region[1] + (pte_valid_addr_start * 4096)) >= \ + (self.size_addressed_per_pde): + + pte_valid_addr_end = self.total_pages + mem_size = (((self.total_pages + 1) - + pte_valid_addr_start) * 4096) + + self.set_pde_pte_values(pde_index, region[0], mem_size, + pte_valid_addr_start, + pte_valid_addr_end, + region[2]) + + if pde_index not in page_tables_list: + page_tables_list.append(pde_index) + + # IF the current pde couldn't fit the entire requested region size + # then there is a need to create new PDEs to match the size. + # Here the overflow_size represents the size that couldn't be fit + # inside the current PDE, this is will now to used to create a + # new PDE/PDEs so the size remaining will be + # requested size - allocated size(in the current PDE) + + overflow_size = region[1] - mem_size + + # create all the extra PDEs needed to fit the requested size + # this loop starts from the current pde till the last pde that is + # needed the last pde is calcualted as the (start_addr + size) >> + # 22 + if overflow_size != 0: + for extra_pde in range(pde_index + 1, self.get_pde_number( + region[0] + region[1]) + 1): + + # new pde's start address + # each page directory entry has a addr range of (1024 *4096) + # thus the new PDE start address is a multiple of that + # number + extra_pde_start_address = (extra_pde * + (self.size_addressed_per_pde)) + + # the start address of and extra pde will always be 0 + # and the end address is calculated with the new pde's start + # address and the overflow_size + extra_pte_valid_addr_end = self.get_pte_number( + extra_pde_start_address + overflow_size - 1) + + # if the overflow_size couldn't be fit inside this new pde + # then need another pde and so we now need to limit the end + # of the PTE to 1024 and set the size of this new region to + # the max possible + extra_region_size = overflow_size + if overflow_size >= (self.size_addressed_per_pde): + extra_region_size = self.size_addressed_per_pde + extra_pte_valid_addr_end = self.total_pages + + # load the new PDE's details + + self.set_pde_pte_values(extra_pde, + extra_pde_start_address, + extra_region_size, + 0, + extra_pte_valid_addr_end, + region[2]) + + # for the next iteration of the loop the size needs to + # decreased. + overflow_size -= extra_region_size + + # print(hex_32(overflow_size),extra_pde) + if extra_pde not in page_tables_list: + page_tables_list.append(extra_pde) + + if overflow_size == 0: + break + + page_tables_list.sort() + + # update the tuple values for the memory regions needed + def set_pde_pte_values(self, pde_index, address, mem_size, + pte_valid_addr_start, pte_valid_addr_end, perm): + + pages_tuple = valid_pages_inside_pde( + start_addr=address, + size=mem_size, + pte_valid_addr_start=pte_valid_addr_start, + pte_valid_addr_end=pte_valid_addr_end, + permissions=perm) + + mem_region_values = mmu_region_details(pde_index=pde_index, + page_entries_info=[]) + + mem_region_values.page_entries_info.append(pages_tuple) + + if pde_index in list_of_pde.keys(): + # this step adds the new page info to the exsisting pages info + list_of_pde[pde_index].page_entries_info.append(pages_tuple) + else: + list_of_pde[pde_index] = mem_region_values + + def page_directory_create_binary_file(self): + global output_buffer + global output_offset + for pde in range(self.total_pages + 1): + binary_value = 0 # the page directory entry is not valid + + # if i have a valid entry to populate + if pde in sorted(list_of_pde.keys()): + value = list_of_pde[pde] + binary_value = self.get_binary_pde_value(value) + self.pde_verbose_output(pde, binary_value) + + struct.pack_into(self.write_page_entry_bin, + output_buffer, + output_offset, + binary_value) + + output_offset += struct.calcsize(self.write_page_entry_bin) + + def page_table_create_binary_file(self): + global output_buffer + global output_offset + + for key, value in sorted(list_of_pde.items()): + for pte in range(self.total_pages + 1): + binary_value = 0 # the page directory entry is not valid + + valid_pte = 0 + for i in value.page_entries_info: + temp_value = ((pte >= i.pte_valid_addr_start) and + (pte <= i.pte_valid_addr_end)) + if temp_value: + perm_for_pte = i.permissions + valid_pte |= temp_value + + # if i have a valid entry to populate + if valid_pte: + binary_value = self.get_binary_pte_value(value, + pte, + perm_for_pte) + self.pte_verbose_output(key, pte, binary_value) + + struct.pack_into(self.write_page_entry_bin, + output_buffer, + output_offset, + binary_value) + output_offset += struct.calcsize(self.write_page_entry_bin) + + # To populate the binary file the module struct needs a buffer of the + # excat size. This returns the size needed for the given set of page + # tables. + def set_binary_file_size(self): + binary_size = ctypes.create_string_buffer((4096) + + (len(list_of_pde.keys()) * + 4096)) + return binary_size + + # prints the details of the pde + def verbose_output(self): + + print("\nTotal Page directory entries " + str(self.get_number_of_pd())) + count = 0 + for key, value in list_of_pde.items(): + for i in value.page_entries_info: + count += 1 + print("In Page directory entry " + + format_string(value.pde_index) + + ": valid start address = " + + hex_32(i.start_addr) + ", end address = " + + hex_32((i.pte_valid_addr_end + 1) * 4096 - 1 + + (value.pde_index * (FourMB)))) + + # print all the tables for a given page table mode + def print_all_page_table_info(self): + self.pde_print_elements() + self.pte_print_elements() + + def pde_verbose_output(self, pde, binary_value): + if args.verbose is False: + return + + global print_string_pde_list + + present = format_string(binary_value & 0x1) + read_write = format_string((binary_value >> 1) & 0x1) + user_mode = format_string((binary_value >> 2) & 0x1) + pwt = format_string((binary_value >> 3) & 0x1) + pcd = format_string((binary_value >> 4) & 0x1) + a = format_string((binary_value >> 5) & 0x1) + ignored1 = format_string(0) + ps = format_string((binary_value >> 7) & 0x1) + ignored2 = format_string(0000) + page_table_addr = format_string(hex((binary_value >> 12) & 0xFFFFF)) + + print_string_pde_list += (format_string(str(pde)) + + " | " + + (present) + + " | " + + (read_write) + " | " + + (user_mode) + " | " + + (pwt) + " | " + + (pcd) + " | " + + (a) + " | " + + (ps) + " | " + + page_table_addr + "\n" + ) + + def pde_print_elements(self): + global print_string_pde_list + print("PAGE DIRECTORY ") + print(format_string("PDE") + " | " + + format_string('P') + " | " + + format_string('rw') + " | " + + format_string('us') + " | " + + format_string('pwt') + " | " + + format_string('pcd') + " | " + + format_string('a') + " | " + + format_string('ps') + " | " + + format_string('Addr page table')) + print(print_string_pde_list) + print("END OF PAGE DIRECTORY") + + def pte_verbose_output(self, pde, pte, binary_value): + global pde_pte_string + + present = format_string((binary_value >> 0) & 0x1) + read_write = format_string((binary_value >> 1) & 0x1) + user_mode = format_string((binary_value >> 2) & 0x1) + pwt = format_string((binary_value >> 3) & 0x1) + pcd = format_string((binary_value >> 4) & 0x1) + a = format_string((binary_value >> 5) & 0x1) + d = format_string((binary_value >> 6) & 0x1) + pat = format_string((binary_value >> 7) & 0x1) + g = format_string((binary_value >> 8) & 0x1) + alloc = format_string((binary_value >> 9) & 0x1) + custom = format_string((binary_value >> 10) & 0x3) + page_table_addr = hex_20((binary_value >> 12) & 0xFFFFF) + + print_string_list = (format_string(str(pte)) + " | " + + (present) + " | " + + (read_write) + " | " + + (user_mode) + " | " + + (pwt) + " | " + + (pcd) + " | " + + (a) + " | " + + (d) + " | " + + (pat) + " | " + + (g) + " | " + + (alloc) + " | " + + (custom) + " | " + + page_table_addr + "\n" + ) + + if pde in pde_pte_string.keys(): + pde_pte_string[pde] += (print_string_list) + else: + pde_pte_string[pde] = print_string_list + + def pte_print_elements(self): + global pde_pte_string + + for pde, print_string in sorted(pde_pte_string.items()): + print("\nPAGE TABLE " + str(pde)) + + print(format_string("PTE") + " | " + + format_string('P') + " | " + + format_string('rw') + " | " + + format_string('us') + " | " + + format_string('pwt') + " | " + + format_string('pcd') + " | " + + format_string('a') + " | " + + format_string('d') + " | " + + format_string('pat') + " | " + + format_string('g') + " | " + + format_string('alloc') + " | " + + format_string('custom') + " | " + + format_string('page addr')) + print(print_string) + print("END OF PAGE TABLE " + str(pde)) + + +#*****************************************************************************# +# class for PAE 4KB Mode +class PageMode_PAE: + total_pages = 511 + write_page_entry_bin = "Q" + size_addressed_per_pde = (512 * 4096) # 2MB In Bytes + size_addressed_per_pdpte = (512 * size_addressed_per_pde) # In Bytes + list_of_pdpte = {} + pdpte_print_string = {} + print_string_pdpte_list = '' + + # TODO enable all page tables on just a flag + + def __init__(self): + for i in range(4): + self.list_of_pdpte[i] = mmu_region_details_pdpt(pdpte_index=i, + pd_entries={}) + + # return the pdpte number for the give address + def get_pdpte_number(self, value): + return (value >> 30) & 0x3 + + # return the page directory number for the give address + def get_pde_number(self, value): + return (value >> 21) & 0x1FF + + # return the page table number for the given address + def get_pte_number(self, value): + return (value >> 12) & 0x1FF + + def get_number_of_pd(self): + return len(self.get_pdpte_list()) + + def get_pdpte_list(self): + return list({temp[0] for temp in pd_tables_list}) + + # the return value will have the page address and it is assumed to be a 4096 + # boundary.hence the output of this API will be a 20bit address of the page + # table + def address_of_page_table(self, pdpte, page_table_number): + global pd_start_addr + + # first page given to page directory pointer + # and 2nd page till 5th page are used for storing the page directories. + + # set the max pdpte used. this tells how many pd are needed after + # that we start keeping the pt + PT_start_addr = self.get_number_of_pd() * 4096 +\ + pd_start_addr + 4096 + return (PT_start_addr + + (pd_tables_list.index([pdpte, page_table_number]) * + 4096) >> 12) + + # union x86_mmu_pae_pde { + # u64_t value; + # struct { + # u64_t p:1; + # u64_t rw:1; + # u64_t us:1; + # u64_t pwt:1; + # u64_t pcd:1; + # u64_t a:1; + # u64_t ignored1:1; + # u64_t ps:1; + # u64_t ignored2:4; + # u64_t page_table:20; + # u64_t igonred3:29; + # u64_t xd:1; + # }; + # }; + + def get_binary_pde_value(self, pdpte, value): + perms = value.page_entries_info[0].permissions + + present = PAGE_ENTRY_PRESENT + read_write = check_bits(perms, [1, 29]) << 1 + user_mode = check_bits(perms, [2, 28]) << 2 + + pwt = PAGE_ENTRY_PWT + pcd = PAGE_ENTRY_PCD + a = PAGE_ENTRY_ACCESSED + ps = 0 << 7 # set to make sure that the phy page is 4KB + page_table = self.address_of_page_table(pdpte, value.pde_index) << 12 + xd = check_bits(perms, [62, 63]) << 63 + return (present | + read_write | + user_mode | + pwt | + pcd | + a | + ps | + page_table | + xd) + + # union x86_mmu_pae_pte { + # u64_t value; + # struct { + # u64_t p:1; + # u64_t rw:1; + # u64_t us:1; + # u64_t pwt:1; + # u64_t pcd:1; + # u64_t a:1; + # u64_t d:1; + # u64_t pat:1; + # u64_t g:1; + # u64_t ignore:3; + # u64_t page:20; + # u64_t igonred3:29; + # u64_t xd:1; + # }; + # }; + def get_binary_pte_value(self, value, pde, pte, perm_for_pte): + present = PAGE_ENTRY_PRESENT + read_write = perm_for_pte & PAGE_ENTRY_READ_WRITE + user_mode = perm_for_pte & PAGE_ENTRY_USER_SUPERVISOR + pwt = PAGE_ENTRY_PWT + pcd = PAGE_ENTRY_PCD + a = PAGE_ENTRY_ALLOC + d = PAGE_ENTRY_DIRTY + pat = PAGE_ENTRY_PAT + g = PAGE_ENTRY_GLOBAL + + # This points to the actual memory in the HW + # totally 20 bits to rep the phy address + # first 2bits is from pdpte then 9bits is the number got from pde and + # next 9bits is pte + page_table = ((value.pdpte_index << 18) | (pde << 9) | pte) << 12 + + xd = ((perm_for_pte >> 63) & 0x1) << 63 + + binary_value = (present | read_write | user_mode | + pwt | pcd | a | d | pat | g | + page_table | xd) + return binary_value + + def clean_up_unused_pdpte(self): + self.list_of_pdpte = {key: value for key, value in + self.list_of_pdpte.items() + if value.pd_entries != {}} + + # update the tuple values for the memory regions needed + def set_pde_pte_values(self, pdpte, pde_index, address, mem_size, + pte_valid_addr_start, pte_valid_addr_end, perm): + + pages_tuple = valid_pages_inside_pde( + start_addr=address, + size=mem_size, + pte_valid_addr_start=pte_valid_addr_start, + pte_valid_addr_end=pte_valid_addr_end, + permissions=perm) + + mem_region_values = mmu_region_details(pde_index=pde_index, + page_entries_info=[]) + + mem_region_values.page_entries_info.append(pages_tuple) + + if pde_index in self.list_of_pdpte[pdpte].pd_entries.keys(): + # this step adds the new page info to the exsisting pages info + self.list_of_pdpte[pdpte].pd_entries[pde_index].\ + page_entries_info.append(pages_tuple) + else: + self.list_of_pdpte[pdpte].pd_entries[pde_index] = mem_region_values + + def populate_required_structs(self): + for region in raw_info: + pdpte_index = self.get_pdpte_number(region[0]) + pde_index = self.get_pde_number(region[0]) + pte_valid_addr_start = self.get_pte_number(region[0]) + + # Get the end of the page table entries + # Since a memory region can take up only a few entries in the Page + # table, this helps us get the last valid PTE. + pte_valid_addr_end = self.get_pte_number(region[0] + + region[1] - 1) + + mem_size = region[1] + + # In-case the start address aligns with a page table entry other + # than zero and the mem_size is greater than (1024*4096) i.e 4MB + # in case where it overflows the currenty PDE's range then limit the + # PTE to 1024 and so make the mem_size reflect the actual size + # taken up in the current PDE + if (region[1] + (pte_valid_addr_start * 4096)) >= \ + (self.size_addressed_per_pde): + + pte_valid_addr_end = self.total_pages + mem_size = (((self.total_pages + 1) - + pte_valid_addr_start) * 4096) + + self.set_pde_pte_values(pdpte_index, + pde_index, + region[0], + mem_size, + pte_valid_addr_start, + pte_valid_addr_end, + region[2]) + + if [pdpte_index, pde_index] not in pd_tables_list: + pd_tables_list.append([pdpte_index, pde_index]) + + # IF the current pde couldn't fit the entire requested region + # size then there is a need to create new PDEs to match the size. + # Here the overflow_size represents the size that couldn't be fit + # inside the current PDE, this is will now to used to create a new + # PDE/PDEs so the size remaining will be + # requested size - allocated size(in the current PDE) + + overflow_size = region[1] - mem_size + + # create all the extra PDEs needed to fit the requested size + # this loop starts from the current pde till the last pde that is + # needed the last pde is calcualted as the (start_addr + size) >> + # 22 + if overflow_size != 0: + for extra_pdpte in range(pdpte_index, + self.get_pdpte_number(region[0] + + region[1]) + 1): + for extra_pde in range(pde_index + 1, self.get_pde_number( + region[0] + region[1]) + 1): + + # new pde's start address + # each page directory entry has a addr range of + # (1024 *4096) thus the new PDE start address is a + # multiple of that number + extra_pde_start_address = (extra_pde * + (self.size_addressed_per_pde)) + + # the start address of and extra pde will always be 0 + # and the end address is calculated with the new + # pde's start address and the overflow_size + extra_pte_valid_addr_end = ( + self.get_pte_number(extra_pde_start_address + + overflow_size - 1)) + + # if the overflow_size couldn't be fit inside this new + # pde then need another pde and so we now need to limit + # the end of the PTE to 1024 and set the size of this + # new region to the max possible + extra_region_size = overflow_size + if overflow_size >= (self.size_addressed_per_pde): + extra_region_size = self.size_addressed_per_pde + extra_pte_valid_addr_end = self.total_pages + + # load the new PDE's details + + self.set_pde_pte_values(extra_pdpte, + extra_pde, + extra_pde_start_address, + extra_region_size, + 0, + extra_pte_valid_addr_end, + region[2]) + + # for the next iteration of the loop the size needs + # to decreased + overflow_size -= extra_region_size + + if [extra_pdpte, extra_pde] not in pd_tables_list: + pd_tables_list.append([extra_pdpte, extra_pde]) + + if overflow_size == 0: + break + + pd_tables_list.sort() + self.clean_up_unused_pdpte() + + def pdpte_create_binary_file(self): + global output_buffer + global output_offset + global pd_start_addr + + # pae needs a pdpte at 32byte aligned address + + # Even though we have only 4 entries in the pdpte we need to move + # the output_offset variable to the next page to start pushing + # the pd contents + for pdpte in range(self.total_pages + 1): + if pdpte in self.get_pdpte_list(): + present = 1 << 0 + pwt = 0 << 3 + pcd = 0 << 4 + addr_of_pd = (((pd_start_addr + 4096) + + self.get_pdpte_list().index(pdpte) * + 4096) >> 12) << 12 + binary_value = (present | pwt | pcd | addr_of_pd) + self.pdpte_verbose_output(pdpte, binary_value) + else: + binary_value = 0 + + struct.pack_into(self.write_page_entry_bin, + output_buffer, + output_offset, + binary_value) + + output_offset += struct.calcsize(self.write_page_entry_bin) + + def page_directory_create_binary_file(self): + global output_buffer + global output_offset + pdpte_number_count = 0 + for pdpte, pde_info in self.list_of_pdpte.items(): + + pde_number_count = 0 + for pde in range(self.total_pages + 1): + binary_value = 0 # the page directory entry is not valid + + # if i have a valid entry to populate + # if pde in sorted(list_of_pde.keys()): + if pde in sorted(pde_info.pd_entries.keys()): + value = pde_info.pd_entries[pde] + binary_value = self.get_binary_pde_value(pdpte, value) + self.pde_verbose_output(pdpte, pde, binary_value) + + pde_number_count += 1 + struct.pack_into(self.write_page_entry_bin, + output_buffer, + output_offset, + binary_value) + + output_offset += struct.calcsize(self.write_page_entry_bin) + + def page_table_create_binary_file(self): + global output_buffer + global output_offset + + pdpte_number_count = 0 + for pdpte, pde_info in sorted(self.list_of_pdpte.items()): + pdpte_number_count += 1 + for pde, pte_info in sorted(pde_info.pd_entries.items()): + pte_number_count = 0 + for pte in range(self.total_pages + 1): + binary_value = 0 # the page directory entry is not valid + + valid_pte = 0 + # go through all the valid pages inside the pde to + # figure out if we need to populate this pte + for i in pte_info.page_entries_info: + temp_value = ((pte >= i.pte_valid_addr_start) and + (pte <= i.pte_valid_addr_end)) + if temp_value: + perm_for_pte = i.permissions + valid_pte |= temp_value + + # if i have a valid entry to populate + if valid_pte: + binary_value = self.get_binary_pte_value(pde_info, + pde, + pte, + perm_for_pte) + pte_number_count += 1 + self.pte_verbose_output(pdpte, pde, pte, binary_value) + + # print(binary_value, (self.write_page_entry_bin)) + + struct.pack_into(self.write_page_entry_bin, + output_buffer, + output_offset, + binary_value) + output_offset += struct.calcsize(self.write_page_entry_bin) + + + # To populate the binary file the module struct needs a buffer of the + # excat size This returns the size needed for the given set of page tables. + def set_binary_file_size(self): + pages_for_pdpte = 1 + pages_for_pd = self.get_number_of_pd() + pages_for_pt = len(pd_tables_list) + binary_size = ctypes.create_string_buffer((pages_for_pdpte + + pages_for_pd + + pages_for_pt) * 4096) + return binary_size + + # prints the details of the pde + def verbose_output(self): + print("\nTotal Page directory Page pointer entries " + + str(self.get_number_of_pd())) + count = 0 + for pdpte, pde_info in sorted(self.list_of_pdpte.items()): + print( + "In page directory page table pointer " + + format_string(pdpte)) + + for pde, pte_info in sorted(pde_info.pd_entries.items()): + for pte in pte_info.page_entries_info: + count += 1 + print(" In Page directory entry " + format_string(pde) + + ": valid start address = " + + hex_32(pte.start_addr) + ", end address = " + + hex_32((pte.pte_valid_addr_end + 1) * 4096 - 1 + + (pde * (self.size_addressed_per_pde)) + + (pdpte * self.size_addressed_per_pdpte))) + + def pdpte_verbose_output(self, pdpte, binary_value): + if args.verbose is False: + return + + present = format_string(binary_value & 0x1) + pwt = format_string((binary_value >> 3) & 0x1) + pcd = format_string((binary_value >> 4) & 0x1) + page_table_addr = format_string(hex((binary_value >> 12) & 0xFFFFF)) + + self.print_string_pdpte_list += (format_string(str(pdpte)) + + " | " + (present) + " | " + + (pwt) + " | " + + (pcd) + " | " + + page_table_addr + "\n") + + def pdpte_print_elements(self): + print("\nPAGE DIRECTORIES POINTER ") + print(format_string("PDPTE") + " | " + + format_string('P') + " | " + + format_string('pwt') + " | " + + format_string('pcd') + " | " + + format_string('Addr')) + print(self.print_string_pdpte_list) + print("END OF PAGE DIRECTORY POINTER") + + def pde_verbose_output(self, pdpte, pde, binary_value): + if args.verbose is False: + return + + global print_string_pde_list + + present = format_string(binary_value & 0x1) + read_write = format_string((binary_value >> 1) & 0x1) + user_mode = format_string((binary_value >> 2) & 0x1) + pwt = format_string((binary_value >> 3) & 0x1) + pcd = format_string((binary_value >> 4) & 0x1) + a = format_string((binary_value >> 5) & 0x1) + ignored1 = format_string(0) + ps = format_string((binary_value >> 7) & 0x1) + ignored2 = format_string(0000) + page_table_addr = format_string(hex((binary_value >> 12) & 0xFFFFF)) + xd = format_string((binary_value >> 63) & 0x1) + + print_string_pde_list = (format_string(str(pde)) + " | " + + (present) + " | " + + (read_write) + " | " + + (user_mode) + " | " + + (pwt) + " | " + + (pcd) + " | " + + (a) + " | " + + (ps) + " | " + + page_table_addr + " | " + + (xd) + "\n") + + if pdpte in self.pdpte_print_string.keys(): + self.pdpte_print_string[pdpte] += (print_string_pde_list) + else: + self.pdpte_print_string[pdpte] = print_string_pde_list + + # print all the tables for a given page table mode + def print_all_page_table_info(self): + self.pdpte_print_elements() + self.pde_print_elements() + self.pte_print_elements() + + def pde_print_elements(self): + global print_string_pde_list + + for pdpte, print_string in sorted(self.pdpte_print_string.items()): + print("\n PAGE DIRECTORIES for PDPT " + str(pdpte)) + print(format_string("PDE") + " | " + + format_string('P') + " | " + + format_string('rw') + " | " + + format_string('us') + " | " + + format_string('pwt') + " | " + + format_string('pcd') + " | " + + format_string('a') + " | " + + format_string('ps') + " | " + + format_string('Addr') + " | " + + format_string('xd')) + print(print_string) + print("END OF PAGE DIRECTORIES for PDPT " + str(pdpte)) + + def pte_verbose_output(self, pdpte, pde, pte, binary_value): + global pde_pte_string + + present = format_string((binary_value >> 0) & 0x1) + read_write = format_string((binary_value >> 1) & 0x1) + user_mode = format_string((binary_value >> 2) & 0x1) + pwt = format_string((binary_value >> 3) & 0x1) + pcd = format_string((binary_value >> 4) & 0x1) + a = format_string((binary_value >> 5) & 0x1) + d = format_string((binary_value >> 6) & 0x1) + pat = format_string((binary_value >> 7) & 0x1) + g = format_string((binary_value >> 8) & 0x1) + page_table_addr = hex_20((binary_value >> 12) & 0xFFFFF) + xd = format_string((binary_value >> 63) & 0x1) + + print_string_list = (format_string(str(pte)) + " | " + + (present) + " | " + + (read_write) + " | " + + (user_mode) + " | " + + (pwt) + " | " + + (pcd) + " | " + + (a) + " | " + + (d) + " | " + + (pat) + " | " + + (g) + " | " + + page_table_addr + " | " + + (xd) + "\n" + ) + + if (pdpte, pde) in pde_pte_string.keys(): + pde_pte_string[(pdpte, pde)] += (print_string_list) + else: + pde_pte_string[(pdpte, pde)] = print_string_list + + def pte_print_elements(self): + global pde_pte_string + + for (pdpte, pde), print_string in sorted(pde_pte_string.items()): + print( + "\nPAGE TABLE for PDPTE = " + + str(pdpte) + + " and PDE = " + + str(pde)) + + print(format_string("PTE") + " | " + + format_string('P') + " | " + + format_string('rw') + " | " + + format_string('us') + " | " + + format_string('pwt') + " | " + + format_string('pcd') + " | " + + format_string('a') + " | " + + format_string('d') + " | " + + format_string('pat') + " | " + + format_string('g') + " | " + + format_string('Page Addr') + " | " + + format_string('xd')) + print(print_string) + print("END OF PAGE TABLE " + str(pde)) + + +#*****************************************************************************# - if pde_index in list_of_pde.keys(): - # this step adds the new page info to the exsisting pages info - list_of_pde[pde_index].page_entries_info.append(pages_tuple) - else: - list_of_pde[pde_index] = mem_region_values def print_list_of_pde(list_of_pde): for key, value in list_of_pde.items(): - print(key,value) + print(key, value) print('\n') @@ -74,8 +1009,8 @@ def print_list_of_pde(list_of_pde): # start address of mem region # size of the region - so page tables entries will be created with this # read write permissions -raw_info=[] -def read_mmu_list_marshal_param(): + +def read_mmu_list_marshal_param(page_mode): global read_buff global page_tables_list @@ -84,131 +1019,51 @@ def read_mmu_list_marshal_param(): read_buff = input_file.read() input_file.close() - # read contents of the binary file first 2 values read are # num_of_regions and page directory start address both calculated and # populated by the linker - num_of_regions, pd_start_addr = struct.unpack_from(header_values_format,read_buff,0); + num_of_regions, pd_start_addr = struct.unpack_from( + header_values_format, read_buff, 0) # a offset used to remember next location to read in the binary - size_read_from_binary = struct.calcsize(header_values_format); + size_read_from_binary = struct.calcsize(header_values_format) # for each of the regions mentioned in the binary loop and populate all the # required parameters for region in range(num_of_regions): basic_mem_region_values = struct.unpack_from(struct_mmu_regions_format, - read_buff, - size_read_from_binary); - size_read_from_binary += struct.calcsize(struct_mmu_regions_format); + read_buff, + size_read_from_binary) + size_read_from_binary += struct.calcsize(struct_mmu_regions_format) + # ignore zero sized memory regions if basic_mem_region_values[1] == 0: continue - #validate for memory overlap here + # validate for memory overlap here for i in raw_info: start_location = basic_mem_region_values[0] - end_location = basic_mem_region_values[0] + basic_mem_region_values[1] + end_location = basic_mem_region_values[0] + \ + basic_mem_region_values[1] - overlap_occurred = ( (start_location >= i[0]) and \ - (start_location <= (i[0]+i[1]))) and \ - ((end_location >= i[0]) and \ - (end_location <= i[0]+i[1])) + overlap_occurred = ((start_location >= i[0]) and + (start_location <= (i[0] + i[1]))) and \ + ((end_location >= i[0]) and + (end_location <= i[0] + i[1])) if overlap_occurred: - validation_issue_memory_overlap = [True, - start_location, - get_pde_number(start_location)] + validation_issue_memory_overlap = [ + True, + start_location, + page_mode.get_pde_number(start_location)] return # add the retrived info another list raw_info.append(basic_mem_region_values) - for region in raw_info: - pde_index = get_pde_number(region[0]) - pte_valid_addr_start = get_pte_number(region[0]) - - # Get the end of the page table entries - # Since a memory region can take up only a few entries in the Page - # table, this helps us get the last valid PTE. - pte_valid_addr_end = get_pte_number(region[0] + - region[1] - 1) - - mem_size = region[1] - - # In-case the start address aligns with a page table entry other than zero - # and the mem_size is greater than (1024*4096) i.e 4MB - # in case where it overflows the currenty PDE's range then limit the - # PTE to 1024 and so make the mem_size reflect the actual size taken up - # in the current PDE - if (region[1] + (pte_valid_addr_start * 4096) ) >= (FourMB): - pte_valid_addr_end = 1023 - mem_size = ( (1024 - pte_valid_addr_start)*4096) - - set_pde_pte_values(pde_index, region[0], mem_size, - pte_valid_addr_start, pte_valid_addr_end, region[2]) - - - if pde_index not in page_tables_list: - page_tables_list.append(pde_index) - - # IF the current pde couldn't fit the entire requested region size then - # there is a need to create new PDEs to match the size. - # Here the overflow_size represents the size that couldn't be fit inside - # the current PDE, this is will now to used to create a new PDE/PDEs - # so the size remaining will be - # requested size - allocated size(in the current PDE) - - overflow_size = region[1] - mem_size - - - # create all the extra PDEs needed to fit the requested size - # this loop starts from the current pde till the last pde that is needed - # the last pde is calcualted as the (start_addr + size) >> 22 - if overflow_size != 0: - for extra_pde in range(pde_index+1, get_pde_number( - region[0] + region[1])+1): - - # new pde's start address - # each page directory entry has a addr range of (1024 *4096) - # thus the new PDE start address is a multiple of that number - extra_pde_start_address = extra_pde*(FourMB) - - # the start address of and extra pde will always be 0 - # and the end address is calculated with the new pde's start address - # and the overflow_size - extra_pte_valid_addr_end = get_pte_number(extra_pde_start_address - + overflow_size - 1) - - # if the overflow_size couldn't be fit inside this new pde then - # need another pde and so we now need to limit the end of the PTE - # to 1024 and set the size of this new region to the max possible - extra_region_size = overflow_size - if overflow_size >= (FourMB): - extra_region_size = FourMB - extra_pte_valid_addr_end = 1023 - - # load the new PDE's details - - set_pde_pte_values(extra_pde, extra_pde_start_address, - extra_region_size, - 0, extra_pte_valid_addr_end, region[2] ) - - - # for the next iteration of the loop the size needs to decreased - overflow_size -= extra_region_size - - # print(hex_32(overflow_size),extra_pde) - if extra_pde not in page_tables_list: - page_tables_list.append(extra_pde) - - if overflow_size == 0: - break - - page_tables_list.sort() - def validate_pde_regions(): - #validation for correct page alignment of the regions + # validation for correct page alignment of the regions for key, value in list_of_pde.items(): for pages_inside_pde in value.page_entries_info: if pages_inside_pde.start_addr & (0xFFF) != 0: @@ -216,152 +1071,34 @@ def validate_pde_regions(): hex(pages_inside_pde.start_addr)) sys.exit(2) - #validation for correct page alignment of the regions + # validation for correct page alignment of the regions if pages_inside_pde.size & (0xFFF) != 0: print("Memory Regions size is not page aligned", hex(pages_inside_pde.size)) sys.exit(2) - #validation for spiling of the regions across various + # validation for spiling of the regions across various if validation_issue_memory_overlap[0] == True: print("Memory Regions are overlapping at memory address " + - str(hex(validation_issue_memory_overlap[1]))+ + str(hex(validation_issue_memory_overlap[1])) + " with Page directory Entry number " + str(validation_issue_memory_overlap[2])) sys.exit(2) - - - -# the return value will have the page address and it is assumed to be a 4096 boundary -# hence the output of this API will be a 20bit address of the page table -def address_of_page_table(page_table_number): - global pd_start_addr - - # location from where the Page tables will be written - PT_start_addr = pd_start_addr + 4096 - return ( (PT_start_addr + (page_tables_list.index(page_table_number)*4096) >>12)) - -# union x86_mmu_pde_pt { -# u32_t value; -# struct { -# u32_t p:1; -# u32_t rw:1; -# u32_t us:1; -# u32_t pwt:1; -# u32_t pcd:1; -# u32_t a:1; -# u32_t ignored1:1; -# u32_t ps:1; -# u32_t ignored2:4; -# u32_t page_table:20; -# }; -# }; - - def check_bits(val, bits): for b in bits: if val & (1 << b): return 1 return 0 -def page_directory_create_binary_file(): - global output_buffer - global output_offset - for pde in range(1024): - binary_value = 0 # the page directory entry is not valid - - # if i have a valid entry to populate - if pde in sorted(list_of_pde.keys()): - value = list_of_pde[pde] - - perms = value.page_entries_info[0].permissions - - present = 1 << 0; - read_write = check_bits(perms, [1, 29]) << 1; - user_mode = check_bits(perms, [2, 28]) << 2; - - pwt = 0 << 3; - pcd = 0 << 4; - a = 0 << 5; # this is a read only field - ps = 0 << 7; # this is a read only field - page_table = address_of_page_table(value.pde_index) << 12; - binary_value = (present | read_write | user_mode | pwt | pcd | a | ps | page_table) - pde_verbose_output(pde, binary_value) - - struct.pack_into(write_4byte_bin,output_buffer, output_offset, binary_value) - output_offset += struct.calcsize(write_4byte_bin) - - -# union x86_mmu_pte { -# u32_t value; -# struct { -# u32_t p:1; -# u32_t rw:1; -# u32_t us:1; -# u32_t pwt:1; -# u32_t pcd:1; -# u32_t a:1; -# u32_t d:1; -# u32_t pat:1; -# u32_t g:1; -# u32_t alloc:1; -# u32_t custom:2; -# u32_t page:20; -# }; -# }; - -def page_table_create_binary_file(): - global output_buffer - global output_offset - - for key, value in sorted(list_of_pde.items()): - for pte in range(1024): - binary_value = 0 # the page directory entry is not valid - - valid_pte = 0 - for i in value.page_entries_info: - temp_value = ((pte >= i.pte_valid_addr_start) and (pte <= i.pte_valid_addr_end)) - if temp_value: - perm_for_pte = i.permissions - valid_pte |= temp_value - - # if i have a valid entry to populate - if valid_pte: - present = 1 << 0; - read_write = ( ( perm_for_pte >> 1) & 0x1) << 1; - user_mode = ( ( perm_for_pte >> 2) & 0x1) << 2; - pwt = 0 << 3; - pcd = 0 << 4; - a = 0 << 5; # this is a read only field - d = 0 << 6; # this is a read only field - pat = 0 << 7 - g = 0<< 8 - alloc = 1 << 9 - custom = 0 <<10 - - # This points to the actual memory in the HW - # totally 20 bits to rep the phy address - # first 10 is the number got from pde and next 10 is pte - page_table = ((value.pde_index <<10) |pte) << 12; - - binary_value = (present | read_write | user_mode | - pwt | pcd | a | d | pat | g | alloc | custom | - page_table) - - pte_verbose_output(key,pte,binary_value) - - struct.pack_into(write_4byte_bin, output_buffer, output_offset, binary_value) - output_offset += struct.calcsize(write_4byte_bin) - # Read the parameters passed to the file def parse_args(): global args - parser = argparse.ArgumentParser(description = __doc__, - formatter_class = argparse.RawDescriptionHelpFormatter) + parser = argparse.ArgumentParser(description=__doc__, + formatter_class=argparse.RawDescriptionHelpFormatter) parser.add_argument("-e", "--big-endian", action="store_true", help="Target encodes data in big-endian format" @@ -369,172 +1106,90 @@ def parse_args(): parser.add_argument("-i", "--input", help="Input file from which MMU regions are read.") + parser.add_argument("-k", "--kernel", + help="Zephyr kernel image") parser.add_argument("-o", "--output", help="Output file into which the page tables are written.") parser.add_argument("-v", "--verbose", action="store_true", help="Lists all the relavent data generated.") args = parser.parse_args() + # the format for writing in the binary file would be decided by the # endian selected -def set_struct_endian_format(): +def set_struct_endian_format(page_mode): endian_string = "<" - if args.big_endian == True: + if args.big_endian is True: endian_string = ">" global struct_mmu_regions_format global header_values_format - global write_4byte_bin - struct_mmu_regions_format = endian_string + "III" + struct_mmu_regions_format = endian_string + "IIQ" header_values_format = endian_string + "II" - write_4byte_bin = endian_string + "I" + page_mode.write_page_entry_bin = (endian_string + + page_mode.write_page_entry_bin) def format_string(input_str): output_str = '{0: <5}'.format(str(input_str)) - return(output_str) + return output_str -#format for 32bit hex value +# format for 32bit hex value def hex_32(input_value): - output_value ="{0:#0{1}x}".format(input_value,10) - return(output_value) + output_value = "{0:#0{1}x}".format(input_value, 10) + return output_value -#format for 20bit hex value +# format for 20bit hex value def hex_20(input_value): - output_value ="{0:#0{1}x}".format(input_value,7) - return(output_value) - -def pde_verbose_output(pde, binary_value): - if args.verbose == False: - return - - global print_string_pde_list - - present = format_string(binary_value & 0x1 ) - read_write = format_string((binary_value >> 1 ) & 0x1 ) - user_mode = format_string((binary_value >> 2 ) & 0x1 ) - pwt = format_string((binary_value >> 3 ) & 0x1 ) - pcd = format_string((binary_value >> 4 ) & 0x1 ) - a = format_string((binary_value >> 5 ) & 0x1 ) - ignored1 = format_string(0) - ps = format_string((binary_value >> 7 ) & 0x1 ) - ignored2 = format_string(0000) - page_table_addr = format_string( hex((binary_value >> 12 ) & 0xFFFFF)) - - print_string_pde_list += ( format_string(str(pde))+" | "+(present)+ " | "+\ - (read_write)+ " | "+\ - (user_mode)+ " | "+\ - (pwt)+ " | "+\ - (pcd)+ " | "+\ - (a)+ " | "+\ - (ps)+ " | "+ - page_table_addr +"\n" - ) - -def pde_print_elements(): - global print_string_pde_list - print("PAGE DIRECTORY ") - print(format_string("PDE")+" | "+ \ - format_string('P') +" | "+ \ - format_string('rw') +" | "+ \ - format_string('us') +" | "+ \ - format_string('pwt') +" | "+ \ - format_string('pcd') +" | "+ \ - format_string('a') +" | "+ \ - format_string('ps') +" | "+ \ - format_string('Addr page table')) - print(print_string_pde_list) - print("END OF PAGE DIRECTORY") + output_value = "{0:#0{1}x}".format(input_value, 7) + return output_value -def pte_verbose_output(pde, pte, binary_value): - global pde_pte_string - - present = format_string( str((binary_value >> 0) & 0x1)) - read_write = format_string( str((binary_value >> 1) & 0x1)) - user_mode = format_string( str((binary_value >> 2) & 0x1)) - pwt = format_string( str((binary_value >> 3) & 0x1)) - pcd = format_string( str((binary_value >> 4) & 0x1)) - a = format_string( str((binary_value >> 5) & 0x1)) - d = format_string( str((binary_value >> 6) & 0x1)) - pat = format_string( str((binary_value >> 7) & 0x1)) - g = format_string( str((binary_value >> 8) & 0x1)) - alloc = format_string( str((binary_value >> 9) & 0x1)) - custom = format_string( str((binary_value >> 10) & 0x3)) - page_table_addr = hex_20((binary_value >> 12) & 0xFFFFF) - - print_string_list = ( format_string(str(pte))+" | "+(present)+ " | "+\ - (read_write)+ " | "+\ - (user_mode)+ " | "+\ - (pwt)+ " | "+\ - (pcd)+ " | "+\ - (a)+ " | "+\ - (d)+ " | "+\ - (pat)+ " | "+\ - (g)+ " | "+\ - (alloc)+ " | "+\ - (custom)+ " | "+\ - page_table_addr +"\n" - ) - - if pde in pde_pte_string.keys(): - pde_pte_string[pde] += (print_string_list) - else: - pde_pte_string[pde] = print_string_list - - -def pte_print_elements(): - global pde_pte_string - - for pde,print_string in sorted(pde_pte_string.items()): - print("\nPAGE TABLE "+str(pde)) - - print(format_string("PTE")+" | "+ \ - format_string('P') +" | "+ \ - format_string('rw') +" | "+ \ - format_string('us') +" | "+ \ - format_string('pwt') +" | "+ \ - format_string('pcd') +" | "+ \ - format_string('a') +" | "+ \ - format_string('d') +" | "+ \ - format_string('pat') +" | "+ \ - format_string('g') +" | "+ \ - format_string('alloc') +" | "+ \ - format_string('custom') +" | "+ \ - format_string('page addr')) - print(print_string) - print("END OF PAGE TABLE "+ str(pde)) - -def verbose_output(): - if args.verbose == False: +def verbose_output(page_mode): + if args.verbose is False: return print("\nMemory Regions as defined:") for info in raw_info: - print("Memory region start address = " + hex_32(info[0]) +\ - ", Memory size = " + hex_32(info[1]) +\ - ", Permission = "+ hex(info[2])) + print("Memory region start address = " + hex_32(info[0]) + + ", Memory size = " + hex_32(info[1]) + + ", Permission = " + hex(info[2])) - print("\nTotal Page directory entries " + str(len(list_of_pde.keys()))) - count =0 - for key, value in list_of_pde.items(): - for i in value.page_entries_info: - count+=1 - print("In Page directory entry "+format_string(value.pde_index) +\ - ": valid start address = "+ \ - hex_32(i.start_addr) + ", end address = " + \ - hex_32((i.pte_valid_addr_end +1 )*4096 -1 +\ - (value.pde_index * (FourMB)))) + page_mode.verbose_output() + page_mode.print_all_page_table_info() + +# build sym table +def get_symbols(obj): + for section in obj.iter_sections(): + if isinstance(section, SymbolTableSection): + return {sym.name: sym.entry.st_value + for sym in section.iter_symbols()} + + raise LookupError("Could not find symbol table") - pde_print_elements() - pte_print_elements() +# determine which paging mode was selected +def get_page_mode(): + with open(args.kernel, "rb") as fp: + kernel = ELFFile(fp) + sym = get_symbols(kernel) + try: + return sym["CONFIG_X86_PAE_MODE"] + except BaseException: + return 0 + def main(): global output_buffer parse_args() - set_struct_endian_format() + # select the page table needed + if get_page_mode(): + page_mode = PageMode_PAE() + else: + page_mode = PageMode_4kb() + + set_struct_endian_format(page_mode) global input_file input_file = open(args.input, 'rb') @@ -543,26 +1198,32 @@ def main(): binary_output_file = open(args.output, 'wb') # inputfile= file_name - read_mmu_list_marshal_param() + read_mmu_list_marshal_param(page_mode) - #validate the inputs + # populate the required structs + page_mode.populate_required_structs() + + # validate the inputs validate_pde_regions() # The size of the output buffer has to match the number of bytes we write # this corresponds to the number of page tables gets created. - output_buffer = ctypes.create_string_buffer((4096)+ - (len(list_of_pde.keys()) * - 4096)) + output_buffer = page_mode.set_binary_file_size() - page_directory_create_binary_file() - page_table_create_binary_file() + try: + page_mode.pdpte_create_binary_file() + except BaseException: + pass + page_mode.page_directory_create_binary_file() + page_mode.page_table_create_binary_file() - #write the binary data into the file - binary_output_file.write(output_buffer); + # write the binary data into the file + binary_output_file.write(output_buffer) binary_output_file.close() # verbose output needed by the build system - verbose_output() + verbose_output(page_mode) + if __name__ == "__main__": - main() + main()