xref: /aosp_15_r20/external/coreboot/util/qualcomm/createxbl.py (revision b9411a12aaaa7e1e6a6fb7c5e057f44ee179a49c)
1#!/usr/bin/env python3
2#============================================================================
3#
4#/** @file createxbl.py
5#
6# GENERAL DESCRIPTION
7#   Concatentates XBL segments into one ELF image
8#
9# SPDX-License-Identifier: BSD-3-Clause
10
11#**/
12#
13#----------------------------------------------------------------------------
14#
15#                      EDIT HISTORY FOR FILE
16#
17#  This section contains comments describing changes made to the module.
18#  Notice that changes are listed in reverse chronological order.
19#
20# when       who       what, where, why
21# --------   ---       ------------------------------------------------------
22# 05/21/19   rissha    Added --mbn_version to add MBN header accordingly
23# 03/26/18   tv        Added -e to enable extended MBNV5 support
24# 09/04/15   et        Added -x and -d to embed xbl_sec ELF
25# 02/11/15   ck        Fixed missing elf type check in ZI OOB feature
26# 11/04/14   ck        Updated calls to mbn_tools functions
27# 10/22/14   ck        Added -z option to remove out of bounds ZI segments when
28#                      converting from 64 to 32
29# 10/10/14   ck        Added -c option and logic to enable elf type swapping
30# 09/12/14   ck        Added single file logic
31# 08/29/14   ck        Added no_hash option
32# 08/29/14   ck        Refactored to use proper python arguments and cleaned code
33# 06/16/14   niting    xbl.mbn to xbl.elf
34# 05/28/14   niting    Initial revision
35#
36#============================================================================
37from optparse import OptionParser
38import os
39import sys
40import shutil
41import mbn_tools
42
43PAGE_SIZE       = 4096
44SEGMENT_ALIGN   = 16
45ELF32_HDR_SIZE  = 52
46ELF32_PHDR_SIZE = 32
47ELF64_HDR_SIZE  = 64
48ELF64_PHDR_SIZE = 56
49
50
51##############################################################################
52# main
53##############################################################################
54def main():
55  parser = OptionParser(usage='usage: %prog [options] arguments')
56
57  parser.add_option("-f", "--first_filepath",
58                    action="store", type="string", dest="elf_inp_file1",
59                    help="First ELF file to merge.")
60
61  parser.add_option("-s", "--second_filepath",
62                    action="store", type="string", dest="elf_inp_file2",
63                    help="Second ELF file to merge.")
64
65  parser.add_option("-x", "--xbl_sec_filepath",
66                    action="store", type="string", dest="elf_inp_xbl_sec",
67                    help="Second ELF file to merge.")
68
69  parser.add_option("-o", "--output_filepath",
70                    action="store", type="string", dest="binary_out",
71                    help="Merged filename and path.")
72
73  parser.add_option("-a", "--first_elf_arch",
74                    action="store", type="string", dest="elf_1_arch",
75                    help="First (and output) ELF file architecture.  '32' or '64'")
76
77  parser.add_option("-b", "--second_elf_arch",
78                    action="store", type="string", dest="elf_2_arch",
79                    help="Second ELF file architecture.  '32' or '64'")
80
81  parser.add_option("-d", "--xbl_sec_elf_arch",
82                    action="store", type="string", dest="elf_xbl_sec_arch",
83                    help="xbl_sec file architecture.  '32' or '64'")
84
85  parser.add_option("-c", "--output_elf_arch",
86                    action="store", type="string", dest="elf_out_arch",
87                    help="Output ELF file architecture. '32' or '64'" + \
88                         "  If not given defaults to first file arch.")
89
90  parser.add_option("-n", "--no_hash",
91                    action="store_true", dest="hash_image",
92                    help="Disables hashing of image after merging.")
93
94  parser.add_option("-z", "--zi_out_of_bounds",
95                    action="store_true", dest="zi_oob",
96                    help="Removes ZI segments that have addresses greater" + \
97                         " than 32 bits when converting from a 64 to 32 bit ELF")
98
99  parser.add_option("--mbn_version",
100                    action="store", type="int", dest="mbn_version",
101                    help="Add mbn header in elf image. '3', '5' or '6'")
102
103
104  (options, args) = parser.parse_args()
105  if not options.elf_inp_file1:
106    parser.error('First ELF filename not given')
107
108  if not options.binary_out:
109    parser.error('Output filename not given')
110
111  if not options.elf_1_arch:
112    parser.error('First ELF architecture not given')
113
114  if (not options.elf_1_arch == '64') and (not options.elf_1_arch == '32'):
115    parser.error('Invalid First ELF architecture given')
116
117  # Only evaluate elf_2_arch if two files are given for merging
118  if options.elf_inp_file2:
119    if (not options.elf_2_arch == '64') and (not options.elf_2_arch == '32'):
120      parser.error('Invalid Second ELF architecture given')
121
122  # Only evaluate elf_xbl_sec_arch if file is given
123  if options.elf_inp_xbl_sec:
124    if (not options.elf_xbl_sec_arch == '64') and (not options.elf_xbl_sec_arch == '32'):
125      parser.error('Invalid xbl_sec ELF architecture given')
126
127  # If output file architecture is given ensure it is either '32' or '64'
128  if options.elf_out_arch:
129    if (not options.elf_out_arch == '64') and (not options.elf_out_arch == '32'):
130      parser.error('Invalid Output ELF architecture given')
131
132
133  gen_dict = {}
134
135  elf_inp_file1 = options.elf_inp_file1
136
137  # It is valid for only one file to be "merged".  This essentially just
138  # strips off the section names.  If second file name is not given then
139  # set elf_inp_file2 to ""
140  if options.elf_inp_file2:
141    elf_inp_file2 = options.elf_inp_file2
142  else:
143    elf_inp_file2 = ""
144
145  # Do same for xbl_sec
146  elf_inp_xbl_sec = options.elf_inp_xbl_sec if options.elf_inp_xbl_sec else ""
147
148  binary_out = options.binary_out
149
150  if options.elf_1_arch == '64':
151    is_elf1_64_bit = True
152  else:
153    is_elf1_64_bit = False
154
155  # If second filename is not given then set is_elf2_64_bit to false so it
156  # can be passed even though it is not used.
157  if options.elf_inp_file2:
158    if options.elf_2_arch == '64':
159      is_elf2_64_bit = True
160    else:
161      is_elf2_64_bit = False
162  else:
163    is_elf2_64_bit = False
164
165  if options.elf_inp_xbl_sec:
166    if options.elf_xbl_sec_arch == '64':
167      is_elf_xbl_sec_64_bit = True
168    else:
169      is_elf_xbl_sec_64_bit = False
170  else:
171    is_elf_xbl_sec_64_bit = False
172
173  # If output ELF arch is given then set is_out_elf_64_bit accordingly.
174  # If not then default to be input1's setting
175  if options.elf_out_arch:
176    if options.elf_out_arch == '64':
177      is_out_elf_64_bit = True
178    else:
179      is_out_elf_64_bit = False
180  else:
181    is_out_elf_64_bit = is_elf1_64_bit
182
183
184  # Store ZI Out of Bounds value
185  if not options.zi_oob:
186    zi_oob_enabled = False
187  else:
188    zi_oob_enabled = True
189
190  header_version = 3
191
192  if options.elf_inp_xbl_sec:
193    header_version = 5
194
195  if options.mbn_version:
196    header_version = options.mbn_version
197
198  mbn_type = 'elf'
199  header_format = 'reg'
200  gen_dict['IMAGE_KEY_IMAGE_ID'] = mbn_tools.ImageType.APPSBL_IMG
201  #gen_dict['IMAGE_KEY_IMAGE_SOURCE'] = 0
202  #gen_dict['IMAGE_KEY_IMAGE_DEST'] = 0
203  gen_dict['IMAGE_KEY_MBN_TYPE'] = mbn_type
204  image_header_secflag = 'non_secure'
205
206  source_base = os.path.splitext(str(binary_out))[0]
207  target_base = os.path.splitext(str(binary_out))[0]
208  merged_elf = source_base + "_merged.elf"
209  source_elf = source_base + "_nohash.elf"
210  target_hash = target_base + ".hash"
211  target_hash_hd = target_base + "_hash.hd"
212  target_phdr_elf = target_base + "_phdr.pbn"
213  target_nonsec = target_base + "_combined_hash.mbn"
214
215
216  #print("Input file 1:", elf_inp_file1)
217  #print("Input file 2:", elf_inp_file2)
218  #print("Output file:", binary_out)
219
220  merge_elfs([],
221             elf_inp_file1,
222	     elf_inp_file2,
223       elf_inp_xbl_sec,
224	     merged_elf,
225	     is_elf1_64_bit,
226	     is_elf2_64_bit,
227       is_elf_xbl_sec_64_bit,
228	     is_out_elf_64_bit,
229	     zi_oob_enabled,
230	     header_version)
231
232
233  # Hash the image if user did not explicitly say not to
234  if options.hash_image:
235    # Just copy the merged elf to the final output name
236    shutil.move(merged_elf, binary_out)
237  else:
238    shutil.copy(merged_elf, source_elf)
239
240    # Create hash table
241    rv = mbn_tools.pboot_gen_elf([],
242                                 source_elf,
243				 target_hash,
244                                 elf_out_file_name = target_phdr_elf,
245                                 secure_type = image_header_secflag,
246                                 header_version = header_version )
247    if rv:
248       raise RuntimeError("Failed to run pboot_gen_elf")
249
250    # Create hash table header
251    rv = mbn_tools.image_header([],
252                                gen_dict,
253				target_hash,
254				target_hash_hd,
255                         	image_header_secflag,
256				elf_file_name = source_elf,
257				header_version = header_version)
258    if rv:
259       raise RuntimeError("Failed to create image header for hash segment")
260
261    files_to_cat_in_order = [target_hash_hd, target_hash]
262    mbn_tools.concat_files (target_nonsec, files_to_cat_in_order)
263
264    # Add the hash segment into the ELF
265    mbn_tools.pboot_add_hash([],
266                             target_phdr_elf,
267                             target_nonsec,
268			     binary_out)
269
270  return
271
272
273##############################################################################
274# roundup
275##############################################################################
276def roundup(x, precision):
277  return x if x % precision == 0 else (x + precision - (x % precision))
278
279##############################################################################
280# merge_elfs
281##############################################################################
282def merge_elfs(env,
283               elf_in_file_name1,
284               elf_in_file_name2,
285               elf_in_file_xbl_sec,
286               elf_out_file_name,
287               is_elf1_64_bit,
288               is_elf2_64_bit,
289               is_elf_xbl_sec_64_bit,
290	             is_out_elf_64_bit,
291	             zi_oob_enabled,
292	             header_version):
293
294  [elf_header1, phdr_table1] = \
295    mbn_tools.preprocess_elf_file(elf_in_file_name1)
296
297  # Check to make sure second file path exists before using
298  if elf_in_file_name2 != "":
299    [elf_header2, phdr_table2] = \
300      mbn_tools.preprocess_elf_file(elf_in_file_name2)
301
302  # Check to make sure xbl_sec file path exists before using
303  if elf_in_file_xbl_sec != "":
304    [elf_headerxblsec, phdr_tablexblsec] = \
305      mbn_tools.preprocess_elf_file(elf_in_file_xbl_sec)
306
307  # Open Files
308  elf_in_fp1 = mbn_tools.OPEN(elf_in_file_name1, "rb")
309  if elf_in_file_name2 != "":
310    elf_in_fp2 = mbn_tools.OPEN(elf_in_file_name2, "rb")
311  if elf_in_file_xbl_sec != "":
312    elf_in_fpxblsec = mbn_tools.OPEN(elf_in_file_xbl_sec, "rb")
313
314  if elf_out_file_name is not None:
315    elf_out_fp = mbn_tools.OPEN(elf_out_file_name, "wb+")
316
317
318  # Calculate the new program header size.  This is dependant on the output
319  # ELF type and number of program headers going into output.
320  if is_out_elf_64_bit:
321    phdr_total_size = elf_header1.e_phnum * ELF64_PHDR_SIZE
322    phdr_total_count = elf_header1.e_phnum
323  else:
324    phdr_total_size = elf_header1.e_phnum * ELF32_PHDR_SIZE
325    phdr_total_count = elf_header1.e_phnum
326
327
328  # This logic only applies if two files are to be merged
329  if elf_in_file_name2 != "":
330    if is_out_elf_64_bit:
331      phdr_total_size += elf_header2.e_phnum * ELF64_PHDR_SIZE
332      phdr_total_count += elf_header2.e_phnum
333    else:
334      phdr_total_size += elf_header2.e_phnum * ELF32_PHDR_SIZE
335      phdr_total_count += elf_header2.e_phnum
336
337  # Account for xbl_sec header if included
338  if elf_in_file_xbl_sec != "":
339    phdr_total_count += 1
340    if is_out_elf_64_bit:
341      phdr_total_size += ELF64_PHDR_SIZE
342    else:
343      phdr_total_size += ELF32_PHDR_SIZE
344
345  # Create a new ELF header for the output file
346  if is_out_elf_64_bit:
347    out_elf_header = mbn_tools.Elf64_Ehdr(b'\0' * ELF64_HDR_SIZE)
348    out_elf_header.e_phoff     = ELF64_HDR_SIZE
349    out_elf_header.e_ehsize    = ELF64_HDR_SIZE
350    out_elf_header.e_phentsize = ELF64_PHDR_SIZE
351    out_elf_header.e_machine   = 183
352    out_elf_header.e_ident     = str('\x7f' + 'E' + 'L' + 'F' + \
353                                 '\x02' + \
354                                 '\x01' + \
355                                 '\x01' + \
356                                 '\x00' + \
357			         '\x00' + \
358                                 ('\x00' * 7))
359
360    out_elf_header.e_entry     = elf_header1.e_entry
361  else:
362    out_elf_header = mbn_tools.Elf32_Ehdr(b'\0' * ELF32_HDR_SIZE)
363    out_elf_header.e_phoff     = ELF32_HDR_SIZE
364    out_elf_header.e_ehsize    = ELF32_HDR_SIZE
365    out_elf_header.e_phentsize = ELF32_PHDR_SIZE
366    out_elf_header.e_machine   = 40
367    out_elf_header.e_entry       = elf_header1.e_entry
368    out_elf_header.e_ident     = str('\x7f' + 'E' + 'L' + 'F' + \
369                                 '\x01' + \
370                                 '\x01' + \
371                                 '\x01' + \
372                                 '\x00' + \
373  	                         '\x00' + \
374                                 ('\x00' * 7))
375
376    # Address needs to be verified that it is not greater than 32 bits
377    # as it is possible to go from a 64 bit elf to 32.
378    if (elf_header1.e_entry > 0xFFFFFFFF):
379      print("ERROR: File 1's entry point is too large to convert.")
380      exit()
381    out_elf_header.e_entry     = elf_header1.e_entry
382
383  # Common header entries
384  out_elf_header.e_type        = 2
385  out_elf_header.e_version     = 1
386  out_elf_header.e_shoff       = 0
387  out_elf_header.e_flags       = 0
388  out_elf_header.e_shentsize   = 0
389  out_elf_header.e_shnum       = 0
390  out_elf_header.e_shstrndx    = 0
391
392
393  # If ZI OOB is enabled then it is possible that a segment could be discarded
394  # Scan for that instance and handle before setting e_phnum and writing header
395  # Ensure ELF output is 32 bit
396  if zi_oob_enabled == True and is_out_elf_64_bit == False:
397    for i in range(len(phdr_table1)):
398      if (phdr_table1[i].p_vaddr > 0xFFFFFFFF) or \
399         (phdr_table1[i].p_paddr > 0xFFFFFFFF):
400        if phdr_table1[i].p_filesz == 0:
401          phdr_total_count = phdr_total_count - 1
402
403    if elf_in_file_name2 != "":
404      for i in range(len(phdr_table2)):
405        if (phdr_table2[i].p_vaddr > 0xFFFFFFFF) or \
406           (phdr_table2[i].p_paddr > 0xFFFFFFFF):
407          if phdr_table2[i].p_filesz == 0:
408            phdr_total_count = phdr_total_count - 1
409    # Do not include xbl_sec in above calculation
410    # xbl_sec is to be treated as a single blob
411
412
413  # Now it is ok to populate the ELF header and write it out
414  out_elf_header.e_phnum = phdr_total_count
415
416  # write elf header
417  if is_out_elf_64_bit == False:
418    elf_out_fp.write(mbn_tools.Elf32_Ehdr.getPackedData(out_elf_header))
419  else:
420    elf_out_fp.write(mbn_tools.Elf64_Ehdr.getPackedData(out_elf_header))
421
422  phdr_offset = out_elf_header.e_phoff  # offset of where to put next phdr
423
424  # offset the start of the segments just after the program headers
425  segment_offset = roundup(out_elf_header.e_phoff + phdr_total_size, PAGE_SIZE)
426
427
428  # Output first elf data
429  for i in range(elf_header1.e_phnum):
430    curr_phdr = phdr_table1[i]
431
432    # Copy program header piece by piece to ensure possible conversion success
433    if is_out_elf_64_bit == True:
434      # Converting from 32 to 64 elf requires no data size validation
435      new_phdr = mbn_tools.Elf64_Phdr(b'\0' * ELF64_PHDR_SIZE)
436      new_phdr.p_type   = curr_phdr.p_type
437      new_phdr.p_offset = segment_offset
438      new_phdr.p_vaddr  = curr_phdr.p_vaddr
439      new_phdr.p_paddr  = curr_phdr.p_paddr
440      new_phdr.p_filesz = curr_phdr.p_filesz
441      new_phdr.p_memsz  = curr_phdr.p_memsz
442      new_phdr.p_flags  = curr_phdr.p_flags
443      new_phdr.p_align  = curr_phdr.p_align
444    else:
445      # Converting from 64 to 32 elf requires data size validation
446      # Note that there is an option to discard a segment if it is only ZI
447      # and its address is greater than 32 bits
448      new_phdr = mbn_tools.Elf32_Phdr(b'\0' * ELF32_PHDR_SIZE)
449      new_phdr.p_type   = curr_phdr.p_type
450      new_phdr.p_offset = segment_offset
451
452      if curr_phdr.p_vaddr > 0xFFFFFFFF:
453        if (zi_oob_enabled == True) and (curr_phdr.p_filesz == 0):
454          continue
455        else:
456          print("ERROR: File 1 VAddr is too large for conversion.")
457          exit()
458      new_phdr.p_vaddr  = curr_phdr.p_vaddr
459
460      if curr_phdr.p_paddr > 0xFFFFFFFF:
461        if (zi_oob_enabled == True) and (curr_phdr.p_filesz == 0):
462          continue
463        else:
464          print("ERROR: File 1 PAddr is too large for conversion.")
465          exit()
466      new_phdr.p_paddr  = curr_phdr.p_paddr
467
468      if curr_phdr.p_filesz > 0xFFFFFFFF:
469        print("ERROR: File 1 Filesz is too large for conversion.")
470        exit()
471      new_phdr.p_filesz = curr_phdr.p_filesz
472
473      if curr_phdr.p_memsz > 0xFFFFFFFF:
474        print("ERROR: File 1 Memsz is too large for conversion.")
475        exit()
476      new_phdr.p_memsz  = curr_phdr.p_memsz
477
478      if curr_phdr.p_flags > 0xFFFFFFFF:
479        print("ERROR: File 1 Flags is too large for conversion.")
480        exit()
481      new_phdr.p_flags  = curr_phdr.p_flags
482
483      if curr_phdr.p_align > 0xFFFFFFFF:
484        print("ERROR: File 1 Align is too large for conversion.")
485        exit()
486      new_phdr.p_align  = curr_phdr.p_align
487
488
489    #print("i=",i)
490    #print("phdr_offset=", phdr_offset)
491
492    # update output file location to next phdr location
493    elf_out_fp.seek(phdr_offset)
494    # increment phdr_offset to next location
495    phdr_offset += out_elf_header.e_phentsize
496
497    inp_data_offset = curr_phdr.p_offset # used to read data from input file
498
499#    print("inp_data_offset=")
500#    print(inp_data_offset)
501#
502#    print("curr_phdr.p_offset=")
503#    print(curr_phdr.p_offset)
504#
505#    print("curr_phdr.p_filesz=")
506#    print(curr_phdr.p_filesz)
507
508    # output current phdr
509    if is_out_elf_64_bit == False:
510      elf_out_fp.write(mbn_tools.Elf32_Phdr.getPackedData(new_phdr))
511    else:
512      elf_out_fp.write(mbn_tools.Elf64_Phdr.getPackedData(new_phdr))
513
514    # Copy the ELF segment
515    bytes_written = mbn_tools.file_copy_offset(elf_in_fp1,
516                 inp_data_offset,
517                                               elf_out_fp,
518                 new_phdr.p_offset,
519                                               new_phdr.p_filesz)
520
521    # update data segment offset to be aligned after previous segment
522    segment_offset += roundup(new_phdr.p_filesz, SEGMENT_ALIGN);
523  elf_in_fp1.close()
524
525  # Output second elf data if applicable
526  if elf_in_file_name2 != "":
527    for i in range(elf_header2.e_phnum):
528      curr_phdr = phdr_table2[i]
529
530      # Copy program header piece by piece to ensure possible conversion success
531      if is_out_elf_64_bit == True:
532        # Converting from 32 to 64 elf requires no data size validation
533        new_phdr = mbn_tools.Elf64_Phdr(b'\0' * ELF64_PHDR_SIZE)
534        new_phdr.p_type   = curr_phdr.p_type
535        new_phdr.p_offset = segment_offset
536        new_phdr.p_vaddr  = curr_phdr.p_vaddr
537        new_phdr.p_paddr  = curr_phdr.p_paddr
538        new_phdr.p_filesz = curr_phdr.p_filesz
539        new_phdr.p_memsz  = curr_phdr.p_memsz
540        new_phdr.p_flags  = curr_phdr.p_flags
541        new_phdr.p_align  = curr_phdr.p_align
542      else:
543        # Converting from 64 to 32 elf requires data size validation
544        # Note that there is an option to discard a segment if it is only ZI
545        # and its address is greater than 32 bits
546        new_phdr = mbn_tools.Elf32_Phdr(b'\0' * ELF32_PHDR_SIZE)
547        new_phdr.p_type   = curr_phdr.p_type
548        new_phdr.p_offset = segment_offset
549
550        if curr_phdr.p_vaddr > 0xFFFFFFFF:
551          if (zi_oob_enabled == True) and (curr_phdr.p_filesz == 0):
552            continue
553          else:
554            print("ERROR: File 2 VAddr is too large for conversion.")
555            exit()
556        new_phdr.p_vaddr  = curr_phdr.p_vaddr
557
558        if curr_phdr.p_paddr > 0xFFFFFFFF:
559          if (zi_oob_enabled == True) and (curr_phdr.p_filesz == 0):
560            continue
561          else:
562            print("ERROR: File 2 PAddr is too large for conversion.")
563            exit()
564        new_phdr.p_paddr  = curr_phdr.p_paddr
565
566        if curr_phdr.p_filesz > 0xFFFFFFFF:
567          print("ERROR: File 2 Filesz is too large for conversion.")
568          exit()
569        new_phdr.p_filesz = curr_phdr.p_filesz
570
571        if curr_phdr.p_memsz > 0xFFFFFFFF:
572          print("ERROR: File 2 Memsz is too large for conversion.")
573          exit()
574        new_phdr.p_memsz  = curr_phdr.p_memsz
575
576        if curr_phdr.p_flags > 0xFFFFFFFF:
577          print("ERROR: File 2 Flags is too large for conversion.")
578          exit()
579        new_phdr.p_flags  = curr_phdr.p_flags
580
581        if curr_phdr.p_align > 0xFFFFFFFF:
582          print("ERROR: File 2 Align is too large for conversion.")
583          exit()
584        new_phdr.p_align  = curr_phdr.p_align
585
586
587#     print("i=",i)
588#     print("phdr_offset=", phdr_offset)
589
590      # update output file location to next phdr location
591      elf_out_fp.seek(phdr_offset)
592      # increment phdr_offset to next location
593      phdr_offset += out_elf_header.e_phentsize
594
595      inp_data_offset = curr_phdr.p_offset # used to read data from input file
596
597#     print("inp_data_offset=")
598#     print(inp_data_offset)
599#
600#     print("curr_phdr.p_offset=")
601#     print(curr_phdr.p_offset)
602#
603#     print("curr_phdr.p_filesz=")
604#     print(curr_phdr.p_filesz)
605
606      # output current phdr
607      if is_out_elf_64_bit == False:
608        elf_out_fp.write(mbn_tools.Elf32_Phdr.getPackedData(new_phdr))
609      else:
610        elf_out_fp.write(mbn_tools.Elf64_Phdr.getPackedData(new_phdr))
611
612      # Copy the ELF segment
613      bytes_written = mbn_tools.file_copy_offset(elf_in_fp2,
614                                                 inp_data_offset,
615                                                 elf_out_fp,
616                                                 new_phdr.p_offset,
617                                                 new_phdr.p_filesz)
618
619      # update data segment offset to be aligned after previous segment
620      segment_offset += roundup(new_phdr.p_filesz, SEGMENT_ALIGN);
621    elf_in_fp2.close()
622
623  # Embed xbl_sec image if provided
624  if elf_in_file_xbl_sec != "":
625
626    # Scan pheaders in xbl_sec for segment that contains entry point address
627    entry_seg_offset = -1
628    entry_addr = elf_headerxblsec.e_entry
629    for i in range(elf_headerxblsec.e_phnum):
630      phdr = phdr_tablexblsec[i]
631      max_addr = phdr.p_vaddr + phdr.p_memsz
632      if phdr.p_vaddr <= entry_addr <= max_addr:
633        entry_seg_offset = phdr.p_offset
634        break
635    if entry_seg_offset == -1:
636      print("Error: Failed to find entry point in any segment!")
637      exit()
638    # magical equation for program header's phys and virt addr
639    phys_virt_addr = entry_addr - entry_seg_offset
640
641    if is_out_elf_64_bit:
642      # Converting from 32 to 64 elf requires no data size validation
643      new_phdr = mbn_tools.Elf64_Phdr(b'\0' * ELF64_PHDR_SIZE)
644      new_phdr.p_type   = 0x1
645      new_phdr.p_offset = segment_offset
646      new_phdr.p_vaddr  = phys_virt_addr
647      new_phdr.p_paddr  = phys_virt_addr
648      new_phdr.p_filesz = os.path.getsize(elf_in_file_xbl_sec)
649      new_phdr.p_memsz  = new_phdr.p_filesz
650      if header_version >= 5:
651        new_phdr.p_flags  = (0x5 |
652           (mbn_tools.MI_PBT_XBL_SEC_SEGMENT <<
653            mbn_tools.MI_PBT_FLAG_SEGMENT_TYPE_SHIFT));
654      else:
655        new_phdr.p_flags  = 0x5
656      new_phdr.p_align  = 0x1000
657    else:
658      # Converting from 64 to 32 elf requires data size validation
659      # Don't discard the segment containing xbl_sec, simply error out
660      # if the address is greater than 32 bits
661      new_phdr = mbn_tools.Elf32_Phdr(b'\0' * ELF32_PHDR_SIZE)
662      new_phdr.p_type   = 0x1 #
663      new_phdr.p_offset = segment_offset
664      if header_version >= 5:
665        new_phdr.p_flags  = (0x5 |
666          (mbn_tools.MI_PBT_XBL_SEC_SEGMENT <<
667           mbn_tools.MI_PBT_FLAG_SEGMENT_TYPE_SHIFT));
668      else:
669        new_phdr.p_flags  = 0x5
670      new_phdr.p_align  = 0x1000
671
672      if phys_virt_addr > 0xFFFFFFFF:
673        if zi_oob_enabled == False or curr_phdr.p_filesz != 0:
674          print("ERROR: File xbl_sec VAddr or PAddr is too big for conversion.")
675          exit()
676      new_phdr.p_vaddr  = phys_virt_addr
677      new_phdr.p_paddr  = phys_virt_addr
678
679      if os.path.getsize(elf_in_file_xbl_sec) > 0xFFFFFFFF:
680        print("ERROR: File xbl_sec Filesz is too big for conversion.")
681        exit()
682      new_phdr.p_filesz = os.path.getsize(elf_in_file_xbl_sec)
683      new_phdr.p_memsz  = new_phdr.p_filesz
684
685
686    # update output file location to next phdr location
687    elf_out_fp.seek(phdr_offset)
688    # increment phdr_offset to next location
689    phdr_offset += out_elf_header.e_phentsize
690    # Copy entire xbl_sec file, so start from byte 0
691    inp_data_offset = 0
692
693    # Output xbl_sec's phdr
694    elf_in_file_xbl_sec
695    if is_out_elf_64_bit == False:
696      elf_out_fp.write(mbn_tools.Elf32_Phdr.getPackedData(new_phdr))
697    else:
698      elf_out_fp.write(mbn_tools.Elf64_Phdr.getPackedData(new_phdr))
699
700    # Copy the ENTIRE xbl_sec image
701    bytes_written = mbn_tools.file_copy_offset(elf_in_fpxblsec,
702                                               inp_data_offset,
703                                               elf_out_fp,
704                                               new_phdr.p_offset,
705                                               new_phdr.p_filesz)
706    # update data segment offset to be aligned after previous segment
707    # Not necessary, unless appending more pheaders after this point
708    segment_offset += roundup(new_phdr.p_filesz, SEGMENT_ALIGN);
709
710    elf_in_fpxblsec.close()
711
712  elf_out_fp.close()
713
714  return 0
715
716
717main()
718