blob: 9abb96c72a11c7d81e49c82d3f65e3f52286d93c [file] [log] [blame]
T Michael Turney540b8ec2020-01-24 08:42:47 -08001#!/usr/bin/env python3
Varadarajan Narayanan2dfbd932016-04-21 16:06:06 +05302#===============================================================================
3#
4# MBN TOOLS
5#
6# GENERAL DESCRIPTION
7# Contains all MBN Utilities for image generation
8#
Patrick Georgi70517072020-05-10 18:47:05 +02009# SPDX-License-Identifier: BSD-3-Clause
10
Varadarajan Narayanan2dfbd932016-04-21 16:06:06 +053011#-------------------------------------------------------------------------------
12# EDIT HISTORY FOR FILE
13#
14# This section contains comments describing changes made to the module.
15# Notice that changes are listed in reverse chronological order.
16#
17# when who what, where, why
18# -------- --- ---------------------------------------------------------
T Michael Turneybcd62f52019-08-07 14:26:32 -070019# 05/21/18 rissha Added support for extended MBNV6 and Add support for hashing elf segments with SHA384
T Michael Turney101098c2018-05-01 15:59:37 -070020# 03/22/18 thiru Added support for extended MBNV5.
Varadarajan Narayanan2dfbd932016-04-21 16:06:06 +053021# 06/06/13 yliong CR 497042: Signed and encrypted image is corrupted. MRC features.
22# 03/18/13 dhaval Add support for hashing elf segments with SHA256 and
23# sync up to mpss, adsp mbn-tools
24# 01/14/13 kedara Remove dependency on .builds, cust<bid>.h, targ<bid>.h files
25# 08/30/12 kedara Add virtual block suppport
26# 02/24/12 dh Add ssd side effect file names
27# 07/08/11 aus Added support for image_id in SBL image header as required by PBL
28# Sahara mode
29# 10/20/11 dxiang Clean up
30#===============================================================================
31
32import stat
33import csv
34import itertools
35import struct
36import os
37import shutil
38import hashlib
39
40#----------------------------------------------------------------------------
41# GLOBAL VARIABLES BEGIN
42#----------------------------------------------------------------------------
T Michael Turneybcd62f52019-08-07 14:26:32 -070043PAD_BYTE_1 = 255 # Padding byte 1s
44PAD_BYTE_0 = 0 # Padding byte 0s
45SHA256_SIGNATURE_SIZE = 256 # Support SHA256
46MAX_NUM_ROOT_CERTS = 4 # Maximum number of OEM root certificates
47MI_BOOT_SBL_HDR_SIZE = 80 # sizeof(sbl_header)
48BOOT_HEADER_LENGTH = 20 # Boot Header Number of Elements
49SBL_HEADER_LENGTH = 20 # SBL Header Number of Elements
50MAX_PHDR_COUNT = 100 # Maximum allowable program headers
51CERT_CHAIN_ONEROOT_MAXSIZE = 6*1024 # Default Cert Chain Max Size for one root
52VIRTUAL_BLOCK_SIZE = 131072 # Virtual block size for MCs insertion in SBL1 if ENABLE_VIRTUAL_BLK ON
53MAGIC_COOKIE_LENGTH = 12 # Length of magic Cookie inserted per VIRTUAL_BLOCK_SIZE
54MIN_IMAGE_SIZE_WITH_PAD = 256*1024 # Minimum image size for sbl1 Nand based OTA feature
Varadarajan Narayanan2dfbd932016-04-21 16:06:06 +053055
T Michael Turneybcd62f52019-08-07 14:26:32 -070056SBL_AARCH64 = 0xF # Indicate that SBL is a Aarch64 image
57SBL_AARCH32 = 0x0 # Indicate that SBL is a Aarch32 image
Varadarajan Narayanan2dfbd932016-04-21 16:06:06 +053058
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
64AUTODETECT_PAGE_SIZE_MAGIC_NUM64 = 0x7D0B5436
65AUTODETECT_PAGE_SIZE_MAGIC_NUM128 = 0x7D0B6577
66SBL_VIRTUAL_BLOCK_MAGIC_NUM = 0xD48B54C6
67
68# ELF Definitions
69ELF_HDR_COMMON_SIZE = 24
70ELF32_HDR_SIZE = 52
71ELF32_PHDR_SIZE = 32
72ELF64_HDR_SIZE = 64
73ELF64_PHDR_SIZE = 56
74ELFINFO_MAG0_INDEX = 0
75ELFINFO_MAG1_INDEX = 1
76ELFINFO_MAG2_INDEX = 2
77ELFINFO_MAG3_INDEX = 3
T Michael Turney540b8ec2020-01-24 08:42:47 -080078ELFINFO_MAG0 = 127 # 0x7F
79ELFINFO_MAG1 = 69 # E
80ELFINFO_MAG2 = 76 # L
81ELFINFO_MAG3 = 70 # F
Varadarajan Narayanan2dfbd932016-04-21 16:06:06 +053082ELFINFO_CLASS_INDEX = 4
T Michael Turney540b8ec2020-01-24 08:42:47 -080083ELFINFO_CLASS_32 = 1
84ELFINFO_CLASS_64 = 2
Varadarajan Narayanan2dfbd932016-04-21 16:06:06 +053085ELFINFO_VERSION_INDEX = 6
T Michael Turney540b8ec2020-01-24 08:42:47 -080086ELFINFO_VERSION_CURRENT = 1
Varadarajan Narayanan2dfbd932016-04-21 16:06:06 +053087ELF_BLOCK_ALIGN = 0x1000
88ALIGNVALUE_1MB = 0x100000
89ALIGNVALUE_4MB = 0x400000
T Michael Turney540b8ec2020-01-24 08:42:47 -080090ELFINFO_DATA2LSB = b'\x01'
91ELFINFO_EXEC_ETYPE = b'\x02\x00'
92ELFINFO_ARM_MACHINETYPE = b'\x28\x00'
93ELFINFO_VERSION_EV_CURRENT = b'\x01\x00\x00\x00'
Varadarajan Narayanan2dfbd932016-04-21 16:06:06 +053094ELFINFO_SHOFF = 0x00
T Michael Turney540b8ec2020-01-24 08:42:47 -080095ELFINFO_PHNUM = b'\x01\x00'
Varadarajan Narayanan2dfbd932016-04-21 16:06:06 +053096ELFINFO_RESERVED = 0x00
97
98# ELF Program Header Types
99NULL_TYPE = 0x0
100LOAD_TYPE = 0x1
101DYNAMIC_TYPE = 0x2
102INTERP_TYPE = 0x3
103NOTE_TYPE = 0x4
104SHLIB_TYPE = 0x5
105PHDR_TYPE = 0x6
106TLS_TYPE = 0x7
107
108"""
109The eight bits between 20 and 27 in the p_flags field in ELF program headers
110is not used by the standard ELF format. We use this byte to hold OS and processor
111specific fields as recommended by ARM.
112
113The bits in this byte are defined as follows:
114
115 Pool Indx Segment type Access type Page/non page
116 bits in p_flags /-----27-----/----26-24-------/---- 23-21----/------20-------/
117
118After parsing segment description strings in the SCL file, the appropriate segment
119flag values are chosen from the follow definitions. The mask defined below is then
120used to update the existing p_flags field in the program headers with the updated
121values.
122"""
123# Mask for bits 20-27 to parse program header p_flags
124MI_PBT_FLAGS_MASK = 0x0FF00000
125
126# Helper defines to help parse ELF program headers
Varadarajan Narayanan2dfbd932016-04-21 16:06:06 +0530127MI_PBT_FLAG_SEGMENT_TYPE_MASK = 0x07000000
128MI_PBT_FLAG_SEGMENT_TYPE_SHIFT = 0x18
129MI_PBT_FLAG_PAGE_MODE_MASK = 0x00100000
130MI_PBT_FLAG_PAGE_MODE_SHIFT = 0x14
131MI_PBT_FLAG_ACCESS_TYPE_MASK = 0x00E00000
132MI_PBT_FLAG_ACCESS_TYPE_SHIFT = 0x15
133MI_PBT_FLAG_POOL_INDEX_MASK = 0x08000000
134MI_PBT_FLAG_POOL_INDEX_SHIFT = 0x1B
135
136# Segment Type
137MI_PBT_L4_SEGMENT = 0x0
138MI_PBT_AMSS_SEGMENT = 0x1
139MI_PBT_HASH_SEGMENT = 0x2
140MI_PBT_BOOT_SEGMENT = 0x3
141MI_PBT_L4BSP_SEGMENT = 0x4
142MI_PBT_SWAPPED_SEGMENT = 0x5
T Michael Turney101098c2018-05-01 15:59:37 -0700143MI_PBT_XBL_SEC_SEGMENT = 0x5
Varadarajan Narayanan2dfbd932016-04-21 16:06:06 +0530144MI_PBT_SWAP_POOL_SEGMENT = 0x6
145MI_PBT_PHDR_SEGMENT = 0x7
146
147# Page/Non-Page Type
148MI_PBT_NON_PAGED_SEGMENT = 0x0
149MI_PBT_PAGED_SEGMENT = 0x1
150
151# Access Type
152MI_PBT_RW_SEGMENT = 0x0
153MI_PBT_RO_SEGMENT = 0x1
154MI_PBT_ZI_SEGMENT = 0x2
155MI_PBT_NOTUSED_SEGMENT = 0x3
156MI_PBT_SHARED_SEGMENT = 0x4
157MI_PBT_RWE_SEGMENT = 0x7
158
159# ELF Segment Flag Definitions
160MI_PBT_ELF_AMSS_NON_PAGED_RO_SEGMENT = 0x01200000
161MI_PBT_ELF_AMSS_PAGED_RO_SEGMENT = 0x01300000
162MI_PBT_ELF_SWAP_POOL_NON_PAGED_ZI_SEGMENT_INDEX0 = 0x06400000
163MI_PBT_ELF_SWAPPED_PAGED_RO_SEGMENT_INDEX0 = 0x05300000
164MI_PBT_ELF_SWAP_POOL_NON_PAGED_ZI_SEGMENT_INDEX1 = 0x0E400000
165MI_PBT_ELF_SWAPPED_PAGED_RO_SEGMENT_INDEX1 = 0x0D300000
166MI_PBT_ELF_AMSS_NON_PAGED_ZI_SEGMENT = 0x01400000
167MI_PBT_ELF_AMSS_PAGED_ZI_SEGMENT = 0x01500000
168MI_PBT_ELF_AMSS_NON_PAGED_RW_SEGMENT = 0x01000000
169MI_PBT_ELF_AMSS_PAGED_RW_SEGMENT = 0x01100000
170MI_PBT_ELF_AMSS_NON_PAGED_NOTUSED_SEGMENT = 0x01600000
171MI_PBT_ELF_AMSS_PAGED_NOTUSED_SEGMENT = 0x01700000
172MI_PBT_ELF_AMSS_NON_PAGED_SHARED_SEGMENT = 0x01800000
173MI_PBT_ELF_AMSS_PAGED_SHARED_SEGMENT = 0x01900000
174MI_PBT_ELF_HASH_SEGMENT = 0x02200000
175MI_PBT_ELF_BOOT_SEGMENT = 0x03200000
176MI_PBT_ELF_PHDR_SEGMENT = 0x07000000
177MI_PBT_ELF_NON_PAGED_L4BSP_SEGMENT = 0x04000000
178MI_PBT_ELF_PAGED_L4BSP_SEGMENT = 0x04100000
179MI_PBT_ELF_AMSS_RELOCATABLE_IMAGE = 0x8000000
180
181# New definitions for EOS demap paging requirement
182# Bit 20 (0b) Bit 24-26(000): Non Paged = 0x0000_0000
183# Bit 20 (1b) Bit 24-26(000): Locked Paged = 0x0010_0000
184# Bit 20 (1b) Bit 24-26(001): Unlocked Paged = 0x0110_0000
185# Bit 20 (0b) Bit 24-26(011): non secure = 0x0310_0000
186MI_PBT_ELF_RESIDENT_SEGMENT = 0x00000000
187MI_PBT_ELF_PAGED_LOCKED_SEGMENT = 0x00100000
188MI_PBT_ELF_PAGED_UNLOCKED_SEGMENT = 0x01100000
189MI_PBT_ELF_UNSECURE_SEGMENT = 0x03100000
190#----------------------------------------------------------------------------
191# GLOBAL VARIABLES END
192#----------------------------------------------------------------------------
193
194#----------------------------------------------------------------------------
195# CLASS DEFINITIONS BEGIN
196#----------------------------------------------------------------------------
197#----------------------------------------------------------------------------
198# OS Type ID Class
199#----------------------------------------------------------------------------
200class OSType:
201 BMP_BOOT_OS = 0
202 WM_BOOT_OS = 1
203 ANDROID_BOOT_OS = 2
204 CHROME_BOOT_OS = 3
205 SYMBIAN_BOOT_OS = 4
206 LINUX_BOOT_OS = 5
207
208#----------------------------------------------------------------------------
209# Image Type ID Class - These values must be kept consistent with mibib.h
210#----------------------------------------------------------------------------
211class ImageType:
212 NONE_IMG = 0
213 OEM_SBL_IMG = 1
214 AMSS_IMG = 2
215 QCSBL_IMG = 3
216 HASH_IMG = 4
217 APPSBL_IMG = 5
218 APPS_IMG = 6
219 HOSTDL_IMG = 7
220 DSP1_IMG = 8
221 FSBL_IMG = 9
222 DBL_IMG = 10
223 OSBL_IMG = 11
224 DSP2_IMG = 12
225 EHOSTDL_IMG = 13
226 NANDPRG_IMG = 14
227 NORPRG_IMG = 15
228 RAMFS1_IMG = 16
229 RAMFS2_IMG = 17
230 ADSP_Q5_IMG = 18
231 APPS_KERNEL_IMG = 19
232 BACKUP_RAMFS_IMG = 20
233 SBL1_IMG = 21
234 SBL2_IMG = 22
235 RPM_IMG = 23
236 SBL3_IMG = 24
237 TZ_IMG = 25
238 PSI_IMG = 32
239
240#----------------------------------------------------------------------------
241# Global Image Type Table
242# Format of the look-up table:
243# KEY - IMAGE_TYPE string as passed into mbn_builder.py
244# VALUE - [Specific ImageType ID enum, Template key string, MBN Type]
245#----------------------------------------------------------------------------
246image_id_table = {
247 'appsbl': [ImageType.APPSBL_IMG, 'APPSBL_IMG', 'bin'],
248 'dbl': [ImageType.DBL_IMG, 'DBL_IMG', 'bin'],
249 'osbl': [ImageType.OSBL_IMG, 'OSBL_IMG', 'bin'],
250 'amss': [ImageType.AMSS_IMG, 'AMSS_IMG', 'elf'],
251 'amss_mbn': [ImageType.HASH_IMG, 'HASH_IMG', 'elf'],
252 'apps': [ImageType.APPS_IMG, 'APPS_IMG', 'bin'],
253 'hostdl': [ImageType.HOSTDL_IMG, 'HOSTDL_IMG', 'bin'],
254 'ehostdl': [ImageType.EHOSTDL_IMG, 'EHOSTDL_IMG', 'bin'],
255 'emmcbld': [ImageType.EHOSTDL_IMG, 'EMMCBLD_IMG', 'bin'],
256 'qdsp6fw': [ImageType.DSP1_IMG, 'DSP1_IMG', 'elf'],
257 'qdsp6sw': [ImageType.DSP2_IMG, 'DSP2_IMG', 'elf'],
258 'qdsp5': [ImageType.ADSP_Q5_IMG, 'ADSP_Q5_IMG', 'bin'],
259 'tz': [ImageType.TZ_IMG, 'TZ_IMG', 'elf'],
260 'tz_rumi': [ImageType.TZ_IMG, 'TZ_IMG', 'elf'],
261 'tz_virtio': [ImageType.TZ_IMG, 'TZ_IMG', 'elf'],
262 'tzbsp_no_xpu': [ImageType.TZ_IMG, 'TZ_IMG', 'elf'],
263 'tzbsp_with_test': [ImageType.TZ_IMG, 'TZ_IMG', 'elf'],
264 'rpm': [ImageType.RPM_IMG, 'RPM_IMG', 'elf'],
265 'sbl1': [ImageType.SBL1_IMG, 'SBL1_IMG', 'bin'],
266 'sbl2': [ImageType.SBL2_IMG, 'SBL2_IMG', 'bin'],
267 'sbl3': [ImageType.SBL3_IMG, 'SBL3_IMG', 'bin'],
268 'efs1': [ImageType.RAMFS1_IMG, 'RAMFS1_IMG', 'bin'],
269 'efs2': [ImageType.RAMFS2_IMG, 'RAMFS2_IMG', 'bin'],
270 'pmic': [ImageType.PSI_IMG, 'PSI_IMG', 'elf'],
271 # DO NOT add any additional image information
272}
273
274#----------------------------------------------------------------------------
275# Header Class Notes:
276# In order to properly read and write the header structures as binary data,
277# the Python Struct library is used to align and package up the header objects
278# All Struct objects are initialized by a special string with the following
279# notation. These structure objects are then used to decode binary data in order
280# to fill out the appropriate class in Python, or they are used to package up
281# the Python class so that we may write the binary data out.
282#----------------------------------------------------------------------------
283"""
284 Format | C Type | Python Type | Standard Size
285 -----------------------------------------------------
286 1) 'X's | char * | string | 'X' bytes
287 2) H | unsigned short | integer | 2 bytes
288 3) I | unsigned int | integer | 4 bytes
289
290"""
291
292#----------------------------------------------------------------------------
293# ELF Header Class
294#----------------------------------------------------------------------------
295class Elf_Ehdr_common:
296 # Structure object to align and package the ELF Header
297 s = struct.Struct('16sHHI')
298
299 def __init__(self, data):
300 unpacked_data = (Elf_Ehdr_common.s).unpack(data)
301 self.unpacked_data = unpacked_data
302 self.e_ident = unpacked_data[0]
303 self.e_type = unpacked_data[1]
304 self.e_machine = unpacked_data[2]
305 self.e_version = unpacked_data[3]
306
307 def printValues(self):
T Michael Turney540b8ec2020-01-24 08:42:47 -0800308 print("ATTRIBUTE / VALUE")
309 for attr, value in self.__dict__.items():
310 print(attr, value)
Varadarajan Narayanan2dfbd932016-04-21 16:06:06 +0530311
312
313
314#----------------------------------------------------------------------------
315# ELF Header Class
316#----------------------------------------------------------------------------
317class Elf32_Ehdr:
318 # Structure object to align and package the ELF Header
319 s = struct.Struct('16sHHIIIIIHHHHHH')
320
321 def __init__(self, data):
322 unpacked_data = (Elf32_Ehdr.s).unpack(data)
323 self.unpacked_data = unpacked_data
324 self.e_ident = unpacked_data[0]
325 self.e_type = unpacked_data[1]
326 self.e_machine = unpacked_data[2]
327 self.e_version = unpacked_data[3]
328 self.e_entry = unpacked_data[4]
329 self.e_phoff = unpacked_data[5]
330 self.e_shoff = unpacked_data[6]
331 self.e_flags = unpacked_data[7]
332 self.e_ehsize = unpacked_data[8]
333 self.e_phentsize = unpacked_data[9]
334 self.e_phnum = unpacked_data[10]
335 self.e_shentsize = unpacked_data[11]
336 self.e_shnum = unpacked_data[12]
337 self.e_shstrndx = unpacked_data[13]
338
339 def printValues(self):
T Michael Turney540b8ec2020-01-24 08:42:47 -0800340 print("ATTRIBUTE / VALUE")
341 for attr, value in self.__dict__.items():
342 print(attr, value)
Varadarajan Narayanan2dfbd932016-04-21 16:06:06 +0530343
344 def getPackedData(self):
T Michael Turney540b8ec2020-01-24 08:42:47 -0800345 if type(self.e_ident) == str:
346 packvalue = bytes(self.e_ident, 'utf-8')
347 else:
348 packvalue = self.e_ident
349 values = [packvalue,
Varadarajan Narayanan2dfbd932016-04-21 16:06:06 +0530350 self.e_type,
351 self.e_machine,
352 self.e_version,
353 self.e_entry,
354 self.e_phoff,
355 self.e_shoff,
356 self.e_flags,
357 self.e_ehsize,
358 self.e_phentsize,
359 self.e_phnum,
360 self.e_shentsize,
361 self.e_shnum,
362 self.e_shstrndx
363 ]
364
365 return (Elf32_Ehdr.s).pack(*values)
366
367#----------------------------------------------------------------------------
368# ELF Program Header Class
369#----------------------------------------------------------------------------
370class Elf32_Phdr:
371
372 # Structure object to align and package the ELF Program Header
373 s = struct.Struct('I' * 8)
374
375 def __init__(self, data):
376 unpacked_data = (Elf32_Phdr.s).unpack(data)
377 self.unpacked_data = unpacked_data
378 self.p_type = unpacked_data[0]
379 self.p_offset = unpacked_data[1]
380 self.p_vaddr = unpacked_data[2]
381 self.p_paddr = unpacked_data[3]
382 self.p_filesz = unpacked_data[4]
383 self.p_memsz = unpacked_data[5]
384 self.p_flags = unpacked_data[6]
385 self.p_align = unpacked_data[7]
386
387 def printValues(self):
T Michael Turney540b8ec2020-01-24 08:42:47 -0800388 print("ATTRIBUTE / VALUE")
389 for attr, value in self.__dict__.items():
390 print(attr, value)
Varadarajan Narayanan2dfbd932016-04-21 16:06:06 +0530391
392 def getPackedData(self):
393 values = [self.p_type,
394 self.p_offset,
395 self.p_vaddr,
396 self.p_paddr,
397 self.p_filesz,
398 self.p_memsz,
399 self.p_flags,
400 self.p_align
401 ]
402
403 return (Elf32_Phdr.s).pack(*values)
404
405#----------------------------------------------------------------------------
406# ELF Header Class
407#----------------------------------------------------------------------------
408class Elf64_Ehdr:
409 # Structure object to align and package the ELF Header
410 s = struct.Struct('16sHHIQQQIHHHHHH')
411
412 def __init__(self, data):
413 unpacked_data = (Elf64_Ehdr.s).unpack(data)
414 self.unpacked_data = unpacked_data
415 self.e_ident = unpacked_data[0]
416 self.e_type = unpacked_data[1]
417 self.e_machine = unpacked_data[2]
418 self.e_version = unpacked_data[3]
419 self.e_entry = unpacked_data[4]
420 self.e_phoff = unpacked_data[5]
421 self.e_shoff = unpacked_data[6]
422 self.e_flags = unpacked_data[7]
423 self.e_ehsize = unpacked_data[8]
424 self.e_phentsize = unpacked_data[9]
425 self.e_phnum = unpacked_data[10]
426 self.e_shentsize = unpacked_data[11]
427 self.e_shnum = unpacked_data[12]
428 self.e_shstrndx = unpacked_data[13]
429
430 def printValues(self):
T Michael Turney540b8ec2020-01-24 08:42:47 -0800431 print("ATTRIBUTE / VALUE")
432 for attr, value in self.__dict__.items():
433 print(attr, value)
Varadarajan Narayanan2dfbd932016-04-21 16:06:06 +0530434
435 def getPackedData(self):
T Michael Turney540b8ec2020-01-24 08:42:47 -0800436 if type(self.e_ident) == str:
437 packvalue = bytes(self.e_ident, 'utf-8')
438 else:
439 packvalue = self.e_ident
440 values = [packvalue,
Varadarajan Narayanan2dfbd932016-04-21 16:06:06 +0530441 self.e_type,
442 self.e_machine,
443 self.e_version,
444 self.e_entry,
445 self.e_phoff,
446 self.e_shoff,
447 self.e_flags,
448 self.e_ehsize,
449 self.e_phentsize,
450 self.e_phnum,
451 self.e_shentsize,
452 self.e_shnum,
453 self.e_shstrndx
454 ]
455
456 return (Elf64_Ehdr.s).pack(*values)
457
458#----------------------------------------------------------------------------
459# ELF Program Header Class
460#----------------------------------------------------------------------------
461class Elf64_Phdr:
462
463 # Structure object to align and package the ELF Program Header
464 s = struct.Struct('IIQQQQQQ')
465
466 def __init__(self, data):
467 unpacked_data = (Elf64_Phdr.s).unpack(data)
468 self.unpacked_data = unpacked_data
469 self.p_type = unpacked_data[0]
470 self.p_flags = unpacked_data[1]
471 self.p_offset = unpacked_data[2]
472 self.p_vaddr = unpacked_data[3]
473 self.p_paddr = unpacked_data[4]
474 self.p_filesz = unpacked_data[5]
475 self.p_memsz = unpacked_data[6]
476 self.p_align = unpacked_data[7]
477
478 def printValues(self):
T Michael Turney540b8ec2020-01-24 08:42:47 -0800479 print("ATTRIBUTE / VALUE")
480 for attr, value in self.__dict__.items():
481 print(attr, value)
Varadarajan Narayanan2dfbd932016-04-21 16:06:06 +0530482
483 def getPackedData(self):
484 values = [self.p_type,
485 self.p_flags,
486 self.p_offset,
487 self.p_vaddr,
488 self.p_paddr,
489 self.p_filesz,
490 self.p_memsz,
491 self.p_align
492 ]
493
494 return (Elf64_Phdr.s).pack(*values)
495
496
497#----------------------------------------------------------------------------
498# ELF Segment Information Class
499#----------------------------------------------------------------------------
500class SegmentInfo:
501 def __init__(self):
502 self.flag = 0
503 def printValues(self):
T Michael Turney540b8ec2020-01-24 08:42:47 -0800504 print('Flag: ' + str(self.flag))
Varadarajan Narayanan2dfbd932016-04-21 16:06:06 +0530505
506#----------------------------------------------------------------------------
507# Regular Boot Header Class
508#----------------------------------------------------------------------------
509class Boot_Hdr:
510 def __init__(self, init_val):
511 self.image_id = ImageType.NONE_IMG
T Michael Turneybcd62f52019-08-07 14:26:32 -0700512 self.flash_parti_ver = 3
Varadarajan Narayanan2dfbd932016-04-21 16:06:06 +0530513 self.image_src = init_val
514 self.image_dest_ptr = init_val
515 self.image_size = init_val
516 self.code_size = init_val
517 self.sig_ptr = init_val
518 self.sig_size = init_val
519 self.cert_chain_ptr = init_val
520 self.cert_chain_size = init_val
521 self.magic_number1 = init_val
522 self.version = init_val
523 self.OS_type = init_val
524 self.boot_apps_parti_entry = init_val
525 self.boot_apps_size_entry = init_val
526 self.boot_apps_ram_loc = init_val
527 self.reserved_ptr = init_val
528 self.reserved_1 = init_val
529 self.reserved_2 = init_val
530 self.reserved_3 = init_val
531
532 def getLength(self):
533 return BOOT_HEADER_LENGTH
534
535 def writePackedData(self, target, write_full_hdr):
536 values = [self.image_id,
537 self.flash_parti_ver,
538 self.image_src,
539 self.image_dest_ptr,
540 self.image_size,
541 self.code_size ,
542 self.sig_ptr,
543 self.sig_size,
544 self.cert_chain_ptr,
545 self.cert_chain_size,
546 self.magic_number1,
547 self.version,
548 self.OS_type,
549 self.boot_apps_parti_entry,
550 self.boot_apps_size_entry,
551 self.boot_apps_ram_loc,
552 self.reserved_ptr,
553 self.reserved_1,
554 self.reserved_2,
555 self.reserved_3 ]
556
T Michael Turneybcd62f52019-08-07 14:26:32 -0700557 if self.flash_parti_ver >= 6:
558 values.insert(10, self.metadata_size_qti)
559 values.insert(11, self.metadata_size)
560
Varadarajan Narayanan2dfbd932016-04-21 16:06:06 +0530561 if self.image_dest_ptr >= 0x100000000:
562 values[3] = 0xFFFFFFFF
563
564 if self.cert_chain_ptr >= 0x100000000:
565 values[6] = 0xFFFFFFFF
566
567 if self.sig_ptr >= 0x100000000:
568 values[8] = 0xFFFFFFFF
569
570 # Write 10 entries(40B) or 20 entries(80B) of boot header
571 if write_full_hdr is False:
T Michael Turneybcd62f52019-08-07 14:26:32 -0700572 if self.flash_parti_ver >= 6:
573 s = struct.Struct('I'* 12)
574 values = values[:12]
575 else:
576 s = struct.Struct('I'* 10)
577 values = values[:10]
Varadarajan Narayanan2dfbd932016-04-21 16:06:06 +0530578 else:
579 s = struct.Struct('I' * self.getLength())
580
581 packed_data = s.pack(*values)
582
583 fp = OPEN(target,'wb')
584 fp.write(packed_data)
585 fp.close()
586
587 return s.size
588
589#----------------------------------------------------------------------------
590# SBL Boot Header Class
591#----------------------------------------------------------------------------
592class Sbl_Hdr:
593 def __init__(self, init_val):
594 self.codeword = init_val
595 self.magic = init_val
596 self.image_id = init_val
597 self.reserved_1 = init_val
598 self.reserved_2 = init_val
599 self.image_src = init_val
600 self.image_dest_ptr = init_val
601 self.image_size = init_val
602 self.code_size = init_val
603 self.sig_ptr = init_val
604 self.sig_size = init_val
605 self.cert_chain_ptr = init_val
606 self.cert_chain_size = init_val
607 self.oem_root_cert_sel = init_val
608 self.oem_num_root_certs = init_val
609 self.booting_image_config = init_val
610 self.reserved_6 = init_val
611 self.reserved_7 = init_val
612 self.reserved_8 = init_val
613 self.reserved_9 = init_val
614
615 def getLength(self):
616 return SBL_HEADER_LENGTH
617
618 def writePackedData(self, target):
619 values = [self.codeword,
620 self.magic,
621 self.image_id,
622 self.reserved_1,
623 self.reserved_2,
624 self.image_src,
625 self.image_dest_ptr,
626 self.image_size,
627 self.code_size,
628 self.sig_ptr,
629 self.sig_size,
630 self.cert_chain_ptr,
631 self.cert_chain_size,
632 self.oem_root_cert_sel,
633 self.oem_num_root_certs,
634 self.booting_image_config,
635 self.reserved_6,
636 self.reserved_7,
637 self.reserved_8,
638 self.reserved_9 ]
639
640 s = struct.Struct('I' * self.getLength())
641 packed_data = s.pack(*values)
642
643 fp = OPEN(target,'wb')
644 fp.write(packed_data)
645 fp.close()
646
647 return s.size
648
649#----------------------------------------------------------------------------
650# CLASS DEFINITIONS END
651#----------------------------------------------------------------------------
652
653#------------------------------------------------------------------------------
654# Hooks for Scons
655#------------------------------------------------------------------------------
656def exists(env):
657 return env.Detect('mbn_tools')
658
659def generate(env):
660
661 #----------------------------------------------------------------------------
662 # Generate Global Dictionary
663 #----------------------------------------------------------------------------
664 generate_global_dict(env)
665
666 #----------------------------------------------------------------------------
667 # Assign Build Configurable Values
668 #----------------------------------------------------------------------------
669 init_build_vars(env)
670
671 #----------------------------------------------------------------------------
672 # Add Methods to Environment
673 #----------------------------------------------------------------------------
674 env.AddMethod(filter_dictionary, "FilterDictionary")
675 env.AddMethod(image_auth, "ImageAuth")
676 env.AddMethod(image_header, "ImageHeader")
677 env.AddMethod(pboot_gen_elf, "PBootGenElf")
678 env.AddMethod(pboot_add_hash, "PBootAddHash")
679 env.AddMethod(modify_elf_flags, "ModifyElfFlags")
680 env.AddMethod(generate_code_hash, "GenerateCodeHash")
681 env.AddMethod(insert_SBL1_magicCookie, "InsertSBLMagicCookie")
682 env.AddMethod(modify_relocatable_flags, "ModifyRelocatableFlags")
683
684 #----------------------------------------------------------------------------
685 # Load Encryption Tools and Methods if required
686 #----------------------------------------------------------------------------
687 if 'USES_ENCRYPT_MBN' in env:
688 # Add Encryption Tools to environment
689 env.Tool('pil_encrypt', toolpath = ['${BUILD_ROOT}/core/securemsm/ssd/tools/pil_encrypt'])
690 env.AddMethod(get_ssd_se_fname, "GetSSDSideEffectFileName")
691 env.AddMethod(encrypt_elf_segments, "EncryptElfSegments")
692 env.AddMethod(generate_meta_data, "GenerateMetaData")
693 env.AddMethod(encrypt_mbn, "EncryptMBN")
694 return None
695
696#----------------------------------------------------------------------------
697# BOOT TOOLS BEGIN
698#----------------------------------------------------------------------------
699
700#----------------------------------------------------------------------------
701# generate_meta_data
702#----------------------------------------------------------------------------
703def generate_meta_data(env, meta_out_file_name, add_magic_num = False):
704
705 '''
706 Make call to SSD API to return buffer filled with XML header information.
707 The XML header which we write contains information regarding the algorithms
708 being used along with specific key values which are to be used for encrpytion.
709 '''
710 xml_header = env.SSDGetMetaData(add_magic_num)
711
712 # Initialize
713 xml_target_file = open(meta_out_file_name,'wb')
714 xml_header_size = len(xml_header)
715
716 # Write XML buffer into target file
717 xml_target_file.write(xml_header)
718
719 # Pad if necessary to the maximum size
720 if xml_header_size <= XML_HEADER_MAXSIZE:
721 bytes_to_pad = XML_HEADER_MAXSIZE - xml_header_size
722 pad_file(xml_target_file, bytes_to_pad, PAD_BYTE_1)
723 xml_target_file.close()
724 else:
725 xml_target_file.close()
T Michael Turney540b8ec2020-01-24 08:42:47 -0800726 raise RuntimeError("XML Size too large: " + str(xml_header_size))
Varadarajan Narayanan2dfbd932016-04-21 16:06:06 +0530727
728#----------------------------------------------------------------------------
729# encrypt_mbn
730#----------------------------------------------------------------------------
731def encrypt_mbn(env, mbn_in_file_name, mbn_out_file_name):
732 # Open Files
733 mbn_in_fp = OPEN(mbn_in_file_name, "rb")
734 mbn_out_fp = OPEN(mbn_out_file_name, "wb+")
735
736 # encrypt the input file content and write to output file
737 mbn_file_size = os.path.getsize(mbn_in_file_name)
738 file_buff = mbn_in_fp.read(mbn_file_size)
739 encrypted_buf = env.SSDEncryptSegment(0, file_buff, mbn_file_size)
740 mbn_out_fp.write(encrypted_buf)
741
742 # Close Files
743 mbn_in_fp.close()
744 mbn_out_fp.close()
745
746 # Clean up encryption files
747 env.SSDDeInit()
748
749#----------------------------------------------------------------------------
750# get_ssd_se_fname
751#----------------------------------------------------------------------------
752def get_ssd_se_fname(env):
753 return env.SSDGetSideEffectFileName()
754
755#----------------------------------------------------------------------------
756# encrypt_elf_segments
757#----------------------------------------------------------------------------
758def encrypt_elf_segments(env, elf_in_file_name,
759 elf_out_file_name):
760
761 # Open Files
762 elf_in_fp = OPEN(elf_in_file_name, "rb")
763 elf_out_fp = OPEN(elf_out_file_name, "wb+")
764
765 # Initialize
766 [elf_header, phdr_table] = preprocess_elf_file(elf_in_file_name)
767 encrypted_seg_counter = 0
768
769 # Copy input file to output file
770 shutil.copyfileobj(elf_in_fp, elf_out_fp, os.path.getsize(elf_in_file_name))
771
772 # Begin ELF segment encryption
773 for i in range(elf_header.e_phnum):
774 curr_phdr = phdr_table[i]
775
776 # Only encrypt segments of LOAD_TYPE. Do not encrypt the hash segment.
777 if curr_phdr.p_type == LOAD_TYPE and \
778 MI_PBT_SEGMENT_TYPE_VALUE(curr_phdr.p_flags) != MI_PBT_HASH_SEGMENT:
779
780 # Read full segment into buffer
781 elf_in_fp.seek(curr_phdr.p_offset)
782 data_len = curr_phdr.p_filesz
783 file_buff = elf_in_fp.read(data_len)
784
785 # Call encryption routine on buffer
786 encrypted_buf = env.SSDEncryptSegment(encrypted_seg_counter, file_buff, data_len)
787 encrypted_seg_counter += 1
788
789 # Write encrypted segment into output file in same location
790 elf_out_fp.seek(curr_phdr.p_offset)
791 elf_out_fp.write(encrypted_buf)
792
793 # Close Files
794 elf_in_fp.close()
795 elf_out_fp.close()
796
797 # Clean up encryption files
798 env.SSDDeInit()
799
800#----------------------------------------------------------------------------
801# Converts integer to bytes. If length after conversion
802# is smaller than given length of byte string, returned value is right-filled
803# with 0x00 bytes. Use Little-endian byte order.
804#----------------------------------------------------------------------------
805def convert_int_to_byte_string(n, l):
806 return b''.join([chr((n >> ((l - i - 1) * 8)) % 256) for i in xrange(l)][::-1])
807
808#----------------------------------------------------------------------------
809# Create default elf header
810#----------------------------------------------------------------------------
811def create_elf_header( output_file_name,
812 image_dest,
813 image_size,
814 is_elf_64_bit = False):
815
816 if (output_file_name is None):
T Michael Turney540b8ec2020-01-24 08:42:47 -0800817 raise RuntimeError("Requires a ELF header file")
Varadarajan Narayanan2dfbd932016-04-21 16:06:06 +0530818
819 # Create a elf header and program header
820 # Write the headers to the output file
821 elf_fp = file(output_file_name, "wb")
822
823 if (is_elf_64_bit is True):
824 # ELf header
825 elf_fp.write(ELFINFO_MAG0)
826 elf_fp.write(ELFINFO_MAG1)
827 elf_fp.write(ELFINFO_MAG2)
828 elf_fp.write(ELFINFO_MAG3)
829 elf_fp.write(ELFINFO_CLASS_64)
830 elf_fp.write(ELFINFO_DATA2LSB)
831 elf_fp.write(ELFINFO_VERSION_CURRENT)
832 elf_fp.write(''.rjust(9, chr(ELFINFO_RESERVED)))
833 elf_fp.write(ELFINFO_EXEC_ETYPE)
834 elf_fp.write(ELFINFO_ARM_MACHINETYPE)
835 elf_fp.write(ELFINFO_VERSION_EV_CURRENT)
836 elf_fp.write(convert_int_to_byte_string(image_dest, 8))
837 elf_fp.write(convert_int_to_byte_string(ELF64_HDR_SIZE, 8))
838 elf_fp.write(convert_int_to_byte_string(ELFINFO_SHOFF, 8))
839 elf_fp.write(''.rjust(4, chr(ELFINFO_RESERVED)))
840 elf_fp.write(convert_int_to_byte_string(ELF64_HDR_SIZE, 2))
841 elf_fp.write(convert_int_to_byte_string(ELF64_PHDR_SIZE, 2))
842 elf_fp.write(ELFINFO_PHNUM)
843 elf_fp.write(''.rjust(6, chr(ELFINFO_RESERVED)))
844
845 # Program Header
846 elf_fp.write(convert_int_to_byte_string(LOAD_TYPE, 4))
847 elf_fp.write(convert_int_to_byte_string(MI_PBT_RWE_SEGMENT, 4))
848 elf_fp.write(convert_int_to_byte_string(ELF64_HDR_SIZE+ELF64_PHDR_SIZE, 8))
849 elf_fp.write(convert_int_to_byte_string(image_dest, 8))
850 elf_fp.write(convert_int_to_byte_string(image_dest, 8))
851 elf_fp.write(convert_int_to_byte_string(image_size, 8))
852 elf_fp.write(convert_int_to_byte_string(image_size, 8))
853 elf_fp.write(convert_int_to_byte_string(ELF_BLOCK_ALIGN, 8))
854 else:
855 # ELf header
856 elf_fp.write(ELFINFO_MAG0)
857 elf_fp.write(ELFINFO_MAG1)
858 elf_fp.write(ELFINFO_MAG2)
859 elf_fp.write(ELFINFO_MAG3)
860 elf_fp.write(ELFINFO_CLASS_32)
861 elf_fp.write(ELFINFO_DATA2LSB)
862 elf_fp.write(ELFINFO_VERSION_CURRENT)
863 elf_fp.write(''.rjust(9, chr(ELFINFO_RESERVED)))
864 elf_fp.write(ELFINFO_EXEC_ETYPE)
865 elf_fp.write(ELFINFO_ARM_MACHINETYPE)
866 elf_fp.write(ELFINFO_VERSION_EV_CURRENT)
867 elf_fp.write(convert_int_to_byte_string(image_dest, 4))
868 elf_fp.write(convert_int_to_byte_string(ELF32_HDR_SIZE, 4))
869 elf_fp.write(convert_int_to_byte_string(ELFINFO_SHOFF, 4))
870 elf_fp.write(''.rjust(4, chr(ELFINFO_RESERVED)))
871 elf_fp.write(convert_int_to_byte_string(ELF32_HDR_SIZE, 2))
872 elf_fp.write(convert_int_to_byte_string(ELF32_PHDR_SIZE, 2))
873 elf_fp.write(ELFINFO_PHNUM)
874 elf_fp.write(''.rjust(6, chr(ELFINFO_RESERVED)))
875
876 # Program Header
877 elf_fp.write(convert_int_to_byte_string(LOAD_TYPE, 4))
878 elf_fp.write(convert_int_to_byte_string(ELF32_HDR_SIZE+ELF32_PHDR_SIZE, 4))
879 elf_fp.write(convert_int_to_byte_string(image_dest, 4))
880 elf_fp.write(convert_int_to_byte_string(image_dest, 4))
881 elf_fp.write(convert_int_to_byte_string(image_size, 4))
882 elf_fp.write(convert_int_to_byte_string(image_size, 4))
883 elf_fp.write(convert_int_to_byte_string(MI_PBT_RWE_SEGMENT, 4))
884 elf_fp.write(convert_int_to_byte_string(ELF_BLOCK_ALIGN, 4))
885
886 elf_fp.close()
887 return 0
888
889#----------------------------------------------------------------------------
890# image_header
891#----------------------------------------------------------------------------
892def image_header(env, gen_dict,
893 code_file_name,
894 output_file_name,
895 secure_type,
896 header_format = 'reg',
897 requires_preamble = False,
898 preamble_file_name = None,
899 elf_file_name = None,
900 write_full_hdr = False,
901 in_code_size = None,
902 cert_chain_size_in = CERT_CHAIN_ONEROOT_MAXSIZE,
T Michael Turneybcd62f52019-08-07 14:26:32 -0700903 num_of_pages = None,
904 header_version = None):
Varadarajan Narayanan2dfbd932016-04-21 16:06:06 +0530905
906 # Preliminary checks
907 if (requires_preamble is True) and (preamble_file_name is None):
T Michael Turney540b8ec2020-01-24 08:42:47 -0800908 raise RuntimeError("Image Header requires a preamble file")
Varadarajan Narayanan2dfbd932016-04-21 16:06:06 +0530909
910 if (gen_dict['IMAGE_KEY_MBN_TYPE'] == 'elf') and (elf_file_name is None):
T Michael Turney540b8ec2020-01-24 08:42:47 -0800911 raise RuntimeError("ELF Image Headers require an elf file")
Varadarajan Narayanan2dfbd932016-04-21 16:06:06 +0530912
913 if (in_code_size is None) and (os.path.exists(code_file_name) is False):
T Michael Turney540b8ec2020-01-24 08:42:47 -0800914 raise RuntimeError("Code size unavailable, and input file does not exist")
Varadarajan Narayanan2dfbd932016-04-21 16:06:06 +0530915
916 # Initialize
917 if in_code_size is not None:
918 code_size = in_code_size
919 else:
920 code_size = os.path.getsize(code_file_name)
921
922 image_dest = 0
923 image_source = 0
924
925 # If secure build, set signature and cert chain sizes
926 if secure_type == 'secure':
927 signature_size = SHA256_SIGNATURE_SIZE
928 cert_chain_size = cert_chain_size_in
929 image_size = code_size + cert_chain_size + signature_size
930 if (image_size % 4) != 0:
931 image_size += (4 - (image_size % 4))
932 else:
933 signature_size = 0
934 cert_chain_size = 0
935 image_size = code_size
936
T Michael Turneybcd62f52019-08-07 14:26:32 -0700937 if header_version:
938 assert header_version in [3, 5, 6], 'Not a valid MBN header version'
939
Varadarajan Narayanan2dfbd932016-04-21 16:06:06 +0530940 # For ELF or hashed images, image destination will be determined from an ELF input file
941 if gen_dict['IMAGE_KEY_MBN_TYPE'] == 'elf':
T Michael Turneybcd62f52019-08-07 14:26:32 -0700942 image_dest = get_hash_address(elf_file_name) + (header_size(header_version))
Varadarajan Narayanan2dfbd932016-04-21 16:06:06 +0530943 elif gen_dict['IMAGE_KEY_MBN_TYPE'] == 'bin':
944 image_dest = gen_dict['IMAGE_KEY_IMAGE_DEST']
945 image_source = gen_dict['IMAGE_KEY_IMAGE_SOURCE']
946
947 # Build the header based on format specified
948 if header_format == 'sbl':
949 boot_sbl_header = Sbl_Hdr(init_val = int('0xFFFFFFFF',16))
950 boot_sbl_header.codeword = FLASH_CODE_WORD
951 boot_sbl_header.magic = MAGIC_NUM
952 boot_sbl_header.image_id = gen_dict['IMAGE_KEY_IMAGE_ID']
953 boot_sbl_header.image_src = MI_BOOT_SBL_HDR_SIZE
954 boot_sbl_header.image_dest_ptr = image_dest
955 boot_sbl_header.image_size = image_size
956 boot_sbl_header.code_size = code_size
957 boot_sbl_header.sig_ptr = image_dest + code_size
958 boot_sbl_header.sig_size = signature_size
959 boot_sbl_header.cert_chain_ptr = image_dest + code_size + signature_size
960 boot_sbl_header.cert_chain_size = cert_chain_size
961 boot_sbl_header.oem_root_cert_sel = gen_dict['IMAGE_KEY_OEM_ROOT_CERT_SEL']
962 boot_sbl_header.oem_num_root_certs = gen_dict['IMAGE_KEY_OEM_NUM_ROOT_CERTS']
963 if 'USES_SBL_FOR_AARCH64' in env:
964 boot_sbl_header.booting_image_config = SBL_AARCH64
965 elif 'USES_SBL_FOR_AARCH632' in env:
966 boot_sbl_header.booting_image_config = SBL_AARCH32
967
968 # If preamble is required, output the preamble file and update the boot_sbl_header
969 if requires_preamble is True:
970 boot_sbl_header = image_preamble(gen_dict, preamble_file_name, boot_sbl_header, num_of_pages)
971
972 # Package up the header and write to output file
973 boot_sbl_header.writePackedData(target = output_file_name)
974
975 elif header_format == 'reg':
976 boot_header = Boot_Hdr(init_val = int('0x0',16))
977 boot_header.image_id = gen_dict['IMAGE_KEY_IMAGE_ID']
978 boot_header.image_src = image_source
979 boot_header.image_dest_ptr = image_dest
980 boot_header.image_size = image_size
981 boot_header.code_size = code_size
982 boot_header.sig_ptr = image_dest + code_size
983 boot_header.sig_size = signature_size
984 boot_header.cert_chain_ptr = image_dest + code_size + signature_size
985 boot_header.cert_chain_size = cert_chain_size
T Michael Turneybcd62f52019-08-07 14:26:32 -0700986 boot_header.flash_parti_ver = header_version # version
Varadarajan Narayanan2dfbd932016-04-21 16:06:06 +0530987
T Michael Turneybcd62f52019-08-07 14:26:32 -0700988 if header_version >= 5:
989 boot_header.image_src = 0 # sig_size_qc
990 boot_header.image_dest_ptr = 0 # cert_chain_size_qc
991
992 if header_version >= 6:
993 boot_header.metadata_size_qti = 0 # qti_metadata size
994 boot_header.metadata_size = 0 # oem_metadata size
T Michael Turney101098c2018-05-01 15:59:37 -0700995
Varadarajan Narayanan2dfbd932016-04-21 16:06:06 +0530996 # If preamble is required, output the preamble file and update the boot_header
997 if requires_preamble is True:
998 boot_header = image_preamble(gen_dict, preamble_file_name, boot_header, num_of_pages)
999
1000 # Package up the header and write to output file
1001 boot_header.writePackedData(target = output_file_name, write_full_hdr = write_full_hdr)
1002
1003 else:
T Michael Turney540b8ec2020-01-24 08:42:47 -08001004 raise RuntimeError("Header format not supported: " + str(header_format))
Varadarajan Narayanan2dfbd932016-04-21 16:06:06 +05301005 return 0
1006
1007
1008#----------------------------------------------------------------------------
1009# pboot_gen_elf
1010#----------------------------------------------------------------------------
1011def pboot_gen_elf(env, elf_in_file_name,
1012 hash_out_file_name,
1013 elf_out_file_name,
1014 secure_type = 'non_secure',
1015 hash_seg_max_size = None,
1016 last_phys_addr = None,
1017 append_xml_hdr = False,
1018 is_sha256_algo = True,
T Michael Turneybcd62f52019-08-07 14:26:32 -07001019 cert_chain_size_in = CERT_CHAIN_ONEROOT_MAXSIZE,
1020 header_version = None):
1021 sha_algo = 'SHA1'
1022 if is_sha256_algo:
1023 sha_algo = 'SHA256'
1024
1025 if header_version >= 6:
1026 sha_algo = 'SHA384'
1027 image_header_size = header_size(header_version)
1028
1029 if (sha_algo == 'SHA384'):
1030 mi_prog_boot_digest_size = 48
1031 elif sha_algo == 'SHA256':
1032 mi_prog_boot_digest_size = 32
Varadarajan Narayanan2dfbd932016-04-21 16:06:06 +05301033 else:
T Michael Turneybcd62f52019-08-07 14:26:32 -07001034 mi_prog_boot_digest_size = 20
Varadarajan Narayanan2dfbd932016-04-21 16:06:06 +05301035
1036 # Open Files
1037 elf_in_fp = OPEN(elf_in_file_name, "rb")
1038 hash_out_fp = OPEN(hash_out_file_name, "wb+")
1039
1040 if elf_out_file_name is not None:
1041 elf_out_fp = OPEN(elf_out_file_name, "wb+")
1042
1043 # Initialize
1044 [elf_header, phdr_table] = preprocess_elf_file(elf_in_file_name)
1045 num_phdrs = elf_header.e_phnum
1046 phdr_total_size = num_phdrs * elf_header.e_phentsize
1047 phdr_size = elf_header.e_phentsize
1048 hashtable_size = 0
1049 hashtable_shift = 0
1050
1051 if elf_header.e_ident[ELFINFO_CLASS_INDEX] == ELFINFO_CLASS_64:
T Michael Turney540b8ec2020-01-24 08:42:47 -08001052 new_phdr = Elf64_Phdr(b'\0' * ELF64_PHDR_SIZE)
Varadarajan Narayanan2dfbd932016-04-21 16:06:06 +05301053 elf_header_size = ELF64_HDR_SIZE
1054 is_elf64 = True
1055 else:
T Michael Turney540b8ec2020-01-24 08:42:47 -08001056 new_phdr = Elf32_Phdr(b'\0' * ELF32_PHDR_SIZE)
Varadarajan Narayanan2dfbd932016-04-21 16:06:06 +05301057 elf_header_size = ELF32_HDR_SIZE
1058 is_elf64 = False
1059
T Michael Turney540b8ec2020-01-24 08:42:47 -08001060 hash = b'\0' * mi_prog_boot_digest_size
Varadarajan Narayanan2dfbd932016-04-21 16:06:06 +05301061 phdr_start = 0
1062 bytes_to_pad = 0
1063 hash_seg_end = 0
1064
1065 # Process program headers if an output elf is specified
1066 if elf_out_file_name is not None:
1067 # Assert limit on number of program headers in input ELF
1068 if num_phdrs > MAX_PHDR_COUNT:
T Michael Turney540b8ec2020-01-24 08:42:47 -08001069 raise RuntimeError("Input ELF has exceeded maximum number of program headers")
Varadarajan Narayanan2dfbd932016-04-21 16:06:06 +05301070
1071 # Create new program header for the ELF Header + Program Headers
1072 new_phdr.p_type = NULL_TYPE
1073 new_phdr.p_flags = MI_PBT_ELF_PHDR_SEGMENT
1074
1075 # If hash table program header is not found, make sure to include it
1076 elf_header.e_phnum += 2
1077
1078 # Create an empty hash entry for PHDR_TYPE
T Michael Turney540b8ec2020-01-24 08:42:47 -08001079 hash_out_fp.write(b'\0' * mi_prog_boot_digest_size)
T Michael Turneybcd62f52019-08-07 14:26:32 -07001080 hashtable_size += mi_prog_boot_digest_size
Varadarajan Narayanan2dfbd932016-04-21 16:06:06 +05301081
1082 # Create an empty hash entry for the hash segment itself
T Michael Turney540b8ec2020-01-24 08:42:47 -08001083 hash_out_fp.write(b'\0' * mi_prog_boot_digest_size)
T Michael Turneybcd62f52019-08-07 14:26:32 -07001084 hashtable_size += mi_prog_boot_digest_size
Varadarajan Narayanan2dfbd932016-04-21 16:06:06 +05301085
1086 # Begin hash table generation
1087 for i in range(num_phdrs):
1088 curr_phdr = phdr_table[i]
1089
1090 if (MI_PBT_PAGE_MODE_VALUE(curr_phdr.p_flags) == MI_PBT_PAGED_SEGMENT):
1091 seg_offset = curr_phdr.p_offset
1092 seg_size = curr_phdr.p_filesz
1093 hash_size = 0
1094
1095 # Check if the vaddr is page aligned
1096 off = curr_phdr.p_vaddr & (ELF_BLOCK_ALIGN - 1)
Baruch Siachb82a5712021-03-11 18:18:37 +02001097 if int(off) != 0:
Varadarajan Narayanan2dfbd932016-04-21 16:06:06 +05301098 seg_size -= (ELF_BLOCK_ALIGN - off)
1099 seg_offset += (ELF_BLOCK_ALIGN - off)
1100
1101 # Seg_size should be page aligned
1102 if (seg_size & (ELF_BLOCK_ALIGN - 1)) > 0:
T Michael Turney540b8ec2020-01-24 08:42:47 -08001103 raise RuntimeError("seg_size: " + hex(seg_size) + " is not ELF page aligned!")
Varadarajan Narayanan2dfbd932016-04-21 16:06:06 +05301104
1105 off = seg_offset + seg_size
1106
1107 while seg_offset < off:
1108
1109 if seg_offset < ELF_BLOCK_ALIGN:
1110 hash_size = seg_offset
1111 else:
1112 hash_size = ELF_BLOCK_ALIGN
1113
1114 elf_in_fp.seek(seg_offset)
1115 fbuf = elf_in_fp.read(hash_size)
1116
1117 if MI_PBT_CHECK_FLAG_TYPE(curr_phdr.p_flags) is True:
T Michael Turneybcd62f52019-08-07 14:26:32 -07001118 hash = generate_hash(fbuf, sha_algo)
Varadarajan Narayanan2dfbd932016-04-21 16:06:06 +05301119 else:
T Michael Turney540b8ec2020-01-24 08:42:47 -08001120 hash = b'\0' * mi_prog_boot_digest_size
Varadarajan Narayanan2dfbd932016-04-21 16:06:06 +05301121
1122 # Write hash to file
1123 hash_out_fp.write(hash)
1124
T Michael Turneybcd62f52019-08-07 14:26:32 -07001125 hashtable_size += mi_prog_boot_digest_size
Varadarajan Narayanan2dfbd932016-04-21 16:06:06 +05301126 seg_offset += ELF_BLOCK_ALIGN
1127
1128 # Copy the hash entry for all that are PAGED segments and those that are not the PHDR type. This is for
1129 # backward tool compatibility where some images are generated using older exe tools.
1130 elif((MI_PBT_PAGE_MODE_VALUE(curr_phdr.p_flags) == MI_PBT_NON_PAGED_SEGMENT) and (curr_phdr.p_type is not PHDR_TYPE)):
1131 # Read full hash entry into buffer
1132 elf_in_fp.seek(curr_phdr.p_offset)
1133 data_len = curr_phdr.p_filesz
1134 file_buff = elf_in_fp.read(data_len)
1135
1136 if (MI_PBT_CHECK_FLAG_TYPE(curr_phdr.p_flags) is True) and (data_len > 0):
T Michael Turneybcd62f52019-08-07 14:26:32 -07001137 hash = generate_hash(file_buff, sha_algo)
Varadarajan Narayanan2dfbd932016-04-21 16:06:06 +05301138 else:
T Michael Turney540b8ec2020-01-24 08:42:47 -08001139 hash = b'\0' * mi_prog_boot_digest_size
Varadarajan Narayanan2dfbd932016-04-21 16:06:06 +05301140
1141 # Write hash to file
1142 hash_out_fp.write(hash)
1143
T Michael Turneybcd62f52019-08-07 14:26:32 -07001144 hashtable_size += mi_prog_boot_digest_size
Varadarajan Narayanan2dfbd932016-04-21 16:06:06 +05301145 # End hash table generation
1146
1147 # Generate the rest of the ELF output file if specified
1148 if elf_out_file_name is not None:
1149
1150 # Preempt hash table size if necessary
1151 if secure_type == 'secure':
1152 hashtable_size += (SHA256_SIGNATURE_SIZE + cert_chain_size_in)
1153
1154 if append_xml_hdr is True:
1155 hashtable_size += XML_HEADER_MAXSIZE
1156
1157 # Initialize the hash table program header
1158 [hash_Phdr, pad_hash_segment, hash_tbl_end_addr, hash_tbl_offset] = \
T Michael Turneybcd62f52019-08-07 14:26:32 -07001159 initialize_hash_phdr(elf_in_file_name, hashtable_size, image_header_size, ELF_BLOCK_ALIGN, is_elf64)
Varadarajan Narayanan2dfbd932016-04-21 16:06:06 +05301160
1161 # Check if hash segment max size parameter was passed
1162 if (hash_seg_max_size is not None):
1163 # Error checking for hash segment size validity
1164 if hashtable_size > hash_seg_max_size:
T Michael Turney540b8ec2020-01-24 08:42:47 -08001165 raise RuntimeError("Hash table exceeds maximum hash segment size: " + hex(hash_seg_max_size))
Baruch Siachb82a5712021-03-11 18:18:37 +02001166 if (hash_seg_max_size & (ELF_BLOCK_ALIGN-1)) != 0:
T Michael Turney540b8ec2020-01-24 08:42:47 -08001167 raise RuntimeError("Hash segment size passed is not ELF Block Aligned: " + hex(hash_seg_max_size))
Varadarajan Narayanan2dfbd932016-04-21 16:06:06 +05301168
1169 # Check if hash physical address parameter was passed
1170 if last_phys_addr is not None:
1171 hash_Phdr.p_vaddr = last_phys_addr
1172 hash_Phdr.p_paddr = last_phys_addr
1173
1174 # Check if hash segment max size was passed
1175 if hash_seg_max_size is not None:
1176 hash_Phdr.p_memsz = hash_seg_max_size
1177
1178 # Determine the end of the hash segment, make sure it's block aligned
1179 bytes_to_pad = ELF_BLOCK_ALIGN - pad_hash_segment
1180 hash_seg_end = hash_tbl_end_addr + bytes_to_pad
1181
Elyes HAOUAS446e4d72018-08-24 08:00:06 +02001182 # Check if a shifting is required to accommodate for the hash segment.
Varadarajan Narayanan2dfbd932016-04-21 16:06:06 +05301183 # Get the minimum offset by going through the program headers.
1184 # Note that the program headers in the input file do not contain
1185 # the dummy program header for ELF + Program header, and the
1186 # program header for the hashtable.
1187 min_offset = phdr_table[0].p_offset
1188 for i in range(num_phdrs):
1189 curr_phdr = phdr_table[i]
1190 if curr_phdr.p_offset < min_offset:
1191 min_offset = curr_phdr.p_offset
1192
1193 if min_offset < hash_seg_end:
1194 hashtable_shift = hash_seg_end - min_offset
1195
1196 # Move program headers to after ELF header
1197 phdr_start = elf_header_size
1198
1199 # We copy over no section headers so assign these values to 0 in ELF Header
1200 elf_header.e_shnum = 0
1201 elf_header.e_shstrndx = 0
1202 elf_header.e_shoff = 0
1203
1204 # Output remaining ELF segments
1205 for i in range(num_phdrs):
1206
1207 # Increment the file offset before writing to the destination file
1208 curr_phdr = phdr_table[i]
1209
1210 # We do not copy over program headers of PHDR type, decrement the program
1211 # header count and continue the loop
1212 if curr_phdr.p_type is PHDR_TYPE:
1213 elf_header.e_phnum -= 1
1214 continue
1215
1216 src_offset = curr_phdr.p_offset
1217
1218 # Copy the ELF segment
1219 file_copy_offset(elf_in_fp, src_offset, elf_out_fp, curr_phdr.p_offset + hashtable_shift, curr_phdr.p_filesz)
1220
1221 # Output remaining program headers and ELF segments
1222 elf_header.e_phoff = phdr_start
1223
1224 # Output new program headers which we have generated
1225 elf_out_fp.seek(phdr_start)
1226 new_phdr.p_filesz = elf_header_size + (elf_header.e_phnum * phdr_size)
1227 elf_out_fp.write(new_phdr.getPackedData())
1228 elf_out_fp.write(hash_Phdr.getPackedData())
1229 phdr_start += (2 * phdr_size)
1230
1231 # Increment the file offset before writing to the destination file
1232 for i in range(num_phdrs):
1233 curr_phdr = phdr_table[i]
1234
1235 if curr_phdr.p_type is PHDR_TYPE:
1236 continue
1237
1238 curr_phdr.p_offset += hashtable_shift
1239
1240 # Copy the program header
1241 elf_out_fp.seek(phdr_start)
1242 elf_out_fp.write(curr_phdr.getPackedData())
1243
1244 # Update phdr_start
1245 phdr_start += phdr_size
1246
1247 # Finally, copy the new ELF header to the destination file
1248 elf_out_fp.seek(0)
1249 elf_out_fp.write(elf_header.getPackedData())
1250
1251 # Recalculate hash of ELF + program headers and output to hash output file
1252 elf_out_fp.seek(0)
1253 # Read the elf header
1254 elfhdr_buff = elf_out_fp.read(elf_header_size)
1255 # Seek to the program header offset listed in elf header.
1256 elf_out_fp.seek(elf_header.e_phoff)
1257 # Read the program header and compute hash
1258 proghdr_buff = elf_out_fp.read(elf_header.e_phnum * phdr_size)
1259
T Michael Turneybcd62f52019-08-07 14:26:32 -07001260 hash = generate_hash(elfhdr_buff + proghdr_buff, sha_algo)
Varadarajan Narayanan2dfbd932016-04-21 16:06:06 +05301261
1262 # Write hash to file as first hash table entry
1263 hash_out_fp.seek(0)
1264 hash_out_fp.write(hash)
1265
1266 # Close files
1267 elf_in_fp.close()
1268 hash_out_fp.close()
1269
1270 if elf_out_file_name is not None:
1271 elf_out_fp.close()
1272
1273 return 0
1274
1275
1276#----------------------------------------------------------------------------
1277# pboot_add_hash
1278#----------------------------------------------------------------------------
1279def pboot_add_hash(env, elf_in_file_name,
1280 hash_tbl_file_name,
1281 elf_out_file_name):
1282
1283 # Open files
1284 elf_in_fp = OPEN(elf_in_file_name, "rb")
1285 hash_tbl_fp = OPEN(hash_tbl_file_name, "rb")
1286 elf_out_fp = OPEN(elf_out_file_name, "wb+")
1287
1288 # Initialize
1289 [elf_header, phdr_table] = preprocess_elf_file(elf_in_file_name)
1290
1291 hash_size = os.path.getsize(hash_tbl_file_name)
1292 hash_segment_found = False
1293
1294 # Attempt to find the location of the hash program header
1295 for i in range(elf_header.e_phnum):
1296 curr_phdr = phdr_table[i]
1297 if curr_phdr.p_flags == MI_PBT_ELF_HASH_SEGMENT:
1298 hash_segment_found = True
1299 break
1300
1301 if hash_segment_found is True:
1302 # Copy input file to output file
1303 shutil.copyfileobj(elf_in_fp, elf_out_fp, os.path.getsize(elf_in_file_name))
1304
1305 # Update ELF to insert hash table at corresponding file offset
1306 hash_hdr_offset = curr_phdr.p_offset
1307 file_copy_offset(hash_tbl_fp, 0, elf_out_fp, hash_hdr_offset, hash_size)
1308
1309 else:
T Michael Turney540b8ec2020-01-24 08:42:47 -08001310 raise RuntimeError("Hash segment program header not found in file " + elf_in_file_name)
Varadarajan Narayanan2dfbd932016-04-21 16:06:06 +05301311
1312 # Close files
1313 elf_in_fp.close()
1314 hash_tbl_fp.close()
1315 elf_out_fp.close()
1316
1317 return 0
1318
1319#----------------------------------------------------------------------------
1320# image_auth
1321#----------------------------------------------------------------------------
1322def image_auth(env, *args):
1323
1324 if len(args) < 7 or len(args) > 8:
T Michael Turney540b8ec2020-01-24 08:42:47 -08001325 raise RuntimeError("Usage Invalid")
Varadarajan Narayanan2dfbd932016-04-21 16:06:06 +05301326
1327 # Initialize File Names
1328 binary_in = args[0]
1329 signature = args[1]
1330 attestation_cert = args[2]
1331 attestation_ca_cert = args[3]
1332 root_cert = args[4]
1333 cert_chain_out = args[5]
1334 signed_image_out = args[6]
1335 if len(args) == 8:
1336 cert_size_max_in = args[7]
1337 else:
1338 cert_size_max_in = CERT_CHAIN_ONEROOT_MAXSIZE
1339
1340 # Creating list of certificates to support creation of certificate chains
1341 # of lenth 1, 2, or 3 certificates
1342 cert_list = []
1343 num_certs = 0
1344 if (os.path.exists(attestation_cert)):
1345 cert_list.append(attestation_cert)
1346 num_certs = num_certs + 1
1347 if (os.path.exists(attestation_ca_cert)):
1348 cert_list.append(attestation_ca_cert)
1349 num_certs = num_certs + 1
1350 if (os.path.exists(root_cert)):
1351 cert_list.append(root_cert)
1352 num_certs = num_certs + 1
1353
1354 if (num_certs == 0):
T Michael Turney540b8ec2020-01-24 08:42:47 -08001355 raise RuntimeError("Missing file(s) required for signing.\n")
Varadarajan Narayanan2dfbd932016-04-21 16:06:06 +05301356
1357 # Create the Certificate Chain
1358 concat_files (cert_chain_out, cert_list)
1359
1360 # Pad to ensure Certificate Chain Size is CERT_CHAIN_MAX_SIZE
1361 cert_size = os.path.getsize(cert_chain_out)
1362
1363 if cert_size <= cert_size_max_in:
1364 bytes_to_pad = cert_size_max_in - cert_size
1365 cert_fp = OPEN(cert_chain_out,'ab')
1366 pad_file(cert_fp, bytes_to_pad, PAD_BYTE_1)
1367 cert_fp.close()
1368 else:
T Michael Turney540b8ec2020-01-24 08:42:47 -08001369 raise RuntimeError("Certificate Size too large: " + str(cert_size))
Varadarajan Narayanan2dfbd932016-04-21 16:06:06 +05301370
1371 # Create the Final Signed Image File
1372 concat_files (signed_image_out, [binary_in, signature, cert_chain_out])
1373
1374 return 0
1375
1376#----------------------------------------------------------------------------
1377# modify_relocatable_flags
1378#----------------------------------------------------------------------------
1379def modify_relocatable_flags(env, output_elf ):
1380
1381 # Offset into program header where the p_flags field is stored
1382 phdr_align_flag_offset = 28
1383 phdr_reloc_flag_offset = 24
1384
1385 # Initialize
1386 [elf_header, phdr_table] = preprocess_elf_file(output_elf)
1387
1388 if elf_header.e_ident[ELFINFO_CLASS_INDEX] == ELFINFO_CLASS_64:
1389 curr_phdr = Elf64_Phdr('\0' * ELF64_PHDR_SIZE)
1390 elf_header_size = ELF64_HDR_SIZE
1391 is_elf64 = True
1392 else:
1393 curr_phdr = Elf32_Phdr('\0' * ELF32_PHDR_SIZE)
1394 elf_header_size = ELF32_HDR_SIZE
1395 is_elf64 = False
1396
1397 # Open files
1398 elf_in_fp = OPEN(output_elf, "r+")
1399
1400 # Go to the start of the p_flag entry in the first program header
1401 file_offset_align_flag = elf_header.e_phoff + phdr_align_flag_offset
1402
1403 # Change the align field in the program header in the ELF file
1404 elf_in_fp.seek(file_offset_align_flag)
1405 curr_phdr = phdr_table[0]
1406
1407 #default alignment value is 1MB unless otherwise specified
1408 if 'USES_RELOC_ALIGN_VALUE_4MB' in env:
1409 alignment_value = ALIGNVALUE_4MB
1410 else:
1411 alignment_value = ALIGNVALUE_1MB
1412
1413
1414
1415 #create new alignment value
1416 new_align = (curr_phdr.p_align & 0) | alignment_value
1417
1418 # Create structure to package new flag field
1419 s = struct.Struct('I')
1420 new_flag_bytes = s.pack(new_align)
1421
1422 # Write the new flag value and incr ement offset
1423 elf_in_fp.write(new_flag_bytes)
1424
1425 # Go to the start of the p_flag entry in the first program header
1426 file_offset_reloc_flag = elf_header.e_phoff + phdr_reloc_flag_offset
1427
1428 # Change each program header flag in the ELF file with relocatable flag
1429 for i in range(elf_header.e_phnum):
1430 # Seek to correct location and create new p_flag value
1431 elf_in_fp.seek(file_offset_reloc_flag)
1432 curr_phdr = phdr_table[i]
1433 new_flag = (curr_phdr.p_flags & ~MI_PBT_FLAGS_MASK) | (MI_PBT_ELF_AMSS_RELOCATABLE_IMAGE)
1434
1435 # Create structure to package new flag field
1436 s = struct.Struct('I')
1437 new_flag_bytes = s.pack(new_flag)
1438
1439 # Write the new flag value and increment offset
1440 elf_in_fp.write(new_flag_bytes)
1441 file_offset_reloc_flag += elf_header.e_phentsize
1442
1443 # Close files
1444 elf_in_fp.close()
1445
1446
1447 return 0
1448
1449
1450#----------------------------------------------------------------------------
1451# modify_elf_flags
1452#----------------------------------------------------------------------------
1453def modify_elf_flags(env, elf_in_file_name,
1454 scl_file_name):
1455
1456 # Initialize
1457 [elf_header, phdr_table] = preprocess_elf_file(elf_in_file_name)
1458 segment_list = readSCL(scl_file_name, env['GLOBAL_DICT'])
1459
1460 if elf_header.e_ident[ELFINFO_CLASS_INDEX] == ELFINFO_CLASS_64:
1461 curr_phdr = Elf64_Phdr('\0' * ELF64_PHDR_SIZE)
1462 # Offset into program header where the p_flags field is stored
1463 phdr_flag_off = 4
1464 else:
1465 curr_phdr = Elf32_Phdr('\0' * ELF32_PHDR_SIZE)
1466 # Offset into program header where the p_flags field is stored
1467 phdr_flag_off = 24
1468
1469 # Open files
1470 elf_in_fp = OPEN(elf_in_file_name, "r+")
1471
1472 # Check for corresponding number of segments
1473 if len(segment_list) is not elf_header.e_phnum:
T Michael Turney540b8ec2020-01-24 08:42:47 -08001474 raise RuntimeError('SCL file and ELF file have different number of segments!')
Varadarajan Narayanan2dfbd932016-04-21 16:06:06 +05301475
1476 # Go to the start of the p_flag entry in the first program header
1477 file_offset = elf_header.e_phoff + phdr_flag_off
1478
1479 # Change each program header flag in the ELF file based off the SCL file
1480 for i in range(elf_header.e_phnum):
1481 # Seek to correct location and create new p_flag value
1482 elf_in_fp.seek(file_offset)
1483 curr_phdr = phdr_table[i]
1484 new_flag = (curr_phdr.p_flags & ~MI_PBT_FLAGS_MASK) | (segment_list[i].flag)
1485
1486 # Create structure to package new flag field
1487 s = struct.Struct('I')
1488 new_flag_bytes = s.pack(new_flag)
1489
1490 # Write the new flag value and increment offset
1491 elf_in_fp.write(new_flag_bytes)
1492 file_offset += elf_header.e_phentsize
1493
1494 # Close files
1495 elf_in_fp.close()
1496
1497 return 0
1498
1499#----------------------------------------------------------------------------
1500# generate_code_hash
1501#----------------------------------------------------------------------------
1502def generate_code_hash(env, elf_in_file_name):
1503
1504 # Initialize
1505 [elf_header, phdr_table] = preprocess_elf_file(elf_in_file_name)
1506
1507 if elf_header.e_ident[ELFINFO_CLASS_INDEX] == ELFINFO_CLASS_64:
1508 curr_phdr = Elf64_Phdr('\0' * ELF64_PHDR_SIZE)
1509 # Offset into program header where the p_flags field is stored
1510 phdr_flag_off = 4
1511 else:
1512 curr_phdr = Elf32_Phdr('\0' * ELF32_PHDR_SIZE)
1513 # Offset into program header where the p_flags field is stored
1514 phdr_flag_off = 24
1515
1516 # Open files
1517 elf_in_fp = OPEN(elf_in_file_name, "rb+")
1518
1519 # Go to the start of the p_flag entry in the first program header
1520 file_offset = elf_header.e_phoff + phdr_flag_off
1521
1522 # XXX Get these from env?
1523 DP_CODE_ALIGN = 0x100
1524 DP_PAGE_SIZE = 4096
1525 DP_HASH_SIZE = 32 # SHA-256
1526 DP_HASH_MAGIC = 0xC0DEDEC0
1527 PH_PERM_RW = 0x06
1528 PH_PERM_RX = 0x05
1529 PH_PERM_RO = 0x04
1530 PH_PERM_MASK = 0x07
1531
1532 page_size = DP_PAGE_SIZE
1533 hash_size = DP_HASH_SIZE
1534
1535 # First identify the hash segment. It is the first RW section.
1536 # Its Align should be 8, and its size a multiple of DP_HASH_SIZE;
1537
1538 hash_seg_idx = -1
1539 for i in range(elf_header.e_phnum):
1540 curr_phdr = phdr_table[i]
1541
1542 if (curr_phdr.p_align == 8 and
1543 (curr_phdr.p_flags & PH_PERM_MASK) == PH_PERM_RW and
1544 curr_phdr.p_filesz != 0 and (curr_phdr.p_filesz % DP_HASH_SIZE) == 0):
1545 hash_seg_idx = i
1546 # Validate the contents of the hash segment. It should be
1547 # filled with DP_HASH_MAGIC
1548 elf_in_fp.seek(curr_phdr.p_offset)
1549 hash_data = "";
1550 while (len(hash_data) < curr_phdr.p_filesz):
1551 hash_data = hash_data + elf_in_fp.read(curr_phdr.p_filesz - len(hash_data))
1552
1553 hash_data = struct.unpack("I" * (curr_phdr.p_filesz / 4), hash_data)
1554
1555 for v in hash_data[:]:
1556 if (v != DP_HASH_MAGIC):
1557 hash_seg_idx = -1
1558 break;
1559
1560 if (hash_seg_idx != -1):
1561 break
1562
1563 if (hash_seg_idx == -1):
1564 # return if there is no hash segment.
1565 return 0
1566
1567 hash_phdr = phdr_table[hash_seg_idx]
1568
1569 # Now find the code segment for the hashes. Look for matching number of pages
1570 code_seg_idx = -1
1571 code_seg_pages = hash_phdr.p_filesz / DP_HASH_SIZE
1572
1573 for i in range(elf_header.e_phnum):
1574 curr_phdr = phdr_table[i]
1575 curr_pages = (curr_phdr.p_filesz + DP_PAGE_SIZE - 1) / DP_PAGE_SIZE
1576
1577 if (curr_phdr.p_align == DP_CODE_ALIGN and
1578 (curr_phdr.p_flags & PH_PERM_MASK) == PH_PERM_RX and
1579 curr_pages == code_seg_pages):
1580 if (code_seg_idx != -1):
T Michael Turney540b8ec2020-01-24 08:42:47 -08001581 raise RuntimeError('Multiple code segments match for: ' + code_seg_pages + ' pages')
Varadarajan Narayanan2dfbd932016-04-21 16:06:06 +05301582 code_seg_idx = i
1583
1584 if (code_seg_idx == -1):
T Michael Turney540b8ec2020-01-24 08:42:47 -08001585 raise RuntimeError('No matching code segment found')
Varadarajan Narayanan2dfbd932016-04-21 16:06:06 +05301586
1587 code_phdr = phdr_table[code_seg_idx]
1588
1589 # Now hash the pages in the code segment
1590 hashes = []
1591 elf_in_fp.seek(code_phdr.p_offset)
1592 bytes_left = code_phdr.p_filesz;
1593 while (bytes_left > 0):
1594 bytes_in_page = min(bytes_left, DP_PAGE_SIZE)
1595 page = "";
1596 while (len(page) < bytes_in_page):
1597 page = page + elf_in_fp.read(bytes_in_page - len(page))
1598 if (len(page) < DP_PAGE_SIZE):
1599 page = page + (struct.pack('b', 0) * (DP_PAGE_SIZE - len(page)))
T Michael Turneybcd62f52019-08-07 14:26:32 -07001600 hashes = hashes + [generate_hash(page, 'SHA256')]
Varadarajan Narayanan2dfbd932016-04-21 16:06:06 +05301601 bytes_left -= bytes_in_page
1602
1603 # And write them to the hash segment
1604 elf_in_fp.seek(hash_phdr.p_offset)
1605
1606 for h in hashes[:]:
1607 elf_in_fp.write(h)
1608
1609 # Close files
1610 elf_in_fp.close()
1611
1612 return 0
1613
1614#----------------------------------------------------------------------------
1615# BOOT TOOLS END
1616#----------------------------------------------------------------------------
1617
1618#----------------------------------------------------------------------------
1619# HELPER FUNCTIONS BEGIN
1620#----------------------------------------------------------------------------
1621
1622#----------------------------------------------------------------------------
1623# Create a list to hold all segment information from an input SCL file
1624#----------------------------------------------------------------------------
1625def readSCL(filename, global_dict):
1626
1627 scl_fp = OPEN(filename,'r')
1628
1629 # Initialize
1630 file_data = scl_fp.readlines()
1631 num_lines = len(file_data)
1632 current_line = ''
1633 previous_line = ''
1634 strip_chars = '(){}[]'
1635 i = 0
1636 bracket_counter = 0
1637 seg_list = []
1638
1639 # Parse through all lines
1640 while i < num_lines:
1641
1642 # Save the last line read
1643 previous_line = current_line
1644 current_line = file_data[i]
1645
1646 # Look for the symbol '{' for the line to read.
1647 # Use bracket counter to skip nested '{ }'
1648 if ('{' in current_line):
Baruch Siachb82a5712021-03-11 18:18:37 +02001649 if bracket_counter == 0:
Varadarajan Narayanan2dfbd932016-04-21 16:06:06 +05301650 # Create a new SegmentInfo class and set up tokens
1651 new_scl_entry = SegmentInfo()
1652 previous_line = previous_line.strip()
1653 tokens = previous_line.split(' ')
1654
1655 # Check that at least two tokens were parsed
1656 # Token 1: Segment Name
1657 # Token 2: Start Address -- not used in MBN tools
1658 if len(tokens) < 2:
T Michael Turney540b8ec2020-01-24 08:42:47 -08001659 raise RuntimeError('SCL Segment Syntax malformed: ' + previous_line)
Varadarajan Narayanan2dfbd932016-04-21 16:06:06 +05301660
1661 # Get the segment flags corresponding to the segment name description
1662 new_scl_entry.flag = getSegmentFlag(tokens[0].strip(strip_chars))
1663 seg_list.append(new_scl_entry)
1664
1665 bracket_counter += 1
1666 elif '}' in current_line:
1667 bracket_counter -= 1
1668
1669 i+=1
1670
1671 scl_fp.close()
1672 return seg_list
1673
1674#----------------------------------------------------------------------------
1675# Given a string parsed from a SCL file, returns the ELF segment flags
1676#----------------------------------------------------------------------------
1677def getSegmentFlag(seg_info):
1678
1679 ret_val = None
1680
1681 # Define string values for various types of segments
1682 RO = "RO"
1683 RW = "RW"
1684 ZI = "ZI"
1685 PAGEABLE = "PAGED"
1686 NOTPAGEABLE = "NOTPAGED"
1687 SWAPABLE = "SWAPPED"
1688 SWAP_POOL = "SWAP_POOL"
1689 RESERVED = "RESERVED"
1690 HASHTBL = "HASH"
1691 SHARED = "SHARED"
1692 NOTUSED = "NOTUSED"
1693 BOOT_SEGMENT = "BOOT_SEGMENT"
1694 CODE = "CODE"
1695 L4BSP = "L4BSP"
1696 POOL_INDEX_0 = "INDEX_0"
1697 POOL_INDEX_1 = "INDEX_1"
1698
1699 # New definitions for EOS demand paging
1700 NONPAGE = "NONPAGE"
1701 PAGEUNLOCKED = "PAGEUNLOCKED"
1702 PAGELOCKED = "PAGELOCKED"
1703 UNSECURE = "UNSECURE"
1704
Baruch Siachb82a5712021-03-11 18:18:37 +02001705 if seg_info is None or len(seg_info) == 0:
T Michael Turney540b8ec2020-01-24 08:42:47 -08001706 raise RuntimeError('Invalid segment information passed: ' + seg_info)
Varadarajan Narayanan2dfbd932016-04-21 16:06:06 +05301707
1708 # Conditional checks and assignments of the corresponding segment flag values
1709 if NOTPAGEABLE in seg_info:
1710 if RO in seg_info:
1711 ret_val = MI_PBT_ELF_AMSS_NON_PAGED_RO_SEGMENT
1712 elif CODE in seg_info:
1713 ret_val = MI_PBT_ELF_AMSS_NON_PAGED_RO_SEGMENT
1714 elif ZI in seg_info:
1715 if SWAP_POOL in seg_info:
1716 if POOL_INDEX_0 in seg_info:
1717 ret_val = MI_PBT_ELF_SWAP_POOL_NON_PAGED_ZI_SEGMENT_INDEX0
1718 else:
1719 ret_val = MI_PBT_ELF_SWAP_POOL_NON_PAGED_ZI_SEGMENT_INDEX1
1720 else:
1721 ret_val = MI_PBT_ELF_AMSS_NON_PAGED_ZI_SEGMENT
1722
1723 elif NOTUSED in seg_info:
1724 ret_val = MI_PBT_ELF_AMSS_NON_PAGED_NOTUSED_SEGMENT
1725
1726 elif SHARED in seg_info:
1727 ret_val = MI_PBT_ELF_AMSS_NON_PAGED_SHARED_SEGMENT
1728 elif HASHTBL in seg_info:
1729 ret_val = MI_PBT_ELF_HASH_SEGMENT
1730 elif BOOT_SEGMENT in seg_info:
1731 ret_val = MI_PBT_ELF_BOOT_SEGMENT
1732 elif L4BSP in seg_info:
1733 ret_val = MI_PBT_ELF_NON_PAGED_L4BSP_SEGMENT
1734 else:
1735 ret_val = MI_PBT_ELF_AMSS_NON_PAGED_RW_SEGMENT
1736
1737 elif PAGEABLE in seg_info:
1738 if RO in seg_info or CODE in seg_info:
1739 if SWAPABLE in seg_info:
1740 if POOL_INDEX_0 in seg_info:
1741 ret_val = MI_PBT_ELF_SWAPPED_PAGED_RO_SEGMENT_INDEX0
1742 else:
1743 ret_val = MI_PBT_ELF_SWAPPED_PAGED_RO_SEGMENT_INDEX1
1744 else:
1745 ret_val = MI_PBT_ELF_AMSS_PAGED_RO_SEGMENT
1746 elif ZI in seg_info:
1747 ret_val = MI_PBT_ELF_AMSS_PAGED_ZI_SEGMENT
1748
1749 elif NOTUSED in seg_info:
1750 ret_val = MI_PBT_ELF_AMSS_PAGED_NOTUSED_SEGMENT
1751 elif SHARED in seg_info:
1752 ret_val = MI_PBT_ELF_AMSS_PAGED_SHARED_SEGMENT
1753 elif L4BSP in seg_info:
1754 ret_val = MI_PBT_ELF_PAGED_L4BSP_SEGMENT
1755 else:
1756 ret_val = MI_PBT_ELF_AMSS_PAGED_RW_SEGMENT
1757
1758 elif PAGELOCKED in seg_info:
1759 ret_val = MI_PBT_ELF_PAGED_LOCKED_SEGMENT
1760 elif PAGEUNLOCKED in seg_info:
1761 ret_val = MI_PBT_ELF_PAGED_UNLOCKED_SEGMENT
1762 elif NONPAGE in seg_info:
1763 ret_val = MI_PBT_ELF_RESIDENT_SEGMENT
1764 elif UNSECURE in seg_info:
1765 ret_val = MI_PBT_ELF_UNSECURE_SEGMENT
1766
1767 else:
T Michael Turney540b8ec2020-01-24 08:42:47 -08001768 raise RuntimeError('The segment name is wrongly defined in the SCL file: ' + seg_info)
Varadarajan Narayanan2dfbd932016-04-21 16:06:06 +05301769
1770 return ret_val
1771
1772#----------------------------------------------------------------------------
1773# Pad a file with specific number of bytes
1774# Note: Assumes the fp is seeked to the correct location of padding
1775#----------------------------------------------------------------------------
1776def pad_file(fp, num_bytes, value):
1777
1778 if num_bytes < 0:
T Michael Turney540b8ec2020-01-24 08:42:47 -08001779 raise RuntimeError("Number of bytes to pad must be greater than zero")
Varadarajan Narayanan2dfbd932016-04-21 16:06:06 +05301780
1781 while num_bytes > 0:
1782 fp.write('%c' % value)
1783 num_bytes -= 1
1784
1785 return
1786
1787#----------------------------------------------------------------------------
1788# Concatenates the files listed in 'sources' in order and writes to 'target'
1789#----------------------------------------------------------------------------
1790def concat_files (target, sources):
1791 if type(sources) is not list:
1792 sources = [sources]
1793
1794 target_file = OPEN(target,'wb')
1795
1796 for fname in sources:
1797 file = OPEN(fname,'rb')
1798 while True:
1799 bin_data = file.read(65536)
1800 if not bin_data:
1801 break
1802 target_file.write(bin_data)
1803 file.close()
1804 target_file.close()
1805
1806#----------------------------------------------------------------------------
1807# Parse build configurable values and assign to global variables for tools
1808#----------------------------------------------------------------------------
1809def init_build_vars(env):
1810
1811 # Maximum size of Certificate Chain used in Secure Boot
1812 global CERT_CHAIN_ONEROOT_MAXSIZE
1813 CERT_CHAIN_ONEROOT_MAXSIZE = get_dict_value(env['GLOBAL_DICT'], 'CERT_CHAIN_MAXSIZE', (6*1024))
1814
1815 # Maximum size of the XML Header used in encrypted ELF images
1816 global XML_HEADER_MAXSIZE
1817 XML_HEADER_MAXSIZE = get_dict_value(env['GLOBAL_DICT'], 'XML_HEADER_MAXSIZE', (2*1024))
1818
1819#----------------------------------------------------------------------------
1820# Generates the global dictionary and add to the environment
1821#----------------------------------------------------------------------------
1822def generate_global_dict(env):
1823
1824 # Get file names for 'cust' and 'targ' auto-generated files inside 'build/ms'
1825 cust_h = env.subst('CUST${BUILD_ID}.H').lower()
1826 targ_h = env.subst('TARG${BUILD_ID}.H').lower()
1827 cust_file_name = str(env.FindFile(cust_h, "${INC_ROOT}/build/ms"))
1828 targ_file_name = str(env.FindFile(targ_h, "${INC_ROOT}/build/ms"))
1829
1830 # Check that files are present
1831 if (os.path.exists(cust_file_name) is True) and \
1832 (os.path.exists(targ_file_name) is True):
1833
1834 # Populate the dictionary from the auto-generated files
1835 global_dict = populate_dictionary(targ_file_name, cust_file_name)
1836 else:
1837 global_dict = {}
1838
1839 # Add the dictionary to the environment
1840 env.Replace(GLOBAL_DICT = global_dict)
1841
1842#----------------------------------------------------------------------------
1843# Populate the dictionary from a list of input files
1844#----------------------------------------------------------------------------
1845def populate_dictionary(*args):
1846
1847 if len(args) < 1:
T Michael Turney540b8ec2020-01-24 08:42:47 -08001848 raise RuntimeError("At least 1 file must be specified as an input")
Varadarajan Narayanan2dfbd932016-04-21 16:06:06 +05301849
1850 global_dict = {}
1851 Fields = ["Define", "Key", "Value"]
1852
1853 # For each input file
1854 for i in range(len(args)):
1855
1856 template_file_path = args[i]
1857 instream = OPEN(template_file_path, 'r')
1858 # Tokenize each line with a white space
1859 values = csv.DictReader(instream, Fields, delimiter=" ")
1860
1861 for values in itertools.izip(values):
1862 new_entry = values[0]
1863 # Verify the parsed tokens
1864 if (new_entry['Define'] == '#define') and \
1865 (new_entry['Key'] != None) and \
1866 (new_entry['Value'] != None):
1867
1868 new_key = new_entry['Key'].strip()
1869 new_value = new_entry['Value'].strip()
1870
1871 # If value pair is empty string, assume feature definition is true
1872 if new_value == '':
1873 new_value = 'yes'
1874
1875 # Check for and handle text replacements as we parse
1876 if global_dict is not None and len(global_dict.keys()) > 0:
1877 for key in global_dict:
1878 new_value = new_value.replace(key, str(global_dict.get(key)))
1879
1880 # Attempt to evaluate value
1881 try:
1882 new_value = eval(new_value)
1883 # Catch exceptions and do not evaluate
1884 except:
1885 pass
1886
1887 # Add to global dictionary
1888 global_dict[new_key] = new_value
1889 instream.close()
1890
1891 return global_dict
1892
1893#----------------------------------------------------------------------------
1894# Filter out a generic dictionary from the global dictionary
1895#----------------------------------------------------------------------------
1896def filter_dictionary(env, global_dict, **kwargs):
1897
1898 # Check for Image Type
1899 # If IMAGE_TYPE parameter is not provided, raise error
1900 if not kwargs.has_key('IMAGE_TYPE'):
T Michael Turney540b8ec2020-01-24 08:42:47 -08001901 raise RuntimeError("IMAGE_TYPE must be defined to use FilterDictionary.")
Varadarajan Narayanan2dfbd932016-04-21 16:06:06 +05301902 else:
1903 image_type = kwargs.get('IMAGE_TYPE')
1904 if type(image_type) is not str:
T Michael Turney540b8ec2020-01-24 08:42:47 -08001905 raise RuntimeError("IMAGE_TYPE must be of string type.")
Varadarajan Narayanan2dfbd932016-04-21 16:06:06 +05301906
1907 # Check for Flash Type
1908 # If FLASH_TYPE parameter is not provided, default to 'nand'
1909 if not kwargs.has_key('FLASH_TYPE'):
1910 flash_type = 'nand'
1911 else:
1912 flash_type = kwargs.get('FLASH_TYPE')
1913 if type(flash_type) is not str:
T Michael Turney540b8ec2020-01-24 08:42:47 -08001914 raise RuntimeError("FLASH_TYPE must be of string type. ")
Varadarajan Narayanan2dfbd932016-04-21 16:06:06 +05301915
1916 # Check for MBN Type
1917 # If MBN_TYPE parameter is not provided, default to 'elf'
1918 if not kwargs.has_key('MBN_TYPE'):
1919 mbn_type = 'elf'
1920 else:
1921 mbn_type = kwargs.get('MBN_TYPE')
1922 if mbn_type != 'elf' and mbn_type != 'bin':
T Michael Turney540b8ec2020-01-24 08:42:47 -08001923 raise RuntimeError("MBN_TYPE currently not supported: " + mbn_type)
Varadarajan Narayanan2dfbd932016-04-21 16:06:06 +05301924
1925 # Check for Image ID
1926 # If IMAGE_ID parameter is not provided, default to ID 0
1927 if not kwargs.has_key('IMAGE_ID'):
1928 image_id = ImageType.NONE_IMG
1929 else:
1930 image_id = kwargs.get('IMAGE_ID')
1931 if type(image_id) is not int:
T Michael Turney540b8ec2020-01-24 08:42:47 -08001932 raise RuntimeError("IMAGE_ID must be of integer type.")
Varadarajan Narayanan2dfbd932016-04-21 16:06:06 +05301933
1934 # Initialize
1935 gen_dict = {}
1936 image_dest = 0
1937 image_source = 0
1938
1939 # Check for image_type
1940 if image_type not in image_id_table:
1941 id = image_id
1942 id_match_str = image_type.upper() + "_IMG"
1943 id_mbn_type = mbn_type
1944 else:
1945 id = image_id_table[image_type][0]
1946 id_match_str = image_id_table[image_type][1]
1947 id_mbn_type = image_id_table[image_type][2]
1948
1949 # Handle MBN Type and assign image destination address
Baruch Siachb82a5712021-03-11 18:18:37 +02001950 if id_mbn_type == 'elf':
Varadarajan Narayanan2dfbd932016-04-21 16:06:06 +05301951 pass
Baruch Siachb82a5712021-03-11 18:18:37 +02001952 elif id_mbn_type == 'bin':
Varadarajan Narayanan2dfbd932016-04-21 16:06:06 +05301953 template_key_match = 'IMAGE_KEY_' + id_match_str + "_DEST_ADDR"
1954 if template_key_match in global_dict:
1955 image_dest = global_dict[template_key_match]
1956 else:
T Michael Turney540b8ec2020-01-24 08:42:47 -08001957 raise RuntimeError("Builds file does not have IMAGE_KEY pair for: " + image_type)
Varadarajan Narayanan2dfbd932016-04-21 16:06:06 +05301958 else:
T Michael Turney540b8ec2020-01-24 08:42:47 -08001959 raise RuntimeError("MBN_TYPE currently not supported: " + mbn_type)
Varadarajan Narayanan2dfbd932016-04-21 16:06:06 +05301960
1961 # Assign generic dictionary key/value pairs
1962 gen_dict['IMAGE_KEY_IMAGE_ID'] = id
1963 gen_dict['IMAGE_KEY_IMAGE_DEST'] = image_dest
1964 gen_dict['IMAGE_KEY_IMAGE_SOURCE'] = image_source
1965 gen_dict['IMAGE_KEY_FLASH_TYPE'] = flash_type
1966 gen_dict['IMAGE_KEY_MBN_TYPE'] = id_mbn_type
1967 gen_dict['IMAGE_KEY_ID_MATCH_STR'] = id_match_str
1968 gen_dict['IMAGE_KEY_FLASH_AUTO_DETECT_MAX_PAGE'] = \
1969 get_dict_value(global_dict,'FLASH_AUTO_DETECT_MAX_PAGE', 8192)
1970 gen_dict['IMAGE_KEY_FLASH_AUTO_DETECT_MIN_PAGE'] = \
1971 get_dict_value(global_dict,'FLASH_AUTO_DETECT_MIN_PAGE', 2048)
1972 gen_dict['IMAGE_KEY_MAX_SIZE_OF_VERIFY_BUFFER'] = \
1973 get_dict_value(global_dict,'MAX_SIZE_OF_VERIFY_BUFFER', 8192)
1974 gen_dict['IMAGE_KEY_BOOT_SMALL_PREAMBLE'] = \
1975 get_dict_value(global_dict,'BOOT_SMALL_PREAMBLE', 1)
1976
1977 # Get OEM root certificate select and number
1978 oem_root_cert_sel = get_dict_value(global_dict,'OEM_ROOT_CERT_SEL', 1)
1979 oem_num_root_certs = get_dict_value(global_dict,'OEM_NUM_ROOT_CERTS', 1)
1980
1981 # Error checking for OEM configurable values
1982 if oem_root_cert_sel in range(1, MAX_NUM_ROOT_CERTS + 1) and \
1983 oem_num_root_certs in range(1, MAX_NUM_ROOT_CERTS + 1) and \
1984 oem_root_cert_sel <= oem_num_root_certs:
1985
1986 gen_dict['IMAGE_KEY_OEM_ROOT_CERT_SEL'] = oem_root_cert_sel
1987 gen_dict['IMAGE_KEY_OEM_NUM_ROOT_CERTS'] = oem_num_root_certs
1988
1989 else:
T Michael Turney540b8ec2020-01-24 08:42:47 -08001990 raise RuntimeError("Invalid OEM root certificate configuration values")
Varadarajan Narayanan2dfbd932016-04-21 16:06:06 +05301991
1992 # Assign additional dictionary key/values pair as needed by tools.
1993
1994 return gen_dict
1995
1996
1997#----------------------------------------------------------------------------
1998# Get index value from dictionary if exists, otherwise return default
1999#----------------------------------------------------------------------------
2000def get_dict_value(dict, key_string, default):
2001
2002 key = 'IMAGE_KEY_' + key_string
2003
2004 if key in dict:
2005 return dict[key]
2006 else:
2007 return default
2008
2009#----------------------------------------------------------------------------
2010# Preprocess an ELF file and return the ELF Header Object and an
2011# array of ELF Program Header Objects
2012#----------------------------------------------------------------------------
2013def preprocess_elf_file(elf_file_name):
2014
2015 # Initialize
2016 elf_fp = OPEN(elf_file_name, 'rb')
2017 elf_header = Elf_Ehdr_common(elf_fp.read(ELF_HDR_COMMON_SIZE))
2018
2019 if verify_elf_header(elf_header) is False:
T Michael Turney540b8ec2020-01-24 08:42:47 -08002020 raise RuntimeError("ELF file failed verification: " + elf_file_name)
Varadarajan Narayanan2dfbd932016-04-21 16:06:06 +05302021
2022 elf_fp.seek(0)
2023
2024 if elf_header.e_ident[ELFINFO_CLASS_INDEX] == ELFINFO_CLASS_64:
2025 elf_header = Elf64_Ehdr(elf_fp.read(ELF64_HDR_SIZE))
2026 else:
2027 elf_header = Elf32_Ehdr(elf_fp.read(ELF32_HDR_SIZE))
2028
2029 phdr_table = []
2030
2031 # Verify ELF header information
2032 if verify_elf_header(elf_header) is False:
T Michael Turney540b8ec2020-01-24 08:42:47 -08002033 raise RuntimeError("ELF file failed verification: " + elf_file_name)
Varadarajan Narayanan2dfbd932016-04-21 16:06:06 +05302034
2035 # Get program header size
2036 phdr_size = elf_header.e_phentsize
2037
2038 # Find the program header offset
2039 file_offset = elf_header.e_phoff
2040 elf_fp.seek(file_offset)
2041
2042 # Read in the program headers
2043 for i in range(elf_header.e_phnum):
2044 if elf_header.e_ident[ELFINFO_CLASS_INDEX] == ELFINFO_CLASS_64:
2045 phdr_table.append(Elf64_Phdr(elf_fp.read(phdr_size)))
2046 else:
2047 phdr_table.append(Elf32_Phdr(elf_fp.read(phdr_size)))
2048
2049 elf_fp.close()
2050 return [elf_header, phdr_table]
2051
2052#----------------------------------------------------------------------------
2053# Get the hash table address from an input ELF file
2054#----------------------------------------------------------------------------
2055def get_hash_address(elf_file_name):
2056
2057 [elf_header, phdr_table] = preprocess_elf_file(elf_file_name)
2058
2059 last_paddr = 0
2060 last_paddr_segment = 0
2061
2062 # Find the segment with the largest physical address.
2063 # Hash segment's physical address will be immediately after this segment.
2064 for i in range(elf_header.e_phnum):
2065 curr_phdr = phdr_table[i]
2066 if curr_phdr.p_paddr > last_paddr:
2067 # Skip the demand paging segment as it would be outside the physical RAM location
T Michael Turney101098c2018-05-01 15:59:37 -07002068 if MI_PBT_SEGMENT_TYPE_VALUE(curr_phdr.p_flags) != MI_PBT_XBL_SEC_SEGMENT:
Varadarajan Narayanan2dfbd932016-04-21 16:06:06 +05302069 last_paddr = curr_phdr.p_paddr;
2070 last_paddr_segment = i;
2071
2072 max_phdr = phdr_table[last_paddr_segment]
2073
2074 ret_val = (((max_phdr.p_paddr + max_phdr.p_memsz - 1) & \
2075 ~(ELF_BLOCK_ALIGN-1)) + ELF_BLOCK_ALIGN)
2076
2077 return ret_val
2078
2079#----------------------------------------------------------------------------
2080# Verify ELF header contents from an input ELF file
2081#----------------------------------------------------------------------------
2082def verify_elf_header(elf_header):
T Michael Turney540b8ec2020-01-24 08:42:47 -08002083 if (elf_header.e_ident[ELFINFO_MAG0_INDEX] != ELFINFO_MAG0):
2084 print("MAG0[{:d}]\n".format((elf_header.e_ident[ELFINFO_MAG0_INDEX])))
Varadarajan Narayanan2dfbd932016-04-21 16:06:06 +05302085 return False
T Michael Turney540b8ec2020-01-24 08:42:47 -08002086 if (elf_header.e_ident[ELFINFO_MAG1_INDEX] != ELFINFO_MAG1):
2087 print("MAG1[{:d}]\n".format((elf_header.e_ident[ELFINFO_MAG1_INDEX])))
2088 return False
2089 if (elf_header.e_ident[ELFINFO_MAG2_INDEX] != ELFINFO_MAG2):
2090 print("MAG2[{:d}]\n".format((elf_header.e_ident[ELFINFO_MAG2_INDEX])))
2091 return False
2092 if (elf_header.e_ident[ELFINFO_MAG3_INDEX] != ELFINFO_MAG3):
2093 print("MAG3[{:d}]\n".format((elf_header.e_ident[ELFINFO_MAG3_INDEX])))
2094 return False
2095 if ((elf_header.e_ident[ELFINFO_CLASS_INDEX] != ELFINFO_CLASS_64) and \
2096 (elf_header.e_ident[ELFINFO_CLASS_INDEX] != ELFINFO_CLASS_32)):
2097 print("ELFINFO_CLASS_INDEX[{:d}]\n".format((elf_header.e_ident[ELFINFO_CLASS_INDEX])))
2098 return False
2099 if (elf_header.e_ident[ELFINFO_VERSION_INDEX] != ELFINFO_VERSION_CURRENT):
2100 print("ELFINFO_VERSION_INDEX[{:d}]\n".format((elf_header.e_ident[ELFINFO_VERSION_INDEX])))
2101 return False
2102 return True
Varadarajan Narayanan2dfbd932016-04-21 16:06:06 +05302103
2104#----------------------------------------------------------------------------
2105# Perform file copy given offsets and the number of bytes to copy
2106#----------------------------------------------------------------------------
2107def file_copy_offset(in_fp, in_off, out_fp, out_off, num_bytes):
2108 in_fp.seek(in_off)
2109 read_in = in_fp.read(num_bytes)
2110 out_fp.seek(out_off)
2111 out_fp.write(read_in)
2112
2113 return num_bytes
2114
2115#----------------------------------------------------------------------------
2116# sha1/sha256 hash routine wrapper
2117#----------------------------------------------------------------------------
T Michael Turneybcd62f52019-08-07 14:26:32 -07002118def header_size(header_version):
2119 if header_version >= 6:
2120 return 48
2121 else:
2122 return 40
2123
2124#----------------------------------------------------------------------------
2125# sha1/sha256 hash routine wrapper
2126#----------------------------------------------------------------------------
2127def generate_hash(in_buf, sha_algo):
Varadarajan Narayanan2dfbd932016-04-21 16:06:06 +05302128 # Initialize a SHA1 object from the Python hash library
T Michael Turneybcd62f52019-08-07 14:26:32 -07002129 if sha_algo == 'SHA384':
2130 m = hashlib.sha384()
2131 elif sha_algo == 'SHA256':
Varadarajan Narayanan2dfbd932016-04-21 16:06:06 +05302132 m = hashlib.sha256()
2133 else:
2134 m = hashlib.sha1()
2135
2136 # Set the input buffer and return the output digest
2137 m.update(in_buf)
2138 return m.digest()
2139
2140#----------------------------------------------------------------------------
2141# Initialize the hash program header.
2142#----------------------------------------------------------------------------
2143def initialize_hash_phdr(elf_in_file_name, hash_tbl_size, hdr_size, hdr_offset, is_elf64):
2144 # Set hash header offset to page size boundary. Hash table will be
2145 # located at first segment of elf image.
2146 hash_hdr_size = hdr_size
2147 hash_hdr_offset = hdr_offset
2148 hash_tbl_offset = hash_hdr_offset + hash_hdr_size
2149 hash_tbl_end_addr = hash_tbl_offset + hash_tbl_size;
2150 pad_hash_segment = (hash_tbl_end_addr) & (ELF_BLOCK_ALIGN-1)
2151
2152 # Update the hash table program header
2153 if is_elf64 is True:
T Michael Turney540b8ec2020-01-24 08:42:47 -08002154 hash_Phdr = Elf64_Phdr(b'\0'*ELF64_PHDR_SIZE)
Varadarajan Narayanan2dfbd932016-04-21 16:06:06 +05302155 else:
T Michael Turney540b8ec2020-01-24 08:42:47 -08002156 hash_Phdr = Elf32_Phdr(b'\0'*ELF32_PHDR_SIZE)
Varadarajan Narayanan2dfbd932016-04-21 16:06:06 +05302157 hash_Phdr.p_flags = MI_PBT_ELF_HASH_SEGMENT
2158 hash_Phdr.p_align = ELF_BLOCK_ALIGN
2159 hash_Phdr.p_offset = hash_hdr_offset
2160 hash_Phdr.p_memsz = hash_hdr_size + hash_tbl_size + (ELF_BLOCK_ALIGN - pad_hash_segment)
2161 hash_Phdr.p_filesz = hash_hdr_size + hash_tbl_size
2162 hash_Phdr.p_type = NULL_TYPE
2163 hash_Phdr.p_vaddr = get_hash_address(elf_in_file_name)
2164 hash_Phdr.p_paddr = hash_Phdr.p_vaddr
2165
2166 return [hash_Phdr, pad_hash_segment, hash_tbl_end_addr, hash_tbl_offset]
2167
2168#----------------------------------------------------------------------------
2169# image_preamble
2170#----------------------------------------------------------------------------
2171def image_preamble(gen_dict, preamble_file_name, boot_sbl_header, num_of_pages=None):
2172 # Generate the preamble file
2173 preamble_fp = OPEN(preamble_file_name, 'wb')
2174
2175 # Initialize
2176 max_size_verify = gen_dict['IMAGE_KEY_MAX_SIZE_OF_VERIFY_BUFFER']
2177 flash_max_page = gen_dict['IMAGE_KEY_FLASH_AUTO_DETECT_MAX_PAGE']
2178 flash_min_page = gen_dict['IMAGE_KEY_FLASH_AUTO_DETECT_MIN_PAGE']
2179 autodetectpage = [int('0xFFFFFFFF',16)] * max_size_verify
2180
2181 # The first three entries in the preamble must include the following values
2182 autodetectpage[0] = FLASH_CODE_WORD
2183 autodetectpage[1] = MAGIC_NUM
2184 if (num_of_pages == 64):
2185 autodetectpage[2] = AUTODETECT_PAGE_SIZE_MAGIC_NUM64
2186 elif (num_of_pages == 128):
2187 autodetectpage[2] = AUTODETECT_PAGE_SIZE_MAGIC_NUM128
2188 else:
2189 autodetectpage[2] = AUTODETECT_PAGE_SIZE_MAGIC_NUM
2190
2191 # Package the list into binary data to be written to the preamble
2192 s = struct.Struct('I' * max_size_verify)
2193 packed_data = s.pack(*autodetectpage)
2194
2195 # Output preamble pages based on maximum/minimum page size support
2196 for i in range(flash_max_page/flash_min_page):
2197 preamble_fp.write(packed_data[:flash_min_page])
2198
2199 # Determine appropriate amount of padding for the preamble and
2200 # update the boot_sbl_header accordingly
2201 if gen_dict['IMAGE_KEY_BOOT_SMALL_PREAMBLE'] == 1:
2202 boot_sbl_header.image_src += (flash_max_page + flash_min_page)
2203 amount_to_write = flash_min_page
2204 else:
2205 boot_sbl_header.image_src += flash_max_page * 2
2206 amount_to_write = flash_max_page
2207
2208 pad_file(preamble_fp, amount_to_write, PAD_BYTE_1)
2209 preamble_fp.close()
2210
2211 return boot_sbl_header
2212
2213#----------------------------------------------------------------------------
2214# Helper functions to parse ELF program headers
2215#----------------------------------------------------------------------------
2216def MI_PBT_SEGMENT_TYPE_VALUE(x):
2217 return ( ((x) & MI_PBT_FLAG_SEGMENT_TYPE_MASK) >> MI_PBT_FLAG_SEGMENT_TYPE_SHIFT )
2218
2219def MI_PBT_PAGE_MODE_VALUE(x):
2220 return ( ((x) & MI_PBT_FLAG_PAGE_MODE_MASK) >> MI_PBT_FLAG_PAGE_MODE_SHIFT )
2221
2222def MI_PBT_ACCESS_TYPE_VALUE(x):
2223 return ( ((x) & MI_PBT_FLAG_ACCESS_TYPE_MASK) >> MI_PBT_FLAG_ACCESS_TYPE_SHIFT )
2224
2225def MI_PBT_CHECK_FLAG_TYPE(x):
2226 return (MI_PBT_SEGMENT_TYPE_VALUE(x) != MI_PBT_HASH_SEGMENT) and \
2227 (MI_PBT_ACCESS_TYPE_VALUE(x) != MI_PBT_NOTUSED_SEGMENT) and \
2228 (MI_PBT_ACCESS_TYPE_VALUE(x) != MI_PBT_SHARED_SEGMENT)
2229
2230
2231#----------------------------------------------------------------------------
2232# Helper functions to open a file and return a valid file object
2233#----------------------------------------------------------------------------
2234def OPEN(file_name, mode):
2235 try:
2236 fp = open(file_name, mode)
2237 except IOError:
T Michael Turney540b8ec2020-01-24 08:42:47 -08002238 raise RuntimeError("The file could not be opened: " + file_name)
Varadarajan Narayanan2dfbd932016-04-21 16:06:06 +05302239
2240 # File open has succeeded with the given mode, return the file object
2241 return fp
2242
2243#----------------------------------------------------------------------------
2244# Helper functions to insert MCs in SBL1(Badger) if ENABLE_VIRTUAL_BLK is ON
2245#----------------------------------------------------------------------------
2246def insert_SBL1_magicCookie (env, target):
2247 file = open(target, "rb")
2248 #read the file contents
2249 filedata = file.read()
2250 length = len(filedata)
2251 file.close()
2252
2253 if (length <= VIRTUAL_BLOCK_SIZE):
2254 return None
2255 else:
2256 #remove the previous file
2257 os.remove(target)
2258 #generate new file for appending target data + required MCs
2259 file = open(target, "ab")
2260
2261 while length > VIRTUAL_BLOCK_SIZE:
2262 filedata_till_128kb = filedata[0:VIRTUAL_BLOCK_SIZE]
2263 filedata_after_128kb = filedata[VIRTUAL_BLOCK_SIZE:length]
2264
2265 a = str(hex(FLASH_CODE_WORD))
2266 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))
2267
2268 b = str(hex(MAGIC_NUM))
2269 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))
2270
2271 c = str(hex(SBL_VIRTUAL_BLOCK_MAGIC_NUM))
2272 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))
2273
2274 MC_inserted_data = filedata_till_128kb + mc1 + mc2 + mc3
2275 file.write(MC_inserted_data)
2276
2277 filedata = filedata_after_128kb
2278 length = len(filedata)
2279
2280 #copy the leftover data (<128KB) in output file
2281 if length > 0:
2282 file.write(filedata)
2283
2284 #close the final output file
2285 file.close()
2286 # MC_insertion code end
2287
2288#----------------------------------------------------------------------------
2289# Helper functions to remove MCs in SBL1(Badger)
2290#----------------------------------------------------------------------------
2291def remove_SBL1_magicCookie (env, target, dest):
2292 file = open(target, "rb")
2293 #read the file contents
2294 filedata = file.read()
2295 length = len(filedata)
2296 file.close()
2297
2298 #generate new file for appending target data + required MCs
2299 file = open(dest, "ab")
2300
2301 while length > VIRTUAL_BLOCK_SIZE:
2302 filedata_till_128kb = filedata[0:VIRTUAL_BLOCK_SIZE]
2303 # skipped 12 byte of Virtual Block Magic Cookie Header
2304 filedata_after_128kb = filedata[VIRTUAL_BLOCK_SIZE+MAGIC_COOKIE_LENGTH:length]
2305
2306 file.write(filedata_till_128kb)
2307
2308 filedata = filedata_after_128kb
2309 length = len(filedata)
2310
2311 #copy the leftover data (<128KB) in output file
2312 if length > 0:
2313 file.write(filedata)
2314
2315 #close the final output file
2316 file.close()
2317
2318 # MC_removal code end
2319
2320#----------------------------------------------------------------------------
2321# Helper functions to pad SBL1 image
2322# min_size defaults to 256k
2323# If page_size or num_of_pages is set to 0, the variable is unset
2324#----------------------------------------------------------------------------
2325def pad_SBL1_image (env, target, min_size_with_pad=MIN_IMAGE_SIZE_WITH_PAD, page_size=0, num_of_pages=0):
2326 file = open(target, "rb")
2327 #read the file contents
2328 filedata = file.read()
2329 length = len(filedata)
2330 file.close()
2331
2332 multiple = 1
2333 alignment = page_size * num_of_pages
2334
2335 if (length > alignment and alignment > 0):
2336 import math
2337 multiple = math.ceil(length/float(alignment))
2338
2339 final_image_size = max(min_size_with_pad, multiple * alignment)
2340
2341 if length < final_image_size:
2342 sbl1_fp = open(target, 'ab')
2343 pad_file (sbl1_fp, (final_image_size-length), PAD_BYTE_0)
2344 sbl1_fp.close()
2345
2346 # SBL1 pad code end
2347#----------------------------------------------------------------------------
2348# HELPER FUNCTIONS END
2349#----------------------------------------------------------------------------