· 7 years ago · Oct 03, 2018, 11:26 PM
1#===============================================================================
2#
3# MBN TOOLS
4#
5# GENERAL DESCRIPTION
6# Contains all MBN Utilities for image generation
7#
8# Copyright 2010-2013 by Qualcomm Technologies, Incorporated.
9# All Rights Reserved.
10# QUALCOMM Proprietary/GTDR
11#
12#-------------------------------------------------------------------------------
13#
14# $Header: //components/rel/core.adsp/2.2/bsp/build/scripts/mbn_tools.py#1 $
15# $DateTime: 2013/04/03 17:22:53 $
16# $Author: coresvc $
17# EDIT HISTORY FOR FILE
18#
19# This section contains comments describing changes made to the module.
20# Notice that changes are listed in reverse chronological order.
21#
22# when who what, where, why
23# -------- --- ---------------------------------------------------------
24# 03/18/13 dhaval Add support for hashing elf segments with SHA256 and
25# sync up to mpss, adsp mbn-tools
26# 01/14/13 kedara Remove dependency on .builds, cust<bid>.h, targ<bid>.h files
27# 08/30/12 kedara Add virtual block suppport
28# 02/24/12 dh Add ssd side effect file names
29# 07/08/11 aus Added support for image_id in SBL image header as required by PBL
30# Sahara mode
31# 10/20/11 dxiang Clean up
32#===============================================================================
33
34import stat
35import csv
36import itertools
37import struct
38import os
39import shutil
40import hashlib
41
42#----------------------------------------------------------------------------
43# GLOBAL VARIABLES BEGIN
44#----------------------------------------------------------------------------
45PAD_BYTE_1 = 255 # Padding byte 1s
46PAD_BYTE_0 = 0 # Padding byte 0s
47SHA256_SIGNATURE_SIZE = 256 # Support SHA256
48MAX_NUM_ROOT_CERTS = 4 # Maximum number of OEM root certificates
49MI_BOOT_IMG_HDR_SIZE = 40 # sizeof(mi_boot_image_header_type)
50MI_BOOT_SBL_HDR_SIZE = 80 # sizeof(sbl_header)
51BOOT_HEADER_LENGTH = 20 # Boot Header Number of Elements
52SBL_HEADER_LENGTH = 20 # SBL Header Number of Elements
53FLASH_PARTI_VERSION = 3 # Flash Partition Version Number
54MAX_PHDR_COUNT = 100 # Maximum allowable program headers
55CERT_CHAIN_MAXSIZE = 6*1024 # Default Cert Chain Max Size
56VIRTUAL_BLOCK_SIZE = 131072 # Virtual block size for MCs insertion in SBL1 if ENABLE_VIRTUAL_BLK ON
57MAGIC_COOKIE_LENGTH = 12 # Length of magic Cookie inserted per VIRTUAL_BLOCK_SIZE
58
59# Magic numbers filled in for boot headers
60FLASH_CODE_WORD = 0x844BDCD1
61UNIFIED_BOOT_COOKIE_MAGIC_NUMBER = 0x33836685
62MAGIC_NUM = 0x73D71034
63AUTODETECT_PAGE_SIZE_MAGIC_NUM = 0x7D0B435A
64SBL_VIRTUAL_BLOCK_MAGIC_NUM = 0xD48B54C6
65
66# ELF Definitions
67ELF_HDR_SIZE = 52
68ELF_PHDR_SIZE = 32
69ELFINFO_MAG0_INDEX = 0
70ELFINFO_MAG1_INDEX = 1
71ELFINFO_MAG2_INDEX = 2
72ELFINFO_MAG3_INDEX = 3
73ELFINFO_MAG0 = '\x7f'
74ELFINFO_MAG1 = 'E'
75ELFINFO_MAG2 = 'L'
76ELFINFO_MAG3 = 'F'
77ELFINFO_CLASS_INDEX = 4
78ELFINFO_CLASS_32 = '\x01'
79ELFINFO_VERSION_INDEX = 6
80ELFINFO_VERSION_CURRENT = '\x01'
81ELF_BLOCK_ALIGN = 0x1000
82ALIGNVALUE_1MB = 0x100000
83ALIGNVALUE_4MB = 0x400000
84
85# ELF Program Header Types
86NULL_TYPE = 0x0
87LOAD_TYPE = 0x1
88DYNAMIC_TYPE = 0x2
89INTERP_TYPE = 0x3
90NOTE_TYPE = 0x4
91SHLIB_TYPE = 0x5
92PHDR_TYPE = 0x6
93TLS_TYPE = 0x7
94
95"""
96The eight bits between 20 and 27 in the p_flags field in ELF program headers
97is not used by the standard ELF format. We use this byte to hold OS and processor
98specific fields as recommended by ARM.
99
100The bits in this byte are defined as follows:
101
102 Pool Indx Segment type Access type Page/non page
103 bits in p_flags /-----27-----/----26-24-------/---- 23-21----/------20-------/
104
105After parsing segment description strings in the SCL file, the appropriate segment
106flag values are chosen from the follow definitions. The mask defined below is then
107used to update the existing p_flags field in the program headers with the updated
108values.
109"""
110# Mask for bits 20-27 to parse program header p_flags
111MI_PBT_FLAGS_MASK = 0x0FF00000
112
113# Helper defines to help parse ELF program headers
114MI_PROG_BOOT_DIGEST_SIZE = 20
115MI_PBT_FLAG_SEGMENT_TYPE_MASK = 0x07000000
116MI_PBT_FLAG_SEGMENT_TYPE_SHIFT = 0x18
117MI_PBT_FLAG_PAGE_MODE_MASK = 0x00100000
118MI_PBT_FLAG_PAGE_MODE_SHIFT = 0x14
119MI_PBT_FLAG_ACCESS_TYPE_MASK = 0x00E00000
120MI_PBT_FLAG_ACCESS_TYPE_SHIFT = 0x15
121MI_PBT_FLAG_POOL_INDEX_MASK = 0x08000000
122MI_PBT_FLAG_POOL_INDEX_SHIFT = 0x1B
123
124# Segment Type
125MI_PBT_L4_SEGMENT = 0x0
126MI_PBT_AMSS_SEGMENT = 0x1
127MI_PBT_HASH_SEGMENT = 0x2
128MI_PBT_BOOT_SEGMENT = 0x3
129MI_PBT_L4BSP_SEGMENT = 0x4
130MI_PBT_SWAPPED_SEGMENT = 0x5
131MI_PBT_SWAP_POOL_SEGMENT = 0x6
132MI_PBT_PHDR_SEGMENT = 0x7
133
134# Page/Non-Page Type
135MI_PBT_NON_PAGED_SEGMENT = 0x0
136MI_PBT_PAGED_SEGMENT = 0x1
137
138# Access Type
139MI_PBT_RW_SEGMENT = 0x0
140MI_PBT_RO_SEGMENT = 0x1
141MI_PBT_ZI_SEGMENT = 0x2
142MI_PBT_NOTUSED_SEGMENT = 0x3
143MI_PBT_SHARED_SEGMENT = 0x4
144
145# ELF Segment Flag Definitions
146MI_PBT_ELF_AMSS_NON_PAGED_RO_SEGMENT = 0x01200000
147MI_PBT_ELF_AMSS_PAGED_RO_SEGMENT = 0x01300000
148MI_PBT_ELF_SWAP_POOL_NON_PAGED_ZI_SEGMENT_INDEX0 = 0x06400000
149MI_PBT_ELF_SWAPPED_PAGED_RO_SEGMENT_INDEX0 = 0x05300000
150MI_PBT_ELF_SWAP_POOL_NON_PAGED_ZI_SEGMENT_INDEX1 = 0x0E400000
151MI_PBT_ELF_SWAPPED_PAGED_RO_SEGMENT_INDEX1 = 0x0D300000
152MI_PBT_ELF_AMSS_NON_PAGED_ZI_SEGMENT = 0x01400000
153MI_PBT_ELF_AMSS_PAGED_ZI_SEGMENT = 0x01500000
154MI_PBT_ELF_AMSS_NON_PAGED_RW_SEGMENT = 0x01000000
155MI_PBT_ELF_AMSS_PAGED_RW_SEGMENT = 0x01100000
156MI_PBT_ELF_AMSS_NON_PAGED_NOTUSED_SEGMENT = 0x01600000
157MI_PBT_ELF_AMSS_PAGED_NOTUSED_SEGMENT = 0x01700000
158MI_PBT_ELF_AMSS_NON_PAGED_SHARED_SEGMENT = 0x01800000
159MI_PBT_ELF_AMSS_PAGED_SHARED_SEGMENT = 0x01900000
160MI_PBT_ELF_HASH_SEGMENT = 0x02200000
161MI_PBT_ELF_BOOT_SEGMENT = 0x03200000
162MI_PBT_ELF_PHDR_SEGMENT = 0x07000000
163MI_PBT_ELF_NON_PAGED_L4BSP_SEGMENT = 0x04000000
164MI_PBT_ELF_PAGED_L4BSP_SEGMENT = 0x04100000
165MI_PBT_ELF_AMSS_RELOCATABLE_IMAGE = 0x8000000
166
167#----------------------------------------------------------------------------
168# GLOBAL VARIABLES END
169#----------------------------------------------------------------------------
170
171#----------------------------------------------------------------------------
172# CLASS DEFINITIONS BEGIN
173#----------------------------------------------------------------------------
174#----------------------------------------------------------------------------
175# OS Type ID Class
176#----------------------------------------------------------------------------
177class OSType:
178 BMP_BOOT_OS = 0
179 WM_BOOT_OS = 1
180 ANDROID_BOOT_OS = 2
181 CHROME_BOOT_OS = 3
182 SYMBIAN_BOOT_OS = 4
183 LINUX_BOOT_OS = 5
184
185#----------------------------------------------------------------------------
186# Image Type ID Class - These values must be kept consistent with mibib.h
187#----------------------------------------------------------------------------
188class ImageType:
189 NONE_IMG = 0
190 OEM_SBL_IMG = 1
191 AMSS_IMG = 2
192 QCSBL_IMG = 3
193 HASH_IMG = 4
194 APPSBL_IMG = 5
195 APPS_IMG = 6
196 HOSTDL_IMG = 7
197 DSP1_IMG = 8
198 FSBL_IMG = 9
199 DBL_IMG = 10
200 OSBL_IMG = 11
201 DSP2_IMG = 12
202 EHOSTDL_IMG = 13
203 NANDPRG_IMG = 14
204 NORPRG_IMG = 15
205 RAMFS1_IMG = 16
206 RAMFS2_IMG = 17
207 ADSP_Q5_IMG = 18
208 APPS_KERNEL_IMG = 19
209 BACKUP_RAMFS_IMG = 20
210 SBL1_IMG = 21
211 SBL2_IMG = 22
212 RPM_IMG = 23
213 SBL3_IMG = 24
214 TZ_IMG = 25
215
216#----------------------------------------------------------------------------
217# Global Image Type Table
218# Format of the look-up table:
219# KEY - IMAGE_TYPE string as passed into mbn_builder.py
220# VALUE - [Specific ImageType ID enum, Template key string, MBN Type]
221#----------------------------------------------------------------------------
222image_id_table = {
223 'appsbl': [ImageType.APPSBL_IMG, 'APPSBL_IMG', 'bin'],
224 'dbl': [ImageType.DBL_IMG, 'DBL_IMG', 'bin'],
225 'osbl': [ImageType.OSBL_IMG, 'OSBL_IMG', 'bin'],
226 'amss': [ImageType.AMSS_IMG, 'AMSS_IMG', 'elf'],
227 'amss_mbn': [ImageType.HASH_IMG, 'HASH_IMG', 'elf'],
228 'apps': [ImageType.APPS_IMG, 'APPS_IMG', 'bin'],
229 'hostdl': [ImageType.HOSTDL_IMG, 'HOSTDL_IMG', 'bin'],
230 'emmcbld': [ImageType.EHOSTDL_IMG, 'EMMCBLD_IMG', 'bin'],
231 'qdsp6fw': [ImageType.DSP1_IMG, 'DSP1_IMG', 'elf'],
232 'qdsp6sw': [ImageType.DSP2_IMG, 'DSP2_IMG', 'elf'],
233 'qdsp5': [ImageType.ADSP_Q5_IMG, 'ADSP_Q5_IMG', 'bin'],
234 'tz': [ImageType.TZ_IMG, 'TZ_IMG', 'elf'],
235 'tz_rumi': [ImageType.TZ_IMG, 'TZ_IMG', 'elf'],
236 'tz_virtio': [ImageType.TZ_IMG, 'TZ_IMG', 'elf'],
237 'tzbsp_no_xpu': [ImageType.TZ_IMG, 'TZ_IMG', 'elf'],
238 'tzbsp_with_test': [ImageType.TZ_IMG, 'TZ_IMG', 'elf'],
239 'rpm': [ImageType.RPM_IMG, 'RPM_IMG', 'elf'],
240 'sbl1': [ImageType.SBL1_IMG, 'SBL1_IMG', 'bin'],
241 'sbl2': [ImageType.SBL2_IMG, 'SBL2_IMG', 'bin'],
242 'sbl3': [ImageType.SBL3_IMG, 'SBL3_IMG', 'bin'],
243 'efs1': [ImageType.RAMFS1_IMG, 'RAMFS1_IMG', 'bin'],
244 'efs2': [ImageType.RAMFS2_IMG, 'RAMFS2_IMG', 'bin'],
245 # DO NOT add any additional image information
246}
247
248#----------------------------------------------------------------------------
249# Header Class Notes:
250# In order to properly read and write the header structures as binary data,
251# the Python Struct library is used to align and package up the header objects
252# All Struct objects are initialized by a special string with the following
253# notation. These structure objects are then used to decode binary data in order
254# to fill out the appropriate class in Python, or they are used to package up
255# the Python class so that we may write the binary data out.
256#----------------------------------------------------------------------------
257"""
258 Format | C Type | Python Type | Standard Size
259 -----------------------------------------------------
260 1) 'X's | char * | string | 'X' bytes
261 2) H | unsigned short | integer | 2 bytes
262 3) I | unsigned int | integer | 4 bytes
263
264"""
265
266#----------------------------------------------------------------------------
267# ELF Header Class
268#----------------------------------------------------------------------------
269class Elf32_Ehdr:
270 # Structure object to align and package the ELF Header
271 s = struct.Struct('16sHHIIIIIHHHHHH')
272
273 def __init__(self, data):
274 unpacked_data = (Elf32_Ehdr.s).unpack(data)
275 self.unpacked_data = unpacked_data
276 self.e_ident = unpacked_data[0]
277 self.e_type = unpacked_data[1]
278 self.e_machine = unpacked_data[2]
279 self.e_version = unpacked_data[3]
280 self.e_entry = unpacked_data[4]
281 self.e_phoff = unpacked_data[5]
282 self.e_shoff = unpacked_data[6]
283 self.e_flags = unpacked_data[7]
284 self.e_ehsize = unpacked_data[8]
285 self.e_phentsize = unpacked_data[9]
286 self.e_phnum = unpacked_data[10]
287 self.e_shentsize = unpacked_data[11]
288 self.e_shnum = unpacked_data[12]
289 self.e_shstrndx = unpacked_data[13]
290
291 def printValues(self):
292 print "ATTRIBUTE / VALUE"
293 for attr, value in self.__dict__.iteritems():
294 print attr, value
295
296 def getPackedData(self):
297 values = [self.e_ident,
298 self.e_type,
299 self.e_machine,
300 self.e_version,
301 self.e_entry,
302 self.e_phoff,
303 self.e_shoff,
304 self.e_flags,
305 self.e_ehsize,
306 self.e_phentsize,
307 self.e_phnum,
308 self.e_shentsize,
309 self.e_shnum,
310 self.e_shstrndx
311 ]
312
313 return (Elf32_Ehdr.s).pack(*values)
314
315#----------------------------------------------------------------------------
316# ELF Program Header Class
317#----------------------------------------------------------------------------
318class Elf32_Phdr:
319
320 # Structure object to align and package the ELF Program Header
321 s = struct.Struct('I' * 8)
322
323 def __init__(self, data):
324 unpacked_data = (Elf32_Phdr.s).unpack(data)
325 self.unpacked_data = unpacked_data
326 self.p_type = unpacked_data[0]
327 self.p_offset = unpacked_data[1]
328 self.p_vaddr = unpacked_data[2]
329 self.p_paddr = unpacked_data[3]
330 self.p_filesz = unpacked_data[4]
331 self.p_memsz = unpacked_data[5]
332 self.p_flags = unpacked_data[6]
333 self.p_align = unpacked_data[7]
334
335 def printValues(self):
336 print "ATTRIBUTE / VALUE"
337 for attr, value in self.__dict__.iteritems():
338 print attr, value
339
340 def getPackedData(self):
341 values = [self.p_type,
342 self.p_offset,
343 self.p_vaddr,
344 self.p_paddr,
345 self.p_filesz,
346 self.p_memsz,
347 self.p_flags,
348 self.p_align
349 ]
350
351 return (Elf32_Phdr.s).pack(*values)
352
353#----------------------------------------------------------------------------
354# ELF Segment Information Class
355#----------------------------------------------------------------------------
356class SegmentInfo:
357 def __init__(self):
358 self.flag = 0
359 self.start_addr = 0
360 def printValues(self):
361 print 'Flag: ' + str(self.flag)
362 print 'Start Address: ' + str(hex(self.start_addr))
363
364#----------------------------------------------------------------------------
365# Regular Boot Header Class
366#----------------------------------------------------------------------------
367class Boot_Hdr:
368 def __init__(self, init_val):
369 self.image_id = ImageType.NONE_IMG
370 self.flash_parti_ver = FLASH_PARTI_VERSION
371 self.image_src = init_val
372 self.image_dest_ptr = init_val
373 self.image_size = init_val
374 self.code_size = init_val
375 self.sig_ptr = init_val
376 self.sig_size = init_val
377 self.cert_chain_ptr = init_val
378 self.cert_chain_size = init_val
379 self.magic_number1 = init_val
380 self.version = init_val
381 self.OS_type = init_val
382 self.boot_apps_parti_entry = init_val
383 self.boot_apps_size_entry = init_val
384 self.boot_apps_ram_loc = init_val
385 self.reserved_ptr = init_val
386 self.reserved_1 = init_val
387 self.reserved_2 = init_val
388 self.reserved_3 = init_val
389
390 def getLength(self):
391 return BOOT_HEADER_LENGTH
392
393 def writePackedData(self, target, write_full_hdr):
394 values = [self.image_id,
395 self.flash_parti_ver,
396 self.image_src,
397 self.image_dest_ptr,
398 self.image_size,
399 self.code_size ,
400 self.sig_ptr,
401 self.sig_size,
402 self.cert_chain_ptr,
403 self.cert_chain_size,
404 self.magic_number1,
405 self.version,
406 self.OS_type,
407 self.boot_apps_parti_entry,
408 self.boot_apps_size_entry,
409 self.boot_apps_ram_loc,
410 self.reserved_ptr,
411 self.reserved_1,
412 self.reserved_2,
413 self.reserved_3 ]
414
415 # Write 10 entries(40B) or 20 entries(80B) of boot header
416 if write_full_hdr is False:
417 s = struct.Struct('I'* 10)
418 values = values[:10]
419 else:
420 s = struct.Struct('I' * self.getLength())
421
422 packed_data = s.pack(*values)
423
424 fp = OPEN(target,'wb')
425 fp.write(packed_data)
426 fp.close()
427
428 return s.size
429
430#----------------------------------------------------------------------------
431# SBL Boot Header Class
432#----------------------------------------------------------------------------
433class Sbl_Hdr:
434 def __init__(self, init_val):
435 self.codeword = init_val
436 self.magic = init_val
437 self.image_id = init_val
438 self.reserved_1 = init_val
439 self.reserved_2 = init_val
440 self.image_src = init_val
441 self.image_dest_ptr = init_val
442 self.image_size = init_val
443 self.code_size = init_val
444 self.sig_ptr = init_val
445 self.sig_size = init_val
446 self.cert_chain_ptr = init_val
447 self.cert_chain_size = init_val
448 self.oem_root_cert_sel = init_val
449 self.oem_num_root_certs = init_val
450 self.reserved_5 = init_val
451 self.reserved_6 = init_val
452 self.reserved_7 = init_val
453 self.reserved_8 = init_val
454 self.reserved_9 = init_val
455
456 def getLength(self):
457 return SBL_HEADER_LENGTH
458
459 def writePackedData(self, target):
460 values = [self.codeword,
461 self.magic,
462 self.image_id,
463 self.reserved_1,
464 self.reserved_2,
465 self.image_src,
466 self.image_dest_ptr,
467 self.image_size,
468 self.code_size,
469 self.sig_ptr,
470 self.sig_size,
471 self.cert_chain_ptr,
472 self.cert_chain_size,
473 self.oem_root_cert_sel,
474 self.oem_num_root_certs,
475 self.reserved_5,
476 self.reserved_6,
477 self.reserved_7,
478 self.reserved_8,
479 self.reserved_9 ]
480
481 s = struct.Struct('I' * self.getLength())
482 packed_data = s.pack(*values)
483
484 fp = OPEN(target,'wb')
485 fp.write(packed_data)
486 fp.close()
487
488 return s.size
489
490#----------------------------------------------------------------------------
491# CLASS DEFINITIONS END
492#----------------------------------------------------------------------------
493
494#------------------------------------------------------------------------------
495# Hooks for Scons
496#------------------------------------------------------------------------------
497def exists(env):
498 return env.Detect('mbn_tools')
499
500def generate(env):
501
502 #----------------------------------------------------------------------------
503 # Generate Global Dictionary
504 #----------------------------------------------------------------------------
505 generate_global_dict(env)
506
507 #----------------------------------------------------------------------------
508 # Assign Build Configurable Values
509 #----------------------------------------------------------------------------
510 init_build_vars(env)
511
512 #----------------------------------------------------------------------------
513 # Add Methods to Environment
514 #----------------------------------------------------------------------------
515 env.AddMethod(filter_dictionary, "FilterDictionary")
516 env.AddMethod(image_auth, "ImageAuth")
517 env.AddMethod(image_header, "ImageHeader")
518 env.AddMethod(pboot_gen_elf, "PBootGenElf")
519 env.AddMethod(pboot_add_hash, "PBootAddHash")
520 env.AddMethod(modify_elf_flags, "ModifyElfFlags")
521 env.AddMethod(generate_code_hash, "GenerateCodeHash")
522 env.AddMethod(insert_SBL1_magicCookie, "InsertSBLMagicCookie")
523 env.AddMethod(modify_relocatable_flags, "ModifyRelocatableFlags")
524
525 #----------------------------------------------------------------------------
526 # Load Encryption Tools and Methods if required
527 #----------------------------------------------------------------------------
528 if 'USES_ENCRYPT_MBN' in env:
529 # Add Encryption Tools to environment
530 env.Tool('pil_encrypt', toolpath = ['${BUILD_ROOT}/core/securemsm/ssd/tools/pil_encrypt'])
531 env.AddMethod(get_ssd_se_fname, "GetSSDSideEffectFileName")
532 env.AddMethod(encrypt_elf_segments, "EncryptElfSegments")
533 env.AddMethod(generate_meta_data, "GenerateMetaData")
534 env.AddMethod(encrypt_mbn, "EncryptMBN")
535 return None
536
537#----------------------------------------------------------------------------
538# BOOT TOOLS BEGIN
539#----------------------------------------------------------------------------
540
541#----------------------------------------------------------------------------
542# generate_meta_data
543#----------------------------------------------------------------------------
544def generate_meta_data(env, meta_out_file_name, add_magic_num = False):
545
546 '''
547 Make call to SSD API to return buffer filled with XML header information.
548 The XML header which we write contains information regarding the algorithms
549 being used along with specific key values which are to be used for encrpytion.
550 '''
551 xml_header = env.SSDGetMetaData(add_magic_num)
552
553 # Initialize
554 xml_target_file = open(meta_out_file_name,'wb')
555 xml_header_size = len(xml_header)
556
557 # Write XML buffer into target file
558 xml_target_file.write(xml_header)
559
560 # Pad if necessary to the maximum size
561 if xml_header_size <= XML_HEADER_MAXSIZE:
562 bytes_to_pad = XML_HEADER_MAXSIZE - xml_header_size
563 pad_file(xml_target_file, bytes_to_pad, PAD_BYTE_1)
564 xml_target_file.close()
565 else:
566 xml_target_file.close()
567 raise RuntimeError, "XML Size too large: " + str(xml_header_size)
568
569#----------------------------------------------------------------------------
570# encrypt_mbn
571#----------------------------------------------------------------------------
572def encrypt_mbn(env, mbn_in_file_name, mbn_out_file_name):
573 # Open Files
574 mbn_in_fp = OPEN(mbn_in_file_name, "rb")
575 mbn_out_fp = OPEN(mbn_out_file_name, "wb+")
576
577 # encrypt the input file content and write to output file
578 mbn_file_size = os.path.getsize(mbn_in_file_name)
579 file_buff = mbn_in_fp.read(mbn_file_size)
580 encrypted_buf = env.SSDEncryptSegment(0, file_buff, mbn_file_size)
581 mbn_out_fp.write(encrypted_buf)
582
583 # Close Files
584 mbn_in_fp.close()
585 mbn_out_fp.close()
586
587 # Clean up encryption files
588 env.SSDDeInit()
589
590#----------------------------------------------------------------------------
591# get_ssd_se_fname
592#----------------------------------------------------------------------------
593def get_ssd_se_fname(env):
594 return env.SSDGetSideEffectFileName()
595
596#----------------------------------------------------------------------------
597# encrypt_elf_segments
598#----------------------------------------------------------------------------
599def encrypt_elf_segments(env, elf_in_file_name,
600 elf_out_file_name):
601
602 # Open Files
603 elf_in_fp = OPEN(elf_in_file_name, "rb")
604 elf_out_fp = OPEN(elf_out_file_name, "wb+")
605
606 # Initialize
607 [elf_header, phdr_table] = preprocess_elf_file(elf_in_file_name)
608 encrypted_seg_counter = 0
609
610 # Copy input file to output file
611 shutil.copyfileobj(elf_in_fp, elf_out_fp, os.path.getsize(elf_in_file_name))
612
613 # Begin ELF segment encryption
614 for i in range(elf_header.e_phnum):
615 curr_phdr = phdr_table[i]
616
617 # Only encrypt segments of LOAD_TYPE. Do not encrypt the hash segment.
618 if curr_phdr.p_type == LOAD_TYPE and \
619 MI_PBT_SEGMENT_TYPE_VALUE(curr_phdr.p_flags) != MI_PBT_HASH_SEGMENT:
620
621 # Read full segment into buffer
622 elf_in_fp.seek(curr_phdr.p_offset)
623 data_len = curr_phdr.p_filesz
624 file_buff = elf_in_fp.read(data_len)
625
626 # Call encryption routine on buffer
627 encrypted_buf = env.SSDEncryptSegment(encrypted_seg_counter, file_buff, data_len)
628 encrypted_seg_counter += 1
629
630 # Write encrypted segment into output file in same location
631 elf_out_fp.seek(curr_phdr.p_offset)
632 elf_out_fp.write(encrypted_buf)
633
634 # Close Files
635 elf_in_fp.close()
636 elf_out_fp.close()
637
638 # Clean up encryption files
639 env.SSDDeInit()
640
641#----------------------------------------------------------------------------
642# image_header
643#----------------------------------------------------------------------------
644def image_header(env, gen_dict,
645 code_file_name,
646 output_file_name,
647 secure_type,
648 header_format = 'reg',
649 requires_preamble = False,
650 preamble_file_name = None,
651 elf_file_name = None,
652 write_full_hdr = False,
653 in_code_size = None):
654
655 # Preliminary checks
656 if (requires_preamble is True) and (preamble_file_name is None):
657 raise RuntimeError, "Image Header requires a preamble file"
658
659 if (gen_dict['IMAGE_KEY_MBN_TYPE'] == 'elf') and (elf_file_name is None):
660 raise RuntimeError, "ELF Image Headers require an elf file"
661
662 if (in_code_size is None) and (os.path.exists(code_file_name) is False):
663 raise RuntimeError, "Code size unavailable, and input file does not exist"
664
665 # Initialize
666 if in_code_size is not None:
667 code_size = in_code_size
668 else:
669 code_size = os.path.getsize(code_file_name)
670
671 image_dest = 0
672 image_source = 0
673
674 # If secure build, set signature and cert chain sizes
675 if secure_type == 'secure':
676 signature_size = SHA256_SIGNATURE_SIZE
677 cert_chain_size = CERT_CHAIN_MAXSIZE
678 image_size = code_size + cert_chain_size + signature_size
679 if (image_size % 4) != 0:
680 image_size += (4 - (image_size % 4))
681 else:
682 signature_size = 0
683 cert_chain_size = 0
684 image_size = code_size
685
686 # For ELF or hashed images, image destination will be determined from an ELF input file
687 if gen_dict['IMAGE_KEY_MBN_TYPE'] == 'elf':
688 image_dest = get_hash_address(elf_file_name) + MI_BOOT_IMG_HDR_SIZE
689 elif gen_dict['IMAGE_KEY_MBN_TYPE'] == 'bin':
690 image_dest = gen_dict['IMAGE_KEY_IMAGE_DEST']
691 image_source = gen_dict['IMAGE_KEY_IMAGE_SOURCE']
692
693 # Build the header based on format specified
694 if header_format == 'sbl':
695 boot_sbl_header = Sbl_Hdr(init_val = int('0xFFFFFFFF',16))
696 boot_sbl_header.codeword = FLASH_CODE_WORD
697 boot_sbl_header.magic = MAGIC_NUM
698 boot_sbl_header.image_id = gen_dict['IMAGE_KEY_IMAGE_ID']
699 boot_sbl_header.image_src = MI_BOOT_SBL_HDR_SIZE
700 boot_sbl_header.image_dest_ptr = image_dest
701 boot_sbl_header.image_size = image_size
702 boot_sbl_header.code_size = code_size
703 boot_sbl_header.sig_ptr = image_dest + code_size
704 boot_sbl_header.sig_size = signature_size
705 boot_sbl_header.cert_chain_ptr = image_dest + code_size + signature_size
706 boot_sbl_header.cert_chain_size = cert_chain_size
707 boot_sbl_header.oem_root_cert_sel = gen_dict['IMAGE_KEY_OEM_ROOT_CERT_SEL']
708 boot_sbl_header.oem_num_root_certs = gen_dict['IMAGE_KEY_OEM_NUM_ROOT_CERTS']
709
710 # If preamble is required, output the preamble file and update the boot_sbl_header
711 if requires_preamble is True:
712 boot_sbl_header = image_preamble(gen_dict, preamble_file_name, boot_sbl_header)
713
714 # Package up the header and write to output file
715 boot_sbl_header.writePackedData(target = output_file_name)
716
717 elif header_format == 'reg':
718 boot_header = Boot_Hdr(init_val = int('0x0',16))
719 boot_header.image_id = gen_dict['IMAGE_KEY_IMAGE_ID']
720 boot_header.image_src = image_source
721 boot_header.image_dest_ptr = image_dest
722 boot_header.image_size = image_size
723 boot_header.code_size = code_size
724 boot_header.sig_ptr = image_dest + code_size
725 boot_header.sig_size = signature_size
726 boot_header.cert_chain_ptr = image_dest + code_size + signature_size
727 boot_header.cert_chain_size = cert_chain_size
728
729 # Package up the header and write to output file
730 boot_header.writePackedData(target = output_file_name, write_full_hdr = write_full_hdr)
731
732 else:
733 raise RuntimeError, "Header format not supported: " + str(header_format)
734 return 0
735
736
737#----------------------------------------------------------------------------
738# pboot_gen_elf
739#----------------------------------------------------------------------------
740def pboot_gen_elf(env, elf_in_file_name,
741 hash_out_file_name,
742 elf_out_file_name,
743 secure_type = 'non_secure',
744 hash_seg_max_size = None,
745 last_phys_addr = None,
746 append_xml_hdr = False,
747 is_sha256_algo = True):
748 global MI_PROG_BOOT_DIGEST_SIZE
749 if (is_sha256_algo is True):
750 MI_PROG_BOOT_DIGEST_SIZE = 32
751
752 # Open Files
753 elf_in_fp = OPEN(elf_in_file_name, "rb")
754 hash_out_fp = OPEN(hash_out_file_name, "wb+")
755
756 if elf_out_file_name is not None:
757 elf_out_fp = OPEN(elf_out_file_name, "wb+")
758
759 # Initialize
760 [elf_header, phdr_table] = preprocess_elf_file(elf_in_file_name)
761 num_phdrs = elf_header.e_phnum
762 phdr_total_size = num_phdrs * elf_header.e_phentsize
763 phdr_size = elf_header.e_phentsize
764 hashtable_size = 0
765 hashtable_shift = 0
766 new_phdr = Elf32_Phdr('\0' * ELF_PHDR_SIZE)
767 hash = '\0' * MI_PROG_BOOT_DIGEST_SIZE
768 phdr_start = 0
769 bytes_to_pad = 0
770 hash_seg_end = 0
771
772 if elf_out_file_name is not None:
773 # Assert limit on number of program headers in input ELF
774 if num_phdrs > MAX_PHDR_COUNT:
775 raise RuntimeError, "Input ELF has exceeded maximum number of program headers"
776
777 # Create new program header for the ELF Header + Program Headers
778 new_phdr.p_type = NULL_TYPE
779 new_phdr.p_flags = MI_PBT_ELF_PHDR_SEGMENT
780
781 # Increment program header count
782 elf_header.e_phnum += 2
783
784 # Create an empty hash entry for PHDR_TYPE
785 hash_out_fp.write('\0' * MI_PROG_BOOT_DIGEST_SIZE)
786 hashtable_size += MI_PROG_BOOT_DIGEST_SIZE
787
788 # Create an empty hash entry for the hash segment itself
789 hash_out_fp.write('\0' * MI_PROG_BOOT_DIGEST_SIZE)
790 hashtable_size += MI_PROG_BOOT_DIGEST_SIZE
791
792 # Begin hash table generation
793 for i in range(num_phdrs):
794 curr_phdr = phdr_table[i]
795
796 if (MI_PBT_PAGE_MODE_VALUE(curr_phdr.p_flags) == MI_PBT_PAGED_SEGMENT):
797 seg_offset = curr_phdr.p_offset
798 seg_size = curr_phdr.p_filesz
799 hash_size = 0
800
801 # Check if the vaddr is page aligned
802 off = curr_phdr.p_vaddr & (ELF_BLOCK_ALIGN - 1)
803 if int(off) is not 0:
804 seg_size -= (ELF_BLOCK_ALIGN - off)
805 seg_offset += (ELF_BLOCK_ALIGN - off)
806
807 # Seg_size should be page aligned
808 if (seg_size & (ELF_BLOCK_ALIGN - 1)) > 0:
809 raise RuntimeError, "seg_size: " + hex(seg_size) + " is not ELF page aligned!"
810
811 off = seg_offset + seg_size
812
813 while seg_offset < off:
814
815 if seg_offset < ELF_BLOCK_ALIGN:
816 hash_size = seg_offset
817 else:
818 hash_size = ELF_BLOCK_ALIGN
819
820 elf_in_fp.seek(seg_offset)
821 fbuf = elf_in_fp.read(hash_size)
822
823 if MI_PBT_CHECK_FLAG_TYPE(curr_phdr.p_flags) is True:
824 hash = generate_hash(fbuf, is_sha256_algo)
825 else:
826 hash = '\0' * MI_PROG_BOOT_DIGEST_SIZE
827
828 # Write hash to file
829 hash_out_fp.write(hash)
830
831 hashtable_size += MI_PROG_BOOT_DIGEST_SIZE
832 seg_offset += ELF_BLOCK_ALIGN
833
834 # Copy the hash entry for all that are PAGED segments and those that are not the PHDR type. This is for
835 # backward tool compatibility where some images are generated using older exe tools.
836 elif((MI_PBT_PAGE_MODE_VALUE(curr_phdr.p_flags) == MI_PBT_NON_PAGED_SEGMENT) and (curr_phdr.p_type is not PHDR_TYPE)):
837 # Read full hash entry into buffer
838 elf_in_fp.seek(curr_phdr.p_offset)
839 data_len = curr_phdr.p_filesz
840 file_buff = elf_in_fp.read(data_len)
841
842 if (MI_PBT_CHECK_FLAG_TYPE(curr_phdr.p_flags) is True) and (data_len > 0):
843 hash = generate_hash(file_buff, is_sha256_algo)
844 else:
845 hash = '\0' * MI_PROG_BOOT_DIGEST_SIZE
846
847 # Write hash to file
848 hash_out_fp.write(hash)
849
850 hashtable_size += MI_PROG_BOOT_DIGEST_SIZE
851 # End hash table generation
852
853 if elf_out_file_name is not None:
854
855 # Preempt hash table size if necessary
856 if secure_type == 'secure':
857 hashtable_size += SHA256_SIGNATURE_SIZE + CERT_CHAIN_MAXSIZE
858
859 if append_xml_hdr is True:
860 hashtable_size += XML_HEADER_MAXSIZE
861
862 # Initialize the hash segment program header
863 [hash_Phdr, pad_hash_segment, hash_tbl_end_addr, hash_tbl_offset] = \
864 initialize_hash_phdr(elf_in_file_name, hashtable_size, MI_BOOT_IMG_HDR_SIZE, ELF_BLOCK_ALIGN)
865
866 # Check if hash segment max size parameter was passed
867 if (hash_seg_max_size is not None):
868 # Error checking for hash segment size validity
869 if hashtable_size > hash_seg_max_size:
870 raise RuntimeError, "Hash table exceeds maximum hash segment size: " + hex(hash_seg_max_size)
871 if (hash_seg_max_size & (ELF_BLOCK_ALIGN-1)) is not 0:
872 raise RuntimeError, "Hash segment size passed is not ELF Block Aligned: " + hex(hash_seg_max_size)
873
874 # Check if hash physical address parameter was passed
875 if last_phys_addr is not None:
876 hash_Phdr.p_vaddr = last_phys_addr
877 hash_Phdr.p_paddr = last_phys_addr
878
879 # Check if hash segment max size was passed
880 if hash_seg_max_size is not None:
881 hash_Phdr.p_memsz = hash_seg_max_size
882
883 # Determine the end of the hash segment, make sure it's block aligned
884 bytes_to_pad = ELF_BLOCK_ALIGN - pad_hash_segment
885 hash_seg_end = hash_tbl_end_addr + bytes_to_pad
886
887 # Check if a shifting is required to accomodate for the hash segment
888 curr_phdr = phdr_table[0]
889 if curr_phdr.p_offset < hash_seg_end:
890 hashtable_shift = hash_seg_end - curr_phdr.p_offset
891
892 # Move program headers to after ELF header
893 phdr_start = ELF_HDR_SIZE
894
895 # We copy over no section headers so assign these values to 0 in ELF Header
896 elf_header.e_shnum = 0
897 elf_header.e_shstrndx = 0
898 elf_header.e_shoff = 0
899
900 # Output remaining ELF segments
901 for i in range(num_phdrs):
902
903 # Increment the file offset before writing to the destination file
904 curr_phdr = phdr_table[i]
905
906 # We do not copy over program headers of PHDR type, decrement the program
907 # header count and continue the loop
908 if curr_phdr.p_type is PHDR_TYPE:
909 elf_header.e_phnum -= 1
910 continue
911
912 src_offset = curr_phdr.p_offset
913
914 # Copy the ELF segment
915 file_copy_offset(elf_in_fp, src_offset, elf_out_fp, curr_phdr.p_offset + hashtable_shift, curr_phdr.p_filesz)
916
917 # Assign new program header start location to the ELF header
918 elf_header.e_phoff = phdr_start
919
920 # Output new program headers which we have generated
921 elf_out_fp.seek(phdr_start)
922 new_phdr.p_filesz = ELF_HDR_SIZE + (elf_header.e_phnum * phdr_size)
923 elf_out_fp.write(new_phdr.getPackedData())
924 elf_out_fp.write(hash_Phdr.getPackedData())
925 phdr_start += (2 * phdr_size)
926
927 # Output all the remaining program headers in order
928 for i in range(num_phdrs):
929 curr_phdr = phdr_table[i]
930
931 if curr_phdr.p_type is PHDR_TYPE:
932 continue
933
934 curr_phdr.p_offset += hashtable_shift
935
936 # Copy the program header
937 elf_out_fp.seek(phdr_start)
938 elf_out_fp.write(curr_phdr.getPackedData())
939
940 # Update phdr_start
941 phdr_start += phdr_size
942
943 # Finally, copy the new ELF header to the destination file
944 elf_out_fp.seek(0)
945 elf_out_fp.write(elf_header.getPackedData())
946
947 # Recalculate hash of ELF + program headers and output to hash output file
948 elf_out_fp.seek(0)
949 # Read the elf header
950 elfhdr_buff = elf_out_fp.read(ELF_HDR_SIZE)
951 # Seek to the program header offset listed in elf header.
952 elf_out_fp.seek(elf_header.e_phoff)
953 # Read the program header and compute hash
954 proghdr_buff = elf_out_fp.read(elf_header.e_phnum * phdr_size)
955
956 hash = generate_hash(elfhdr_buff + proghdr_buff, is_sha256_algo)
957
958 # Write hash to file as first hash table entry
959 hash_out_fp.seek(0)
960 hash_out_fp.write(hash)
961
962 # Close files
963 elf_in_fp.close()
964 hash_out_fp.close()
965
966 if elf_out_file_name is not None:
967 elf_out_fp.close()
968
969 return 0
970
971
972#----------------------------------------------------------------------------
973# pboot_add_hash
974#----------------------------------------------------------------------------
975def pboot_add_hash(env, elf_in_file_name,
976 hash_tbl_file_name,
977 elf_out_file_name):
978
979 # Open files
980 elf_in_fp = OPEN(elf_in_file_name, "rb")
981 hash_tbl_fp = OPEN(hash_tbl_file_name, "rb")
982 elf_out_fp = OPEN(elf_out_file_name, "wb+")
983
984 # Initialize
985 [elf_header, phdr_table] = preprocess_elf_file(elf_in_file_name)
986
987 hash_size = os.path.getsize(hash_tbl_file_name)
988 hash_segment_found = False
989
990 # Attempt to find the location of the hash program header
991 for i in range(elf_header.e_phnum):
992 curr_phdr = phdr_table[i]
993 if curr_phdr.p_flags == MI_PBT_ELF_HASH_SEGMENT:
994 hash_segment_found = True
995 break
996
997 if hash_segment_found is True:
998 # Copy input file to output file
999 shutil.copyfileobj(elf_in_fp, elf_out_fp, os.path.getsize(elf_in_file_name))
1000
1001 # Update ELF to insert hash table at corresponding file offset
1002 hash_hdr_offset = curr_phdr.p_offset
1003 file_copy_offset(hash_tbl_fp, 0, elf_out_fp, hash_hdr_offset, hash_size)
1004
1005 else:
1006 raise RuntimeError, "Hash segment program header not found!"
1007
1008 # Close files
1009 elf_in_fp.close()
1010 hash_tbl_fp.close()
1011 elf_out_fp.close()
1012
1013 return 0
1014
1015#----------------------------------------------------------------------------
1016# image_auth
1017#----------------------------------------------------------------------------
1018def image_auth(env, *args):
1019
1020 if len(args) != 7:
1021 raise RuntimeError, "Usage Invalid"
1022
1023 # Initialize File Names
1024 binary_in = args[0]
1025 signature = args[1]
1026 attestation_cert = args[2]
1027 attestation_ca_cert = args[3]
1028 root_cert = args[4]
1029 cert_chain_out = args[5]
1030 signed_image_out = args[6]
1031
1032 # Creating list of certificates to support creation of certificate chains
1033 # of lenth 1, 2, or 3 certificates
1034 cert_list = []
1035 num_certs = 0
1036 if (os.path.exists(attestation_cert)):
1037 cert_list.append(attestation_cert)
1038 num_certs = num_certs + 1
1039 if (os.path.exists(attestation_ca_cert)):
1040 cert_list.append(attestation_ca_cert)
1041 num_certs = num_certs + 1
1042 if (os.path.exists(root_cert)):
1043 cert_list.append(root_cert)
1044 num_certs = num_certs + 1
1045
1046 if (num_certs == 0):
1047 raise RuntimeError, "Missing file(s) required for signing.\n"
1048
1049 # Create the Certificate Chain
1050 concat_files (cert_chain_out, cert_list)
1051
1052 # Pad to ensure Certificate Chain Size is CERT_CHAIN_MAX_SIZE
1053 cert_size = os.path.getsize(cert_chain_out)
1054
1055 if cert_size <= CERT_CHAIN_MAXSIZE:
1056 bytes_to_pad = CERT_CHAIN_MAXSIZE - cert_size
1057 cert_fp = OPEN(cert_chain_out,'ab')
1058 pad_file(cert_fp, bytes_to_pad, PAD_BYTE_1)
1059 cert_fp.close()
1060 else:
1061 raise RuntimeError, "Certificate Size too large: " + str(cert_size)
1062
1063 # Create the Final Signed Image File
1064 concat_files (signed_image_out, [binary_in, signature, cert_chain_out])
1065
1066 return 0
1067
1068#----------------------------------------------------------------------------
1069# modify_relocatable_flags
1070#----------------------------------------------------------------------------
1071def modify_relocatable_flags(env, output_elf ):
1072
1073 curr_phdr = Elf32_Phdr('\0' * ELF_PHDR_SIZE)
1074
1075 # Offset into program header where the p_flags field is stored
1076 phdr_align_flag_offset = 28
1077 phdr_reloc_flag_offset = 24
1078
1079 # Initialize
1080 [elf_header, phdr_table] = preprocess_elf_file(output_elf)
1081
1082 # Open files
1083 elf_in_fp = OPEN(output_elf, "r+")
1084
1085 # Go to the start of the p_flag entry in the first program header
1086 file_offset_align_flag = elf_header.e_phoff + phdr_align_flag_offset
1087
1088 # Change the align field in the program header in the ELF file
1089 elf_in_fp.seek(file_offset_align_flag)
1090 curr_phdr = phdr_table[0]
1091
1092 #default alignment value is 1MB unless otherwise specified
1093 if 'USES_RELOC_ALIGN_VALUE_4MB' in env:
1094 alignment_value = ALIGNVALUE_4MB
1095 else:
1096 alignment_value = ALIGNVALUE_1MB
1097
1098
1099
1100 #create new alignment value
1101 new_align = (curr_phdr.p_align & 0) | alignment_value
1102
1103 # Create structure to package new flag field
1104 s = struct.Struct('I')
1105 new_flag_bytes = s.pack(new_align)
1106
1107 # Write the new flag value and incr ement offset
1108 elf_in_fp.write(new_flag_bytes)
1109
1110 # Go to the start of the p_flag entry in the first program header
1111 file_offset_reloc_flag = elf_header.e_phoff + phdr_reloc_flag_offset
1112
1113 # Change each program header flag in the ELF file with relocatable flag
1114 for i in range(elf_header.e_phnum):
1115 # Seek to correct location and create new p_flag value
1116 elf_in_fp.seek(file_offset_reloc_flag)
1117 curr_phdr = phdr_table[i]
1118 new_flag = (curr_phdr.p_flags & ~MI_PBT_FLAGS_MASK) | (MI_PBT_ELF_AMSS_RELOCATABLE_IMAGE)
1119
1120 # Create structure to package new flag field
1121 s = struct.Struct('I')
1122 new_flag_bytes = s.pack(new_flag)
1123
1124 # Write the new flag value and increment offset
1125 elf_in_fp.write(new_flag_bytes)
1126 file_offset_reloc_flag += elf_header.e_phentsize
1127
1128 # Close files
1129 elf_in_fp.close()
1130
1131
1132 return 0
1133
1134
1135#----------------------------------------------------------------------------
1136# modify_elf_flags
1137#----------------------------------------------------------------------------
1138def modify_elf_flags(env, elf_in_file_name,
1139 scl_file_name):
1140
1141 curr_phdr = Elf32_Phdr('\0' * ELF_PHDR_SIZE)
1142 # Offset into program header where the p_flags field is stored
1143 phdr_flag_off = 24
1144
1145 # Initialize
1146 [elf_header, phdr_table] = preprocess_elf_file(elf_in_file_name)
1147 segment_list = readSCL(scl_file_name, env['GLOBAL_DICT'])
1148
1149 # Open files
1150 elf_in_fp = OPEN(elf_in_file_name, "r+")
1151
1152 # Check for corresponding number of segments
1153 if len(segment_list) is not elf_header.e_phnum:
1154 raise RuntimeError, 'SCL file and ELF file have different number of segments!'
1155
1156 # Go to the start of the p_flag entry in the first program header
1157 file_offset = elf_header.e_phoff + phdr_flag_off
1158
1159 # Change each program header flag in the ELF file based off the SCL file
1160 for i in range(elf_header.e_phnum):
1161 # Seek to correct location and create new p_flag value
1162 elf_in_fp.seek(file_offset)
1163 curr_phdr = phdr_table[i]
1164 new_flag = (curr_phdr.p_flags & ~MI_PBT_FLAGS_MASK) | (segment_list[i].flag)
1165
1166 # Create structure to package new flag field
1167 s = struct.Struct('I')
1168 new_flag_bytes = s.pack(new_flag)
1169
1170 # Write the new flag value and increment offset
1171 elf_in_fp.write(new_flag_bytes)
1172 file_offset += elf_header.e_phentsize
1173
1174 # Close files
1175 elf_in_fp.close()
1176
1177 return 0
1178
1179#----------------------------------------------------------------------------
1180# generate_code_hash
1181#----------------------------------------------------------------------------
1182def generate_code_hash(env, elf_in_file_name):
1183
1184 curr_phdr = Elf32_Phdr('\0' * ELF_PHDR_SIZE)
1185 # Offset into program header where the p_flags field is stored
1186 phdr_flag_off = 24
1187
1188 # Initialize
1189 [elf_header, phdr_table] = preprocess_elf_file(elf_in_file_name)
1190
1191 # Open files
1192 elf_in_fp = OPEN(elf_in_file_name, "rb+")
1193
1194 # Go to the start of the p_flag entry in the first program header
1195 file_offset = elf_header.e_phoff + phdr_flag_off
1196
1197 # XXX Get these from env?
1198 DP_CODE_ALIGN = 0x100
1199 DP_PAGE_SIZE = 4096
1200 DP_HASH_SIZE = 32 # SHA-256
1201 DP_HASH_MAGIC = 0xC0DEDEC0
1202 PH_PERM_RW = 0x06
1203 PH_PERM_RX = 0x05
1204 PH_PERM_RO = 0x04
1205 PH_PERM_MASK = 0x07
1206
1207 page_size = DP_PAGE_SIZE
1208 hash_size = DP_HASH_SIZE
1209
1210 # First identify the hash segment. It is the first RW section.
1211 # Its Align should be 8, and its size a multiple of DP_HASH_SIZE;
1212
1213 hash_seg_idx = -1
1214 for i in range(elf_header.e_phnum):
1215 curr_phdr = phdr_table[i]
1216
1217 if (curr_phdr.p_align == 8 and
1218 (curr_phdr.p_flags & PH_PERM_MASK) == PH_PERM_RW and
1219 curr_phdr.p_filesz != 0 and (curr_phdr.p_filesz % DP_HASH_SIZE) == 0):
1220 hash_seg_idx = i
1221 # Validate the contents of the hash segment. It should be
1222 # filled with DP_HASH_MAGIC
1223 elf_in_fp.seek(curr_phdr.p_offset)
1224 hash_data = "";
1225 while (len(hash_data) < curr_phdr.p_filesz):
1226 hash_data = hash_data + elf_in_fp.read(curr_phdr.p_filesz - len(hash_data))
1227
1228 hash_data = struct.unpack("I" * (curr_phdr.p_filesz / 4), hash_data)
1229
1230 for v in hash_data[:]:
1231 if (v != DP_HASH_MAGIC):
1232 hash_seg_idx = -1
1233 break;
1234
1235 if (hash_seg_idx != -1):
1236 break
1237
1238 if (hash_seg_idx == -1):
1239 # return if there is no hash segment.
1240 return 0
1241
1242 hash_phdr = phdr_table[hash_seg_idx]
1243
1244 # Now find the code segment for the hashes. Look for matching number of pages
1245 code_seg_idx = -1
1246 code_seg_pages = hash_phdr.p_filesz / DP_HASH_SIZE
1247
1248 for i in range(elf_header.e_phnum):
1249 curr_phdr = phdr_table[i]
1250 curr_pages = (curr_phdr.p_filesz + DP_PAGE_SIZE - 1) / DP_PAGE_SIZE
1251
1252 if (curr_phdr.p_align == DP_CODE_ALIGN and
1253 (curr_phdr.p_flags & PH_PERM_MASK) == PH_PERM_RX and
1254 curr_pages == code_seg_pages):
1255 if (code_seg_idx != -1):
1256 raise RuntimeError, 'Multiple code segments match for: ' + code_seg_pages + ' pages'
1257 code_seg_idx = i
1258
1259 if (code_seg_idx == -1):
1260 raise RuntimeError, 'No matching code segment found'
1261
1262 code_phdr = phdr_table[code_seg_idx]
1263
1264 # Now hash the pages in the code segment
1265 hashes = []
1266 elf_in_fp.seek(code_phdr.p_offset)
1267 bytes_left = code_phdr.p_filesz;
1268 while (bytes_left > 0):
1269 bytes_in_page = min(bytes_left, DP_PAGE_SIZE)
1270 page = "";
1271 while (len(page) < bytes_in_page):
1272 page = page + elf_in_fp.read(bytes_in_page - len(page))
1273 if (len(page) < DP_PAGE_SIZE):
1274 page = page + (struct.pack('b', 0) * (DP_PAGE_SIZE - len(page)))
1275 hashes = hashes + [generate_hash(page, True)]
1276 bytes_left -= bytes_in_page
1277
1278 # And write them to the hash segment
1279 elf_in_fp.seek(hash_phdr.p_offset)
1280
1281 for h in hashes[:]:
1282 elf_in_fp.write(h)
1283
1284 # Finally, mark the hash segment read-only
1285 phdr_flag_off = 24
1286 file_offset = elf_header.e_phoff + (elf_header.e_phentsize * hash_seg_idx) + phdr_flag_off
1287 elf_in_fp.seek(file_offset)
1288
1289 new_flag = (hash_phdr.p_flags & ~PH_PERM_MASK) | PH_PERM_RO
1290 s = struct.Struct('I')
1291 new_flag_bytes = s.pack(new_flag)
1292
1293 elf_in_fp.write(new_flag_bytes)
1294
1295 # Close files
1296 elf_in_fp.close()
1297
1298 return 0
1299
1300#----------------------------------------------------------------------------
1301# BOOT TOOLS END
1302#----------------------------------------------------------------------------
1303
1304#----------------------------------------------------------------------------
1305# HELPER FUNCTIONS BEGIN
1306#----------------------------------------------------------------------------
1307
1308#----------------------------------------------------------------------------
1309# Create a list to hold all segment information from an input SCL file
1310#----------------------------------------------------------------------------
1311def readSCL(filename, global_dict):
1312
1313 scl_fp = OPEN(filename,'r')
1314
1315 # Initialize
1316 file_data = scl_fp.readlines()
1317 num_lines = len(file_data)
1318 current_line = ''
1319 previous_line = ''
1320 strip_chars = '(){}[]'
1321 i = 0
1322 bracket_counter = 0
1323 seg_list = []
1324
1325 # Parse through all lines
1326 while i < num_lines:
1327
1328 # Save the last line read
1329 previous_line = current_line
1330 current_line = file_data[i]
1331
1332 # Look for the symbol '{' for the line to read.
1333 # Use bracket counter to skip nested '{ }'
1334 if ('{' in current_line):
1335 if bracket_counter is 0:
1336 # Create a new SegmentInfo class and set up tokens
1337 new_scl_entry = SegmentInfo()
1338 previous_line = previous_line.strip()
1339 tokens = previous_line.split(' ')
1340
1341 # Check that at least two tokens were parsed
1342 # Token 1: Segment Name
1343 # Token 2: Start Address
1344 if len(tokens) < 2:
1345 raise RuntimeError, 'SCL Segment Syntax malformed: ' + previous_line
1346
1347 # Get the segment flags corresponding to the segment name description
1348 new_scl_entry.flag = getSegmentFlag(tokens[0].strip(strip_chars))
1349
1350 # Get the start address of the segment based off the SCL string
1351 start_addr = tokens[1].strip(strip_chars)
1352 try:
1353 start_addr_final = eval(start_addr)
1354 # Catch NameError and attempt to locate start address from dictionary
1355 except NameError:
1356 if start_addr in global_dict:
1357 return global_dict[start_addr]
1358 else:
1359 raise RuntimeError, 'Unrecognized start address: ' + start_addr
1360
1361 new_scl_entry.start_addr = start_addr_final
1362 seg_list.append(new_scl_entry)
1363
1364 bracket_counter += 1
1365 elif '}' in current_line:
1366 bracket_counter -= 1
1367
1368 i+=1
1369
1370 scl_fp.close()
1371 return seg_list
1372
1373#----------------------------------------------------------------------------
1374# Given a string parsed from a SCL file, returns the ELF segment flags
1375#----------------------------------------------------------------------------
1376def getSegmentFlag(seg_info):
1377
1378 ret_val = None
1379
1380 # Define string values for various types of segments
1381 RO = "RO"
1382 RW = "RW"
1383 ZI = "ZI"
1384 PAGEABLE = "PAGED"
1385 NOTPAGEABLE = "NOTPAGED"
1386 SWAPABLE = "SWAPPED"
1387 SWAP_POOL = "SWAP_POOL"
1388 RESERVED = "RESERVED"
1389 HASHTBL = "HASH"
1390 SHARED = "SHARED"
1391 NOTUSED = "NOTUSED"
1392 BOOT_SEGMENT = "BOOT_SEGMENT"
1393 CODE = "CODE"
1394 L4BSP = "L4BSP"
1395 POOL_INDEX_0 = "INDEX_0"
1396 POOL_INDEX_1 = "INDEX_1"
1397
1398 if seg_info is None or len(seg_info) is 0:
1399 raise RuntimeError, 'Invalid segment information passed: ' + seg_info
1400
1401 # Conditional checks and assignments of the corresponding segment flag values
1402 if NOTPAGEABLE in seg_info:
1403 if RO in seg_info:
1404 ret_val = MI_PBT_ELF_AMSS_NON_PAGED_RO_SEGMENT
1405 elif CODE in seg_info:
1406 ret_val = MI_PBT_ELF_AMSS_NON_PAGED_RO_SEGMENT
1407 elif ZI in seg_info:
1408 if SWAP_POOL in seg_info:
1409 if POOL_INDEX_0 in seg_info:
1410 ret_val = MI_PBT_ELF_SWAP_POOL_NON_PAGED_ZI_SEGMENT_INDEX0
1411 else:
1412 ret_val = MI_PBT_ELF_SWAP_POOL_NON_PAGED_ZI_SEGMENT_INDEX1
1413 else:
1414 ret_val = MI_PBT_ELF_AMSS_NON_PAGED_ZI_SEGMENT
1415
1416 elif NOTUSED in seg_info:
1417 ret_val = MI_PBT_ELF_AMSS_NON_PAGED_NOTUSED_SEGMENT
1418
1419 elif SHARED in seg_info:
1420 ret_val = MI_PBT_ELF_AMSS_NON_PAGED_SHARED_SEGMENT
1421 elif HASHTBL in seg_info:
1422 ret_val = MI_PBT_ELF_HASH_SEGMENT
1423 elif BOOT_SEGMENT in seg_info:
1424 ret_val = MI_PBT_ELF_BOOT_SEGMENT
1425 elif L4BSP in seg_info:
1426 ret_val = MI_PBT_ELF_NON_PAGED_L4BSP_SEGMENT
1427 else:
1428 ret_val = MI_PBT_ELF_AMSS_NON_PAGED_RW_SEGMENT
1429
1430 elif PAGEABLE in seg_info:
1431 if RO in seg_info or CODE in seg_info:
1432 if SWAPABLE in seg_info:
1433 if POOL_INDEX_0 in seg_info:
1434 ret_val = MI_PBT_ELF_SWAPPED_PAGED_RO_SEGMENT_INDEX0
1435 else:
1436 ret_val = MI_PBT_ELF_SWAPPED_PAGED_RO_SEGMENT_INDEX1
1437 else:
1438 ret_val = MI_PBT_ELF_AMSS_PAGED_RO_SEGMENT
1439 elif ZI in seg_info:
1440 ret_val = MI_PBT_ELF_AMSS_PAGED_ZI_SEGMENT
1441
1442 elif NOTUSED in seg_info:
1443 ret_val = MI_PBT_ELF_AMSS_PAGED_NOTUSED_SEGMENT
1444 elif SHARED in seg_info:
1445 ret_val = MI_PBT_ELF_AMSS_PAGED_SHARED_SEGMENT
1446 elif L4BSP in seg_info:
1447 ret_val = MI_PBT_ELF_PAGED_L4BSP_SEGMENT
1448 else:
1449 ret_val = MI_PBT_ELF_AMSS_PAGED_RW_SEGMENT
1450
1451 else:
1452 raise RuntimeError, 'The segment name is wrongly defined in the SCL file: ' + seg_info
1453
1454 return ret_val
1455
1456#----------------------------------------------------------------------------
1457# Pad a file with specific number of bytes
1458# Note: Assumes the fp is seeked to the correct location of padding
1459#----------------------------------------------------------------------------
1460def pad_file(fp, num_bytes, value):
1461
1462 if num_bytes < 0:
1463 raise RuntimeError, "Number of bytes to pad must be greater than zero"
1464
1465 while num_bytes > 0:
1466 fp.write('%c' % value)
1467 num_bytes -= 1
1468
1469 return
1470
1471#----------------------------------------------------------------------------
1472# Concatenates the files listed in 'sources' in order and writes to 'target'
1473#----------------------------------------------------------------------------
1474def concat_files (target, sources):
1475 if type(sources) is not list:
1476 sources = [sources]
1477
1478 target_file = OPEN(target,'wb')
1479
1480 for fname in sources:
1481 file = OPEN(fname,'rb')
1482 while True:
1483 bin_data = file.read(65536)
1484 if not bin_data:
1485 break
1486 target_file.write(bin_data)
1487 file.close()
1488 target_file.close()
1489
1490#----------------------------------------------------------------------------
1491# Parse build configurable values and assign to global variables for tools
1492#----------------------------------------------------------------------------
1493def init_build_vars(env):
1494
1495 # Maximum size of Certificate Chain used in Secure Boot
1496 global CERT_CHAIN_MAXSIZE
1497 CERT_CHAIN_MAXSIZE = get_dict_value(env['GLOBAL_DICT'], 'CERT_CHAIN_MAXSIZE', (6*1024))
1498
1499 # Maximum size of the XML Header used in encrypted ELF images
1500 global XML_HEADER_MAXSIZE
1501 XML_HEADER_MAXSIZE = get_dict_value(env['GLOBAL_DICT'], 'XML_HEADER_MAXSIZE', (2*1024))
1502
1503#----------------------------------------------------------------------------
1504# Generates the global dictionary and add to the environment
1505#----------------------------------------------------------------------------
1506def generate_global_dict(env):
1507
1508 # Get file names for 'cust' and 'targ' auto-generated files inside 'build/ms'
1509 cust_h = env.subst('CUST${BUILD_ID}.H').lower()
1510 targ_h = env.subst('TARG${BUILD_ID}.H').lower()
1511 cust_file_name = str(env.FindFile(cust_h, "${INC_ROOT}/build/ms"))
1512 targ_file_name = str(env.FindFile(targ_h, "${INC_ROOT}/build/ms"))
1513
1514 # Check that files are present
1515 if (os.path.exists(cust_file_name) is True) and \
1516 (os.path.exists(targ_file_name) is True):
1517
1518 # Populate the dictionary from the auto-generated files
1519 global_dict = populate_dictionary(targ_file_name, cust_file_name)
1520 else:
1521 global_dict = {}
1522
1523 # Add the dictionary to the environment
1524 env.Replace(GLOBAL_DICT = global_dict)
1525
1526#----------------------------------------------------------------------------
1527# Populate the dictionary from a list of input files
1528#----------------------------------------------------------------------------
1529def populate_dictionary(*args):
1530
1531 if len(args) < 1:
1532 raise RuntimeError, "At least 1 file must be specified as an input"
1533
1534 global_dict = {}
1535 Fields = ["Define", "Key", "Value"]
1536
1537 # For each input file
1538 for i in range(len(args)):
1539
1540 template_file_path = args[i]
1541 instream = OPEN(template_file_path, 'r')
1542 # Tokenize each line with a white space
1543 values = csv.DictReader(instream, Fields, delimiter=" ")
1544
1545 for values in itertools.izip(values):
1546 new_entry = values[0]
1547 # Verify the parsed tokens
1548 if (new_entry['Define'] == '#define') and \
1549 (new_entry['Key'] != None) and \
1550 (new_entry['Value'] != None):
1551
1552 new_key = new_entry['Key'].strip()
1553 new_value = new_entry['Value'].strip()
1554
1555 # If value pair is empty string, assume feature definition is true
1556 if new_value == '':
1557 new_value = 'yes'
1558
1559 # Check for and handle text replacements as we parse
1560 if global_dict is not None and len(global_dict.keys()) > 0:
1561 for key in global_dict:
1562 new_value = new_value.replace(key, str(global_dict.get(key)))
1563
1564 # Attempt to evaluate value
1565 try:
1566 new_value = eval(new_value)
1567 # Catch exceptions and do not evaluate
1568 except:
1569 pass
1570
1571 # Add to global dictionary
1572 global_dict[new_key] = new_value
1573 instream.close()
1574
1575 return global_dict
1576
1577#----------------------------------------------------------------------------
1578# Filter out a generic dictionary from the global dictionary
1579#----------------------------------------------------------------------------
1580def filter_dictionary(env, global_dict, **kwargs):
1581
1582 # Check for Image Type
1583 # If IMAGE_TYPE parameter is not provided, raise error
1584 if not kwargs.has_key('IMAGE_TYPE'):
1585 raise RuntimeError, "IMAGE_TYPE must be defined to use FilterDictionary."
1586 else:
1587 image_type = kwargs.get('IMAGE_TYPE')
1588 if type(image_type) is not str:
1589 raise RuntimeError, "IMAGE_TYPE must be of string type."
1590
1591 # Check for Flash Type
1592 # If FLASH_TYPE parameter is not provided, default to 'nand'
1593 if not kwargs.has_key('FLASH_TYPE'):
1594 flash_type = 'nand'
1595 else:
1596 flash_type = kwargs.get('FLASH_TYPE')
1597 if type(flash_type) is not str:
1598 raise RuntimeError, "FLASH_TYPE must be of string type. "
1599
1600 # Check for MBN Type
1601 # If MBN_TYPE parameter is not provided, default to 'elf'
1602 if not kwargs.has_key('MBN_TYPE'):
1603 mbn_type = 'elf'
1604 else:
1605 mbn_type = kwargs.get('MBN_TYPE')
1606 if mbn_type != 'elf' and mbn_type != 'bin':
1607 raise RuntimeError, "MBN_TYPE currently not supported: " + mbn_type
1608
1609 # Check for Image ID
1610 # If IMAGE_ID parameter is not provided, default to ID 0
1611 if not kwargs.has_key('IMAGE_ID'):
1612 image_id = ImageType.NONE_IMG
1613 else:
1614 image_id = kwargs.get('IMAGE_ID')
1615 if type(image_id) is not int:
1616 raise RuntimeError, "IMAGE_ID must be of integer type."
1617
1618 # Initialize
1619 gen_dict = {}
1620 image_dest = 0
1621 image_source = 0
1622
1623 # Check for image_type
1624 if image_type not in image_id_table:
1625 id = image_id
1626 id_match_str = image_type.upper() + "_IMG"
1627 id_mbn_type = mbn_type
1628 else:
1629 id = image_id_table[image_type][0]
1630 id_match_str = image_id_table[image_type][1]
1631 id_mbn_type = image_id_table[image_type][2]
1632
1633 # Handle MBN Type and assign image destination address
1634 if id_mbn_type is 'elf':
1635 pass
1636 elif id_mbn_type is 'bin':
1637 template_key_match = 'IMAGE_KEY_' + id_match_str + "_DEST_ADDR"
1638 if template_key_match in global_dict:
1639 image_dest = global_dict[template_key_match]
1640 else:
1641 raise RuntimeError, "Builds file does not have IMAGE_KEY pair for: " + image_type
1642 else:
1643 raise RuntimeError, "MBN_TYPE currently not supported: " + mbn_type
1644
1645 # Assign generic dictionary key/value pairs
1646 gen_dict['IMAGE_KEY_IMAGE_ID'] = id
1647 gen_dict['IMAGE_KEY_IMAGE_DEST'] = image_dest
1648 gen_dict['IMAGE_KEY_IMAGE_SOURCE'] = image_source
1649 gen_dict['IMAGE_KEY_FLASH_TYPE'] = flash_type
1650 gen_dict['IMAGE_KEY_MBN_TYPE'] = id_mbn_type
1651 gen_dict['IMAGE_KEY_ID_MATCH_STR'] = id_match_str
1652 gen_dict['IMAGE_KEY_FLASH_AUTO_DETECT_MAX_PAGE'] = \
1653 get_dict_value(global_dict,'FLASH_AUTO_DETECT_MAX_PAGE', 8192)
1654 gen_dict['IMAGE_KEY_FLASH_AUTO_DETECT_MIN_PAGE'] = \
1655 get_dict_value(global_dict,'FLASH_AUTO_DETECT_MIN_PAGE', 2048)
1656 gen_dict['IMAGE_KEY_MAX_SIZE_OF_VERIFY_BUFFER'] = \
1657 get_dict_value(global_dict,'MAX_SIZE_OF_VERIFY_BUFFER', 8192)
1658 gen_dict['IMAGE_KEY_BOOT_SMALL_PREAMBLE'] = \
1659 get_dict_value(global_dict,'BOOT_SMALL_PREAMBLE', 1)
1660
1661 # Get OEM root certificate select and number
1662 oem_root_cert_sel = get_dict_value(global_dict,'OEM_ROOT_CERT_SEL', 1)
1663 oem_num_root_certs = get_dict_value(global_dict,'OEM_NUM_ROOT_CERTS', 1)
1664
1665 # Error checking for OEM configurable values
1666 if oem_root_cert_sel in range(1, MAX_NUM_ROOT_CERTS + 1) and \
1667 oem_num_root_certs in range(1, MAX_NUM_ROOT_CERTS + 1) and \
1668 oem_root_cert_sel <= oem_num_root_certs:
1669
1670 gen_dict['IMAGE_KEY_OEM_ROOT_CERT_SEL'] = oem_root_cert_sel
1671 gen_dict['IMAGE_KEY_OEM_NUM_ROOT_CERTS'] = oem_num_root_certs
1672
1673 else:
1674 raise RuntimeError, "Invalid OEM root certificate configuration values"
1675
1676 # Assign additional dictionary key/values pair as needed by tools.
1677
1678 return gen_dict
1679
1680
1681#----------------------------------------------------------------------------
1682# Get index value from dictionary if exists, otherwise return default
1683#----------------------------------------------------------------------------
1684def get_dict_value(dict, key_string, default):
1685
1686 key = 'IMAGE_KEY_' + key_string
1687
1688 if key in dict:
1689 return dict[key]
1690 else:
1691 return default
1692
1693#----------------------------------------------------------------------------
1694# Preprocess an ELF file and return the ELF Header Object and an
1695# array of ELF Program Header Objects
1696#----------------------------------------------------------------------------
1697def preprocess_elf_file(elf_file_name):
1698
1699 # Initialize
1700 elf_fp = OPEN(elf_file_name, 'rb')
1701 elf_header = Elf32_Ehdr(elf_fp.read(ELF_HDR_SIZE))
1702 phdr_table = []
1703
1704 # Verify ELF header information
1705 if verify_elf_header(elf_header) is False:
1706 raise RuntimeError, "ELF file failed verification: " + elf_file_name
1707
1708 # Get program header size
1709 phdr_size = elf_header.e_phentsize
1710
1711 # Find the program header offset
1712 file_offset = elf_header.e_phoff
1713 elf_fp.seek(file_offset)
1714
1715 # Read in the program headers
1716 for i in range(elf_header.e_phnum):
1717 phdr_table.append(Elf32_Phdr(elf_fp.read(phdr_size)))
1718
1719 elf_fp.close()
1720 return [elf_header, phdr_table]
1721
1722#----------------------------------------------------------------------------
1723# Get the hash table address from an input ELF file
1724#----------------------------------------------------------------------------
1725def get_hash_address(elf_file_name):
1726
1727 [elf_header, phdr_table] = preprocess_elf_file(elf_file_name)
1728
1729 last_paddr = 0
1730 last_paddr_segment = 0
1731
1732 # Find the segment with the largest physical address.
1733 # Hash segment's physical address will be immediately after this segment.
1734 for i in range(elf_header.e_phnum):
1735 curr_phdr = phdr_table[i]
1736 if curr_phdr.p_paddr > last_paddr:
1737 # Skip the demand paging segment as it would be outside the physical RAM location
1738 if MI_PBT_SEGMENT_TYPE_VALUE(curr_phdr.p_flags) != MI_PBT_SWAPPED_SEGMENT:
1739 last_paddr = curr_phdr.p_paddr;
1740 last_paddr_segment = i;
1741
1742 max_phdr = phdr_table[last_paddr_segment]
1743
1744 ret_val = (((max_phdr.p_paddr + max_phdr.p_memsz - 1) & \
1745 ~(ELF_BLOCK_ALIGN-1)) + ELF_BLOCK_ALIGN)
1746
1747 return ret_val
1748
1749#----------------------------------------------------------------------------
1750# Verify ELF header contents from an input ELF file
1751#----------------------------------------------------------------------------
1752def verify_elf_header(elf_header):
1753 if (elf_header.e_ident[ELFINFO_MAG0_INDEX] != ELFINFO_MAG0) or \
1754 (elf_header.e_ident[ELFINFO_MAG1_INDEX] != ELFINFO_MAG1) or \
1755 (elf_header.e_ident[ELFINFO_MAG2_INDEX] != ELFINFO_MAG2) or \
1756 (elf_header.e_ident[ELFINFO_MAG3_INDEX] != ELFINFO_MAG3) or \
1757 (elf_header.e_ident[ELFINFO_CLASS_INDEX] != ELFINFO_CLASS_32) or \
1758 (elf_header.e_ident[ELFINFO_VERSION_INDEX] != ELFINFO_VERSION_CURRENT):
1759
1760 return False
1761 else:
1762 return True
1763
1764#----------------------------------------------------------------------------
1765# Perform file copy given offsets and the number of bytes to copy
1766#----------------------------------------------------------------------------
1767def file_copy_offset(in_fp, in_off, out_fp, out_off, num_bytes):
1768 in_fp.seek(in_off)
1769 read_in = in_fp.read(num_bytes)
1770 out_fp.seek(out_off)
1771 out_fp.write(read_in)
1772
1773 return num_bytes
1774
1775#----------------------------------------------------------------------------
1776# sha1/sha256 hash routine wrapper
1777#----------------------------------------------------------------------------
1778def generate_hash(in_buf, is_sha256_algo):
1779 # Initialize a SHA1 object from the Python hash library
1780 if (is_sha256_algo is True):
1781 m = hashlib.sha256()
1782 else:
1783 m = hashlib.sha1()
1784
1785 # Set the input buffer and return the output digest
1786 m.update(in_buf)
1787 return m.digest()
1788
1789#----------------------------------------------------------------------------
1790# Initialize the hash program header.
1791#----------------------------------------------------------------------------
1792def initialize_hash_phdr(elf_in_file_name, hash_tbl_size, hdr_size, hdr_offset):
1793 # Set hash header offset to page size boundary. Hash table will be
1794 # located at first segment of elf image.
1795 hash_hdr_size = hdr_size
1796 hash_hdr_offset = hdr_offset
1797 hash_tbl_offset = hash_hdr_offset + hash_hdr_size
1798 hash_tbl_end_addr = hash_tbl_offset + hash_tbl_size;
1799 pad_hash_segment = (hash_tbl_end_addr) & (ELF_BLOCK_ALIGN-1)
1800
1801 # Update the hash table program header
1802 hash_Phdr = Elf32_Phdr('\0'*32)
1803 hash_Phdr.p_flags = MI_PBT_ELF_HASH_SEGMENT
1804 hash_Phdr.p_align = ELF_BLOCK_ALIGN
1805 hash_Phdr.p_offset = hash_hdr_offset
1806 hash_Phdr.p_memsz = hash_hdr_size + hash_tbl_size + (ELF_BLOCK_ALIGN - pad_hash_segment)
1807 hash_Phdr.p_filesz = hash_hdr_size + hash_tbl_size
1808 hash_Phdr.p_type = NULL_TYPE
1809 hash_Phdr.p_vaddr = get_hash_address(elf_in_file_name)
1810 hash_Phdr.p_paddr = hash_Phdr.p_vaddr
1811
1812 return [hash_Phdr, pad_hash_segment, hash_tbl_end_addr, hash_tbl_offset]
1813
1814#----------------------------------------------------------------------------
1815# image_preamble
1816#----------------------------------------------------------------------------
1817def image_preamble(gen_dict, preamble_file_name, boot_sbl_header):
1818 # Generate the preamble file
1819 preamble_fp = OPEN(preamble_file_name, 'wb')
1820
1821 # Initialize
1822 max_size_verify = gen_dict['IMAGE_KEY_MAX_SIZE_OF_VERIFY_BUFFER']
1823 flash_max_page = gen_dict['IMAGE_KEY_FLASH_AUTO_DETECT_MAX_PAGE']
1824 flash_min_page = gen_dict['IMAGE_KEY_FLASH_AUTO_DETECT_MIN_PAGE']
1825 autodetectpage = [int('0xFFFFFFFF',16)] * max_size_verify
1826
1827 # The first three entries in the preamble must include the following values
1828 autodetectpage[0] = FLASH_CODE_WORD
1829 autodetectpage[1] = MAGIC_NUM
1830 autodetectpage[2] = AUTODETECT_PAGE_SIZE_MAGIC_NUM
1831
1832 # Package the list into binary data to be written to the preamble
1833 s = struct.Struct('I' * max_size_verify)
1834 packed_data = s.pack(*autodetectpage)
1835
1836 # Output preamble pages based on maximum/minimum page size support
1837 for i in range(flash_max_page/flash_min_page):
1838 preamble_fp.write(packed_data[:flash_min_page])
1839
1840 # Determine appropriate amount of padding for the preamble and
1841 # update the boot_sbl_header accordingly
1842 if gen_dict['IMAGE_KEY_BOOT_SMALL_PREAMBLE'] == 1:
1843 boot_sbl_header.image_src += (flash_max_page + flash_min_page)
1844 amount_to_write = flash_min_page
1845 else:
1846 boot_sbl_header.image_src += flash_max_page * 2
1847 amount_to_write = flash_max_page
1848
1849 pad_file(preamble_fp, amount_to_write, PAD_BYTE_1)
1850 preamble_fp.close()
1851
1852 return boot_sbl_header
1853
1854#----------------------------------------------------------------------------
1855# Helper functions to parse ELF program headers
1856#----------------------------------------------------------------------------
1857def MI_PBT_SEGMENT_TYPE_VALUE(x):
1858 return ( ((x) & MI_PBT_FLAG_SEGMENT_TYPE_MASK) >> MI_PBT_FLAG_SEGMENT_TYPE_SHIFT )
1859
1860def MI_PBT_PAGE_MODE_VALUE(x):
1861 return ( ((x) & MI_PBT_FLAG_PAGE_MODE_MASK) >> MI_PBT_FLAG_PAGE_MODE_SHIFT )
1862
1863def MI_PBT_ACCESS_TYPE_VALUE(x):
1864 return ( ((x) & MI_PBT_FLAG_ACCESS_TYPE_MASK) >> MI_PBT_FLAG_ACCESS_TYPE_SHIFT )
1865
1866def MI_PBT_CHECK_FLAG_TYPE(x):
1867 return (MI_PBT_SEGMENT_TYPE_VALUE(x) != MI_PBT_HASH_SEGMENT) and \
1868 (MI_PBT_ACCESS_TYPE_VALUE(x) != MI_PBT_NOTUSED_SEGMENT) and \
1869 (MI_PBT_ACCESS_TYPE_VALUE(x) != MI_PBT_SHARED_SEGMENT)
1870
1871
1872#----------------------------------------------------------------------------
1873# Helper functions to open a file and return a valid file object
1874#----------------------------------------------------------------------------
1875def OPEN(file_name, mode):
1876 try:
1877 fp = open(file_name, mode)
1878 except IOError:
1879 raise RuntimeError, "The file could not be opened: " + file_name
1880
1881 # File open has succeeded with the given mode, return the file object
1882 return fp
1883
1884#----------------------------------------------------------------------------
1885# Helper functions to insert MCs in SBL1(Badger) if ENABLE_VIRTUAL_BLK is ON
1886#----------------------------------------------------------------------------
1887def insert_SBL1_magicCookie (env, target):
1888 file = open(target, "rb")
1889 #read the file contents
1890 filedata = file.read()
1891 length = len(filedata)
1892 file.close()
1893
1894 if (length <= VIRTUAL_BLOCK_SIZE):
1895 return None
1896 else:
1897 #remove the previous file
1898 os.remove(target)
1899 #generate new file for appending target data + required MCs
1900 file = open(target, "ab")
1901
1902 while length > VIRTUAL_BLOCK_SIZE:
1903 filedata_till_128kb = filedata[0:VIRTUAL_BLOCK_SIZE]
1904 filedata_after_128kb = filedata[VIRTUAL_BLOCK_SIZE:length]
1905
1906 a = str(hex(FLASH_CODE_WORD))
1907 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))
1908
1909 b = str(hex(MAGIC_NUM))
1910 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))
1911
1912 c = str(hex(SBL_VIRTUAL_BLOCK_MAGIC_NUM))
1913 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))
1914
1915 MC_inserted_data = filedata_till_128kb + mc1 + mc2 + mc3
1916 file.write(MC_inserted_data)
1917
1918 filedata = filedata_after_128kb
1919 length = len(filedata)
1920
1921 #copy the leftover data (<128KB) in output file
1922 if length > 0:
1923 file.write(filedata)
1924
1925 #close the final output file
1926 file.close()
1927 # MC_insertion code end
1928
1929#----------------------------------------------------------------------------
1930# Helper functions to remove MCs in SBL1(Badger)
1931#----------------------------------------------------------------------------
1932def remove_SBL1_magicCookie (env, target, dest):
1933 file = open(target, "rb")
1934 #read the file contents
1935 filedata = file.read()
1936 length = len(filedata)
1937 file.close()
1938
1939 #generate new file for appending target data + required MCs
1940 file = open(dest, "ab")
1941
1942 while length > VIRTUAL_BLOCK_SIZE:
1943 filedata_till_128kb = filedata[0:VIRTUAL_BLOCK_SIZE]
1944 # skipped 12 byte of Virtual Block Magic Cookie Header
1945 filedata_after_128kb = filedata[VIRTUAL_BLOCK_SIZE+MAGIC_COOKIE_LENGTH:length]
1946
1947 file.write(filedata_till_128kb)
1948
1949 filedata = filedata_after_128kb
1950 length = len(filedata)
1951
1952 #copy the leftover data (<128KB) in output file
1953 if length > 0:
1954 file.write(filedata)
1955
1956 #close the final output file
1957 file.close()
1958
1959 # MC_removal code end
1960
1961#----------------------------------------------------------------------------
1962# HELPER FUNCTIONS END
1963#----------------------------------------------------------------------------