summaryrefslogtreecommitdiff
path: root/util/qualcomm
diff options
context:
space:
mode:
authorT Michael Turney <mturney@codeaurora.org>2018-05-01 15:59:37 -0700
committerJulius Werner <jwerner@chromium.org>2019-05-03 21:59:05 +0000
commit101098c41a047184e3eceabca2c1baa11141f36e (patch)
treeb6fcf8f46131e4e8fc28554e0c79eda984bb7fca /util/qualcomm
parent61309e39b3c4545f47c9107a0e0ddaedef854505 (diff)
sdm845: Combine BB with QC-Sec for ROM boot
TEST=build & run Change-Id: I222a56f1c9b74856a1e1ff8132bab5e041672c5d Signed-off-by: T Michael Turney <mturney@codeaurora.org> Reviewed-on: https://review.coreboot.org/c/coreboot/+/25207 Reviewed-by: Julius Werner <jwerner@chromium.org> Tested-by: build bot (Jenkins) <no-reply@coreboot.org>
Diffstat (limited to 'util/qualcomm')
-rwxr-xr-xutil/qualcomm/createxbl.py733
-rwxr-xr-xutil/qualcomm/ipqheader.py129
-rwxr-xr-xutil/qualcomm/mbn_tools.py2324
-rwxr-xr-xutil/qualcomm/mbncat.py200
-rwxr-xr-xutil/qualcomm/qgpt.py234
5 files changed, 3620 insertions, 0 deletions
diff --git a/util/qualcomm/createxbl.py b/util/qualcomm/createxbl.py
new file mode 100755
index 0000000000..4a218544c0
--- /dev/null
+++ b/util/qualcomm/createxbl.py
@@ -0,0 +1,733 @@
+#!/usr/bin/env python2
+#============================================================================
+#
+#/** @file createxbl.py
+#
+# GENERAL DESCRIPTION
+# Concatentates XBL segments into one ELF image
+#
+# Copyright (c) 2016, 2018, The Linux Foundation. All rights reserved.
+#
+# Redistribution and use in source and binary forms, with or without
+# modification, are permitted provided that the following conditions are
+# met:
+# * Redistributions of source code must retain the above copyright
+# notice, this list of conditions and the following disclaimer.
+# * Redistributions in binary form must reproduce the above
+# copyright notice, this list of conditions and the following
+# disclaimer in the documentation and/or other materials provided
+# with the distribution.
+# * Neither the name of The Linux Foundation nor the names of its
+# contributors may be used to endorse or promote products derived
+# from this software without specific prior written permission.
+#
+# THIS SOFTWARE IS PROVIDED "AS IS" AND ANY EXPRESS OR IMPLIED
+# WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+# MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT
+# ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS
+# BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+# CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+# SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
+# BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
+# WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
+# OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN
+# IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+#
+#**/
+#
+#----------------------------------------------------------------------------
+#
+# EDIT HISTORY FOR FILE
+#
+# This section contains comments describing changes made to the module.
+# Notice that changes are listed in reverse chronological order.
+#
+# when who what, where, why
+# -------- --- ------------------------------------------------------
+# 03/26/18 tv Added -e to enable extended MBNV5 support
+# 09/04/15 et Added -x and -d to embed xbl_sec ELF
+# 02/11/15 ck Fixed missing elf type check in ZI OOB feature
+# 11/04/14 ck Updated calls to mbn_tools functions
+# 10/22/14 ck Added -z option to remove out of bounds ZI segments when converting from 64 to 32
+# 10/10/14 ck Added -c option and logic to enable elf type swapping
+# 09/12/14 ck Added single file logic
+# 08/29/14 ck Added no_hash option
+# 08/29/14 ck Refactored to use proper python arguments and cleaned code
+# 06/16/14 niting xbl.mbn to xbl.elf
+# 05/28/14 niting Initial revision
+#
+#============================================================================
+from optparse import OptionParser
+import os
+import sys
+import shutil
+import mbn_tools
+
+PAGE_SIZE = 4096
+SEGMENT_ALIGN = 16
+ELF32_HDR_SIZE = 52
+ELF32_PHDR_SIZE = 32
+ELF64_HDR_SIZE = 64
+ELF64_PHDR_SIZE = 56
+
+
+##############################################################################
+# main
+##############################################################################
+def main():
+ parser = OptionParser(usage='usage: %prog [options] arguments')
+
+ parser.add_option("-f", "--first_filepath",
+ action="store", type="string", dest="elf_inp_file1",
+ help="First ELF file to merge.")
+
+ parser.add_option("-s", "--second_filepath",
+ action="store", type="string", dest="elf_inp_file2",
+ help="Second ELF file to merge.")
+
+ parser.add_option("-x", "--xbl_sec_filepath",
+ action="store", type="string", dest="elf_inp_xbl_sec",
+ help="Second ELF file to merge.")
+
+ parser.add_option("-o", "--output_filepath",
+ action="store", type="string", dest="binary_out",
+ help="Merged filename and path.")
+
+ parser.add_option("-a", "--first_elf_arch",
+ action="store", type="string", dest="elf_1_arch",
+ help="First (and output) ELF file architecture. '32' or '64'")
+
+ parser.add_option("-b", "--second_elf_arch",
+ action="store", type="string", dest="elf_2_arch",
+ help="Second ELF file architecture. '32' or '64'")
+
+ parser.add_option("-d", "--xbl_sec_elf_arch",
+ action="store", type="string", dest="elf_xbl_sec_arch",
+ help="xbl_sec file architecture. '32' or '64'")
+
+ parser.add_option("-c", "--output_elf_arch",
+ action="store", type="string", dest="elf_out_arch",
+ help="Output ELF file architecture. '32' or '64'" + \
+ " If not given defaults to first file arch.")
+
+ parser.add_option("-n", "--no_hash",
+ action="store_true", dest="hash_image",
+ help="Disables hashing of image after merging.")
+
+ parser.add_option("-z", "--zi_out_of_bounds",
+ action="store_true", dest="zi_oob",
+ help="Removes ZI segments that have addresses greater" + \
+ " than 32 bits when converting from a 64 to 32 bit ELF")
+
+
+ (options, args) = parser.parse_args()
+ if not options.elf_inp_file1:
+ parser.error('First ELF filename not given')
+
+ if not options.binary_out:
+ parser.error('Output filename not given')
+
+ if not options.elf_1_arch:
+ parser.error('First ELF architecture not given')
+
+ if (not options.elf_1_arch == '64') and (not options.elf_1_arch == '32'):
+ parser.error('Invalid First ELF architecture given')
+
+ # Only evaluate elf_2_arch if two files are given for merging
+ if options.elf_inp_file2:
+ if (not options.elf_2_arch == '64') and (not options.elf_2_arch == '32'):
+ parser.error('Invalid Second ELF architecture given')
+
+ # Only evaluate elf_xbl_sec_arch if file is given
+ if options.elf_inp_xbl_sec:
+ if (not options.elf_xbl_sec_arch == '64') and (not options.elf_xbl_sec_arch == '32'):
+ parser.error('Invalid xbl_sec ELF architecture given')
+
+ # If output file architecture is given ensure it is either '32' or '64'
+ if options.elf_out_arch:
+ if (not options.elf_out_arch == '64') and (not options.elf_out_arch == '32'):
+ parser.error('Invalid Output ELF architecture given')
+
+
+ gen_dict = {}
+
+ elf_inp_file1 = options.elf_inp_file1
+
+ # It is valid for only one file to be "merged". This essentially just
+ # strips off the section names. If second file name is not given then
+ # set elf_inp_file2 to ""
+ if options.elf_inp_file2:
+ elf_inp_file2 = options.elf_inp_file2
+ else:
+ elf_inp_file2 = ""
+
+ # Do same for xbl_sec
+ elf_inp_xbl_sec = options.elf_inp_xbl_sec if options.elf_inp_xbl_sec else ""
+
+ binary_out = options.binary_out
+
+ if options.elf_1_arch == '64':
+ is_elf1_64_bit = True
+ else:
+ is_elf1_64_bit = False
+
+ # If second filename is not given then set is_elf2_64_bit to false so it
+ # can be passed even though it is not used.
+ if options.elf_inp_file2:
+ if options.elf_2_arch == '64':
+ is_elf2_64_bit = True
+ else:
+ is_elf2_64_bit = False
+ else:
+ is_elf2_64_bit = False
+
+ if options.elf_inp_xbl_sec:
+ if options.elf_xbl_sec_arch == '64':
+ is_elf_xbl_sec_64_bit = True
+ else:
+ is_elf_xbl_sec_64_bit = False
+ else:
+ is_elf_xbl_sec_64_bit = False
+
+ # If output ELF arch is given then set is_out_elf_64_bit accordingly.
+ # If not then default to be input1's setting
+ if options.elf_out_arch:
+ if options.elf_out_arch == '64':
+ is_out_elf_64_bit = True
+ else:
+ is_out_elf_64_bit = False
+ else:
+ is_out_elf_64_bit = is_elf1_64_bit
+
+
+ # Store ZI Out of Bounds value
+ if not options.zi_oob:
+ zi_oob_enabled = False
+ else:
+ zi_oob_enabled = True
+
+ if options.elf_inp_xbl_sec:
+ is_ext_mbn_v5 = True
+ else:
+ is_ext_mbn_v5 = False
+
+
+ mbn_type = 'elf'
+ header_format = 'reg'
+ gen_dict['IMAGE_KEY_IMAGE_ID'] = mbn_tools.ImageType.APPSBL_IMG
+ #gen_dict['IMAGE_KEY_IMAGE_SOURCE'] = 0
+ #gen_dict['IMAGE_KEY_IMAGE_DEST'] = 0
+ gen_dict['IMAGE_KEY_MBN_TYPE'] = mbn_type
+ image_header_secflag = 'non_secure'
+
+ source_base = os.path.splitext(str(binary_out))[0]
+ target_base = os.path.splitext(str(binary_out))[0]
+ merged_elf = source_base + "_merged.elf"
+ source_elf = source_base + "_nohash.elf"
+ target_hash = target_base + ".hash"
+ target_hash_hd = target_base + "_hash.hd"
+ target_phdr_elf = target_base + "_phdr.pbn"
+ target_nonsec = target_base + "_combined_hash.mbn"
+
+
+ #print "Input file 1:", elf_inp_file1
+ #print "Input file 2:", elf_inp_file2
+ #print "Output file:", binary_out
+
+ merge_elfs([],
+ elf_inp_file1,
+ elf_inp_file2,
+ elf_inp_xbl_sec,
+ merged_elf,
+ is_elf1_64_bit,
+ is_elf2_64_bit,
+ is_elf_xbl_sec_64_bit,
+ is_out_elf_64_bit,
+ zi_oob_enabled,
+ is_ext_mbn_v5)
+
+
+ # Hash the image if user did not explicitly say not to
+ if options.hash_image:
+ # Just copy the merged elf to the final output name
+ shutil.move(merged_elf, binary_out)
+ else:
+ shutil.copy(merged_elf, source_elf)
+
+ # Create hash table
+ rv = mbn_tools.pboot_gen_elf([],
+ source_elf,
+ target_hash,
+ elf_out_file_name = target_phdr_elf,
+ secure_type = image_header_secflag)
+ if rv:
+ raise RuntimeError, "Failed to run pboot_gen_elf"
+
+ # Create hash table header
+ rv = mbn_tools.image_header([],
+ gen_dict,
+ target_hash,
+ target_hash_hd,
+ image_header_secflag,
+ is_ext_mbn_v5,
+ elf_file_name = source_elf)
+ if rv:
+ raise RuntimeError, "Failed to create image header for hash segment"
+
+ files_to_cat_in_order = [target_hash_hd, target_hash]
+ mbn_tools.concat_files (target_nonsec, files_to_cat_in_order)
+
+ # Add the hash segment into the ELF
+ mbn_tools.pboot_add_hash([],
+ target_phdr_elf,
+ target_nonsec,
+ binary_out)
+
+ return
+
+
+##############################################################################
+# roundup
+##############################################################################
+def roundup(x, precision):
+ return x if x % precision == 0 else (x + precision - (x % precision))
+
+##############################################################################
+# merge_elfs
+##############################################################################
+def merge_elfs(env,
+ elf_in_file_name1,
+ elf_in_file_name2,
+ elf_in_file_xbl_sec,
+ elf_out_file_name,
+ is_elf1_64_bit,
+ is_elf2_64_bit,
+ is_elf_xbl_sec_64_bit,
+ is_out_elf_64_bit,
+ zi_oob_enabled,
+ is_ext_mbn_v5):
+
+ [elf_header1, phdr_table1] = \
+ mbn_tools.preprocess_elf_file(elf_in_file_name1)
+
+ # Check to make sure second file path exists before using
+ if elf_in_file_name2 != "":
+ [elf_header2, phdr_table2] = \
+ mbn_tools.preprocess_elf_file(elf_in_file_name2)
+
+ # Check to make sure xbl_sec file path exists before using
+ if elf_in_file_xbl_sec != "":
+ [elf_headerxblsec, phdr_tablexblsec] = \
+ mbn_tools.preprocess_elf_file(elf_in_file_xbl_sec)
+
+ # Open Files
+ elf_in_fp1 = mbn_tools.OPEN(elf_in_file_name1, "rb")
+ if elf_in_file_name2 != "":
+ elf_in_fp2 = mbn_tools.OPEN(elf_in_file_name2, "rb")
+ if elf_in_file_xbl_sec != "":
+ elf_in_fpxblsec = mbn_tools.OPEN(elf_in_file_xbl_sec, "rb")
+
+ if elf_out_file_name is not None:
+ elf_out_fp = mbn_tools.OPEN(elf_out_file_name, "wb+")
+
+
+ # Calculate the new program header size. This is dependant on the output
+ # ELF type and number of program headers going into output.
+ if is_out_elf_64_bit:
+ phdr_total_size = elf_header1.e_phnum * ELF64_PHDR_SIZE
+ phdr_total_count = elf_header1.e_phnum
+ else:
+ phdr_total_size = elf_header1.e_phnum * ELF32_PHDR_SIZE
+ phdr_total_count = elf_header1.e_phnum
+
+
+ # This logic only applies if two files are to be merged
+ if elf_in_file_name2 != "":
+ if is_out_elf_64_bit:
+ phdr_total_size += elf_header2.e_phnum * ELF64_PHDR_SIZE
+ phdr_total_count += elf_header2.e_phnum
+ else:
+ phdr_total_size += elf_header2.e_phnum * ELF32_PHDR_SIZE
+ phdr_total_count += elf_header2.e_phnum
+
+ # Account for xbl_sec header if included
+ if elf_in_file_xbl_sec != "":
+ phdr_total_count += 1
+ if is_out_elf_64_bit:
+ phdr_total_size += ELF64_PHDR_SIZE
+ else:
+ phdr_total_size += ELF32_PHDR_SIZE
+
+ # Create a new ELF header for the output file
+ if is_out_elf_64_bit:
+ out_elf_header = mbn_tools.Elf64_Ehdr('\0' * ELF64_HDR_SIZE)
+ out_elf_header.e_phoff = ELF64_HDR_SIZE
+ out_elf_header.e_ehsize = ELF64_HDR_SIZE
+ out_elf_header.e_phentsize = ELF64_PHDR_SIZE
+ out_elf_header.e_machine = 183
+ out_elf_header.e_ident = str('\x7f' + 'E' + 'L' + 'F' + \
+ '\x02' + \
+ '\x01' + \
+ '\x01' + \
+ '\x00' + \
+ '\x00' + \
+ ('\x00' * 7))
+
+ out_elf_header.e_entry = elf_header1.e_entry
+ else:
+ out_elf_header = mbn_tools.Elf32_Ehdr('\0' * ELF32_HDR_SIZE)
+ out_elf_header.e_phoff = ELF32_HDR_SIZE
+ out_elf_header.e_ehsize = ELF32_HDR_SIZE
+ out_elf_header.e_phentsize = ELF32_PHDR_SIZE
+ out_elf_header.e_machine = 40
+ out_elf_header.e_entry = elf_header1.e_entry
+ out_elf_header.e_ident = str('\x7f' + 'E' + 'L' + 'F' + \
+ '\x01' + \
+ '\x01' + \
+ '\x01' + \
+ '\x00' + \
+ '\x00' + \
+ ('\x00' * 7))
+
+ # Address needs to be verified that it is not greater than 32 bits
+ # as it is possible to go from a 64 bit elf to 32.
+ if (elf_header1.e_entry > 0xFFFFFFFF):
+ print "ERROR: File 1's entry point is too large to convert."
+ exit()
+ out_elf_header.e_entry = elf_header1.e_entry
+
+ # Common header entries
+ out_elf_header.e_type = 2
+ out_elf_header.e_version = 1
+ out_elf_header.e_shoff = 0
+ out_elf_header.e_flags = 0
+ out_elf_header.e_shentsize = 0
+ out_elf_header.e_shnum = 0
+ out_elf_header.e_shstrndx = 0
+
+
+ # If ZI OOB is enabled then it is possible that a segment could be discarded
+ # Scan for that instance and handle before setting e_phnum and writing header
+ # Ensure ELF output is 32 bit
+ if zi_oob_enabled == True and is_out_elf_64_bit == False:
+ for i in range(len(phdr_table1)):
+ if (phdr_table1[i].p_vaddr > 0xFFFFFFFF) or \
+ (phdr_table1[i].p_paddr > 0xFFFFFFFF):
+ if phdr_table1[i].p_filesz == 0:
+ phdr_total_count = phdr_total_count - 1
+
+ if elf_in_file_name2 != "":
+ for i in range(len(phdr_table2)):
+ if (phdr_table2[i].p_vaddr > 0xFFFFFFFF) or \
+ (phdr_table2[i].p_paddr > 0xFFFFFFFF):
+ if phdr_table2[i].p_filesz == 0:
+ phdr_total_count = phdr_total_count - 1
+ # Do not include xbl_sec in above calculation
+ # xbl_sec is to be treated as a single blob
+
+
+ # Now it is ok to populate the ELF header and write it out
+ out_elf_header.e_phnum = phdr_total_count
+
+ # write elf header
+ if is_out_elf_64_bit == False:
+ elf_out_fp.write(mbn_tools.Elf32_Ehdr.getPackedData(out_elf_header))
+ else:
+ elf_out_fp.write(mbn_tools.Elf64_Ehdr.getPackedData(out_elf_header))
+
+ phdr_offset = out_elf_header.e_phoff # offset of where to put next phdr
+
+ # offset the start of the segments just after the program headers
+ segment_offset = roundup(out_elf_header.e_phoff + phdr_total_size, PAGE_SIZE)
+
+
+ # Output first elf data
+ for i in range(elf_header1.e_phnum):
+ curr_phdr = phdr_table1[i]
+
+ # Copy program header piece by piece to ensure possible conversion success
+ if is_out_elf_64_bit == True:
+ # Converting from 32 to 64 elf requires no data size validation
+ new_phdr = mbn_tools.Elf64_Phdr('\0' * ELF64_PHDR_SIZE)
+ new_phdr.p_type = curr_phdr.p_type
+ new_phdr.p_offset = segment_offset
+ new_phdr.p_vaddr = curr_phdr.p_vaddr
+ new_phdr.p_paddr = curr_phdr.p_paddr
+ new_phdr.p_filesz = curr_phdr.p_filesz
+ new_phdr.p_memsz = curr_phdr.p_memsz
+ new_phdr.p_flags = curr_phdr.p_flags
+ new_phdr.p_align = curr_phdr.p_align
+ else:
+ # Converting from 64 to 32 elf requires data size validation
+ # Note that there is an option to discard a segment if it is only ZI
+ # and its address is greater than 32 bits
+ new_phdr = mbn_tools.Elf32_Phdr('\0' * ELF32_PHDR_SIZE)
+ new_phdr.p_type = curr_phdr.p_type
+ new_phdr.p_offset = segment_offset
+
+ if curr_phdr.p_vaddr > 0xFFFFFFFF:
+ if (zi_oob_enabled == True) and (curr_phdr.p_filesz == 0):
+ continue
+ else:
+ print "ERROR: File 1 VAddr is too large for conversion."
+ exit()
+ new_phdr.p_vaddr = curr_phdr.p_vaddr
+
+ if curr_phdr.p_paddr > 0xFFFFFFFF:
+ if (zi_oob_enabled == True) and (curr_phdr.p_filesz == 0):
+ continue
+ else:
+ print "ERROR: File 1 PAddr is too large for conversion."
+ exit()
+ new_phdr.p_paddr = curr_phdr.p_paddr
+
+ if curr_phdr.p_filesz > 0xFFFFFFFF:
+ print "ERROR: File 1 Filesz is too large for conversion."
+ exit()
+ new_phdr.p_filesz = curr_phdr.p_filesz
+
+ if curr_phdr.p_memsz > 0xFFFFFFFF:
+ print "ERROR: File 1 Memsz is too large for conversion."
+ exit()
+ new_phdr.p_memsz = curr_phdr.p_memsz
+
+ if curr_phdr.p_flags > 0xFFFFFFFF:
+ print "ERROR: File 1 Flags is too large for conversion."
+ exit()
+ new_phdr.p_flags = curr_phdr.p_flags
+
+ if curr_phdr.p_align > 0xFFFFFFFF:
+ print "ERROR: File 1 Align is too large for conversion."
+ exit()
+ new_phdr.p_align = curr_phdr.p_align
+
+
+ #print "i=",i
+ #print "phdr_offset=", phdr_offset
+
+ # update output file location to next phdr location
+ elf_out_fp.seek(phdr_offset)
+ # increment phdr_offset to next location
+ phdr_offset += out_elf_header.e_phentsize
+
+ inp_data_offset = curr_phdr.p_offset # used to read data from input file
+
+# print "inp_data_offset="
+# print inp_data_offset
+#
+# print "curr_phdr.p_offset="
+# print curr_phdr.p_offset
+#
+# print "curr_phdr.p_filesz="
+# print curr_phdr.p_filesz
+
+ # output current phdr
+ if is_out_elf_64_bit == False:
+ elf_out_fp.write(mbn_tools.Elf32_Phdr.getPackedData(new_phdr))
+ else:
+ elf_out_fp.write(mbn_tools.Elf64_Phdr.getPackedData(new_phdr))
+
+ # Copy the ELF segment
+ bytes_written = mbn_tools.file_copy_offset(elf_in_fp1,
+ inp_data_offset,
+ elf_out_fp,
+ new_phdr.p_offset,
+ new_phdr.p_filesz)
+
+ # update data segment offset to be aligned after previous segment
+ segment_offset += roundup(new_phdr.p_filesz, SEGMENT_ALIGN);
+ elf_in_fp1.close()
+
+ # Output second elf data if applicable
+ if elf_in_file_name2 != "":
+ for i in range(elf_header2.e_phnum):
+ curr_phdr = phdr_table2[i]
+
+ # Copy program header piece by piece to ensure possible conversion success
+ if is_out_elf_64_bit == True:
+ # Converting from 32 to 64 elf requires no data size validation
+ new_phdr = mbn_tools.Elf64_Phdr('\0' * ELF64_PHDR_SIZE)
+ new_phdr.p_type = curr_phdr.p_type
+ new_phdr.p_offset = segment_offset
+ new_phdr.p_vaddr = curr_phdr.p_vaddr
+ new_phdr.p_paddr = curr_phdr.p_paddr
+ new_phdr.p_filesz = curr_phdr.p_filesz
+ new_phdr.p_memsz = curr_phdr.p_memsz
+ new_phdr.p_flags = curr_phdr.p_flags
+ new_phdr.p_align = curr_phdr.p_align
+ else:
+ # Converting from 64 to 32 elf requires data size validation
+ # Note that there is an option to discard a segment if it is only ZI
+ # and its address is greater than 32 bits
+ new_phdr = mbn_tools.Elf32_Phdr('\0' * ELF32_PHDR_SIZE)
+ new_phdr.p_type = curr_phdr.p_type
+ new_phdr.p_offset = segment_offset
+
+ if curr_phdr.p_vaddr > 0xFFFFFFFF:
+ if (zi_oob_enabled == True) and (curr_phdr.p_filesz == 0):
+ continue
+ else:
+ print "ERROR: File 2 VAddr is too large for conversion."
+ exit()
+ new_phdr.p_vaddr = curr_phdr.p_vaddr
+
+ if curr_phdr.p_paddr > 0xFFFFFFFF:
+ if (zi_oob_enabled == True) and (curr_phdr.p_filesz == 0):
+ continue
+ else:
+ print "ERROR: File 2 PAddr is too large for conversion."
+ exit()
+ new_phdr.p_paddr = curr_phdr.p_paddr
+
+ if curr_phdr.p_filesz > 0xFFFFFFFF:
+ print "ERROR: File 2 Filesz is too large for conversion."
+ exit()
+ new_phdr.p_filesz = curr_phdr.p_filesz
+
+ if curr_phdr.p_memsz > 0xFFFFFFFF:
+ print "ERROR: File 2 Memsz is too large for conversion."
+ exit()
+ new_phdr.p_memsz = curr_phdr.p_memsz
+
+ if curr_phdr.p_flags > 0xFFFFFFFF:
+ print "ERROR: File 2 Flags is too large for conversion."
+ exit()
+ new_phdr.p_flags = curr_phdr.p_flags
+
+ if curr_phdr.p_align > 0xFFFFFFFF:
+ print "ERROR: File 2 Align is too large for conversion."
+ exit()
+ new_phdr.p_align = curr_phdr.p_align
+
+
+# print "i=",i
+# print "phdr_offset=", phdr_offset
+
+ # update output file location to next phdr location
+ elf_out_fp.seek(phdr_offset)
+ # increment phdr_offset to next location
+ phdr_offset += out_elf_header.e_phentsize
+
+ inp_data_offset = curr_phdr.p_offset # used to read data from input file
+
+# print "inp_data_offset="
+# print inp_data_offset
+#
+# print "curr_phdr.p_offset="
+# print curr_phdr.p_offset
+#
+# print "curr_phdr.p_filesz="
+# print curr_phdr.p_filesz
+
+ # output current phdr
+ if is_out_elf_64_bit == False:
+ elf_out_fp.write(mbn_tools.Elf32_Phdr.getPackedData(new_phdr))
+ else:
+ elf_out_fp.write(mbn_tools.Elf64_Phdr.getPackedData(new_phdr))
+
+ # Copy the ELF segment
+ bytes_written = mbn_tools.file_copy_offset(elf_in_fp2,
+ inp_data_offset,
+ elf_out_fp,
+ new_phdr.p_offset,
+ new_phdr.p_filesz)
+
+ # update data segment offset to be aligned after previous segment
+ segment_offset += roundup(new_phdr.p_filesz, SEGMENT_ALIGN);
+ elf_in_fp2.close()
+
+ # Embed xbl_sec image if provided
+ if elf_in_file_xbl_sec != "":
+
+ # Scan pheaders in xbl_sec for segment that contains entry point address
+ entry_seg_offset = -1
+ entry_addr = elf_headerxblsec.e_entry
+ for i in range(elf_headerxblsec.e_phnum):
+ phdr = phdr_tablexblsec[i]
+ max_addr = phdr.p_vaddr + phdr.p_memsz
+ if phdr.p_vaddr <= entry_addr <= max_addr:
+ entry_seg_offset = phdr.p_offset
+ break
+ if entry_seg_offset == -1:
+ print "Error: Failed to find entry point in any segment!"
+ exit()
+ # magical equation for program header's phys and virt addr
+ phys_virt_addr = entry_addr - entry_seg_offset
+
+ if is_out_elf_64_bit:
+ # Converting from 32 to 64 elf requires no data size validation
+ new_phdr = mbn_tools.Elf64_Phdr('\0' * ELF64_PHDR_SIZE)
+ new_phdr.p_type = 0x1
+ new_phdr.p_offset = segment_offset
+ new_phdr.p_vaddr = phys_virt_addr
+ new_phdr.p_paddr = phys_virt_addr
+ new_phdr.p_filesz = os.path.getsize(elf_in_file_xbl_sec)
+ new_phdr.p_memsz = new_phdr.p_filesz
+ if is_ext_mbn_v5 == True:
+ new_phdr.p_flags = (0x5 |
+ (mbn_tools.MI_PBT_XBL_SEC_SEGMENT <<
+ mbn_tools.MI_PBT_FLAG_SEGMENT_TYPE_SHIFT));
+ else:
+ new_phdr.p_flags = 0x5
+ new_phdr.p_align = 0x1000
+ else:
+ # Converting from 64 to 32 elf requires data size validation
+ # Don't discard the segment containing xbl_sec, simply error out
+ # if the address is greater than 32 bits
+ new_phdr = mbn_tools.Elf32_Phdr('\0' * ELF32_PHDR_SIZE)
+ new_phdr.p_type = 0x1 #
+ new_phdr.p_offset = segment_offset
+ if is_ext_mbn_v5 == True:
+ new_phdr.p_flags = (0x5 |
+ (mbn_tools.MI_PBT_XBL_SEC_SEGMENT <<
+ mbn_tools.MI_PBT_FLAG_SEGMENT_TYPE_SHIFT));
+ else:
+ new_phdr.p_flags = 0x5
+ new_phdr.p_align = 0x1000
+
+ if phys_virt_addr > 0xFFFFFFFF:
+ if zi_oob_enabled == False or curr_phdr.p_filesz != 0:
+ print "ERROR: File xbl_sec VAddr or PAddr is too big for conversion."
+ exit()
+ new_phdr.p_vaddr = phys_virt_addr
+ new_phdr.p_paddr = phys_virt_addr
+
+ if os.path.getsize(elf_in_file_xbl_sec) > 0xFFFFFFFF:
+ print "ERROR: File xbl_sec Filesz is too big for conversion."
+ exit()
+ new_phdr.p_filesz = os.path.getsize(elf_in_file_xbl_sec)
+ new_phdr.p_memsz = new_phdr.p_filesz
+
+
+ # update output file location to next phdr location
+ elf_out_fp.seek(phdr_offset)
+ # increment phdr_offset to next location
+ phdr_offset += out_elf_header.e_phentsize
+ # Copy entire xbl_sec file, so start from byte 0
+ inp_data_offset = 0
+
+ # Output xbl_sec's phdr
+ elf_in_file_xbl_sec
+ if is_out_elf_64_bit == False:
+ elf_out_fp.write(mbn_tools.Elf32_Phdr.getPackedData(new_phdr))
+ else:
+ elf_out_fp.write(mbn_tools.Elf64_Phdr.getPackedData(new_phdr))
+
+ # Copy the ENTIRE xbl_sec image
+ bytes_written = mbn_tools.file_copy_offset(elf_in_fpxblsec,
+ inp_data_offset,
+ elf_out_fp,
+ new_phdr.p_offset,
+ new_phdr.p_filesz)
+ # update data segment offset to be aligned after previous segment
+ # Not necessary, unless appending more pheaders after this point
+ segment_offset += roundup(new_phdr.p_filesz, SEGMENT_ALIGN);
+
+ elf_in_fpxblsec.close()
+
+ elf_out_fp.close()
+
+ return 0
+
+
+main()
diff --git a/util/qualcomm/ipqheader.py b/util/qualcomm/ipqheader.py
new file mode 100755
index 0000000000..7615146499
--- /dev/null
+++ b/util/qualcomm/ipqheader.py
@@ -0,0 +1,129 @@
+#!/usr/bin/env python2
+#
+# Copyright (c) 2013 The Linux Foundation. All rights reserved.
+#
+# Redistribution and use in source and binary forms, with or without
+# modification, are permitted provided that the following conditions are met:
+#
+# 1. Redistributions of source code must retain the above copyright notice,
+# this list of conditions and the following disclaimer.
+#
+# 2. Redistributions in binary form must reproduce the above copyright notice,
+# this list of conditions and the following disclaimer in the documentation
+# and/or other materials provided with the distribution.
+#
+# 3. Neither the name of the copyright holder nor the names of its
+# contributors may be used to endorse or promote products derived from this
+# software without specific prior written permission.
+#
+# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+# AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+# IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+# ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
+# LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+# CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+# SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+# INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+# CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+# ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+# POSSIBILITY OF SUCH DAMAGE.
+#
+
+import os
+import struct
+import sys
+
+PROG_NAME = os.path.basename(sys.argv[0])
+
+def create_header(base, size):
+ """Returns a packed MBN header image with the specified base and size.
+
+ @arg base: integer, specifies the image load address in RAM
+ @arg size: integer, specifies the size of the image
+ @returns: string, the MBN header
+ """
+
+ # SBLs require size to be 4 bytes aligned.
+ size = (size + 3) & 0xfffffffc
+
+ # We currently do not support appending certificates. Signing GPL
+ # code might violate the GPL. So U-Boot will never be signed. So
+ # this is not required for U-Boot.
+
+ header = [
+ 0x5, # Type: APPSBL
+ 0x3, # Version: 3
+ 0x0, # Image source pointer
+ base, # Image destination pointer
+ size, # Code Size + Cert Size + Signature Size
+ size, # Code Size
+ base + size, # Destination + Code Size
+ 0x0, # Signature Size
+ base + size, # Destination + Code Size + Signature Size
+ 0x0, # Cert Size
+ ]
+
+ header_packed = struct.pack('<10I', *header)
+ return header_packed
+
+def mkheader(base_addr, infname, outfname):
+ """Prepends the image with the MBN header.
+
+ @arg base_addr: integer, specifies the image load address in RAM
+ @arg infname: string, image filename
+ @arg outfname: string, output image with header prepended
+ @raises IOError: if reading/writing input/output file fails
+ """
+ with open(infname, "rb") as infp:
+ image = infp.read()
+ insize = len(image)
+
+ if base_addr > 0xFFFFFFFF:
+ raise ValueError("invalid base address")
+
+ if base_addr + insize > 0xFFFFFFFF:
+ raise ValueError("invalid destination range")
+
+ header = create_header(base_addr, insize)
+ with open(outfname, "wb") as outfp:
+ outfp.write(header)
+ outfp.write(image)
+
+def usage(msg=None):
+ """Print command usage.
+
+ @arg msg: string, error message if any (default: None)
+ """
+ if msg != None:
+ sys.stderr.write("%s: %s\n" % (PROG_NAME, msg))
+
+ print "Usage: %s <base-addr> <input-file> <output-file>" % PROG_NAME
+
+ if msg != None:
+ exit(1)
+
+def main():
+ """Main entry function"""
+
+ if len(sys.argv) != 4:
+ usage("incorrect number of arguments")
+
+ try:
+ base_addr = int(sys.argv[1], 0)
+ infname = sys.argv[2]
+ outfname = sys.argv[3]
+ except ValueError as e:
+ sys.stderr.write("mkheader: invalid base address '%s'\n" % sys.argv[1])
+ exit(1)
+
+ try:
+ mkheader(base_addr, infname, outfname)
+ except IOError as e:
+ sys.stderr.write("%s: %s\n" % (PROG_NAME, e))
+ exit(1)
+ except ValueError as e:
+ sys.stderr.write("%s: %s\n" % (PROG_NAME, e))
+ exit(1)
+
+if __name__ == "__main__":
+ main()
diff --git a/util/qualcomm/mbn_tools.py b/util/qualcomm/mbn_tools.py
new file mode 100755
index 0000000000..12dc210cac
--- /dev/null
+++ b/util/qualcomm/mbn_tools.py
@@ -0,0 +1,2324 @@
+#!/usr/bin/env python2
+#===============================================================================
+#
+# MBN TOOLS
+#
+# GENERAL DESCRIPTION
+# Contains all MBN Utilities for image generation
+#
+# Copyright (c) 2016, 2018, The Linux Foundation. All rights reserved.
+#
+# Redistribution and use in source and binary forms, with or without
+# modification, are permitted provided that the following conditions are
+# met:
+# * Redistributions of source code must retain the above copyright
+# notice, this list of conditions and the following disclaimer.
+# * Redistributions in binary form must reproduce the above
+# copyright notice, this list of conditions and the following
+# disclaimer in the documentation and/or other materials provided
+# with the distribution.
+# * Neither the name of The Linux Foundation nor the names of its
+# contributors may be used to endorse or promote products derived
+# from this software without specific prior written permission.
+#
+# THIS SOFTWARE IS PROVIDED "AS IS" AND ANY EXPRESS OR IMPLIED
+# WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+# MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT
+# ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS
+# BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+# CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+# SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
+# BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
+# WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
+# OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN
+# IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+#
+#-------------------------------------------------------------------------------
+# EDIT HISTORY FOR FILE
+#
+# This section contains comments describing changes made to the module.
+# Notice that changes are listed in reverse chronological order.
+#
+# when who what, where, why
+# -------- --- ---------------------------------------------------------
+# 03/22/18 thiru Added support for extended MBNV5.
+# 06/06/13 yliong CR 497042: Signed and encrypted image is corrupted. MRC features.
+# 03/18/13 dhaval Add support for hashing elf segments with SHA256 and
+# sync up to mpss, adsp mbn-tools
+# 01/14/13 kedara Remove dependency on .builds, cust<bid>.h, targ<bid>.h files
+# 08/30/12 kedara Add virtual block suppport
+# 02/24/12 dh Add ssd side effect file names
+# 07/08/11 aus Added support for image_id in SBL image header as required by PBL
+# Sahara mode
+# 10/20/11 dxiang Clean up
+#===============================================================================
+
+import stat
+import csv
+import itertools
+import struct
+import os
+import shutil
+import hashlib
+
+#----------------------------------------------------------------------------
+# GLOBAL VARIABLES BEGIN
+#----------------------------------------------------------------------------
+PAD_BYTE_1 = 255 # Padding byte 1s
+PAD_BYTE_0 = 0 # Padding byte 0s
+SHA256_SIGNATURE_SIZE = 256 # Support SHA256
+MAX_NUM_ROOT_CERTS = 4 # Maximum number of OEM root certificates
+MI_BOOT_IMG_HDR_SIZE = 40 # sizeof(mi_boot_image_header_type)
+MI_BOOT_SBL_HDR_SIZE = 80 # sizeof(sbl_header)
+BOOT_HEADER_LENGTH = 20 # Boot Header Number of Elements
+SBL_HEADER_LENGTH = 20 # SBL Header Number of Elements
+FLASH_PARTI_VERSION = 3 # Flash Partition Version Number
+MAX_PHDR_COUNT = 100 # Maximum allowable program headers
+CERT_CHAIN_ONEROOT_MAXSIZE = 6*1024 # Default Cert Chain Max Size for one root
+VIRTUAL_BLOCK_SIZE = 131072 # Virtual block size for MCs insertion in SBL1 if ENABLE_VIRTUAL_BLK ON
+MAGIC_COOKIE_LENGTH = 12 # Length of magic Cookie inserted per VIRTUAL_BLOCK_SIZE
+MIN_IMAGE_SIZE_WITH_PAD = 256*1024 # Minimum image size for sbl1 Nand based OTA feature
+
+SBL_AARCH64 = 0xF # Indicate that SBL is a Aarch64 image
+SBL_AARCH32 = 0x0 # Indicate that SBL is a Aarch32 image
+
+# Magic numbers filled in for boot headers
+FLASH_CODE_WORD = 0x844BDCD1
+UNIFIED_BOOT_COOKIE_MAGIC_NUMBER = 0x33836685
+MAGIC_NUM = 0x73D71034
+AUTODETECT_PAGE_SIZE_MAGIC_NUM = 0x7D0B435A
+AUTODETECT_PAGE_SIZE_MAGIC_NUM64 = 0x7D0B5436
+AUTODETECT_PAGE_SIZE_MAGIC_NUM128 = 0x7D0B6577
+SBL_VIRTUAL_BLOCK_MAGIC_NUM = 0xD48B54C6
+
+# ELF Definitions
+ELF_HDR_COMMON_SIZE = 24
+ELF32_HDR_SIZE = 52
+ELF32_PHDR_SIZE = 32
+ELF64_HDR_SIZE = 64
+ELF64_PHDR_SIZE = 56
+ELFINFO_MAG0_INDEX = 0
+ELFINFO_MAG1_INDEX = 1
+ELFINFO_MAG2_INDEX = 2
+ELFINFO_MAG3_INDEX = 3
+ELFINFO_MAG0 = '\x7f'
+ELFINFO_MAG1 = 'E'
+ELFINFO_MAG2 = 'L'
+ELFINFO_MAG3 = 'F'
+ELFINFO_CLASS_INDEX = 4
+ELFINFO_CLASS_32 = '\x01'
+ELFINFO_CLASS_64 = '\x02'
+ELFINFO_VERSION_INDEX = 6
+ELFINFO_VERSION_CURRENT = '\x01'
+ELF_BLOCK_ALIGN = 0x1000
+ALIGNVALUE_1MB = 0x100000
+ALIGNVALUE_4MB = 0x400000
+ELFINFO_DATA2LSB = '\x01'
+ELFINFO_EXEC_ETYPE = '\x02\x00'
+ELFINFO_ARM_MACHINETYPE = '\x28\x00'
+ELFINFO_VERSION_EV_CURRENT = '\x01\x00\x00\x00'
+ELFINFO_SHOFF = 0x00
+ELFINFO_PHNUM = '\x01\x00'
+ELFINFO_RESERVED = 0x00
+
+# ELF Program Header Types
+NULL_TYPE = 0x0
+LOAD_TYPE = 0x1
+DYNAMIC_TYPE = 0x2
+INTERP_TYPE = 0x3
+NOTE_TYPE = 0x4
+SHLIB_TYPE = 0x5
+PHDR_TYPE = 0x6
+TLS_TYPE = 0x7
+
+"""
+The eight bits between 20 and 27 in the p_flags field in ELF program headers
+is not used by the standard ELF format. We use this byte to hold OS and processor
+specific fields as recommended by ARM.
+
+The bits in this byte are defined as follows:
+
+ Pool Indx Segment type Access type Page/non page
+ bits in p_flags /-----27-----/----26-24-------/---- 23-21----/------20-------/
+
+After parsing segment description strings in the SCL file, the appropriate segment
+flag values are chosen from the follow definitions. The mask defined below is then
+used to update the existing p_flags field in the program headers with the updated
+values.
+"""
+# Mask for bits 20-27 to parse program header p_flags
+MI_PBT_FLAGS_MASK = 0x0FF00000
+
+# Helper defines to help parse ELF program headers
+MI_PROG_BOOT_DIGEST_SIZE = 20
+MI_PBT_FLAG_SEGMENT_TYPE_MASK = 0x07000000
+MI_PBT_FLAG_SEGMENT_TYPE_SHIFT = 0x18
+MI_PBT_FLAG_PAGE_MODE_MASK = 0x00100000
+MI_PBT_FLAG_PAGE_MODE_SHIFT = 0x14
+MI_PBT_FLAG_ACCESS_TYPE_MASK = 0x00E00000
+MI_PBT_FLAG_ACCESS_TYPE_SHIFT = 0x15
+MI_PBT_FLAG_POOL_INDEX_MASK = 0x08000000
+MI_PBT_FLAG_POOL_INDEX_SHIFT = 0x1B
+
+# Segment Type
+MI_PBT_L4_SEGMENT = 0x0
+MI_PBT_AMSS_SEGMENT = 0x1
+MI_PBT_HASH_SEGMENT = 0x2
+MI_PBT_BOOT_SEGMENT = 0x3
+MI_PBT_L4BSP_SEGMENT = 0x4
+MI_PBT_SWAPPED_SEGMENT = 0x5
+MI_PBT_XBL_SEC_SEGMENT = 0x5
+MI_PBT_SWAP_POOL_SEGMENT = 0x6
+MI_PBT_PHDR_SEGMENT = 0x7
+
+# Page/Non-Page Type
+MI_PBT_NON_PAGED_SEGMENT = 0x0
+MI_PBT_PAGED_SEGMENT = 0x1
+
+# Access Type
+MI_PBT_RW_SEGMENT = 0x0
+MI_PBT_RO_SEGMENT = 0x1
+MI_PBT_ZI_SEGMENT = 0x2
+MI_PBT_NOTUSED_SEGMENT = 0x3
+MI_PBT_SHARED_SEGMENT = 0x4
+MI_PBT_RWE_SEGMENT = 0x7
+
+# ELF Segment Flag Definitions
+MI_PBT_ELF_AMSS_NON_PAGED_RO_SEGMENT = 0x01200000
+MI_PBT_ELF_AMSS_PAGED_RO_SEGMENT = 0x01300000
+MI_PBT_ELF_SWAP_POOL_NON_PAGED_ZI_SEGMENT_INDEX0 = 0x06400000
+MI_PBT_ELF_SWAPPED_PAGED_RO_SEGMENT_INDEX0 = 0x05300000
+MI_PBT_ELF_SWAP_POOL_NON_PAGED_ZI_SEGMENT_INDEX1 = 0x0E400000
+MI_PBT_ELF_SWAPPED_PAGED_RO_SEGMENT_INDEX1 = 0x0D300000
+MI_PBT_ELF_AMSS_NON_PAGED_ZI_SEGMENT = 0x01400000
+MI_PBT_ELF_AMSS_PAGED_ZI_SEGMENT = 0x01500000
+MI_PBT_ELF_AMSS_NON_PAGED_RW_SEGMENT = 0x01000000
+MI_PBT_ELF_AMSS_PAGED_RW_SEGMENT = 0x01100000
+MI_PBT_ELF_AMSS_NON_PAGED_NOTUSED_SEGMENT = 0x01600000
+MI_PBT_ELF_AMSS_PAGED_NOTUSED_SEGMENT = 0x01700000
+MI_PBT_ELF_AMSS_NON_PAGED_SHARED_SEGMENT = 0x01800000
+MI_PBT_ELF_AMSS_PAGED_SHARED_SEGMENT = 0x01900000
+MI_PBT_ELF_HASH_SEGMENT = 0x02200000
+MI_PBT_ELF_BOOT_SEGMENT = 0x03200000
+MI_PBT_ELF_PHDR_SEGMENT = 0x07000000
+MI_PBT_ELF_NON_PAGED_L4BSP_SEGMENT = 0x04000000
+MI_PBT_ELF_PAGED_L4BSP_SEGMENT = 0x04100000
+MI_PBT_ELF_AMSS_RELOCATABLE_IMAGE = 0x8000000
+
+# New definitions for EOS demap paging requirement
+# Bit 20 (0b) Bit 24-26(000): Non Paged = 0x0000_0000
+# Bit 20 (1b) Bit 24-26(000): Locked Paged = 0x0010_0000
+# Bit 20 (1b) Bit 24-26(001): Unlocked Paged = 0x0110_0000
+# Bit 20 (0b) Bit 24-26(011): non secure = 0x0310_0000
+MI_PBT_ELF_RESIDENT_SEGMENT = 0x00000000
+MI_PBT_ELF_PAGED_LOCKED_SEGMENT = 0x00100000
+MI_PBT_ELF_PAGED_UNLOCKED_SEGMENT = 0x01100000
+MI_PBT_ELF_UNSECURE_SEGMENT = 0x03100000
+#----------------------------------------------------------------------------
+# GLOBAL VARIABLES END
+#----------------------------------------------------------------------------
+
+#----------------------------------------------------------------------------
+# CLASS DEFINITIONS BEGIN
+#----------------------------------------------------------------------------
+#----------------------------------------------------------------------------
+# OS Type ID Class
+#----------------------------------------------------------------------------
+class OSType:
+ BMP_BOOT_OS = 0
+ WM_BOOT_OS = 1
+ ANDROID_BOOT_OS = 2
+ CHROME_BOOT_OS = 3
+ SYMBIAN_BOOT_OS = 4
+ LINUX_BOOT_OS = 5
+
+#----------------------------------------------------------------------------
+# Image Type ID Class - These values must be kept consistent with mibib.h
+#----------------------------------------------------------------------------
+class ImageType:
+ NONE_IMG = 0
+ OEM_SBL_IMG = 1
+ AMSS_IMG = 2
+ QCSBL_IMG = 3
+ HASH_IMG = 4
+ APPSBL_IMG = 5
+ APPS_IMG = 6
+ HOSTDL_IMG = 7
+ DSP1_IMG = 8
+ FSBL_IMG = 9
+ DBL_IMG = 10
+ OSBL_IMG = 11
+ DSP2_IMG = 12
+ EHOSTDL_IMG = 13
+ NANDPRG_IMG = 14
+ NORPRG_IMG = 15
+ RAMFS1_IMG = 16
+ RAMFS2_IMG = 17
+ ADSP_Q5_IMG = 18
+ APPS_KERNEL_IMG = 19
+ BACKUP_RAMFS_IMG = 20
+ SBL1_IMG = 21
+ SBL2_IMG = 22
+ RPM_IMG = 23
+ SBL3_IMG = 24
+ TZ_IMG = 25
+ PSI_IMG = 32
+
+#----------------------------------------------------------------------------
+# Global Image Type Table
+# Format of the look-up table:
+# KEY - IMAGE_TYPE string as passed into mbn_builder.py
+# VALUE - [Specific ImageType ID enum, Template key string, MBN Type]
+#----------------------------------------------------------------------------
+image_id_table = {
+ 'appsbl': [ImageType.APPSBL_IMG, 'APPSBL_IMG', 'bin'],
+ 'dbl': [ImageType.DBL_IMG, 'DBL_IMG', 'bin'],
+ 'osbl': [ImageType.OSBL_IMG, 'OSBL_IMG', 'bin'],
+ 'amss': [ImageType.AMSS_IMG, 'AMSS_IMG', 'elf'],
+ 'amss_mbn': [ImageType.HASH_IMG, 'HASH_IMG', 'elf'],
+ 'apps': [ImageType.APPS_IMG, 'APPS_IMG', 'bin'],
+ 'hostdl': [ImageType.HOSTDL_IMG, 'HOSTDL_IMG', 'bin'],
+ 'ehostdl': [ImageType.EHOSTDL_IMG, 'EHOSTDL_IMG', 'bin'],
+ 'emmcbld': [ImageType.EHOSTDL_IMG, 'EMMCBLD_IMG', 'bin'],
+ 'qdsp6fw': [ImageType.DSP1_IMG, 'DSP1_IMG', 'elf'],
+ 'qdsp6sw': [ImageType.DSP2_IMG, 'DSP2_IMG', 'elf'],
+ 'qdsp5': [ImageType.ADSP_Q5_IMG, 'ADSP_Q5_IMG', 'bin'],
+ 'tz': [ImageType.TZ_IMG, 'TZ_IMG', 'elf'],
+ 'tz_rumi': [ImageType.TZ_IMG, 'TZ_IMG', 'elf'],
+ 'tz_virtio': [ImageType.TZ_IMG, 'TZ_IMG', 'elf'],
+ 'tzbsp_no_xpu': [ImageType.TZ_IMG, 'TZ_IMG', 'elf'],
+ 'tzbsp_with_test': [ImageType.TZ_IMG, 'TZ_IMG', 'elf'],
+ 'rpm': [ImageType.RPM_IMG, 'RPM_IMG', 'elf'],
+ 'sbl1': [ImageType.SBL1_IMG, 'SBL1_IMG', 'bin'],
+ 'sbl2': [ImageType.SBL2_IMG, 'SBL2_IMG', 'bin'],
+ 'sbl3': [ImageType.SBL3_IMG, 'SBL3_IMG', 'bin'],
+ 'efs1': [ImageType.RAMFS1_IMG, 'RAMFS1_IMG', 'bin'],
+ 'efs2': [ImageType.RAMFS2_IMG, 'RAMFS2_IMG', 'bin'],
+ 'pmic': [ImageType.PSI_IMG, 'PSI_IMG', 'elf'],
+ # DO NOT add any additional image information
+}
+
+#----------------------------------------------------------------------------
+# Header Class Notes:
+# In order to properly read and write the header structures as binary data,
+# the Python Struct library is used to align and package up the header objects
+# All Struct objects are initialized by a special string with the following
+# notation. These structure objects are then used to decode binary data in order
+# to fill out the appropriate class in Python, or they are used to package up
+# the Python class so that we may write the binary data out.
+#----------------------------------------------------------------------------
+"""
+ Format | C Type | Python Type | Standard Size
+ -----------------------------------------------------
+ 1) 'X's | char * | string | 'X' bytes
+ 2) H | unsigned short | integer | 2 bytes
+ 3) I | unsigned int | integer | 4 bytes
+
+"""
+
+#----------------------------------------------------------------------------
+# ELF Header Class
+#----------------------------------------------------------------------------
+class Elf_Ehdr_common:
+ # Structure object to align and package the ELF Header
+ s = struct.Struct('16sHHI')
+
+ def __init__(self, data):
+ unpacked_data = (Elf_Ehdr_common.s).unpack(data)
+ self.unpacked_data = unpacked_data
+ self.e_ident = unpacked_data[0]
+ self.e_type = unpacked_data[1]
+ self.e_machine = unpacked_data[2]
+ self.e_version = unpacked_data[3]
+
+ def printValues(self):
+ print "ATTRIBUTE / VALUE"
+ for attr, value in self.__dict__.iteritems():
+ print attr, value
+
+
+
+#----------------------------------------------------------------------------
+# ELF Header Class
+#----------------------------------------------------------------------------
+class Elf32_Ehdr:
+ # Structure object to align and package the ELF Header
+ s = struct.Struct('16sHHIIIIIHHHHHH')
+
+ def __init__(self, data):
+ unpacked_data = (Elf32_Ehdr.s).unpack(data)
+ self.unpacked_data = unpacked_data
+ self.e_ident = unpacked_data[0]
+ self.e_type = unpacked_data[1]
+ self.e_machine = unpacked_data[2]
+ self.e_version = unpacked_data[3]
+ self.e_entry = unpacked_data[4]
+ self.e_phoff = unpacked_data[5]
+ self.e_shoff = unpacked_data[6]
+ self.e_flags = unpacked_data[7]
+ self.e_ehsize = unpacked_data[8]
+ self.e_phentsize = unpacked_data[9]
+ self.e_phnum = unpacked_data[10]
+ self.e_shentsize = unpacked_data[11]
+ self.e_shnum = unpacked_data[12]
+ self.e_shstrndx = unpacked_data[13]
+
+ def printValues(self):
+ print "ATTRIBUTE / VALUE"
+ for attr, value in self.__dict__.iteritems():
+ print attr, value
+
+ def getPackedData(self):
+ values = [self.e_ident,
+ self.e_type,
+ self.e_machine,
+ self.e_version,
+ self.e_entry,
+ self.e_phoff,
+ self.e_shoff,
+ self.e_flags,
+ self.e_ehsize,
+ self.e_phentsize,
+ self.e_phnum,
+ self.e_shentsize,
+ self.e_shnum,
+ self.e_shstrndx
+ ]
+
+ return (Elf32_Ehdr.s).pack(*values)
+
+#----------------------------------------------------------------------------
+# ELF Program Header Class
+#----------------------------------------------------------------------------
+class Elf32_Phdr:
+
+ # Structure object to align and package the ELF Program Header
+ s = struct.Struct('I' * 8)
+
+ def __init__(self, data):
+ unpacked_data = (Elf32_Phdr.s).unpack(data)
+ self.unpacked_data = unpacked_data
+ self.p_type = unpacked_data[0]
+ self.p_offset = unpacked_data[1]
+ self.p_vaddr = unpacked_data[2]
+ self.p_paddr = unpacked_data[3]
+ self.p_filesz = unpacked_data[4]
+ self.p_memsz = unpacked_data[5]
+ self.p_flags = unpacked_data[6]
+ self.p_align = unpacked_data[7]
+
+ def printValues(self):
+ print "ATTRIBUTE / VALUE"
+ for attr, value in self.__dict__.iteritems():
+ print attr, value
+
+ def getPackedData(self):
+ values = [self.p_type,
+ self.p_offset,
+ self.p_vaddr,
+ self.p_paddr,
+ self.p_filesz,
+ self.p_memsz,
+ self.p_flags,
+ self.p_align
+ ]
+
+ return (Elf32_Phdr.s).pack(*values)
+
+#----------------------------------------------------------------------------
+# ELF Header Class
+#----------------------------------------------------------------------------
+class Elf64_Ehdr:
+ # Structure object to align and package the ELF Header
+ s = struct.Struct('16sHHIQQQIHHHHHH')
+
+ def __init__(self, data):
+ unpacked_data = (Elf64_Ehdr.s).unpack(data)
+ self.unpacked_data = unpacked_data
+ self.e_ident = unpacked_data[0]
+ self.e_type = unpacked_data[1]
+ self.e_machine = unpacked_data[2]
+ self.e_version = unpacked_data[3]
+ self.e_entry = unpacked_data[4]
+ self.e_phoff = unpacked_data[5]
+ self.e_shoff = unpacked_data[6]
+ self.e_flags = unpacked_data[7]
+ self.e_ehsize = unpacked_data[8]
+ self.e_phentsize = unpacked_data[9]
+ self.e_phnum = unpacked_data[10]
+ self.e_shentsize = unpacked_data[11]
+ self.e_shnum = unpacked_data[12]
+ self.e_shstrndx = unpacked_data[13]
+
+ def printValues(self):
+ print "ATTRIBUTE / VALUE"
+ for attr, value in self.__dict__.iteritems():
+ print attr, value
+
+ def getPackedData(self):
+ values = [self.e_ident,
+ self.e_type,
+ self.e_machine,
+ self.e_version,
+ self.e_entry,
+ self.e_phoff,
+ self.e_shoff,
+ self.e_flags,
+ self.e_ehsize,
+ self.e_phentsize,
+ self.e_phnum,
+ self.e_shentsize,
+ self.e_shnum,
+ self.e_shstrndx
+ ]
+
+ return (Elf64_Ehdr.s).pack(*values)
+
+#----------------------------------------------------------------------------
+# ELF Program Header Class
+#----------------------------------------------------------------------------
+class Elf64_Phdr:
+
+ # Structure object to align and package the ELF Program Header
+ s = struct.Struct('IIQQQQQQ')
+
+ def __init__(self, data):
+ unpacked_data = (Elf64_Phdr.s).unpack(data)
+ self.unpacked_data = unpacked_data
+ self.p_type = unpacked_data[0]
+ self.p_flags = unpacked_data[1]
+ self.p_offset = unpacked_data[2]
+ self.p_vaddr = unpacked_data[3]
+ self.p_paddr = unpacked_data[4]
+ self.p_filesz = unpacked_data[5]
+ self.p_memsz = unpacked_data[6]
+ self.p_align = unpacked_data[7]
+
+ def printValues(self):
+ print "ATTRIBUTE / VALUE"
+ for attr, value in self.__dict__.iteritems():
+ print attr, value
+
+ def getPackedData(self):
+ values = [self.p_type,
+ self.p_flags,
+ self.p_offset,
+ self.p_vaddr,
+ self.p_paddr,
+ self.p_filesz,
+ self.p_memsz,
+ self.p_align
+ ]
+
+ return (Elf64_Phdr.s).pack(*values)
+
+
+#----------------------------------------------------------------------------
+# ELF Segment Information Class
+#----------------------------------------------------------------------------
+class SegmentInfo:
+ def __init__(self):
+ self.flag = 0
+ def printValues(self):
+ print 'Flag: ' + str(self.flag)
+
+#----------------------------------------------------------------------------
+# Regular Boot Header Class
+#----------------------------------------------------------------------------
+class Boot_Hdr:
+ def __init__(self, init_val):
+ self.image_id = ImageType.NONE_IMG
+ self.flash_parti_ver = FLASH_PARTI_VERSION
+ self.image_src = init_val
+ self.image_dest_ptr = init_val
+ self.image_size = init_val
+ self.code_size = init_val
+ self.sig_ptr = init_val
+ self.sig_size = init_val
+ self.cert_chain_ptr = init_val
+ self.cert_chain_size = init_val
+ self.magic_number1 = init_val
+ self.version = init_val
+ self.OS_type = init_val
+ self.boot_apps_parti_entry = init_val
+ self.boot_apps_size_entry = init_val
+ self.boot_apps_ram_loc = init_val
+ self.reserved_ptr = init_val
+ self.reserved_1 = init_val
+ self.reserved_2 = init_val
+ self.reserved_3 = init_val
+
+ def getLength(self):
+ return BOOT_HEADER_LENGTH
+
+ def writePackedData(self, target, write_full_hdr):
+ values = [self.image_id,
+ self.flash_parti_ver,
+ self.image_src,
+ self.image_dest_ptr,
+ self.image_size,
+ self.code_size ,
+ self.sig_ptr,
+ self.sig_size,
+ self.cert_chain_ptr,
+ self.cert_chain_size,
+ self.magic_number1,
+ self.version,
+ self.OS_type,
+ self.boot_apps_parti_entry,
+ self.boot_apps_size_entry,
+ self.boot_apps_ram_loc,
+ self.reserved_ptr,
+ self.reserved_1,
+ self.reserved_2,
+ self.reserved_3 ]
+
+ if self.image_dest_ptr >= 0x100000000:
+ values[3] = 0xFFFFFFFF
+
+ if self.cert_chain_ptr >= 0x100000000:
+ values[6] = 0xFFFFFFFF
+
+ if self.sig_ptr >= 0x100000000:
+ values[8] = 0xFFFFFFFF
+
+ # Write 10 entries(40B) or 20 entries(80B) of boot header
+ if write_full_hdr is False:
+ s = struct.Struct('I'* 10)
+ values = values[:10]
+ else:
+ s = struct.Struct('I' * self.getLength())
+
+ packed_data = s.pack(*values)
+
+ fp = OPEN(target,'wb')
+ fp.write(packed_data)
+ fp.close()
+
+ return s.size
+
+#----------------------------------------------------------------------------
+# SBL Boot Header Class
+#----------------------------------------------------------------------------
+class Sbl_Hdr:
+ def __init__(self, init_val):
+ self.codeword = init_val
+ self.magic = init_val
+ self.image_id = init_val
+ self.reserved_1 = init_val
+ self.reserved_2 = init_val
+ self.image_src = init_val
+ self.image_dest_ptr = init_val
+ self.image_size = init_val
+ self.code_size = init_val
+ self.sig_ptr = init_val
+ self.sig_size = init_val
+ self.cert_chain_ptr = init_val
+ self.cert_chain_size = init_val
+ self.oem_root_cert_sel = init_val
+ self.oem_num_root_certs = init_val
+ self.booting_image_config = init_val
+ self.reserved_6 = init_val
+ self.reserved_7 = init_val
+ self.reserved_8 = init_val
+ self.reserved_9 = init_val
+
+ def getLength(self):
+ return SBL_HEADER_LENGTH
+
+ def writePackedData(self, target):
+ values = [self.codeword,
+ self.magic,
+ self.image_id,
+ self.reserved_1,
+ self.reserved_2,
+ self.image_src,
+ self.image_dest_ptr,
+ self.image_size,
+ self.code_size,
+ self.sig_ptr,
+ self.sig_size,
+ self.cert_chain_ptr,
+ self.cert_chain_size,
+ self.oem_root_cert_sel,
+ self.oem_num_root_certs,
+ self.booting_image_config,
+ self.reserved_6,
+ self.reserved_7,
+ self.reserved_8,
+ self.reserved_9 ]
+
+ s = struct.Struct('I' * self.getLength())
+ packed_data = s.pack(*values)
+
+ fp = OPEN(target,'wb')
+ fp.write(packed_data)
+ fp.close()
+
+ return s.size
+
+#----------------------------------------------------------------------------
+# CLASS DEFINITIONS END
+#----------------------------------------------------------------------------
+
+#------------------------------------------------------------------------------
+# Hooks for Scons
+#------------------------------------------------------------------------------
+def exists(env):
+ return env.Detect('mbn_tools')
+
+def generate(env):
+
+ #----------------------------------------------------------------------------
+ # Generate Global Dictionary
+ #----------------------------------------------------------------------------
+ generate_global_dict(env)
+
+ #----------------------------------------------------------------------------
+ # Assign Build Configurable Values
+ #----------------------------------------------------------------------------
+ init_build_vars(env)
+
+ #----------------------------------------------------------------------------
+ # Add Methods to Environment
+ #----------------------------------------------------------------------------
+ env.AddMethod(filter_dictionary, "FilterDictionary")
+ env.AddMethod(image_auth, "ImageAuth")
+ env.AddMethod(image_header, "ImageHeader")
+ env.AddMethod(pboot_gen_elf, "PBootGenElf")
+ env.AddMethod(pboot_add_hash, "PBootAddHash")
+ env.AddMethod(modify_elf_flags, "ModifyElfFlags")
+ env.AddMethod(generate_code_hash, "GenerateCodeHash")
+ env.AddMethod(insert_SBL1_magicCookie, "InsertSBLMagicCookie")
+ env.AddMethod(modify_relocatable_flags, "ModifyRelocatableFlags")
+
+ #----------------------------------------------------------------------------
+ # Load Encryption Tools and Methods if required
+ #----------------------------------------------------------------------------
+ if 'USES_ENCRYPT_MBN' in env:
+ # Add Encryption Tools to environment
+ env.Tool('pil_encrypt', toolpath = ['${BUILD_ROOT}/core/securemsm/ssd/tools/pil_encrypt'])
+ env.AddMethod(get_ssd_se_fname, "GetSSDSideEffectFileName")
+ env.AddMethod(encrypt_elf_segments, "EncryptElfSegments")
+ env.AddMethod(generate_meta_data, "GenerateMetaData")
+ env.AddMethod(encrypt_mbn, "EncryptMBN")
+ return None
+
+#----------------------------------------------------------------------------
+# BOOT TOOLS BEGIN
+#----------------------------------------------------------------------------
+
+#----------------------------------------------------------------------------
+# generate_meta_data
+#----------------------------------------------------------------------------
+def generate_meta_data(env, meta_out_file_name, add_magic_num = False):
+
+ '''
+ Make call to SSD API to return buffer filled with XML header information.
+ The XML header which we write contains information regarding the algorithms
+ being used along with specific key values which are to be used for encrpytion.
+ '''
+ xml_header = env.SSDGetMetaData(add_magic_num)
+
+ # Initialize
+ xml_target_file = open(meta_out_file_name,'wb')
+ xml_header_size = len(xml_header)
+
+ # Write XML buffer into target file
+ xml_target_file.write(xml_header)
+
+ # Pad if necessary to the maximum size
+ if xml_header_size <= XML_HEADER_MAXSIZE:
+ bytes_to_pad = XML_HEADER_MAXSIZE - xml_header_size
+ pad_file(xml_target_file, bytes_to_pad, PAD_BYTE_1)
+ xml_target_file.close()
+ else:
+ xml_target_file.close()
+ raise RuntimeError, "XML Size too large: " + str(xml_header_size)
+
+#----------------------------------------------------------------------------
+# encrypt_mbn
+#----------------------------------------------------------------------------
+def encrypt_mbn(env, mbn_in_file_name, mbn_out_file_name):
+ # Open Files
+ mbn_in_fp = OPEN(mbn_in_file_name, "rb")
+ mbn_out_fp = OPEN(mbn_out_file_name, "wb+")
+
+ # encrypt the input file content and write to output file
+ mbn_file_size = os.path.getsize(mbn_in_file_name)
+ file_buff = mbn_in_fp.read(mbn_file_size)
+ encrypted_buf = env.SSDEncryptSegment(0, file_buff, mbn_file_size)
+ mbn_out_fp.write(encrypted_buf)
+
+ # Close Files
+ mbn_in_fp.close()
+ mbn_out_fp.close()
+
+ # Clean up encryption files
+ env.SSDDeInit()
+
+#----------------------------------------------------------------------------
+# get_ssd_se_fname
+#----------------------------------------------------------------------------
+def get_ssd_se_fname(env):
+ return env.SSDGetSideEffectFileName()
+
+#----------------------------------------------------------------------------
+# encrypt_elf_segments
+#----------------------------------------------------------------------------
+def encrypt_elf_segments(env, elf_in_file_name,
+ elf_out_file_name):
+
+ # Open Files
+ elf_in_fp = OPEN(elf_in_file_name, "rb")
+ elf_out_fp = OPEN(elf_out_file_name, "wb+")
+
+ # Initialize
+ [elf_header, phdr_table] = preprocess_elf_file(elf_in_file_name)
+ encrypted_seg_counter = 0
+
+ # Copy input file to output file
+ shutil.copyfileobj(elf_in_fp, elf_out_fp, os.path.getsize(elf_in_file_name))
+
+ # Begin ELF segment encryption
+ for i in range(elf_header.e_phnum):
+ curr_phdr = phdr_table[i]
+
+ # Only encrypt segments of LOAD_TYPE. Do not encrypt the hash segment.
+ if curr_phdr.p_type == LOAD_TYPE and \
+ MI_PBT_SEGMENT_TYPE_VALUE(curr_phdr.p_flags) != MI_PBT_HASH_SEGMENT:
+
+ # Read full segment into buffer
+ elf_in_fp.seek(curr_phdr.p_offset)
+ data_len = curr_phdr.p_filesz
+ file_buff = elf_in_fp.read(data_len)
+
+ # Call encryption routine on buffer
+ encrypted_buf = env.SSDEncryptSegment(encrypted_seg_counter, file_buff, data_len)
+ encrypted_seg_counter += 1
+
+ # Write encrypted segment into output file in same location
+ elf_out_fp.seek(curr_phdr.p_offset)
+ elf_out_fp.write(encrypted_buf)
+
+ # Close Files
+ elf_in_fp.close()
+ elf_out_fp.close()
+
+ # Clean up encryption files
+ env.SSDDeInit()
+
+#----------------------------------------------------------------------------
+# Converts integer to bytes. If length after conversion
+# is smaller than given length of byte string, returned value is right-filled
+# with 0x00 bytes. Use Little-endian byte order.
+#----------------------------------------------------------------------------
+def convert_int_to_byte_string(n, l):
+ return b''.join([chr((n >> ((l - i - 1) * 8)) % 256) for i in xrange(l)][::-1])
+
+#----------------------------------------------------------------------------
+# Create default elf header
+#----------------------------------------------------------------------------
+def create_elf_header( output_file_name,
+ image_dest,
+ image_size,
+ is_elf_64_bit = False):
+
+ if (output_file_name is None):
+ raise RuntimeError, "Requires a ELF header file"
+
+ # Create a elf header and program header
+ # Write the headers to the output file
+ elf_fp = file(output_file_name, "wb")
+
+ if (is_elf_64_bit is True):
+ # ELf header
+ elf_fp.write(ELFINFO_MAG0)
+ elf_fp.write(ELFINFO_MAG1)
+ elf_fp.write(ELFINFO_MAG2)
+ elf_fp.write(ELFINFO_MAG3)
+ elf_fp.write(ELFINFO_CLASS_64)
+ elf_fp.write(ELFINFO_DATA2LSB)
+ elf_fp.write(ELFINFO_VERSION_CURRENT)
+ elf_fp.write(''.rjust(9, chr(ELFINFO_RESERVED)))
+ elf_fp.write(ELFINFO_EXEC_ETYPE)
+ elf_fp.write(ELFINFO_ARM_MACHINETYPE)
+ elf_fp.write(ELFINFO_VERSION_EV_CURRENT)
+ elf_fp.write(convert_int_to_byte_string(image_dest, 8))
+ elf_fp.write(convert_int_to_byte_string(ELF64_HDR_SIZE, 8))
+ elf_fp.write(convert_int_to_byte_string(ELFINFO_SHOFF, 8))
+ elf_fp.write(''.rjust(4, chr(ELFINFO_RESERVED)))
+ elf_fp.write(convert_int_to_byte_string(ELF64_HDR_SIZE, 2))
+ elf_fp.write(convert_int_to_byte_string(ELF64_PHDR_SIZE, 2))
+ elf_fp.write(ELFINFO_PHNUM)
+ elf_fp.write(''.rjust(6, chr(ELFINFO_RESERVED)))
+
+ # Program Header
+ elf_fp.write(convert_int_to_byte_string(LOAD_TYPE, 4))
+ elf_fp.write(convert_int_to_byte_string(MI_PBT_RWE_SEGMENT, 4))
+ elf_fp.write(convert_int_to_byte_string(ELF64_HDR_SIZE+ELF64_PHDR_SIZE, 8))
+ elf_fp.write(convert_int_to_byte_string(image_dest, 8))
+ elf_fp.write(convert_int_to_byte_string(image_dest, 8))
+ elf_fp.write(convert_int_to_byte_string(image_size, 8))
+ elf_fp.write(convert_int_to_byte_string(image_size, 8))
+ elf_fp.write(convert_int_to_byte_string(ELF_BLOCK_ALIGN, 8))
+ else:
+ # ELf header
+ elf_fp.write(ELFINFO_MAG0)
+ elf_fp.write(ELFINFO_MAG1)
+ elf_fp.write(ELFINFO_MAG2)
+ elf_fp.write(ELFINFO_MAG3)
+ elf_fp.write(ELFINFO_CLASS_32)
+ elf_fp.write(ELFINFO_DATA2LSB)
+ elf_fp.write(ELFINFO_VERSION_CURRENT)
+ elf_fp.write(''.rjust(9, chr(ELFINFO_RESERVED)))
+ elf_fp.write(ELFINFO_EXEC_ETYPE)
+ elf_fp.write(ELFINFO_ARM_MACHINETYPE)
+ elf_fp.write(ELFINFO_VERSION_EV_CURRENT)
+ elf_fp.write(convert_int_to_byte_string(image_dest, 4))
+ elf_fp.write(convert_int_to_byte_string(ELF32_HDR_SIZE, 4))
+ elf_fp.write(convert_int_to_byte_string(ELFINFO_SHOFF, 4))
+ elf_fp.write(''.rjust(4, chr(ELFINFO_RESERVED)))
+ elf_fp.write(convert_int_to_byte_string(ELF32_HDR_SIZE, 2))
+ elf_fp.write(convert_int_to_byte_string(ELF32_PHDR_SIZE, 2))
+ elf_fp.write(ELFINFO_PHNUM)
+ elf_fp.write(''.rjust(6, chr(ELFINFO_RESERVED)))
+
+ # Program Header
+ elf_fp.write(convert_int_to_byte_string(LOAD_TYPE, 4))
+ elf_fp.write(convert_int_to_byte_string(ELF32_HDR_SIZE+ELF32_PHDR_SIZE, 4))
+ elf_fp.write(convert_int_to_byte_string(image_dest, 4))
+ elf_fp.write(convert_int_to_byte_string(image_dest, 4))
+ elf_fp.write(convert_int_to_byte_string(image_size, 4))
+ elf_fp.write(convert_int_to_byte_string(image_size, 4))
+ elf_fp.write(convert_int_to_byte_string(MI_PBT_RWE_SEGMENT, 4))
+ elf_fp.write(convert_int_to_byte_string(ELF_BLOCK_ALIGN, 4))
+
+ elf_fp.close()
+ return 0
+
+#----------------------------------------------------------------------------
+# image_header
+#----------------------------------------------------------------------------
+def image_header(env, gen_dict,
+ code_file_name,
+ output_file_name,
+ secure_type,
+ is_ext_mbn_v5,
+ header_format = 'reg',
+ requires_preamble = False,
+ preamble_file_name = None,
+ elf_file_name = None,
+ write_full_hdr = False,
+ in_code_size = None,
+ cert_chain_size_in = CERT_CHAIN_ONEROOT_MAXSIZE,
+ num_of_pages = None):
+
+ # Preliminary checks
+ if (requires_preamble is True) and (preamble_file_name is None):
+ raise RuntimeError, "Image Header requires a preamble file"
+
+ if (gen_dict['IMAGE_KEY_MBN_TYPE'] == 'elf') and (elf_file_name is None):
+ raise RuntimeError, "ELF Image Headers require an elf file"
+
+ if (in_code_size is None) and (os.path.exists(code_file_name) is False):
+ raise RuntimeError, "Code size unavailable, and input file does not exist"
+
+ # Initialize
+ if in_code_size is not None:
+ code_size = in_code_size
+ else:
+ code_size = os.path.getsize(code_file_name)
+
+ image_dest = 0
+ image_source = 0
+
+ # If secure build, set signature and cert chain sizes
+ if secure_type == 'secure':
+ signature_size = SHA256_SIGNATURE_SIZE
+ cert_chain_size = cert_chain_size_in
+ image_size = code_size + cert_chain_size + signature_size
+ if (image_size % 4) != 0:
+ image_size += (4 - (image_size % 4))
+ else:
+ signature_size = 0
+ cert_chain_size = 0
+ image_size = code_size
+
+ # For ELF or hashed images, image destination will be determined from an ELF input file
+ if gen_dict['IMAGE_KEY_MBN_TYPE'] == 'elf':
+ image_dest = get_hash_address(elf_file_name) + MI_BOOT_IMG_HDR_SIZE
+ elif gen_dict['IMAGE_KEY_MBN_TYPE'] == 'bin':
+ image_dest = gen_dict['IMAGE_KEY_IMAGE_DEST']
+ image_source = gen_dict['IMAGE_KEY_IMAGE_SOURCE']
+
+ # Build the header based on format specified
+ if header_format == 'sbl':
+ boot_sbl_header = Sbl_Hdr(init_val = int('0xFFFFFFFF',16))
+ boot_sbl_header.codeword = FLASH_CODE_WORD
+ boot_sbl_header.magic = MAGIC_NUM
+ boot_sbl_header.image_id = gen_dict['IMAGE_KEY_IMAGE_ID']
+ boot_sbl_header.image_src = MI_BOOT_SBL_HDR_SIZE
+ boot_sbl_header.image_dest_ptr = image_dest
+ boot_sbl_header.image_size = image_size
+ boot_sbl_header.code_size = code_size
+ boot_sbl_header.sig_ptr = image_dest + code_size
+ boot_sbl_header.sig_size = signature_size
+ boot_sbl_header.cert_chain_ptr = image_dest + code_size + signature_size
+ boot_sbl_header.cert_chain_size = cert_chain_size
+ boot_sbl_header.oem_root_cert_sel = gen_dict['IMAGE_KEY_OEM_ROOT_CERT_SEL']
+ boot_sbl_header.oem_num_root_certs = gen_dict['IMAGE_KEY_OEM_NUM_ROOT_CERTS']
+ if 'USES_SBL_FOR_AARCH64' in env:
+ boot_sbl_header.booting_image_config = SBL_AARCH64
+ elif 'USES_SBL_FOR_AARCH632' in env:
+ boot_sbl_header.booting_image_config = SBL_AARCH32
+
+ # If preamble is required, output the preamble file and update the boot_sbl_header
+ if requires_preamble is True:
+ boot_sbl_header = image_preamble(gen_dict, preamble_file_name, boot_sbl_header, num_of_pages)
+
+ # Package up the header and write to output file
+ boot_sbl_header.writePackedData(target = output_file_name)
+
+ elif header_format == 'reg':
+ boot_header = Boot_Hdr(init_val = int('0x0',16))
+ boot_header.image_id = gen_dict['IMAGE_KEY_IMAGE_ID']
+ boot_header.image_src = image_source
+ boot_header.image_dest_ptr = image_dest
+ boot_header.image_size = image_size
+ boot_header.code_size = code_size
+ boot_header.sig_ptr = image_dest + code_size
+ boot_header.sig_size = signature_size
+ boot_header.cert_chain_ptr = image_dest + code_size + signature_size
+ boot_header.cert_chain_size = cert_chain_size
+
+ if is_ext_mbn_v5 == True:
+ # If platform image integrity check is enabled
+ boot_header.flash_parti_ver = 5 # version
+ boot_header.image_src = 0 # sig_size_qc
+ boot_header.image_dest_ptr = 0 # cert_chain_size_qc
+
+ # If preamble is required, output the preamble file and update the boot_header
+ if requires_preamble is True:
+ boot_header = image_preamble(gen_dict, preamble_file_name, boot_header, num_of_pages)
+
+ # Package up the header and write to output file
+ boot_header.writePackedData(target = output_file_name, write_full_hdr = write_full_hdr)
+
+ else:
+ raise RuntimeError, "Header format not supported: " + str(header_format)
+ return 0
+
+
+#----------------------------------------------------------------------------
+# pboot_gen_elf
+#----------------------------------------------------------------------------
+def pboot_gen_elf(env, elf_in_file_name,
+ hash_out_file_name,
+ elf_out_file_name,
+ secure_type = 'non_secure',
+ hash_seg_max_size = None,
+ last_phys_addr = None,
+ append_xml_hdr = False,
+ is_sha256_algo = True,
+ cert_chain_size_in = CERT_CHAIN_ONEROOT_MAXSIZE):
+ global MI_PROG_BOOT_DIGEST_SIZE
+ if (is_sha256_algo is True):
+ MI_PROG_BOOT_DIGEST_SIZE = 32
+ else:
+ MI_PROG_BOOT_DIGEST_SIZE = 20
+
+ # Open Files
+ elf_in_fp = OPEN(elf_in_file_name, "rb")
+ hash_out_fp = OPEN(hash_out_file_name, "wb+")
+
+ if elf_out_file_name is not None:
+ elf_out_fp = OPEN(elf_out_file_name, "wb+")
+
+ # Initialize
+ [elf_header, phdr_table] = preprocess_elf_file(elf_in_file_name)
+ num_phdrs = elf_header.e_phnum
+ phdr_total_size = num_phdrs * elf_header.e_phentsize
+ phdr_size = elf_header.e_phentsize
+ hashtable_size = 0
+ hashtable_shift = 0
+
+ if elf_header.e_ident[ELFINFO_CLASS_INDEX] == ELFINFO_CLASS_64:
+ new_phdr = Elf64_Phdr('\0' * ELF64_PHDR_SIZE)
+ elf_header_size = ELF64_HDR_SIZE
+ is_elf64 = True
+ else:
+ new_phdr = Elf32_Phdr('\0' * ELF32_PHDR_SIZE)
+ elf_header_size = ELF32_HDR_SIZE
+ is_elf64 = False
+
+ hash = '\0' * MI_PROG_BOOT_DIGEST_SIZE
+ phdr_start = 0
+ bytes_to_pad = 0
+ hash_seg_end = 0
+
+ # Process program headers if an output elf is specified
+ if elf_out_file_name is not None:
+ # Assert limit on number of program headers in input ELF
+ if num_phdrs > MAX_PHDR_COUNT:
+ raise RuntimeError, "Input ELF has exceeded maximum number of program headers"
+
+ # Create new program header for the ELF Header + Program Headers
+ new_phdr.p_type = NULL_TYPE
+ new_phdr.p_flags = MI_PBT_ELF_PHDR_SEGMENT
+
+ # If hash table program header is not found, make sure to include it
+ elf_header.e_phnum += 2
+
+ # Create an empty hash entry for PHDR_TYPE
+ hash_out_fp.write('\0' * MI_PROG_BOOT_DIGEST_SIZE)
+ hashtable_size += MI_PROG_BOOT_DIGEST_SIZE
+
+ # Create an empty hash entry for the hash segment itself
+ hash_out_fp.write('\0' * MI_PROG_BOOT_DIGEST_SIZE)
+ hashtable_size += MI_PROG_BOOT_DIGEST_SIZE
+
+ # Begin hash table generation
+ for i in range(num_phdrs):
+ curr_phdr = phdr_table[i]
+
+ if (MI_PBT_PAGE_MODE_VALUE(curr_phdr.p_flags) == MI_PBT_PAGED_SEGMENT):
+ seg_offset = curr_phdr.p_offset
+ seg_size = curr_phdr.p_filesz
+ hash_size = 0
+
+ # Check if the vaddr is page aligned
+ off = curr_phdr.p_vaddr & (ELF_BLOCK_ALIGN - 1)
+ if int(off) is not 0:
+ seg_size -= (ELF_BLOCK_ALIGN - off)
+ seg_offset += (ELF_BLOCK_ALIGN - off)
+
+ # Seg_size should be page aligned
+ if (seg_size & (ELF_BLOCK_ALIGN - 1)) > 0:
+ raise RuntimeError, "seg_size: " + hex(seg_size) + " is not ELF page aligned!"
+
+ off = seg_offset + seg_size
+
+ while seg_offset < off:
+
+ if seg_offset < ELF_BLOCK_ALIGN:
+ hash_size = seg_offset
+ else:
+ hash_size = ELF_BLOCK_ALIGN
+
+ elf_in_fp.seek(seg_offset)
+ fbuf = elf_in_fp.read(hash_size)
+
+ if MI_PBT_CHECK_FLAG_TYPE(curr_phdr.p_flags) is True:
+ hash = generate_hash(fbuf, is_sha256_algo)
+ else:
+ hash = '\0' * MI_PROG_BOOT_DIGEST_SIZE
+
+ # Write hash to file
+ hash_out_fp.write(hash)
+
+ hashtable_size += MI_PROG_BOOT_DIGEST_SIZE
+ seg_offset += ELF_BLOCK_ALIGN
+
+ # Copy the hash entry for all that are PAGED segments and those that are not the PHDR type. This is for
+ # backward tool compatibility where some images are generated using older exe tools.
+ elif((MI_PBT_PAGE_MODE_VALUE(curr_phdr.p_flags) == MI_PBT_NON_PAGED_SEGMENT) and (curr_phdr.p_type is not PHDR_TYPE)):
+ # Read full hash entry into buffer
+ elf_in_fp.seek(curr_phdr.p_offset)
+ data_len = curr_phdr.p_filesz
+ file_buff = elf_in_fp.read(data_len)
+
+ if (MI_PBT_CHECK_FLAG_TYPE(curr_phdr.p_flags) is True) and (data_len > 0):
+ hash = generate_hash(file_buff, is_sha256_algo)
+ else:
+ hash = '\0' * MI_PROG_BOOT_DIGEST_SIZE
+
+ # Write hash to file
+ hash_out_fp.write(hash)
+
+ hashtable_size += MI_PROG_BOOT_DIGEST_SIZE
+ # End hash table generation
+
+ # Generate the rest of the ELF output file if specified
+ if elf_out_file_name is not None:
+
+ # Preempt hash table size if necessary
+ if secure_type == 'secure':
+ hashtable_size += (SHA256_SIGNATURE_SIZE + cert_chain_size_in)
+
+ if append_xml_hdr is True:
+ hashtable_size += XML_HEADER_MAXSIZE
+
+ # Initialize the hash table program header
+ [hash_Phdr, pad_hash_segment, hash_tbl_end_addr, hash_tbl_offset] = \
+ initialize_hash_phdr(elf_in_file_name, hashtable_size, MI_BOOT_IMG_HDR_SIZE, ELF_BLOCK_ALIGN, is_elf64)
+
+ # Check if hash segment max size parameter was passed
+ if (hash_seg_max_size is not None):
+ # Error checking for hash segment size validity
+ if hashtable_size > hash_seg_max_size:
+ raise RuntimeError, "Hash table exceeds maximum hash segment size: " + hex(hash_seg_max_size)
+ if (hash_seg_max_size & (ELF_BLOCK_ALIGN-1)) is not 0:
+ raise RuntimeError, "Hash segment size passed is not ELF Block Aligned: " + hex(hash_seg_max_size)
+
+ # Check if hash physical address parameter was passed
+ if last_phys_addr is not None:
+ hash_Phdr.p_vaddr = last_phys_addr
+ hash_Phdr.p_paddr = last_phys_addr
+
+ # Check if hash segment max size was passed
+ if hash_seg_max_size is not None:
+ hash_Phdr.p_memsz = hash_seg_max_size
+
+ # Determine the end of the hash segment, make sure it's block aligned
+ bytes_to_pad = ELF_BLOCK_ALIGN - pad_hash_segment
+ hash_seg_end = hash_tbl_end_addr + bytes_to_pad
+
+ # Check if a shifting is required to accommodate for the hash segment.
+ # Get the minimum offset by going through the program headers.
+ # Note that the program headers in the input file do not contain
+ # the dummy program header for ELF + Program header, and the
+ # program header for the hashtable.
+ min_offset = phdr_table[0].p_offset
+ for i in range(num_phdrs):
+ curr_phdr = phdr_table[i]
+ if curr_phdr.p_offset < min_offset:
+ min_offset = curr_phdr.p_offset
+
+ if min_offset < hash_seg_end:
+ hashtable_shift = hash_seg_end - min_offset
+
+ # Move program headers to after ELF header
+ phdr_start = elf_header_size
+
+ # We copy over no section headers so assign these values to 0 in ELF Header
+ elf_header.e_shnum = 0
+ elf_header.e_shstrndx = 0
+ elf_header.e_shoff = 0
+
+ # Output remaining ELF segments
+ for i in range(num_phdrs):
+
+ # Increment the file offset before writing to the destination file
+ curr_phdr = phdr_table[i]
+
+ # We do not copy over program headers of PHDR type, decrement the program
+ # header count and continue the loop
+ if curr_phdr.p_type is PHDR_TYPE:
+ elf_header.e_phnum -= 1
+ continue
+
+ src_offset = curr_phdr.p_offset
+
+ # Copy the ELF segment
+ file_copy_offset(elf_in_fp, src_offset, elf_out_fp, curr_phdr.p_offset + hashtable_shift, curr_phdr.p_filesz)
+
+ # Output remaining program headers and ELF segments
+ elf_header.e_phoff = phdr_start
+
+ # Output new program headers which we have generated
+ elf_out_fp.seek(phdr_start)
+ new_phdr.p_filesz = elf_header_size + (elf_header.e_phnum * phdr_size)
+ elf_out_fp.write(new_phdr.getPackedData())
+ elf_out_fp.write(hash_Phdr.getPackedData())
+ phdr_start += (2 * phdr_size)
+
+ # Increment the file offset before writing to the destination file
+ for i in range(num_phdrs):
+ curr_phdr = phdr_table[i]
+
+ if curr_phdr.p_type is PHDR_TYPE:
+ continue
+
+ curr_phdr.p_offset += hashtable_shift
+
+ # Copy the program header
+ elf_out_fp.seek(phdr_start)
+ elf_out_fp.write(curr_phdr.getPackedData())
+
+ # Update phdr_start
+ phdr_start += phdr_size
+
+ # Finally, copy the new ELF header to the destination file
+ elf_out_fp.seek(0)
+ elf_out_fp.write(elf_header.getPackedData())
+
+ # Recalculate hash of ELF + program headers and output to hash output file
+ elf_out_fp.seek(0)
+ # Read the elf header
+ elfhdr_buff = elf_out_fp.read(elf_header_size)
+ # Seek to the program header offset listed in elf header.
+ elf_out_fp.seek(elf_header.e_phoff)
+ # Read the program header and compute hash
+ proghdr_buff = elf_out_fp.read(elf_header.e_phnum * phdr_size)
+
+ hash = generate_hash(elfhdr_buff + proghdr_buff, is_sha256_algo)
+
+ # Write hash to file as first hash table entry
+ hash_out_fp.seek(0)
+ hash_out_fp.write(hash)
+
+ # Close files
+ elf_in_fp.close()
+ hash_out_fp.close()
+
+ if elf_out_file_name is not None:
+ elf_out_fp.close()
+
+ return 0
+
+
+#----------------------------------------------------------------------------
+# pboot_add_hash
+#----------------------------------------------------------------------------
+def pboot_add_hash(env, elf_in_file_name,
+ hash_tbl_file_name,
+ elf_out_file_name):
+
+ # Open files
+ elf_in_fp = OPEN(elf_in_file_name, "rb")
+ hash_tbl_fp = OPEN(hash_tbl_file_name, "rb")
+ elf_out_fp = OPEN(elf_out_file_name, "wb+")
+
+ # Initialize
+ [elf_header, phdr_table] = preprocess_elf_file(elf_in_file_name)
+
+ hash_size = os.path.getsize(hash_tbl_file_name)
+ hash_segment_found = False
+
+ # Attempt to find the location of the hash program header
+ for i in range(elf_header.e_phnum):
+ curr_phdr = phdr_table[i]
+ if curr_phdr.p_flags == MI_PBT_ELF_HASH_SEGMENT:
+ hash_segment_found = True
+ break
+
+ if hash_segment_found is True:
+ # Copy input file to output file
+ shutil.copyfileobj(elf_in_fp, elf_out_fp, os.path.getsize(elf_in_file_name))
+
+ # Update ELF to insert hash table at corresponding file offset
+ hash_hdr_offset = curr_phdr.p_offset
+ file_copy_offset(hash_tbl_fp, 0, elf_out_fp, hash_hdr_offset, hash_size)
+
+ else:
+ raise RuntimeError, "Hash segment program header not found in file " + elf_in_file_name
+
+ # Close files
+ elf_in_fp.close()
+ hash_tbl_fp.close()
+ elf_out_fp.close()
+
+ return 0
+
+#----------------------------------------------------------------------------
+# image_auth
+#----------------------------------------------------------------------------
+def image_auth(env, *args):
+
+ if len(args) < 7 or len(args) > 8:
+ raise RuntimeError, "Usage Invalid"
+
+ # Initialize File Names
+ binary_in = args[0]
+ signature = args[1]
+ attestation_cert = args[2]
+ attestation_ca_cert = args[3]
+ root_cert = args[4]
+ cert_chain_out = args[5]
+ signed_image_out = args[6]
+ if len(args) == 8:
+ cert_size_max_in = args[7]
+ else:
+ cert_size_max_in = CERT_CHAIN_ONEROOT_MAXSIZE
+
+ # Creating list of certificates to support creation of certificate chains
+ # of lenth 1, 2, or 3 certificates
+ cert_list = []
+ num_certs = 0
+ if (os.path.exists(attestation_cert)):
+ cert_list.append(attestation_cert)
+ num_certs = num_certs + 1
+ if (os.path.exists(attestation_ca_cert)):
+ cert_list.append(attestation_ca_cert)
+ num_certs = num_certs + 1
+ if (os.path.exists(root_cert)):
+ cert_list.append(root_cert)
+ num_certs = num_certs + 1
+
+ if (num_certs == 0):
+ raise RuntimeError, "Missing file(s) required for signing.\n"
+
+ # Create the Certificate Chain
+ concat_files (cert_chain_out, cert_list)
+
+ # Pad to ensure Certificate Chain Size is CERT_CHAIN_MAX_SIZE
+ cert_size = os.path.getsize(cert_chain_out)
+
+ if cert_size <= cert_size_max_in:
+ bytes_to_pad = cert_size_max_in - cert_size
+ cert_fp = OPEN(cert_chain_out,'ab')
+ pad_file(cert_fp, bytes_to_pad, PAD_BYTE_1)
+ cert_fp.close()
+ else:
+ raise RuntimeError, "Certificate Size too large: " + str(cert_size)
+
+ # Create the Final Signed Image File
+ concat_files (signed_image_out, [binary_in, signature, cert_chain_out])
+
+ return 0
+
+#----------------------------------------------------------------------------
+# modify_relocatable_flags
+#----------------------------------------------------------------------------
+def modify_relocatable_flags(env, output_elf ):
+
+ # Offset into program header where the p_flags field is stored
+ phdr_align_flag_offset = 28
+ phdr_reloc_flag_offset = 24
+
+ # Initialize
+ [elf_header, phdr_table] = preprocess_elf_file(output_elf)
+
+ if elf_header.e_ident[ELFINFO_CLASS_INDEX] == ELFINFO_CLASS_64:
+ curr_phdr = Elf64_Phdr('\0' * ELF64_PHDR_SIZE)
+ elf_header_size = ELF64_HDR_SIZE
+ is_elf64 = True
+ else:
+ curr_phdr = Elf32_Phdr('\0' * ELF32_PHDR_SIZE)
+ elf_header_size = ELF32_HDR_SIZE
+ is_elf64 = False
+
+ # Open files
+ elf_in_fp = OPEN(output_elf, "r+")
+
+ # Go to the start of the p_flag entry in the first program header
+ file_offset_align_flag = elf_header.e_phoff + phdr_align_flag_offset
+
+ # Change the align field in the program header in the ELF file
+ elf_in_fp.seek(file_offset_align_flag)
+ curr_phdr = phdr_table[0]
+
+ #default alignment value is 1MB unless otherwise specified
+ if 'USES_RELOC_ALIGN_VALUE_4MB' in env:
+ alignment_value = ALIGNVALUE_4MB
+ else:
+ alignment_value = ALIGNVALUE_1MB
+
+
+
+ #create new alignment value
+ new_align = (curr_phdr.p_align & 0) | alignment_value
+
+ # Create structure to package new flag field
+ s = struct.Struct('I')
+ new_flag_bytes = s.pack(new_align)
+
+ # Write the new flag value and incr ement offset
+ elf_in_fp.write(new_flag_bytes)
+
+ # Go to the start of the p_flag entry in the first program header
+ file_offset_reloc_flag = elf_header.e_phoff + phdr_reloc_flag_offset
+
+ # Change each program header flag in the ELF file with relocatable flag
+ for i in range(elf_header.e_phnum):
+ # Seek to correct location and create new p_flag value
+ elf_in_fp.seek(file_offset_reloc_flag)
+ curr_phdr = phdr_table[i]
+ new_flag = (curr_phdr.p_flags & ~MI_PBT_FLAGS_MASK) | (MI_PBT_ELF_AMSS_RELOCATABLE_IMAGE)
+
+ # Create structure to package new flag field
+ s = struct.Struct('I')
+ new_flag_bytes = s.pack(new_flag)
+
+ # Write the new flag value and increment offset
+ elf_in_fp.write(new_flag_bytes)
+ file_offset_reloc_flag += elf_header.e_phentsize
+
+ # Close files
+ elf_in_fp.close()
+
+
+ return 0
+
+
+#----------------------------------------------------------------------------
+# modify_elf_flags
+#----------------------------------------------------------------------------
+def modify_elf_flags(env, elf_in_file_name,
+ scl_file_name):
+
+ # Initialize
+ [elf_header, phdr_table] = preprocess_elf_file(elf_in_file_name)
+ segment_list = readSCL(scl_file_name, env['GLOBAL_DICT'])
+
+ if elf_header.e_ident[ELFINFO_CLASS_INDEX] == ELFINFO_CLASS_64:
+ curr_phdr = Elf64_Phdr('\0' * ELF64_PHDR_SIZE)
+ # Offset into program header where the p_flags field is stored
+ phdr_flag_off = 4
+ else:
+ curr_phdr = Elf32_Phdr('\0' * ELF32_PHDR_SIZE)
+ # Offset into program header where the p_flags field is stored
+ phdr_flag_off = 24
+
+ # Open files
+ elf_in_fp = OPEN(elf_in_file_name, "r+")
+
+ # Check for corresponding number of segments
+ if len(segment_list) is not elf_header.e_phnum:
+ raise RuntimeError, 'SCL file and ELF file have different number of segments!'
+
+ # Go to the start of the p_flag entry in the first program header
+ file_offset = elf_header.e_phoff + phdr_flag_off
+
+ # Change each program header flag in the ELF file based off the SCL file
+ for i in range(elf_header.e_phnum):
+ # Seek to correct location and create new p_flag value
+ elf_in_fp.seek(file_offset)
+ curr_phdr = phdr_table[i]
+ new_flag = (curr_phdr.p_flags & ~MI_PBT_FLAGS_MASK) | (segment_list[i].flag)
+
+ # Create structure to package new flag field
+ s = struct.Struct('I')
+ new_flag_bytes = s.pack(new_flag)
+
+ # Write the new flag value and increment offset
+ elf_in_fp.write(new_flag_bytes)
+ file_offset += elf_header.e_phentsize
+
+ # Close files
+ elf_in_fp.close()
+
+ return 0
+
+#----------------------------------------------------------------------------
+# generate_code_hash
+#----------------------------------------------------------------------------
+def generate_code_hash(env, elf_in_file_name):
+
+ # Initialize
+ [elf_header, phdr_table] = preprocess_elf_file(elf_in_file_name)
+
+ if elf_header.e_ident[ELFINFO_CLASS_INDEX] == ELFINFO_CLASS_64:
+ curr_phdr = Elf64_Phdr('\0' * ELF64_PHDR_SIZE)
+ # Offset into program header where the p_flags field is stored
+ phdr_flag_off = 4
+ else:
+ curr_phdr = Elf32_Phdr('\0' * ELF32_PHDR_SIZE)
+ # Offset into program header where the p_flags field is stored
+ phdr_flag_off = 24
+
+ # Open files
+ elf_in_fp = OPEN(elf_in_file_name, "rb+")
+
+ # Go to the start of the p_flag entry in the first program header
+ file_offset = elf_header.e_phoff + phdr_flag_off
+
+ # XXX Get these from env?
+ DP_CODE_ALIGN = 0x100
+ DP_PAGE_SIZE = 4096
+ DP_HASH_SIZE = 32 # SHA-256
+ DP_HASH_MAGIC = 0xC0DEDEC0
+ PH_PERM_RW = 0x06
+ PH_PERM_RX = 0x05
+ PH_PERM_RO = 0x04
+ PH_PERM_MASK = 0x07
+
+ page_size = DP_PAGE_SIZE
+ hash_size = DP_HASH_SIZE
+
+ # First identify the hash segment. It is the first RW section.
+ # Its Align should be 8, and its size a multiple of DP_HASH_SIZE;
+
+ hash_seg_idx = -1
+ for i in range(elf_header.e_phnum):
+ curr_phdr = phdr_table[i]
+
+ if (curr_phdr.p_align == 8 and
+ (curr_phdr.p_flags & PH_PERM_MASK) == PH_PERM_RW and
+ curr_phdr.p_filesz != 0 and (curr_phdr.p_filesz % DP_HASH_SIZE) == 0):
+ hash_seg_idx = i
+ # Validate the contents of the hash segment. It should be
+ # filled with DP_HASH_MAGIC
+ elf_in_fp.seek(curr_phdr.p_offset)
+ hash_data = "";
+ while (len(hash_data) < curr_phdr.p_filesz):
+ hash_data = hash_data + elf_in_fp.read(curr_phdr.p_filesz - len(hash_data))
+
+ hash_data = struct.unpack("I" * (curr_phdr.p_filesz / 4), hash_data)
+
+ for v in hash_data[:]:
+ if (v != DP_HASH_MAGIC):
+ hash_seg_idx = -1
+ break;
+
+ if (hash_seg_idx != -1):
+ break
+
+ if (hash_seg_idx == -1):
+ # return if there is no hash segment.
+ return 0
+
+ hash_phdr = phdr_table[hash_seg_idx]
+
+ # Now find the code segment for the hashes. Look for matching number of pages
+ code_seg_idx = -1
+ code_seg_pages = hash_phdr.p_filesz / DP_HASH_SIZE
+
+ for i in range(elf_header.e_phnum):
+ curr_phdr = phdr_table[i]
+ curr_pages = (curr_phdr.p_filesz + DP_PAGE_SIZE - 1) / DP_PAGE_SIZE
+
+ if (curr_phdr.p_align == DP_CODE_ALIGN and
+ (curr_phdr.p_flags & PH_PERM_MASK) == PH_PERM_RX and
+ curr_pages == code_seg_pages):
+ if (code_seg_idx != -1):
+ raise RuntimeError, 'Multiple code segments match for: ' + code_seg_pages + ' pages'
+ code_seg_idx = i
+
+ if (code_seg_idx == -1):
+ raise RuntimeError, 'No matching code segment found'
+
+ code_phdr = phdr_table[code_seg_idx]
+
+ # Now hash the pages in the code segment
+ hashes = []
+ elf_in_fp.seek(code_phdr.p_offset)
+ bytes_left = code_phdr.p_filesz;
+ while (bytes_left > 0):
+ bytes_in_page = min(bytes_left, DP_PAGE_SIZE)
+ page = "";
+ while (len(page) < bytes_in_page):
+ page = page + elf_in_fp.read(bytes_in_page - len(page))
+ if (len(page) < DP_PAGE_SIZE):
+ page = page + (struct.pack('b', 0) * (DP_PAGE_SIZE - len(page)))
+ hashes = hashes + [generate_hash(page, True)]
+ bytes_left -= bytes_in_page
+
+ # And write them to the hash segment
+ elf_in_fp.seek(hash_phdr.p_offset)
+
+ for h in hashes[:]:
+ elf_in_fp.write(h)
+
+ # Close files
+ elf_in_fp.close()
+
+ return 0
+
+#----------------------------------------------------------------------------
+# BOOT TOOLS END
+#----------------------------------------------------------------------------
+
+#----------------------------------------------------------------------------
+# HELPER FUNCTIONS BEGIN
+#----------------------------------------------------------------------------
+
+#----------------------------------------------------------------------------
+# Create a list to hold all segment information from an input SCL file
+#----------------------------------------------------------------------------
+def readSCL(filename, global_dict):
+
+ scl_fp = OPEN(filename,'r')
+
+ # Initialize
+ file_data = scl_fp.readlines()
+ num_lines = len(file_data)
+ current_line = ''
+ previous_line = ''
+ strip_chars = '(){}[]'
+ i = 0
+ bracket_counter = 0
+ seg_list = []
+
+ # Parse through all lines
+ while i < num_lines:
+
+ # Save the last line read
+ previous_line = current_line
+ current_line = file_data[i]
+
+ # Look for the symbol '{' for the line to read.
+ # Use bracket counter to skip nested '{ }'
+ if ('{' in current_line):
+ if bracket_counter is 0:
+ # Create a new SegmentInfo class and set up tokens
+ new_scl_entry = SegmentInfo()
+ previous_line = previous_line.strip()
+ tokens = previous_line.split(' ')
+
+ # Check that at least two tokens were parsed
+ # Token 1: Segment Name
+ # Token 2: Start Address -- not used in MBN tools
+ if len(tokens) < 2:
+ raise RuntimeError, 'SCL Segment Syntax malformed: ' + previous_line
+
+ # Get the segment flags corresponding to the segment name description
+ new_scl_entry.flag = getSegmentFlag(tokens[0].strip(strip_chars))
+ seg_list.append(new_scl_entry)
+
+ bracket_counter += 1
+ elif '}' in current_line:
+ bracket_counter -= 1
+
+ i+=1
+
+ scl_fp.close()
+ return seg_list
+
+#----------------------------------------------------------------------------
+# Given a string parsed from a SCL file, returns the ELF segment flags
+#----------------------------------------------------------------------------
+def getSegmentFlag(seg_info):
+
+ ret_val = None
+
+ # Define string values for various types of segments
+ RO = "RO"
+ RW = "RW"
+ ZI = "ZI"
+ PAGEABLE = "PAGED"
+ NOTPAGEABLE = "NOTPAGED"
+ SWAPABLE = "SWAPPED"
+ SWAP_POOL = "SWAP_POOL"
+ RESERVED = "RESERVED"
+ HASHTBL = "HASH"
+ SHARED = "SHARED"
+ NOTUSED = "NOTUSED"
+ BOOT_SEGMENT = "BOOT_SEGMENT"
+ CODE = "CODE"
+ L4BSP = "L4BSP"
+ POOL_INDEX_0 = "INDEX_0"
+ POOL_INDEX_1 = "INDEX_1"
+
+ # New definitions for EOS demand paging
+ NONPAGE = "NONPAGE"
+ PAGEUNLOCKED = "PAGEUNLOCKED"
+ PAGELOCKED = "PAGELOCKED"
+ UNSECURE = "UNSECURE"
+
+ if seg_info is None or len(seg_info) is 0:
+ raise RuntimeError, 'Invalid segment information passed: ' + seg_info
+
+ # Conditional checks and assignments of the corresponding segment flag values
+ if NOTPAGEABLE in seg_info:
+ if RO in seg_info:
+ ret_val = MI_PBT_ELF_AMSS_NON_PAGED_RO_SEGMENT
+ elif CODE in seg_info:
+ ret_val = MI_PBT_ELF_AMSS_NON_PAGED_RO_SEGMENT
+ elif ZI in seg_info:
+ if SWAP_POOL in seg_info:
+ if POOL_INDEX_0 in seg_info:
+ ret_val = MI_PBT_ELF_SWAP_POOL_NON_PAGED_ZI_SEGMENT_INDEX0
+ else:
+ ret_val = MI_PBT_ELF_SWAP_POOL_NON_PAGED_ZI_SEGMENT_INDEX1
+ else:
+ ret_val = MI_PBT_ELF_AMSS_NON_PAGED_ZI_SEGMENT
+
+ elif NOTUSED in seg_info:
+ ret_val = MI_PBT_ELF_AMSS_NON_PAGED_NOTUSED_SEGMENT
+
+ elif SHARED in seg_info:
+ ret_val = MI_PBT_ELF_AMSS_NON_PAGED_SHARED_SEGMENT
+ elif HASHTBL in seg_info:
+ ret_val = MI_PBT_ELF_HASH_SEGMENT
+ elif BOOT_SEGMENT in seg_info:
+ ret_val = MI_PBT_ELF_BOOT_SEGMENT
+ elif L4BSP in seg_info:
+ ret_val = MI_PBT_ELF_NON_PAGED_L4BSP_SEGMENT
+ else:
+ ret_val = MI_PBT_ELF_AMSS_NON_PAGED_RW_SEGMENT
+
+ elif PAGEABLE in seg_info:
+ if RO in seg_info or CODE in seg_info:
+ if SWAPABLE in seg_info:
+ if POOL_INDEX_0 in seg_info:
+ ret_val = MI_PBT_ELF_SWAPPED_PAGED_RO_SEGMENT_INDEX0
+ else:
+ ret_val = MI_PBT_ELF_SWAPPED_PAGED_RO_SEGMENT_INDEX1
+ else:
+ ret_val = MI_PBT_ELF_AMSS_PAGED_RO_SEGMENT
+ elif ZI in seg_info:
+ ret_val = MI_PBT_ELF_AMSS_PAGED_ZI_SEGMENT
+
+ elif NOTUSED in seg_info:
+ ret_val = MI_PBT_ELF_AMSS_PAGED_NOTUSED_SEGMENT
+ elif SHARED in seg_info:
+ ret_val = MI_PBT_ELF_AMSS_PAGED_SHARED_SEGMENT
+ elif L4BSP in seg_info:
+ ret_val = MI_PBT_ELF_PAGED_L4BSP_SEGMENT
+ else:
+ ret_val = MI_PBT_ELF_AMSS_PAGED_RW_SEGMENT
+
+ elif PAGELOCKED in seg_info:
+ ret_val = MI_PBT_ELF_PAGED_LOCKED_SEGMENT
+ elif PAGEUNLOCKED in seg_info:
+ ret_val = MI_PBT_ELF_PAGED_UNLOCKED_SEGMENT
+ elif NONPAGE in seg_info:
+ ret_val = MI_PBT_ELF_RESIDENT_SEGMENT
+ elif UNSECURE in seg_info:
+ ret_val = MI_PBT_ELF_UNSECURE_SEGMENT
+
+ else:
+ raise RuntimeError, 'The segment name is wrongly defined in the SCL file: ' + seg_info
+
+ return ret_val
+
+#----------------------------------------------------------------------------
+# Pad a file with specific number of bytes
+# Note: Assumes the fp is seeked to the correct location of padding
+#----------------------------------------------------------------------------
+def pad_file(fp, num_bytes, value):
+
+ if num_bytes < 0:
+ raise RuntimeError, "Number of bytes to pad must be greater than zero"
+
+ while num_bytes > 0:
+ fp.write('%c' % value)
+ num_bytes -= 1
+
+ return
+
+#----------------------------------------------------------------------------
+# Concatenates the files listed in 'sources' in order and writes to 'target'
+#----------------------------------------------------------------------------
+def concat_files (target, sources):
+ if type(sources) is not list:
+ sources = [sources]
+
+ target_file = OPEN(target,'wb')
+
+ for fname in sources:
+ file = OPEN(fname,'rb')
+ while True:
+ bin_data = file.read(65536)
+ if not bin_data:
+ break
+ target_file.write(bin_data)
+ file.close()
+ target_file.close()
+
+#----------------------------------------------------------------------------
+# Parse build configurable values and assign to global variables for tools
+#----------------------------------------------------------------------------
+def init_build_vars(env):
+
+ # Maximum size of Certificate Chain used in Secure Boot
+ global CERT_CHAIN_ONEROOT_MAXSIZE
+ CERT_CHAIN_ONEROOT_MAXSIZE = get_dict_value(env['GLOBAL_DICT'], 'CERT_CHAIN_MAXSIZE', (6*1024))
+
+ # Maximum size of the XML Header used in encrypted ELF images
+ global XML_HEADER_MAXSIZE
+ XML_HEADER_MAXSIZE = get_dict_value(env['GLOBAL_DICT'], 'XML_HEADER_MAXSIZE', (2*1024))
+
+#----------------------------------------------------------------------------
+# Generates the global dictionary and add to the environment
+#----------------------------------------------------------------------------
+def generate_global_dict(env):
+
+ # Get file names for 'cust' and 'targ' auto-generated files inside 'build/ms'
+ cust_h = env.subst('CUST${BUILD_ID}.H').lower()
+ targ_h = env.subst('TARG${BUILD_ID}.H').lower()
+ cust_file_name = str(env.FindFile(cust_h, "${INC_ROOT}/build/ms"))
+ targ_file_name = str(env.FindFile(targ_h, "${INC_ROOT}/build/ms"))
+
+ # Check that files are present
+ if (os.path.exists(cust_file_name) is True) and \
+ (os.path.exists(targ_file_name) is True):
+
+ # Populate the dictionary from the auto-generated files
+ global_dict = populate_dictionary(targ_file_name, cust_file_name)
+ else:
+ global_dict = {}
+
+ # Add the dictionary to the environment
+ env.Replace(GLOBAL_DICT = global_dict)
+
+#----------------------------------------------------------------------------
+# Populate the dictionary from a list of input files
+#----------------------------------------------------------------------------
+def populate_dictionary(*args):
+
+ if len(args) < 1:
+ raise RuntimeError, "At least 1 file must be specified as an input"
+
+ global_dict = {}
+ Fields = ["Define", "Key", "Value"]
+
+ # For each input file
+ for i in range(len(args)):
+
+ template_file_path = args[i]
+ instream = OPEN(template_file_path, 'r')
+ # Tokenize each line with a white space
+ values = csv.DictReader(instream, Fields, delimiter=" ")
+
+ for values in itertools.izip(values):
+ new_entry = values[0]
+ # Verify the parsed tokens
+ if (new_entry['Define'] == '#define') and \
+ (new_entry['Key'] != None) and \
+ (new_entry['Value'] != None):
+
+ new_key = new_entry['Key'].strip()
+ new_value = new_entry['Value'].strip()
+
+ # If value pair is empty string, assume feature definition is true
+ if new_value == '':
+ new_value = 'yes'
+
+ # Check for and handle text replacements as we parse
+ if global_dict is not None and len(global_dict.keys()) > 0:
+ for key in global_dict:
+ new_value = new_value.replace(key, str(global_dict.get(key)))
+
+ # Attempt to evaluate value
+ try:
+ new_value = eval(new_value)
+ # Catch exceptions and do not evaluate
+ except:
+ pass
+
+ # Add to global dictionary
+ global_dict[new_key] = new_value
+ instream.close()
+
+ return global_dict
+
+#----------------------------------------------------------------------------
+# Filter out a generic dictionary from the global dictionary
+#----------------------------------------------------------------------------
+def filter_dictionary(env, global_dict, **kwargs):
+
+ # Check for Image Type
+ # If IMAGE_TYPE parameter is not provided, raise error
+ if not kwargs.has_key('IMAGE_TYPE'):
+ raise RuntimeError, "IMAGE_TYPE must be defined to use FilterDictionary."
+ else:
+ image_type = kwargs.get('IMAGE_TYPE')
+ if type(image_type) is not str:
+ raise RuntimeError, "IMAGE_TYPE must be of string type."
+
+ # Check for Flash Type
+ # If FLASH_TYPE parameter is not provided, default to 'nand'
+ if not kwargs.has_key('FLASH_TYPE'):
+ flash_type = 'nand'
+ else:
+ flash_type = kwargs.get('FLASH_TYPE')
+ if type(flash_type) is not str:
+ raise RuntimeError, "FLASH_TYPE must be of string type. "
+
+ # Check for MBN Type
+ # If MBN_TYPE parameter is not provided, default to 'elf'
+ if not kwargs.has_key('MBN_TYPE'):
+ mbn_type = 'elf'
+ else:
+ mbn_type = kwargs.get('MBN_TYPE')
+ if mbn_type != 'elf' and mbn_type != 'bin':
+ raise RuntimeError, "MBN_TYPE currently not supported: " + mbn_type
+
+ # Check for Image ID
+ # If IMAGE_ID parameter is not provided, default to ID 0
+ if not kwargs.has_key('IMAGE_ID'):
+ image_id = ImageType.NONE_IMG
+ else:
+ image_id = kwargs.get('IMAGE_ID')
+ if type(image_id) is not int:
+ raise RuntimeError, "IMAGE_ID must be of integer type."
+
+ # Initialize
+ gen_dict = {}
+ image_dest = 0
+ image_source = 0
+
+ # Check for image_type
+ if image_type not in image_id_table:
+ id = image_id
+ id_match_str = image_type.upper() + "_IMG"
+ id_mbn_type = mbn_type
+ else:
+ id = image_id_table[image_type][0]
+ id_match_str = image_id_table[image_type][1]
+ id_mbn_type = image_id_table[image_type][2]
+
+ # Handle MBN Type and assign image destination address
+ if id_mbn_type is 'elf':
+ pass
+ elif id_mbn_type is 'bin':
+ template_key_match = 'IMAGE_KEY_' + id_match_str + "_DEST_ADDR"
+ if template_key_match in global_dict:
+ image_dest = global_dict[template_key_match]
+ else:
+ raise RuntimeError, "Builds file does not have IMAGE_KEY pair for: " + image_type
+ else:
+ raise RuntimeError, "MBN_TYPE currently not supported: " + mbn_type
+
+ # Assign generic dictionary key/value pairs
+ gen_dict['IMAGE_KEY_IMAGE_ID'] = id
+ gen_dict['IMAGE_KEY_IMAGE_DEST'] = image_dest
+ gen_dict['IMAGE_KEY_IMAGE_SOURCE'] = image_source
+ gen_dict['IMAGE_KEY_FLASH_TYPE'] = flash_type
+ gen_dict['IMAGE_KEY_MBN_TYPE'] = id_mbn_type
+ gen_dict['IMAGE_KEY_ID_MATCH_STR'] = id_match_str
+ gen_dict['IMAGE_KEY_FLASH_AUTO_DETECT_MAX_PAGE'] = \
+ get_dict_value(global_dict,'FLASH_AUTO_DETECT_MAX_PAGE', 8192)
+ gen_dict['IMAGE_KEY_FLASH_AUTO_DETECT_MIN_PAGE'] = \
+ get_dict_value(global_dict,'FLASH_AUTO_DETECT_MIN_PAGE', 2048)
+ gen_dict['IMAGE_KEY_MAX_SIZE_OF_VERIFY_BUFFER'] = \
+ get_dict_value(global_dict,'MAX_SIZE_OF_VERIFY_BUFFER', 8192)
+ gen_dict['IMAGE_KEY_BOOT_SMALL_PREAMBLE'] = \
+ get_dict_value(global_dict,'BOOT_SMALL_PREAMBLE', 1)
+
+ # Get OEM root certificate select and number
+ oem_root_cert_sel = get_dict_value(global_dict,'OEM_ROOT_CERT_SEL', 1)
+ oem_num_root_certs = get_dict_value(global_dict,'OEM_NUM_ROOT_CERTS', 1)
+
+ # Error checking for OEM configurable values
+ if oem_root_cert_sel in range(1, MAX_NUM_ROOT_CERTS + 1) and \
+ oem_num_root_certs in range(1, MAX_NUM_ROOT_CERTS + 1) and \
+ oem_root_cert_sel <= oem_num_root_certs:
+
+ gen_dict['IMAGE_KEY_OEM_ROOT_CERT_SEL'] = oem_root_cert_sel
+ gen_dict['IMAGE_KEY_OEM_NUM_ROOT_CERTS'] = oem_num_root_certs
+
+ else:
+ raise RuntimeError, "Invalid OEM root certificate configuration values"
+
+ # Assign additional dictionary key/values pair as needed by tools.
+
+ return gen_dict
+
+
+#----------------------------------------------------------------------------
+# Get index value from dictionary if exists, otherwise return default
+#----------------------------------------------------------------------------
+def get_dict_value(dict, key_string, default):
+
+ key = 'IMAGE_KEY_' + key_string
+
+ if key in dict:
+ return dict[key]
+ else:
+ return default
+
+#----------------------------------------------------------------------------
+# Preprocess an ELF file and return the ELF Header Object and an
+# array of ELF Program Header Objects
+#----------------------------------------------------------------------------
+def preprocess_elf_file(elf_file_name):
+
+ # Initialize
+ elf_fp = OPEN(elf_file_name, 'rb')
+ elf_header = Elf_Ehdr_common(elf_fp.read(ELF_HDR_COMMON_SIZE))
+
+ if verify_elf_header(elf_header) is False:
+ raise RuntimeError, "ELF file failed verification: " + elf_file_name
+
+ elf_fp.seek(0)
+
+ if elf_header.e_ident[ELFINFO_CLASS_INDEX] == ELFINFO_CLASS_64:
+ elf_header = Elf64_Ehdr(elf_fp.read(ELF64_HDR_SIZE))
+ else:
+ elf_header = Elf32_Ehdr(elf_fp.read(ELF32_HDR_SIZE))
+
+ phdr_table = []
+
+ # Verify ELF header information
+ if verify_elf_header(elf_header) is False:
+ raise RuntimeError, "ELF file failed verification: " + elf_file_name
+
+ # Get program header size
+ phdr_size = elf_header.e_phentsize
+
+ # Find the program header offset
+ file_offset = elf_header.e_phoff
+ elf_fp.seek(file_offset)
+
+ # Read in the program headers
+ for i in range(elf_header.e_phnum):
+ if elf_header.e_ident[ELFINFO_CLASS_INDEX] == ELFINFO_CLASS_64:
+ phdr_table.append(Elf64_Phdr(elf_fp.read(phdr_size)))
+ else:
+ phdr_table.append(Elf32_Phdr(elf_fp.read(phdr_size)))
+
+ elf_fp.close()
+ return [elf_header, phdr_table]
+
+#----------------------------------------------------------------------------
+# Get the hash table address from an input ELF file
+#----------------------------------------------------------------------------
+def get_hash_address(elf_file_name):
+
+ [elf_header, phdr_table] = preprocess_elf_file(elf_file_name)
+
+ last_paddr = 0
+ last_paddr_segment = 0
+
+ # Find the segment with the largest physical address.
+ # Hash segment's physical address will be immediately after this segment.
+ for i in range(elf_header.e_phnum):
+ curr_phdr = phdr_table[i]
+ if curr_phdr.p_paddr > last_paddr:
+ # Skip the demand paging segment as it would be outside the physical RAM location
+ if MI_PBT_SEGMENT_TYPE_VALUE(curr_phdr.p_flags) != MI_PBT_XBL_SEC_SEGMENT:
+ last_paddr = curr_phdr.p_paddr;
+ last_paddr_segment = i;
+
+ max_phdr = phdr_table[last_paddr_segment]
+
+ ret_val = (((max_phdr.p_paddr + max_phdr.p_memsz - 1) & \
+ ~(ELF_BLOCK_ALIGN-1)) + ELF_BLOCK_ALIGN)
+
+ return ret_val
+
+#----------------------------------------------------------------------------
+# Verify ELF header contents from an input ELF file
+#----------------------------------------------------------------------------
+def verify_elf_header(elf_header):
+ if (elf_header.e_ident[ELFINFO_MAG0_INDEX] != ELFINFO_MAG0) or \
+ (elf_header.e_ident[ELFINFO_MAG1_INDEX] != ELFINFO_MAG1) or \
+ (elf_header.e_ident[ELFINFO_MAG2_INDEX] != ELFINFO_MAG2) or \
+ (elf_header.e_ident[ELFINFO_MAG3_INDEX] != ELFINFO_MAG3) or \
+ ((elf_header.e_ident[ELFINFO_CLASS_INDEX] != ELFINFO_CLASS_64) and \
+ (elf_header.e_ident[ELFINFO_CLASS_INDEX] != ELFINFO_CLASS_32)) or \
+ (elf_header.e_ident[ELFINFO_VERSION_INDEX] != ELFINFO_VERSION_CURRENT):
+
+ return False
+ else:
+ return True
+
+#----------------------------------------------------------------------------
+# Perform file copy given offsets and the number of bytes to copy
+#----------------------------------------------------------------------------
+def file_copy_offset(in_fp, in_off, out_fp, out_off, num_bytes):
+ in_fp.seek(in_off)
+ read_in = in_fp.read(num_bytes)
+ out_fp.seek(out_off)
+ out_fp.write(read_in)
+
+ return num_bytes
+
+#----------------------------------------------------------------------------
+# sha1/sha256 hash routine wrapper
+#----------------------------------------------------------------------------
+def generate_hash(in_buf, is_sha256_algo):
+ # Initialize a SHA1 object from the Python hash library
+ if (is_sha256_algo is True):
+ m = hashlib.sha256()
+ else:
+ m = hashlib.sha1()
+
+ # Set the input buffer and return the output digest
+ m.update(in_buf)
+ return m.digest()
+
+#----------------------------------------------------------------------------
+# Initialize the hash program header.
+#----------------------------------------------------------------------------
+def initialize_hash_phdr(elf_in_file_name, hash_tbl_size, hdr_size, hdr_offset, is_elf64):
+ # Set hash header offset to page size boundary. Hash table will be
+ # located at first segment of elf image.
+ hash_hdr_size = hdr_size
+ hash_hdr_offset = hdr_offset
+ hash_tbl_offset = hash_hdr_offset + hash_hdr_size
+ hash_tbl_end_addr = hash_tbl_offset + hash_tbl_size;
+ pad_hash_segment = (hash_tbl_end_addr) & (ELF_BLOCK_ALIGN-1)
+
+ # Update the hash table program header
+ if is_elf64 is True:
+ hash_Phdr = Elf64_Phdr('\0'*ELF64_PHDR_SIZE)
+ else:
+ hash_Phdr = Elf32_Phdr('\0'*ELF32_PHDR_SIZE)
+ hash_Phdr.p_flags = MI_PBT_ELF_HASH_SEGMENT
+ hash_Phdr.p_align = ELF_BLOCK_ALIGN
+ hash_Phdr.p_offset = hash_hdr_offset
+ hash_Phdr.p_memsz = hash_hdr_size + hash_tbl_size + (ELF_BLOCK_ALIGN - pad_hash_segment)
+ hash_Phdr.p_filesz = hash_hdr_size + hash_tbl_size
+ hash_Phdr.p_type = NULL_TYPE
+ hash_Phdr.p_vaddr = get_hash_address(elf_in_file_name)
+ hash_Phdr.p_paddr = hash_Phdr.p_vaddr
+
+ return [hash_Phdr, pad_hash_segment, hash_tbl_end_addr, hash_tbl_offset]
+
+#----------------------------------------------------------------------------
+# image_preamble
+#----------------------------------------------------------------------------
+def image_preamble(gen_dict, preamble_file_name, boot_sbl_header, num_of_pages=None):
+ # Generate the preamble file
+ preamble_fp = OPEN(preamble_file_name, 'wb')
+
+ # Initialize
+ max_size_verify = gen_dict['IMAGE_KEY_MAX_SIZE_OF_VERIFY_BUFFER']
+ flash_max_page = gen_dict['IMAGE_KEY_FLASH_AUTO_DETECT_MAX_PAGE']
+ flash_min_page = gen_dict['IMAGE_KEY_FLASH_AUTO_DETECT_MIN_PAGE']
+ autodetectpage = [int('0xFFFFFFFF',16)] * max_size_verify
+
+ # The first three entries in the preamble must include the following values
+ autodetectpage[0] = FLASH_CODE_WORD
+ autodetectpage[1] = MAGIC_NUM
+ if (num_of_pages == 64):
+ autodetectpage[2] = AUTODETECT_PAGE_SIZE_MAGIC_NUM64
+ elif (num_of_pages == 128):
+ autodetectpage[2] = AUTODETECT_PAGE_SIZE_MAGIC_NUM128
+ else:
+ autodetectpage[2] = AUTODETECT_PAGE_SIZE_MAGIC_NUM
+
+ # Package the list into binary data to be written to the preamble
+ s = struct.Struct('I' * max_size_verify)
+ packed_data = s.pack(*autodetectpage)
+
+ # Output preamble pages based on maximum/minimum page size support
+ for i in range(flash_max_page/flash_min_page):
+ preamble_fp.write(packed_data[:flash_min_page])
+
+ # Determine appropriate amount of padding for the preamble and
+ # update the boot_sbl_header accordingly
+ if gen_dict['IMAGE_KEY_BOOT_SMALL_PREAMBLE'] == 1:
+ boot_sbl_header.image_src += (flash_max_page + flash_min_page)
+ amount_to_write = flash_min_page
+ else:
+ boot_sbl_header.image_src += flash_max_page * 2
+ amount_to_write = flash_max_page
+
+ pad_file(preamble_fp, amount_to_write, PAD_BYTE_1)
+ preamble_fp.close()
+
+ return boot_sbl_header
+
+#----------------------------------------------------------------------------
+# Helper functions to parse ELF program headers
+#----------------------------------------------------------------------------
+def MI_PBT_SEGMENT_TYPE_VALUE(x):
+ return ( ((x) & MI_PBT_FLAG_SEGMENT_TYPE_MASK) >> MI_PBT_FLAG_SEGMENT_TYPE_SHIFT )
+
+def MI_PBT_PAGE_MODE_VALUE(x):
+ return ( ((x) & MI_PBT_FLAG_PAGE_MODE_MASK) >> MI_PBT_FLAG_PAGE_MODE_SHIFT )
+
+def MI_PBT_ACCESS_TYPE_VALUE(x):
+ return ( ((x) & MI_PBT_FLAG_ACCESS_TYPE_MASK) >> MI_PBT_FLAG_ACCESS_TYPE_SHIFT )
+
+def MI_PBT_CHECK_FLAG_TYPE(x):
+ return (MI_PBT_SEGMENT_TYPE_VALUE(x) != MI_PBT_HASH_SEGMENT) and \
+ (MI_PBT_ACCESS_TYPE_VALUE(x) != MI_PBT_NOTUSED_SEGMENT) and \
+ (MI_PBT_ACCESS_TYPE_VALUE(x) != MI_PBT_SHARED_SEGMENT)
+
+
+#----------------------------------------------------------------------------
+# Helper functions to open a file and return a valid file object
+#----------------------------------------------------------------------------
+def OPEN(file_name, mode):
+ try:
+ fp = open(file_name, mode)
+ except IOError:
+ raise RuntimeError, "The file could not be opened: " + file_name
+
+ # File open has succeeded with the given mode, return the file object
+ return fp
+
+#----------------------------------------------------------------------------
+# Helper functions to insert MCs in SBL1(Badger) if ENABLE_VIRTUAL_BLK is ON
+#----------------------------------------------------------------------------
+def insert_SBL1_magicCookie (env, target):
+ file = open(target, "rb")
+ #read the file contents
+ filedata = file.read()
+ length = len(filedata)
+ file.close()
+
+ if (length <= VIRTUAL_BLOCK_SIZE):
+ return None
+ else:
+ #remove the previous file
+ os.remove(target)
+ #generate new file for appending target data + required MCs
+ file = open(target, "ab")
+
+ while length > VIRTUAL_BLOCK_SIZE:
+ filedata_till_128kb = filedata[0:VIRTUAL_BLOCK_SIZE]
+ filedata_after_128kb = filedata[VIRTUAL_BLOCK_SIZE:length]
+
+ a = str(hex(FLASH_CODE_WORD))
+ mc1 = chr(int(a[8:10],16)) + chr(int(a[6:8],16)) + chr(int(a[4:6],16)) + chr(int(a[2:4],16))
+
+ b = str(hex(MAGIC_NUM))
+ mc2 = chr(int(b[8:10],16)) + chr(int(b[6:8],16)) + chr(int(b[4:6],16)) + chr(int(b[2:4],16))
+
+ c = str(hex(SBL_VIRTUAL_BLOCK_MAGIC_NUM))
+ mc3 = chr(int(c[8:10],16)) + chr(int(c[6:8],16)) + chr(int(c[4:6],16)) + chr(int(c[2:4],16))
+
+ MC_inserted_data = filedata_till_128kb + mc1 + mc2 + mc3
+ file.write(MC_inserted_data)
+
+ filedata = filedata_after_128kb
+ length = len(filedata)
+
+ #copy the leftover data (<128KB) in output file
+ if length > 0:
+ file.write(filedata)
+
+ #close the final output file
+ file.close()
+ # MC_insertion code end
+
+#----------------------------------------------------------------------------
+# Helper functions to remove MCs in SBL1(Badger)
+#----------------------------------------------------------------------------
+def remove_SBL1_magicCookie (env, target, dest):
+ file = open(target, "rb")
+ #read the file contents
+ filedata = file.read()
+ length = len(filedata)
+ file.close()
+
+ #generate new file for appending target data + required MCs
+ file = open(dest, "ab")
+
+ while length > VIRTUAL_BLOCK_SIZE:
+ filedata_till_128kb = filedata[0:VIRTUAL_BLOCK_SIZE]
+ # skipped 12 byte of Virtual Block Magic Cookie Header
+ filedata_after_128kb = filedata[VIRTUAL_BLOCK_SIZE+MAGIC_COOKIE_LENGTH:length]
+
+ file.write(filedata_till_128kb)
+
+ filedata = filedata_after_128kb
+ length = len(filedata)
+
+ #copy the leftover data (<128KB) in output file
+ if length > 0:
+ file.write(filedata)
+
+ #close the final output file
+ file.close()
+
+ # MC_removal code end
+
+#----------------------------------------------------------------------------
+# Helper functions to pad SBL1 image
+# min_size defaults to 256k
+# If page_size or num_of_pages is set to 0, the variable is unset
+#----------------------------------------------------------------------------
+def pad_SBL1_image (env, target, min_size_with_pad=MIN_IMAGE_SIZE_WITH_PAD, page_size=0, num_of_pages=0):
+ file = open(target, "rb")
+ #read the file contents
+ filedata = file.read()
+ length = len(filedata)
+ file.close()
+
+ multiple = 1
+ alignment = page_size * num_of_pages
+
+ if (length > alignment and alignment > 0):
+ import math
+ multiple = math.ceil(length/float(alignment))
+
+ final_image_size = max(min_size_with_pad, multiple * alignment)
+
+ if length < final_image_size:
+ sbl1_fp = open(target, 'ab')
+ pad_file (sbl1_fp, (final_image_size-length), PAD_BYTE_0)
+ sbl1_fp.close()
+
+ # SBL1 pad code end
+#----------------------------------------------------------------------------
+# HELPER FUNCTIONS END
+#----------------------------------------------------------------------------
diff --git a/util/qualcomm/mbncat.py b/util/qualcomm/mbncat.py
new file mode 100755
index 0000000000..c4da265f80
--- /dev/null
+++ b/util/qualcomm/mbncat.py
@@ -0,0 +1,200 @@
+#!/usr/bin/env python2
+# Copyright (c) 2014, The Linux Foundation. All rights reserved.
+#
+# Redistribution and use in source and binary forms, with or without
+# modification, are permitted provided that the following conditions are
+# met:
+# * Redistributions of source code must retain the above copyright
+# notice, this list of conditions and the following disclaimer.
+# * Redistributions in binary form must reproduce the above
+# copyright notice, this list of conditions and the following
+# disclaimer in the documentation and/or other materials provided
+# with the distribution.
+# * Neither the name of The Linux Foundation nor the names of its
+# contributors may be used to endorse or promote products derived
+# from this software without specific prior written permission.
+
+# THIS SOFTWARE IS PROVIDED "AS IS" AND ANY EXPRESS OR IMPLIED
+# WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+# MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT
+# ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS
+# BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+# CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+# SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
+# BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
+# WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
+# OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN
+# IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+import struct
+import sys
+import os
+
+"""A utility to generate ipq8064 uber SBL..
+
+The very first blob (aka 'uber SBL') read out of NOR SPI flash by the IPQ8064
+maskrom is supposed to be a concatenation of up to three binaries: one to run
+on the RPM, another one to run on the AP, and the third one - the actual
+coreboot bootblock.
+
+The uber SBL starts with the combined header descriptor of 80 bytes, with the
+first two 4 byte words set to certain values, and the total size of the
+payload saved at offsets 28 and 32.
+
+To generate the uber SBL this utility expects two or three input file names in
+the command line, the first file including the described header, and the
+following one(s) - in QCA MBN format. This allows to create the uber SBL in
+one or two invocations.
+
+The input files are concatenated together aligned at 256 byte boundary offset
+from the combined header. See Usage() below for more details.
+
+The resulting uber SBL file is prepended by the same combined header adjusted
+to reflect the new total file size.
+"""
+
+DEFAULT_OUTPUT_FILE_NAME = 'sbl-ro.mbn'
+
+class NorSbl:
+ """Object representing the uber SBL."""
+
+ NOR_SBL1_HEADER = '<II72s'
+ NOR_SBL1_HEADER_SZ = struct.calcsize(NOR_SBL1_HEADER)
+ ALIGNMENT = 256 # Make sure this == UBER_SBL_PAD_SIZE
+ NOR_CODE_WORD = 0x844bdcd1
+ MAGIC_NUM = 0x73d71034
+
+ def __init__(self, sbl1, verbose):
+ """Initialize the object and verify the first file in the sequence.
+
+ Args:
+ sbl1: string, the name of the first out of the three input blobs,
+ must be prepended by the combined header.
+ verbose: boolean, if True - print debug information on the console.
+ """
+ self.verbose = verbose
+ self.mbn_file_names = []
+ if self.verbose:
+ print 'Reading ' + sbl1
+
+ try:
+ self.sbl1 = open(sbl1, 'rb').read()
+ except IOError as e:
+ print 'I/O error({0}): {1}'.format(e.errno, e.strerror)
+ raise
+
+ (codeword, magic, _) = struct.unpack_from(
+ self.NOR_SBL1_HEADER, self.sbl1)
+
+ if codeword != self.NOR_CODE_WORD:
+ print '\n\nError: Unexpected Codeword!'
+ print 'Codeword : ' + ('0x%x' % self.NOR_CODE_WORD) + \
+ ' != ' + ('0x%x' % codeword)
+ sys.exit(-1)
+
+ if magic != self.MAGIC_NUM:
+ print '\n\nError: Unexpected Magic!'
+ print 'Magic : ' + ('0x%x' % self.MAGIC_NUM) + \
+ ' != ' + ('0x%x' % magic)
+ sys.exit(-1)
+
+ def Append(self, src):
+ """Add a file to the list of files to be concatenated"""
+ self.mbn_file_names.append(src)
+
+ def PadOutput(self, outfile, size):
+ """Pad output file to the required alignment.
+
+ Adds 0xff to the passed in file to get its size to the ALIGNMENT
+ boundary.
+
+ Args:
+ outfile: file handle of the file to be padded
+ size: int, current size of the file
+
+ Returns number of bytes in the added padding.
+ """
+
+ # Is padding needed?
+ overflow = size % self.ALIGNMENT
+ if overflow:
+ pad_size = self.ALIGNMENT - overflow
+ pad = '\377' * pad_size
+ outfile.write(pad)
+ if self.verbose:
+ print 'Added %d byte padding' % pad_size
+ return pad_size
+ return 0
+
+ def Create(self, out_file_name):
+ """Create the uber SBL.
+
+ Concatenate input files with the appropriate padding and update the
+ combined header to reflect the new blob size.
+
+ Args:
+ out_file_name: string, name of the file to save the generated uber
+ SBL in.
+ """
+ outfile = open(out_file_name, 'wb')
+ total_size = len(self.sbl1) - self.NOR_SBL1_HEADER_SZ
+ outfile.write(self.sbl1)
+
+ for mbn_file_name in self.mbn_file_names:
+ total_size += self.PadOutput(outfile, total_size)
+ mbn_file_data = open(mbn_file_name, 'r').read()
+ outfile.write(mbn_file_data)
+ if self.verbose:
+ print 'Added %s (%d bytes)' % (mbn_file_name,
+ len(mbn_file_data))
+ total_size += len(mbn_file_data)
+
+ outfile.seek(28)
+ outfile.write(struct.pack('<I', total_size))
+ outfile.write(struct.pack('<I', total_size))
+
+
+def Usage(v):
+ print '%s: [-v] [-h] [-o Output MBN] sbl1 sbl2 [bootblock]' % (
+ os.path.basename(sys.argv[0]))
+ print
+ print 'Concatenates up to three mbn files: two SBLs and a coreboot bootblock'
+ print ' -h This message'
+ print ' -v verbose'
+ print ' -o Output file name, (default: %s)\n' % DEFAULT_OUTPUT_FILE_NAME
+ sys.exit(v)
+
+def main():
+ verbose = 0
+ mbn_output = DEFAULT_OUTPUT_FILE_NAME
+ i = 0
+
+ while i < (len(sys.argv) - 1):
+ i += 1
+ if (sys.argv[i] == '-h'):
+ Usage(0) # doesn't return
+
+ if (sys.argv[i] == '-o'):
+ mbn_output = sys.argv[i + 1]
+ i += 1
+ continue
+
+ if (sys.argv[i] == '-v'):
+ verbose = 1
+ continue
+
+ break
+
+ argv = sys.argv[i:]
+ if len(argv) < 2 or len(argv) > 3:
+ Usage(-1)
+
+ nsbl = NorSbl(argv[0], verbose)
+
+ for mbnf in argv[1:]:
+ nsbl.Append(mbnf)
+
+ nsbl.Create(mbn_output)
+
+if __name__ == '__main__':
+ main()
diff --git a/util/qualcomm/qgpt.py b/util/qualcomm/qgpt.py
new file mode 100755
index 0000000000..51018361e1
--- /dev/null
+++ b/util/qualcomm/qgpt.py
@@ -0,0 +1,234 @@
+#!/usr/bin/python
+#============================================================================
+#
+#/** @file qgpt.py
+#
+# GENERAL DESCRIPTION
+# Generates QCom GPT header for wrapping Bootblock
+#
+# Copyright (c) 2018, The Linux Foundation. All rights reserved.
+#
+# Redistribution and use in source and binary forms, with or without
+# modification, are permitted provided that the following conditions are
+# met:
+# * Redistributions of source code must retain the above copyright
+# notice, this list of conditions and the following disclaimer.
+# * Redistributions in binary form must reproduce the above
+# copyright notice, this list of conditions and the following
+# disclaimer in the documentation and/or other materials provided
+# with the distribution.
+# * Neither the name of The Linux Foundation nor the names of its
+# contributors may be used to endorse or promote products derived
+# from this software without specific prior written permission.
+#
+# THIS SOFTWARE IS PROVIDED "AS IS" AND ANY EXPRESS OR IMPLIED
+# WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+# MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT
+# ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS
+# BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+# CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+# SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
+# BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
+# WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
+# OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN
+# IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+#
+#**/
+#
+
+import os
+import math
+import random
+import re
+import struct
+import sys
+import tempfile
+
+from binascii import crc32
+from optparse import OptionParser
+from types import *
+
+
+def UpdateMBR(options, GPTBlobBuffer):
+ i = 0x1BE
+ GPTBlobBuffer[i + 0] = 0x00 # not bootable
+ GPTBlobBuffer[i + 1] = 0x00 # head
+ GPTBlobBuffer[i + 2] = 0x01 # sector
+ GPTBlobBuffer[i + 3] = 0x00 # cylinder
+ GPTBlobBuffer[i + 4] = 0xEE # type
+ GPTBlobBuffer[i + 5] = 0xFF # head
+ GPTBlobBuffer[i + 6] = 0xFF # sector
+ GPTBlobBuffer[i + 7] = 0xFF # cylinder
+ GPTBlobBuffer[i + 8:i + 8 + 4] = [0x01, 0x00, 0x00, 0x00]
+
+ GPTBlobBuffer[i + 12:i + 16] = [0x00, 0x0f, 0x00, 0x00]
+
+ # magic byte for MBR partitioning - always at this location regardless of
+ # options.sector
+ GPTBlobBuffer[510:512] = [0x55, 0xAA]
+ return i
+
+
+def UpdatePartitionEntry(options, GPTBlobBuffer):
+
+ i = 2 * options.sector_size
+ # GUID of Boot Block
+ GPTBlobBuffer[i:i + 16] = [0x2c, 0xba, 0xa0, 0xde, 0xdd, 0xcb, 0x05, 0x48,
+ 0xb4, 0xf9, 0xf4, 0x28, 0x25, 0x1c, 0x3e, 0x98]
+ i += 16
+
+ #This is to set Unique Partition GUID. Below Hex Value is : 00ChezaBootblock00
+ GPTBlobBuffer[i:i + 16] = [0x00, 0x43, 0x68, 0x65, 0x7a, 0x61, 0x42, 0x6f,
+ 0x6f, 0x74, 0x62, 0x6c, 0x6f, 0x63, 0x6b, 0x00]
+ i += 16
+
+ # LBA of BootBlock Start Content
+ GPTBlobBuffer[i:i + 8] = [0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00]
+ i += 8
+
+ # End LBA of BootBlock Content
+ GPTBlobBuffer[i] = options.end_lba & 0xFF
+ GPTBlobBuffer[i+1] = (options.end_lba>>8) & 0xFF
+ GPTBlobBuffer[i+2] = (options.end_lba>>16) & 0xFF
+ GPTBlobBuffer[i+3] = (options.end_lba>>24) & 0xFF
+ GPTBlobBuffer[i+4] = (options.end_lba>>32) & 0xFF
+ GPTBlobBuffer[i+5] = (options.end_lba>>40) & 0xFF
+ GPTBlobBuffer[i+6] = (options.end_lba>>48) & 0xFF
+ GPTBlobBuffer[i+7] = (options.end_lba>>56) & 0xFF
+ i += 8
+
+ # Attributes
+ GPTBlobBuffer[i:i + 8] = [0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00]
+ i += 8
+
+ # Label
+ GPTBlobBuffer[i:i + 17] = [0x62, 0x00, 0x6f, 0x00, 0x6f, 0x00, 0x74, 0x00,
+ 0x62, 0x00, 0x6c, 0x00, 0x6f, 0x00, 0x63, 0x00, 0x6b]
+
+ return i
+
+def UpdateGPTHeader(options, GPTBlobBuffer):
+
+ i = options.sector_size
+ # Signature and Revision and HeaderSize i.e. "EFI PART" and 00 00 01 00
+ # and 5C 00 00 00
+ GPTBlobBuffer[i:i + 16] = [0x45, 0x46, 0x49, 0x20, 0x50, 0x41, 0x52, 0x54,
+ 0x00, 0x00, 0x01, 0x00, 0x5C, 0x00, 0x00, 0x00]
+ i += 16
+
+ # CRC is zeroed out till calculated later
+ GPTBlobBuffer[i:i + 4] = [0x00, 0x00, 0x00, 0x00]
+ i += 4
+
+ # Reserved, set to 0
+ GPTBlobBuffer[i:i + 4] = [0x00, 0x00, 0x00, 0x00]
+ i += 4
+
+ # Current LBA
+ GPTBlobBuffer[i:i + 8] = [0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00]
+ i += 8
+
+ # Backup LBA, No Backup Gpt Used
+ GPTBlobBuffer[i:i + 8] = [0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00]
+ i += 8
+
+ # First Usuable LBA (qc_sec + bootblock location)
+ GPTBlobBuffer[i:i + 8] = [0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00]
+ i += 8
+
+ # Last Usuable LBA (qc_sec + bootblock end location)
+ GPTBlobBuffer[i] = options.end_lba & 0xFF
+ GPTBlobBuffer[i+1] = (options.end_lba>>8) & 0xFF
+ GPTBlobBuffer[i+2] = (options.end_lba>>16) & 0xFF
+ GPTBlobBuffer[i+3] = (options.end_lba>>24) & 0xFF
+ GPTBlobBuffer[i+4] = (options.end_lba>>32) & 0xFF
+ GPTBlobBuffer[i+5] = (options.end_lba>>40) & 0xFF
+ GPTBlobBuffer[i+6] = (options.end_lba>>48) & 0xFF
+ GPTBlobBuffer[i+7] = (options.end_lba>>56) & 0xFF
+ i += 8
+
+ # GUID
+ GPTBlobBuffer[i:i + 16] = [0x32,0x1B,0x10,0x98,0xE2,0xBB,0xF2,0x4B,
+ 0xA0,0x6E,0x2B,0xB3,0x3D,0x00,0x0C,0x20]
+ i += 16
+
+ # Partition Table Entry LBA
+ GPTBlobBuffer[i:i + 8] = [0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00]
+ i += 8
+
+ # Number of Partition Entries
+ GPTBlobBuffer[i:i + 4] = [0x01, 0x00, 0x00, 0x00]
+ i += 4
+
+ # Size of One Partition Entry
+ GPTBlobBuffer[i:i + 4] = [0x80, 0x00, 0x00, 0x00]
+ i += 4
+
+ # CRC of Partition Entry
+
+ PartEntry = GPTBlobBuffer[options.sector_size*2:options.sector_size*2 + 128]
+ CalcEntryCRC = crc32(''.join(struct.pack("B", x) for x in PartEntry))
+
+ GPTBlobBuffer[i] = CalcEntryCRC & 0xFF
+ GPTBlobBuffer[i+1] = (CalcEntryCRC>>8) & 0xFF
+ GPTBlobBuffer[i+2] = (CalcEntryCRC>>16) & 0xFF
+ GPTBlobBuffer[i+3] = (CalcEntryCRC>>24) & 0xFF
+ i += 4
+
+ # CRC of Partition Table Header
+ GPTHeader = GPTBlobBuffer[options.sector_size:options.sector_size + 92]
+ CalcEntryCRC = crc32(''.join(struct.pack("B", x) for x in GPTHeader))
+ i = options.sector_size + 16
+
+ GPTBlobBuffer[i] = CalcEntryCRC & 0xFF
+ GPTBlobBuffer[i+1] = (CalcEntryCRC>>8) & 0xFF
+ GPTBlobBuffer[i+2] = (CalcEntryCRC>>16) & 0xFF
+ GPTBlobBuffer[i+3] = (CalcEntryCRC>>24) & 0xFF
+
+ return i
+
+
+if __name__ == '__main__':
+ usage = 'usage: %prog [OPTIONS] INFILE OUTFILE\n\n' + \
+ 'Packages IMAGE in a GPT format.'
+ parser = OptionParser(usage)
+ parser.add_option('-s', type="int", dest='sector_size', default=4096,
+ help='Sector size in bytes [Default:4096(4KB)]',
+ metavar='SIZE')
+
+ (options, args) = parser.parse_args()
+ if len(args) != 2:
+ print("Invalid arguments! Exiting...\n")
+ parser.print_help()
+ sys.exit(1)
+
+ if options.sector_size != 4096 and options.sector_size != 512:
+ print("Invalid Sector Size")
+ sys.exit(1)
+
+ options.inputfile = args[0]
+ options.outputfile = args[1]
+
+ with open(options.inputfile, 'r+') as fin:
+ bb_buffer = fin.read()
+
+ # Round up to next sector if bootblock size not evenly divisible
+ options.end_lba = ((len(bb_buffer) + options.sector_size - 1) /
+ options.sector_size)
+ # Add 3 sectors for MBR, GPT header and GPT partition entry
+ options.end_lba += 3
+ # Subtract one because this is last usable LBA, not amount of LBAs
+ options.end_lba -= 1
+
+ GPTBlobBuffer = [0] * (options.sector_size*3) #Size of MBR+GPT+PART_ENTRY
+
+ UpdateMBR(options, GPTBlobBuffer)
+
+ UpdatePartitionEntry(options, GPTBlobBuffer)
+
+ UpdateGPTHeader(options, GPTBlobBuffer)
+
+ with open(options.outputfile, 'wb') as fout:
+ for b in GPTBlobBuffer:
+ fout.write(struct.pack("B", b))
+ fout.write(bb_buffer)