Last active
November 30, 2025 08:19
-
-
Save sunflower2333/f93ec07e6f981e0ff30d5f87ab6aefe0 to your computer and use it in GitHub Desktop.
This program help your parse your uefiplat to C code.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| from pyfdt.pyfdt import FdtBlobParse | |
| # NOTICE, you need to install pyfdt package first :) | |
| # pip install pyfdt | |
| SIZE_2GB = 0x80000000 | |
| class MemoryDescriptor: | |
| # base = 0 | |
| # size = 0 | |
| # label = "" | |
| # build_hob = "" | |
| # resource_type = "" | |
| # resource_attribute = "" | |
| # mem_type = "" | |
| # cache_attributes = "" | |
| def __init__(self, label, base, size, build_hob, resource_type, resource_attribute, mem_type, cache_attributes): | |
| self.label = str(label) | |
| self.base = int(base, 16) | |
| self.size = int(size, 16) | |
| self.build_hob = str(build_hob) | |
| self.resource_type = str(resource_type) | |
| self.resource_attribute = str(resource_attribute) | |
| self.mem_type = str(mem_type) | |
| self.cache_attributes = str(cache_attributes) | |
| def region2msg(self): | |
| msg = '{' + self.label + "0x%08X" % self.base + ', ' + "0x%08X" % self.size + ',' + self.build_hob \ | |
| + ',' + self.resource_type + ',' + self.resource_attribute + ',' + self.mem_type + ',' \ | |
| + self.cache_attributes + ' },' | |
| return msg | |
| class DDRBank: | |
| def __init__(self, base, size): | |
| self.base = base | |
| self.size = size | |
| def ddr_bank_to_msg(self): | |
| msg = "/* RAM Entry: Base 0x%016X\tSize 0x%016X" % (self.base, self.size) + " */" | |
| return msg | |
| def check_if_locate_in_bank(self, descriptor) -> bool: | |
| # err_msg = "WARNING: descriptor region is invalid: \n" | |
| # desc_info = "base: " + str(descriptor.base) + ", \t size:" + str(descriptor.size) | |
| # err_cases = { | |
| # "base_not_in_range_err": "The provided memory region's base address is not located in ddr regions.\n", | |
| # "big_size_error": "The provided memory region's size if bigger than ddr size.\n", | |
| # "oversize_error": "The provided memory region is greater than ddr region.\n" | |
| # } | |
| # if descriptor.base < self.base: | |
| # print(err_msg + err_cases["base_not_in_range_err"] + desc_info) | |
| # # raise MemoryError(err_msg + err_cases["base_not_in_range_err"] + desc_info) | |
| # if descriptor.size > self.size: | |
| # print(err_msg + err_cases["base_not_in_range_err"] + desc_info) | |
| # # raise MemoryError(err_msg + err_cases["big_size_error"] + desc_info) | |
| # if descriptor.base + descriptor.size > self.base + self.size: | |
| # print(err_msg + err_cases["base_not_in_range_err"] + desc_info) | |
| # # raise MemoryError(err_msg + err_cases["oversize_error"] + desc_info) | |
| return (descriptor.base + descriptor.size <= self.base + self.size) and (descriptor.base >= self.base) | |
| def generate_conv_region(base, size): | |
| conv_region = MemoryDescriptor(" \"RAM Partition\", ", "0x0", "0x0", " AddMem", " SYS_MEM", | |
| " SYS_MEM_CAP", " Conv", " WRITE_BACK_XN") | |
| conv_region.base = base | |
| conv_region.size = size | |
| return conv_region | |
| def parse_memory_line_to_msg(line): | |
| if line[-1] == '\n': | |
| line = line[0:-1] | |
| mem_base, mem_size, mem_label, build_hob, \ | |
| resource_type, resource_attribute, memory_type, cache_attributes = line.split(',') | |
| mem_label+=',' | |
| # Sort Code | |
| space_count = build_hob.count(' ') | |
| build_hob = build_hob[(space_count - 1):] | |
| mem_label = mem_label + space_count * ' ' | |
| # print C code | |
| msg = '{' + mem_label + mem_base + ',' + mem_size + ',' + build_hob \ | |
| + ',' + resource_type + ',' + resource_attribute + ',' + memory_type + ',' + cache_attributes + '},' | |
| return msg | |
| # Parse memory part in uefiplat.cfg, then return the memory descriptor. | |
| def parse_memory_line_to_object(line): | |
| if line[-1] == '\n': | |
| line = line[0:-1] | |
| mem_base, mem_size, mem_label, build_hob, \ | |
| resource_type, resource_attribute, memory_type, cache_attributes = line.split(',') | |
| # Sort Code | |
| space_count = build_hob.count(' ') | |
| build_hob = build_hob[(space_count - 1):] | |
| mem_label = mem_label + ',' + space_count * ' ' | |
| return MemoryDescriptor(mem_label, mem_base, mem_size, build_hob, resource_type, resource_attribute, memory_type, | |
| cache_attributes) | |
| # Check Overlap in a sorted memory region descriptor array. | |
| def overlap_checker(in_descriptors): | |
| descriptors = in_descriptors.copy() | |
| # Firstly, sorted this array by region base | |
| descriptors.sort(key=lambda d: d.base) | |
| # Secondly, check overlap. | |
| overlap_flag = False | |
| last_desc = descriptors[0] | |
| descriptors.pop(0) | |
| for desc in descriptors: | |
| if last_desc.base + last_desc.size > desc.base: | |
| print("WARNING!!! Overlap Detected!") | |
| print("last_descriptor:\n\tbase: " + str(last_desc.base) + ",\tsize: " + str(last_desc.size)) | |
| print("current_descriptor:\n\tbase: " + str(desc.base) + ",\tsize: " + str(desc.size)) | |
| overlap_flag = True | |
| continue | |
| last_desc = desc | |
| continue | |
| if overlap_flag: | |
| raise MemoryError("Please Check Your Uefiplat.cfg !!!") | |
| # Check if there are memory gaps in given ddr bank and memory descriptors. | |
| def gap_checker(ddr_regions, in_descriptors): | |
| # backup descriptors | |
| result = in_descriptors.copy() | |
| descriptors = in_descriptors.copy() | |
| # Insure descriptors array is sorted. | |
| descriptors.sort(key=lambda d: d.base) | |
| # Firstly, check if all regions is valid. | |
| for desc in descriptors: | |
| available_flag = False | |
| for ddr_bank in ddr_regions: | |
| if ddr_bank.check_if_locate_in_bank(desc): | |
| available_flag = True | |
| if not available_flag: | |
| desc_info = "base: " + hex(desc.base) + ", \t size:" + hex(desc.size) | |
| print("// WARNING: gap_checker failed. Unknown error happen." + desc_info) | |
| # raise MemoryError("gap_checker failed. Unknown error happen.") | |
| # Secondly, check if there are gaps near regions | |
| last_desc = descriptors[0] | |
| descriptors.pop(0) | |
| for desc in descriptors: | |
| if last_desc.base + last_desc.size < desc.base: | |
| # Fill conventional regions here. | |
| # 1, Calculate conv region base and size. | |
| conv_region = generate_conv_region(last_desc.base + last_desc.size, | |
| desc.base - (last_desc.base + last_desc.size)) | |
| # 2. Check if conv region available in DDR banks. | |
| for ddr_bank in ddr_regions: | |
| if not ddr_bank.check_if_locate_in_bank(last_desc): | |
| continue | |
| if not ddr_bank.check_if_locate_in_bank(conv_region): | |
| conv_region.size = (ddr_bank.base + ddr_bank.size) - conv_region.base | |
| if conv_region.size: | |
| result.append(conv_region) | |
| last_desc = desc | |
| # Finally, sorted the array before returning. | |
| result.sort(key=lambda d: d.base) | |
| return result | |
| # Parse the config part in uefiplat.cfg, then return the c code. | |
| def parse_config_line(line): | |
| if line[-1] == '\n': | |
| line = line[0:-1] | |
| config_name, config_value = line.split(' = ') | |
| msg = '{\"' + config_name + '\", ' + config_value + '},\n' | |
| if config_value[0] == '\"': | |
| msg = '' | |
| return msg | |
| # This function will split a memory region which is greater than 2GB into 2GB pieces in a list. | |
| def split_region(descriptor): | |
| result = [] | |
| tmp_size = descriptor.size | |
| tmp_base = descriptor.base | |
| while tmp_size >= SIZE_2GB: | |
| result.append(generate_conv_region(tmp_base, SIZE_2GB)) | |
| tmp_size -= SIZE_2GB | |
| tmp_base += SIZE_2GB | |
| if tmp_size: | |
| result.append(generate_conv_region(tmp_base, tmp_size)) | |
| return result | |
| # In this function, all the unmapped memory in | |
| # ddr bank will be filled be conventional system memory. | |
| def ddr_filler(ddr_regions, in_descriptor): | |
| descriptor = in_descriptor.copy() | |
| # Make sure the array is sorted. | |
| descriptor.sort(key=lambda d: d.base) | |
| # Firstly, find the last region and all unmapped banks. | |
| passed_banks_flag = False | |
| for ddr_region in ddr_regions: | |
| if not passed_banks_flag: | |
| if not ddr_region.check_if_locate_in_bank(descriptor[-1]): | |
| continue | |
| # if (descriptor[-1].base + descriptor[-1].size) == (ddr_region.base + ddr_region.size): | |
| # continue | |
| passed_banks_flag = True | |
| descriptor += split_region(generate_conv_region(descriptor[-1].base + descriptor[-1].size, | |
| (ddr_region.base + ddr_region.size) - ( | |
| descriptor[-1].base + descriptor[-1].size))) | |
| else: | |
| # Secondly, split and fill the rest parts | |
| descriptor += split_region(generate_conv_region(ddr_region.base, ddr_region.size)) | |
| return descriptor | |
| def find_cells_by_reg(path, cells_name, obj_fdt): | |
| cells_val = 1 | |
| folders = path.split('/') | |
| folders.pop(-1) | |
| for f in reversed(folders): | |
| if None is not obj_fdt.resolve_path(path + cells_name): | |
| cells_val = obj_fdt.resolve_path(path + cells_name)[0] | |
| return cells_val | |
| if f != '': | |
| path = path.removesuffix(f + '/') | |
| return cells_val # Not found | |
| def regs_to_ddr_banks_by_cells(this_addr_cells, this_size_cells, this_regs): | |
| this_ddr_banks = [] | |
| # [addr, size, addr, size, ...] | |
| for i in range(0, len(this_regs), this_addr_cells + this_size_cells): | |
| if this_addr_cells == 1: | |
| this_ddr_banks.append( | |
| DDRBank(this_regs[i], | |
| this_regs[i + 1] if this_size_cells == 1 else (this_regs[i + 1] << 32) + this_regs[i + 2])) | |
| if this_addr_cells == 2: | |
| this_ddr_banks.append(DDRBank((this_regs[i] << 32) + this_regs[i + 1], | |
| this_regs[i + 2] if this_size_cells == 1 else | |
| (this_regs[i + 2] << 32) + this_regs[i + 3])) | |
| return this_ddr_banks | |
| if __name__ == "__main__": | |
| uefi_plat_file_path = "./uefiplat.cfg" | |
| fdt_file_path = "./fdt" | |
| pFile = open(uefi_plat_file_path, "r", encoding="utf-8") | |
| pFDT = open(fdt_file_path, "rb") | |
| this_line = "value" # mustn't be none here | |
| # Get DDR Banks from FDT | |
| fdt = FdtBlobParse(pFDT).to_fdt() | |
| mem_reg_path = "/memory/reg/" | |
| addr_cells = find_cells_by_reg(mem_reg_path, "#address-cells", fdt) | |
| size_cells = find_cells_by_reg(mem_reg_path, "#size-cells", fdt) | |
| ddr_banks = regs_to_ddr_banks_by_cells(addr_cells, size_cells, fdt.resolve_path(mem_reg_path)) | |
| ddr_banks.sort(key=lambda d: d.base) | |
| for bank in ddr_banks: | |
| print(bank.ddr_bank_to_msg()) | |
| # Find [MemoryMap] | |
| while this_line != "[MemoryMap]\n": | |
| this_line = pFile.readline() | |
| if this_line == '': # EOF | |
| print("Invalid uefiplat.cfg") | |
| break | |
| if this_line[0] == '#': # Pass comment | |
| continue | |
| # Parse [MemoryMap] | |
| regions = [] | |
| while True: | |
| this_line = pFile.readline() | |
| if this_line == '' or this_line[0] == '[': | |
| break | |
| if this_line[0] == '\n' or this_line[0] == '#' and this_line[0:2] != '#-': | |
| continue | |
| if this_line[0:2] == '#-': | |
| this_line = "//" + this_line[1:] | |
| print(this_line) | |
| continue | |
| regions.append(parse_memory_line_to_object(this_line)) | |
| # Sort regions by memory base. | |
| regions.sort(key=lambda r: r.base) | |
| # Check for overlap. | |
| overlap_checker(regions) | |
| # Find and fill memory gaps between regions | |
| regions = gap_checker(ddr_banks, regions) | |
| # Fill the reset of spaces in ddr bank with conventional regions. | |
| regions = ddr_filler(ddr_banks, regions) | |
| for region in regions: | |
| print(region.region2msg()) | |
| # Find [RegisterMap] | |
| while this_line != "[RegisterMap]\n": | |
| this_line = pFile.readline() | |
| if this_line == '': # EOF | |
| print("Invalid UefiCfg") | |
| break | |
| if this_line[0] == '#': # Pass comment | |
| continue | |
| # Parse [RegisterMap] | |
| while True: | |
| this_line = pFile.readline() | |
| if this_line == '' or this_line[0] == '[': | |
| break | |
| if this_line[0] == '\n' or this_line[0] == '#' and this_line[0:2] != '#-': | |
| continue | |
| if this_line[0:2] == '#-': | |
| this_line = "//" + this_line[1:] | |
| print(this_line) | |
| continue | |
| print(parse_memory_line_to_msg(this_line)) | |
| # print("\n// Configuration Map") | |
| # | |
| # Find [ConfigParameters] | |
| # while this_line != "[ConfigParameters]\n": | |
| # this_line = pFile.readline() | |
| # if this_line == '': # EOF | |
| # print("Invalid UefiCfg") | |
| # break | |
| # if this_line[0] == '#': # Pass comment | |
| # continue | |
| # | |
| # # Parse [ConfigParameters] | |
| # while True: | |
| # this_line = pFile.readline() | |
| # if this_line == '' or this_line[0] == '[': | |
| # break | |
| # if this_line[0] == '\n' or this_line[0] == '#': | |
| # continue | |
| # print(parse_config_line(this_line), end='') | |
| pFile.close() | |
| pFDT.close() |
Author
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
It will print memory map you need and configuration map you need.
You need to run
pip install pyfdtbefore run this script.Ensure there is a file named
fdtand a file nameduefiplat.cfgunder the working folder.Example: