x86: MMU: Generation of PAE tables
If CONFIG_X86_PAE_MODE is enabled for the build, then gen_mmu.py
would generate the boot time page tables in PAE format.
This supports 3 level paging i.e Page Directory Pointer(PDPT), Page
Directory(PD) and Page Table(PT). Each Page Table Entry(PTE) maps to
a 4KB region. Each Page Directory Entry(PDE) maps a 2MB region.
Each Page Directory Pointer Entry(PDPTE) maps to a 1GB region.
JIRA: ZEP-2511
Signed-off-by: Adithya Baglody <adithya.nagaraj.baglody@intel.com>
diff --git a/scripts/gen_mmu.py b/scripts/gen_mmu.py
index a97a2de..6fb2701 100755
--- a/scripts/gen_mmu.py
+++ b/scripts/gen_mmu.py
@@ -7,66 +7,1001 @@
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())
- 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
+ # 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))
+
+
+#*****************************************************************************#
+
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 @@
# 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 @@
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 @@
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 @@
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 @@
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()