mirror of
https://github.com/openmv/openmv.git
synced 2025-11-04 14:49:50 +08:00
683 lines
27 KiB
Python
Executable File
683 lines
27 KiB
Python
Executable File
#!/usr/bin/env python3
|
|
#pylint: disable=invalid-name,superfluous-parens,anomalous-unicode-escape-in-string
|
|
|
|
"""
|
|
__author__ = ""
|
|
__copyright__ =Copyright 2021, ALIF Semiconductor"
|
|
__version__ = "0.06.000"
|
|
|
|
|
|
|
|
where:
|
|
OBJECT_TYPE: FIREWALL or IMAGE
|
|
CPU_ID: A32_0, A32_1, A32_2, A32_3, M55_HP, M55_HE
|
|
FLAGS: COMPRESS, ENCRYPT, LOAD and BOOT
|
|
|
|
"""
|
|
|
|
import os
|
|
import sys
|
|
import struct
|
|
import argparse
|
|
from pathlib import Path
|
|
import zlib
|
|
import json
|
|
from utils import toc_common
|
|
from utils.config import *
|
|
from utils.toc_common import *
|
|
from json.decoder import JSONDecodeError
|
|
from utils.device_config import gen_device_config
|
|
from utils.sign_image_util import sign_image
|
|
from printInfo import *
|
|
from utils.gen_fw_cfg import *
|
|
|
|
# Define Version constant for each separate tool
|
|
# 0.30.000 includes image signing
|
|
# 0.31.000 strip console output to a minimum (includes printInfo)
|
|
# 0.32.000 split image signature
|
|
# 0.33.000 add mramAddress as sufix in content certificate name (to differentiate when using the same image name...)
|
|
TOOL_VERSION = "0.33.000"
|
|
|
|
EXIT_WITH_ERROR = 1
|
|
|
|
|
|
# memory defines for Alif/OEM MRAM Addresses and Sizes
|
|
#ALIF_BASE_ADDRESS = utils.mem_defs.ALIF_BASE_ADDRESS
|
|
#OEM_BASE_ADDRESS = utils.mem_defs.OEM_BASE_ADDRESS
|
|
#MRAM_BASE_ADDRESS = utils.mem_defs.MRAM_BASE_ADDRESS
|
|
|
|
# OEM TOC sizes
|
|
TOC_ENTRY_SIZE = 32
|
|
TOC_HEADER_SIZE = 32
|
|
TOC_TAIL_SIZE = 16
|
|
TOC_HEADER_VERSION = 1
|
|
|
|
# Supported CPU_ID for IMAGE object type
|
|
SUPPORTED_CPU_ID = ['A32_0',
|
|
'A32_1',
|
|
'A32_2',
|
|
'A32_3',
|
|
'M55_HP',
|
|
'M55_HE']
|
|
|
|
# Supported flags for IMAGE object type
|
|
SUPPORTED_FLAGS = ['COMPRESS',
|
|
'LOAD',
|
|
'BOOT',
|
|
'ENCRYPT',
|
|
'DEFERRED']
|
|
|
|
|
|
# Supported Attributes for JSON configuration file
|
|
SUPPORTED_ATTRIBUTES = [
|
|
'disabled',
|
|
'binary',
|
|
'signed',
|
|
'loadAddress',
|
|
'version',
|
|
'mramAddress',
|
|
'cpu_id',
|
|
'flags',
|
|
'extensions'
|
|
]
|
|
|
|
# Swtchers: there are different options for ICV and OEM...
|
|
# switcher for getObjectType()
|
|
image_switcher = {
|
|
'DEVICE' : 3
|
|
}
|
|
|
|
# switcher for getCPUID()
|
|
cpuid_switcher = {
|
|
'A32_0' : 0,
|
|
'A32_1' : 1,
|
|
'M55_HP' : 2,
|
|
'M55_HE' : 3
|
|
}
|
|
|
|
|
|
certPath = Path("cert/")
|
|
imagePath = Path("build/images")
|
|
|
|
# sizes of Certificates
|
|
CERT_CHAIN_SIZE = utils.toc_common.CERT_CHAIN_SIZE
|
|
CONT_CERT_SIZE = utils.toc_common.CONT_CERT_SIZE
|
|
CERT_CHAIN_SIZE = utils.toc_common.CERT_CHAIN_SIZE
|
|
|
|
# Global Variables
|
|
numImages = 0
|
|
oemManagedAreaStartAddress = 0
|
|
oemManagedAreaSize = 0
|
|
otocStartAddress = 0
|
|
unmanaged = []
|
|
|
|
|
|
def createOemTocPackage(fwsections, outputFile):
|
|
global oemManagedAreaStartAddress
|
|
global oemManagedAreaSize
|
|
global otocStartAddress
|
|
global unmanaged
|
|
|
|
print('Creating APP TOC Package...')
|
|
# Start by loading the Key1/Key2 Certificates for later on
|
|
printInfo("Loading Key1 Cert...")
|
|
key1Cert = getBlob(certPath / 'OEMSBKey1.crt')
|
|
printInfo("Loading Key2 Cert...")
|
|
key2Cert = getBlob(certPath / 'OEMSBKey2.crt')
|
|
|
|
# create the output file
|
|
outf = open(outputFile, 'wb')
|
|
|
|
# create a memory layout map for debugging
|
|
mapf = open('build/app-package-map.txt', 'w')
|
|
mapf.write('* * * User managed MRAM locations* * * \n')
|
|
|
|
debugScript = ''
|
|
for img in unmanaged:
|
|
printInfo('Unmanaged Images:')
|
|
imgFile = img[4]
|
|
if img[5] == 'compressed':
|
|
imgFile += '.lzf'
|
|
|
|
if img[6] == 'encrypted':
|
|
imgFile = img[4][:-4] + '_enc.bin'
|
|
|
|
printInfo(img)
|
|
mapf.write(f'{img[1]}\t{hex(img[2])}\t{img[2]}\t{img[3]}\t{imgFile}\n')
|
|
debugScript += '../build/images/' + imgFile + ' ' + img[1] + ' '
|
|
sign_image('build/images/' + imgFile, int(img[1], 16), 0xFFFFFFFF, "OEM")
|
|
|
|
|
|
# create a pointer to keep track addresses of components (object_address in OTOC)
|
|
mPointer = oemManagedAreaStartAddress
|
|
#print(f'mPointer start: {mPointer - oemManagedAreaStartAddress}')
|
|
mapf.write('\n* * * APP Package Start Address* * * \n')
|
|
mapf.write('\n - Certificates for User managed images\n')
|
|
printInfo('Unmanaged images certificates')
|
|
# start adding all Certificate Chains for Unmanaged images
|
|
for sec in fwsections:
|
|
# filter out disabled images
|
|
if sec['disabled'] == True:
|
|
continue
|
|
|
|
# filter out Managed components (they will be included after)
|
|
if sec['location'] == 'managed':
|
|
continue
|
|
|
|
# update MRAM position for object_address in OTOC
|
|
sec['object_address'] = hex(mPointer)
|
|
|
|
if sec['signed'] != False:
|
|
#print('...including Key1/key2 certs')
|
|
outf.write(key1Cert)
|
|
outf.write(key2Cert)
|
|
#mapf.write(f"{hostAddress(mPointer)}\t{hex(CERT_CHAIN_SIZE - CONT_CERT_SIZE)}\t{(CERT_CHAIN_SIZE - CONT_CERT_SIZE)}\tKey1/Key2 Certificates \n")
|
|
mapf.write(f"{hex(mPointer)}\t{hex(CERT_CHAIN_SIZE - CONT_CERT_SIZE)}\t{(CERT_CHAIN_SIZE - CONT_CERT_SIZE)}\tKey1/Key2 Certificates \n")
|
|
mPointer += (CERT_CHAIN_SIZE - CONT_CERT_SIZE)
|
|
#print(f'mPointer KC un: {mPointer - oemManagedAreaStartAddress}')
|
|
# copy the Content Certificate (for signed or unsigned images)
|
|
addContentCertificate(outf, sec['binary'] + "_" + str(sec['mramAddress']))
|
|
#mapf.write(f"{hostAddress(mPointer)}\t{hex(CONT_CERT_SIZE)}\t{(CONT_CERT_SIZE)}\tSB" + sec['binary'] + ".crt\n")
|
|
mapf.write(f"{hex(mPointer)}\t{hex(CONT_CERT_SIZE)}\t{(CONT_CERT_SIZE)}\tSB" + sec['binary'] + ".crt\n")
|
|
mPointer += CONT_CERT_SIZE
|
|
#print(f'mPointer CC un: {mPointer - oemManagedAreaStartAddress}')
|
|
|
|
# add Managed components with their respective Certificates in front of them
|
|
printInfo('Managed components')
|
|
mapf.write('\n - Certificates & images for Tool managed images\n')
|
|
for sec in fwsections:
|
|
# filter out disabled images
|
|
if sec['disabled'] == True:
|
|
continue
|
|
|
|
# filter out Unmanaged components (they were already included above)
|
|
if sec['location'] == 'unmanaged':
|
|
continue
|
|
|
|
# update MRAM position for object_address in OTOC
|
|
sec['object_address'] = hex(mPointer)
|
|
|
|
# for each managed component, copy certificates and image
|
|
if sec['signed'] != False:
|
|
#print('...including Key1/key2 certs')
|
|
outf.write(key1Cert)
|
|
outf.write(key2Cert)
|
|
#mapf.write(f"{hostAddress(mPointer)}\t{hex(CERT_CHAIN_SIZE - CONT_CERT_SIZE)}\t{(CERT_CHAIN_SIZE - CONT_CERT_SIZE)}\tKey1/Key2 Certificates \n")
|
|
mapf.write(f"{hex(mPointer)}\t{hex(CERT_CHAIN_SIZE - CONT_CERT_SIZE)}\t{(CERT_CHAIN_SIZE - CONT_CERT_SIZE)}\tKey1/Key2 Certificates \n")
|
|
mPointer += (CERT_CHAIN_SIZE - CONT_CERT_SIZE)
|
|
#print(f'mPointer - KCs: {mPointer - oemManagedAreaStartAddress}')
|
|
# copy the Content Certificate (for signed or unsigned images)
|
|
addContentCertificate(outf, sec['binary'] + "_" + str(sec['mramAddress']))
|
|
#mapf.write(f"{hostAddress(mPointer)}\t{hex(CONT_CERT_SIZE)}\t{(CONT_CERT_SIZE)}\tSB" + sec['binary'] + ".crt\n")
|
|
mapf.write(f"{hex(mPointer)}\t{hex(CONT_CERT_SIZE)}\t{(CONT_CERT_SIZE)}\tSB" + sec['binary'] + ".crt\n")
|
|
mPointer += CONT_CERT_SIZE
|
|
#print(f'mPointer - CC: {mPointer - oemManagedAreaStartAddress}')
|
|
# copy image (check for encryption or compression - both are not supported!)
|
|
binFile = sec['binary']
|
|
if 'ENCRYPT' in sec['flags']:
|
|
binFile = binFile[:-4] + "_enc.bin"
|
|
|
|
if 'COMPRESS' in sec['flags']:
|
|
binFile += '.lzf'
|
|
|
|
#print("Copying: " + binFile)
|
|
outf.write(getBlob(imagePath / binFile))
|
|
#mapf.write(f"{hostAddress(mPointer)}\t{hex(sec['size'])}\t{sec['size']}\t" + binFile + "\n")
|
|
mapf.write(f"{hex(mPointer)}\t{hex(sec['size'])}\t{sec['size']}\t" + binFile + "\n")
|
|
mPointer += sec['size']
|
|
#print(f'mPointer - size: {mPointer - oemManagedAreaStartAddress}')
|
|
# padding with 0s
|
|
if sec['padlen'] > 0:
|
|
outf.write(('\0' * sec['padlen']).encode('utf8'))
|
|
#mapf.write(f"{hostAddress(mPointer)}\t{hex(sec['padlen'])}\t{sec['padlen']}\tPadding\n")
|
|
mapf.write(f"{hex(mPointer)}\t{hex(sec['padlen'])}\t{sec['padlen']}\tPadding\n")
|
|
mPointer += sec['padlen']
|
|
#print(f'mPointer - pad: {mPointer - oemManagedAreaStartAddress}')
|
|
|
|
|
|
# finally, create the OEM TOC (verify the current pointer matches the OEM TOC Address we previously calculated)
|
|
if mPointer != otocStartAddress:
|
|
print("[ERROR] ATOC STARTS IS DIFFERENT THAN THE CALCULATED ONE!!!")
|
|
#print(f"ATOC Starts at {hostAddress(mPointer)}")
|
|
print(f"ATOC Starts at {hex(mPointer)}")
|
|
#print(f"ATOC calculated at {hostAddress(otocStartAddress)}")
|
|
print(f"ATOC calculated at {hex(otocStartAddress)}")
|
|
sys.exit(EXIT_WITH_ERROR)
|
|
|
|
#print(f"Start of ATOC: {hostAddress(otocStartAddress)}")
|
|
printInfo(f"Start of ATOC: {hex(otocStartAddress)}")
|
|
mapf.write('\n - APP TOC (Table of Content)\n')
|
|
# create the OEM TOC Header
|
|
print("Adding ATOC...")
|
|
# TOC token (identifier)
|
|
outf.write("OEMTOC01".encode('utf8'))
|
|
# TOC Header size (in bytes)
|
|
outf.write(struct.pack("H", TOC_HEADER_SIZE))
|
|
# Number of TOC entries and size
|
|
outf.write(struct.pack("H", numImages))
|
|
outf.write(struct.pack("H", TOC_ENTRY_SIZE))
|
|
# TOC version
|
|
outf.write(struct.pack("H", TOC_HEADER_VERSION))
|
|
# pad 16 bytes with 00s
|
|
outf.write(('\0' * 16).encode('utf8'))
|
|
|
|
#mapf.write(f"{hostAddress(mPointer)}\t{hex(TOC_HEADER_SIZE)}\t{TOC_HEADER_SIZE}\tAPP TOC Header\n")
|
|
mapf.write(f"{hex(mPointer)}\t{hex(TOC_HEADER_SIZE)}\t{TOC_HEADER_SIZE}\tAPP TOC Header\n")
|
|
mPointer += TOC_HEADER_SIZE
|
|
#print(f'mPointer otoc hdr: {mPointer - oemManagedAreaStartAddress}')
|
|
# create OEM TOC (numImages entries)
|
|
for sec in fwsections:
|
|
# filter out disabled images
|
|
if sec['disabled'] == True:
|
|
continue
|
|
|
|
#print(sec)
|
|
# Object_address
|
|
outf.write(struct.pack("I", int(sec['object_address'], 16)))
|
|
# object_length
|
|
outf.write(struct.pack("I", sec['size'])) # do not need to declare the pad as seram doesn't need it
|
|
# object_type
|
|
outf.write(struct.pack("I", getObjectType(sec['identifier'].rstrip('\0'), image_switcher)))
|
|
# flags
|
|
outf.write(struct.pack("I", getObjectFlags(sec['flags']) + getCPUID(sec['cpu_id'], cpuid_switcher) ))
|
|
|
|
# version
|
|
outf.write(struct.pack("I", getObjectVersion(sec['version'])))
|
|
# image_identifier
|
|
outf.write(sec['identifier'][:8].encode('utf8'))
|
|
# extension_header
|
|
outf.write(struct.pack("I", 0))
|
|
|
|
#mapf.write(f"{hostAddress(mPointer)}\t{hex(TOC_ENTRY_SIZE)}\t{TOC_ENTRY_SIZE}\tAPP TOC entry for {sec['identifier']} obj_address {hostAddress(int(sec['object_address'],16))}\n")
|
|
mapf.write(f"{hex(mPointer)}\t{hex(TOC_ENTRY_SIZE)}\t{TOC_ENTRY_SIZE}\tAPP TOC entry for {sec['identifier']} obj_address {sec['object_address']}\n")
|
|
mPointer += TOC_ENTRY_SIZE
|
|
#print(f'mPointer otoc entry: {mPointer - oemManagedAreaStartAddress}')
|
|
|
|
# write current data to file, so we can read back and calculate CRC32
|
|
outf.flush()
|
|
|
|
# create Checksum (crc32)
|
|
f = open(outputFile, "rb")
|
|
# locate start of OTOC
|
|
s = otocStartAddress - oemManagedAreaStartAddress
|
|
f.seek(s)
|
|
#f.seek((TOC_ENTRY_SIZE * numImages) + TOC_HEADER_SIZE, 2)
|
|
otoc = f.read()
|
|
f.close()
|
|
crc32 = zlib.crc32(otoc)
|
|
printInfo('Calculated CRC32: ' + hex(crc32))
|
|
|
|
# now, in the OEM, we are adding other fields in the TOC Tail
|
|
# OTOC crc32 + OTOC_startAddress + OEM_packageStart + OEM_packageSize
|
|
outf.write(struct.pack("I", crc32))
|
|
outf.write(struct.pack("I", otocStartAddress))
|
|
outf.write(struct.pack("I", oemManagedAreaStartAddress))
|
|
outf.write(struct.pack("I", oemManagedAreaSize))
|
|
|
|
#mapf.write(f"{hostAddress(mPointer)}\t{hex(TOC_TAIL_SIZE)}\t{TOC_TAIL_SIZE}\tAPP TOC Tail\n")
|
|
mapf.write(f"{hex(mPointer)}\t{hex(TOC_TAIL_SIZE)}\t{TOC_TAIL_SIZE}\tAPP TOC Tail\n")
|
|
mPointer += TOC_TAIL_SIZE
|
|
printInfo(f'mPointer atoc tail - end: {mPointer - oemManagedAreaStartAddress}')
|
|
|
|
# check the OEM Package size is the same we calculated before
|
|
if (mPointer - oemManagedAreaStartAddress) != oemManagedAreaSize:
|
|
print('[ERROR] Something is wrong! Final APP Package size is different than the calculated one...')
|
|
print(f'Calculated: {oemManagedAreaSize} bytes')
|
|
print(f'Real size: {mPointer - oemManagedAreaStartAddress} bytes')
|
|
sys.exit(EXIT_WITH_ERROR)
|
|
|
|
mapf.write("\nAPP Package Summary:\n")
|
|
mapf.write(f" - APP Package total size: {mPointer - oemManagedAreaStartAddress} bytes\n")
|
|
#mapf.write(f" - APP Package Start Address: {hostAddress(oemManagedAreaStartAddress)}\n")
|
|
mapf.write(f" - APP Package Start Address: {hex(oemManagedAreaStartAddress)}\n")
|
|
mapf.write(f" - APP TOC size: {(TOC_ENTRY_SIZE * numImages) + TOC_HEADER_SIZE + TOC_TAIL_SIZE} bytes\n")
|
|
#mapf.write(f" - APP TOC Start Address: {hostAddress(otocStartAddress)}\n")
|
|
mapf.write(f" - APP TOC Start Address: {hex(otocStartAddress)}\n")
|
|
mapf.write(f" - APP CRC32: {hex(crc32)}\n")
|
|
|
|
mapf.write('\n* * * END of APP Package * * * \n')
|
|
|
|
debugScript += '../' + outputFile + ' ' + hex(oemManagedAreaStartAddress)
|
|
|
|
# close the file
|
|
outf.close()
|
|
|
|
mapf.close()
|
|
|
|
# generate debug script file
|
|
dsFile = 'bin/application_package.ds' # Was bin/oempackage.ds
|
|
try:
|
|
os.makedirs(os.path.dirname(dsFile), exist_ok=True)
|
|
ds = open(dsFile, 'w')
|
|
#f.write('reset system\n')
|
|
ds.write('set semihosting args ' + debugScript + '\n' )
|
|
ds.write('continue\n')
|
|
ds.write('wait\n')
|
|
ds.write('reset reset.hardware\n')
|
|
ds.close()
|
|
|
|
except:
|
|
print('[ERROR] generating debug script file!')
|
|
sys.exit(EXIT_WITH_ERROR)
|
|
|
|
printInfo('Write the APP TOC package to ' + hex(oemManagedAreaStartAddress))
|
|
|
|
# take second element for sort
|
|
def orderByAddress(elem):
|
|
return elem[1]
|
|
|
|
def calcOemManagedArea(fwsections):
|
|
global numImages
|
|
global oemManagedAreaStartAddress
|
|
global oemManagedAreaSize
|
|
global otocStartAddress
|
|
global unmanaged
|
|
|
|
# verify images exist and calculate size and padding
|
|
numSignedImages = 0
|
|
numManagedImages = 0
|
|
sizeManagedImages = 0
|
|
|
|
print('Calculating APP area...')
|
|
for sec in fwsections:
|
|
# check if entry is disabled
|
|
if sec['disabled'] == True:
|
|
printInfo('Entry disabled:' + sec['identifier'])
|
|
continue
|
|
|
|
numImages += 1
|
|
|
|
# determine the size of file and if padding is needed
|
|
fsize, padlen = getImageSize('build/images/' + sec['binary'])
|
|
# update the size and padding information
|
|
sec['size'] = fsize
|
|
sec['padlen'] = padlen
|
|
|
|
# check if image requires compression
|
|
# if so, create the file using lzf utility
|
|
compressLabel = 'uncompressed'
|
|
if 'COMPRESS' in sec['flags']:
|
|
compressLabel = 'compressed'
|
|
compressImage('build/images/' + sec['binary'])
|
|
# we should have the (new) compressed file, so we will check if this is the case...
|
|
|
|
# determine the size of (compressed) file and if padding is needed
|
|
fsize, padlen = getImageSize('build/images/' + sec['binary'] + '.lzf')
|
|
# add compressed file size and update padding information
|
|
# (the compressed image will be included in the package so pad should be calculated for
|
|
# compressed file size)
|
|
sec['uncompressedSize'] = sec['size'] # uncompressed Size will be used by the certificate creation process
|
|
sec['size'] = fsize
|
|
sec['padlen'] = padlen
|
|
|
|
# check encryption
|
|
encryptionLabel = 'unencrypted'
|
|
if 'ENCRYPT' in sec['flags']:
|
|
encryptionLabel = 'encrypted'
|
|
|
|
|
|
# if image is signed
|
|
if sec['signed'] != False:
|
|
numSignedImages += 1
|
|
|
|
# if image is Managed (not Fixed Address => mramAddress different than 0 or none)
|
|
if sec['mramAddress'] == 'none' or sec['mramAddress'] == 0:
|
|
numManagedImages += 1
|
|
sizeManagedImages += ( sec['size'] + sec['padlen'] )
|
|
sec['location'] = 'managed'
|
|
else:
|
|
sec['location'] = 'unmanaged'
|
|
if sec['signed'] == False:
|
|
signature = 'unsigned'
|
|
else:
|
|
signature = 'signed'
|
|
|
|
printInfo(f"Unmanaged: {sec['identifier']}")
|
|
tmp = (sec['identifier'], sec['mramAddress'], fsize + padlen, signature, sec['binary'], compressLabel, encryptionLabel) # we normally don't pad unmanaged images, but just in case this change in the future...
|
|
unmanaged.append(tmp)
|
|
|
|
printInfo(f"Signed Images: {numSignedImages}")
|
|
printInfo(f"Managed Images: {numManagedImages}")
|
|
printInfo(f"Managed Images total size: {sizeManagedImages:,} bytes")
|
|
|
|
# First Check: Total Managed Images should not be greater than APP MRAM SIZE
|
|
if sizeManagedImages > APP_MRAM_SIZE:
|
|
print('\n[ERROR] Images DO NOT FIT in available space. Please review images sizes \nconsidering this information:')
|
|
print(f'Total APP MRAM size: {APP_MRAM_SIZE:,} bytes')
|
|
sys.exit(EXIT_WITH_ERROR)
|
|
|
|
# calculate size of OEM TOC
|
|
otocSize = (TOC_ENTRY_SIZE * numImages) + TOC_HEADER_SIZE + TOC_TAIL_SIZE
|
|
printInfo(f"APP TOC Size: {hex(otocSize)}")
|
|
# calculate OEM TOC Starting Address in MRAM
|
|
otocStartAddress = ALIF_BASE_ADDRESS - otocSize
|
|
printInfo(f"APP TOC Address: {hex(otocStartAddress)}")
|
|
|
|
# calculate size of OEM Managed Area (total of OEM Package - don't include images with fixed addresses)
|
|
# OEM Managed Area size = size(OTOC) + size(Managed Images with Padding) + (numSignedImages * CERT_CHAIN_SIZE) + (numUnsignedImages * CONT_CERT_SIZE)
|
|
oemManagedAreaSize = otocSize + sizeManagedImages + ( numSignedImages * CERT_CHAIN_SIZE) + ( (numImages - numSignedImages) * CONT_CERT_SIZE)
|
|
printInfo(f"APP Managed Area size: {oemManagedAreaSize}")
|
|
|
|
# calculate OEM Managed Area Starting Addresses
|
|
oemManagedAreaStartAddress = ALIF_BASE_ADDRESS - oemManagedAreaSize
|
|
printInfo(f"APP Package Start Address: {hex(oemManagedAreaStartAddress)}")
|
|
|
|
# now that we know where OEM Managed Area will start (oemManagedAreaStartAddress),
|
|
# we should verify that OEM Unmanaged Area is below above address
|
|
boundary = 0
|
|
# sort list with key
|
|
unmanaged.sort(key=orderByAddress)
|
|
printInfo("Unmanaged Images - Ordered by MRAM Address")
|
|
for img in unmanaged:
|
|
printInfo(img)
|
|
|
|
startAddress = int(img[1], 16)
|
|
size = img[2]
|
|
# check overlap with previous image
|
|
if startAddress < boundary:
|
|
print('[ERROR] There is an overlap between image ' + img[0] + ' and previous image!')
|
|
print('Please correct this to continue.')
|
|
sys.exit(EXIT_WITH_ERROR)
|
|
|
|
boundary = startAddress + size
|
|
#print(hex(boundary))
|
|
|
|
|
|
|
|
# check boundary is below OEM Managed Area Starting Address
|
|
if boundary > oemManagedAreaStartAddress:
|
|
print('\n[ERROR] Images DO NOT FIT in available space. Please review layout \nconsidering this information:')
|
|
print(f'Available space is {otocStartAddress - OEM_BASE_ADDRESS} bytes starting at MRAM address {hex(OEM_BASE_ADDRESS)}')
|
|
sys.exit(EXIT_WITH_ERROR)
|
|
else:
|
|
if boundary == 0:
|
|
boundary += MRAM_BASE_ADDRESS
|
|
printInfo(f"Final boundary: {hex(boundary)}")
|
|
printInfo(f"Available MRAM: {oemManagedAreaStartAddress - boundary} bytes")
|
|
|
|
|
|
# now that we know everything fits well, we can proceed to calculate the
|
|
# the MRAM addresses for the managed images, to update the 'mramAddress' field
|
|
# (we need the MRAM address to generate the Content Certificates before start
|
|
# creating the OEM Package binary)
|
|
|
|
# we keep a pointer starting at OEM Managed Area address
|
|
mPointer = oemManagedAreaStartAddress
|
|
# we will start the OEM Managed Area layout with all certificates for Unmanaged Images
|
|
# so we need to know How many Unmanaged images are and from those, how many are Signed
|
|
# and how many are Unsigned (because we need more space for signed images than for unsigned ones)
|
|
|
|
for img in unmanaged:
|
|
if img[3] == 'signed':
|
|
mPointer += CERT_CHAIN_SIZE
|
|
else:
|
|
mPointer += CONT_CERT_SIZE
|
|
|
|
for sec in fwsections:
|
|
# check if entry is disabled
|
|
if sec['disabled'] == True:
|
|
continue
|
|
|
|
# we won't create Content Certificate for Device COnfiguration (at the moment...)
|
|
#if sec['identifier'] == 'FIREWALL':
|
|
# continue
|
|
|
|
# if image is Managed (not Fixed Address => mramAddress different than 0 or none)
|
|
if sec['mramAddress'] == 'none' or sec['mramAddress'] == 0:
|
|
# for each managed image, we need to calculate the image storage address in MRAM,
|
|
# needed to create the Content Certificate for each image
|
|
if sec['signed'] == False:
|
|
mPointer += CONT_CERT_SIZE
|
|
else:
|
|
mPointer += CERT_CHAIN_SIZE
|
|
|
|
# save the MRAM store address for Managed images
|
|
sec['mramAddress'] = hex(mPointer)
|
|
#print(sec['identifier'], sec['mramAddress'])
|
|
|
|
# move the pointer to the end of the image
|
|
mPointer += ( sec['size'] + sec['padlen'])
|
|
|
|
|
|
def validateVersAttr(version):
|
|
items = version.split('.')
|
|
if len(items)>3:
|
|
print("[ERROR] Invalid version string. Please use 'xxx.yyy.zzz' format")
|
|
sys.exit(EXIT_WITH_ERROR)
|
|
|
|
for item in items:
|
|
try:
|
|
i = int(item)
|
|
if i>=0 and i<=255:
|
|
continue
|
|
print("[ERROR] Invalid value '" + item + "' in version string: " + version)
|
|
except:
|
|
print("[ERROR] Invalid item '" + item + "' in version string: " + version)
|
|
|
|
sys.exit(EXIT_WITH_ERROR)
|
|
|
|
def updateDeviceConfig(file):
|
|
#print('*** updateDeviceConfig: ', file)
|
|
# Update the firewall configuration in the OEM DEVICE config file
|
|
update_fw_cfg_oem(file)
|
|
|
|
cfg = read_global_config('build/config/' + file)
|
|
if 'miscellaneous' in cfg:
|
|
for item in cfg['miscellaneous']:
|
|
item.pop('sdesc', None)
|
|
item.pop('ldesc', None)
|
|
item.pop('options', None)
|
|
with open('build/config/' + file, "w") as json_file:
|
|
json.dump(cfg, json_file, indent=2)
|
|
|
|
|
|
def main():
|
|
cwd_path = os.getcwd()
|
|
os.chdir(cwd_path)
|
|
global MRAM_BASE_ADDRESS
|
|
global ALIF_BASE_ADDRESS
|
|
global OEM_BASE_ADDRESS
|
|
global APP_MRAM_SIZE
|
|
|
|
if sys.version_info.major == 2:
|
|
print("[ERROR] You need Python 3 for this application!")
|
|
sys.exit(EXIT_WITH_ERROR)
|
|
|
|
"""
|
|
Parse user arguments
|
|
"""
|
|
parser = argparse.ArgumentParser(description='Generate APP TOC Package',
|
|
epilog="\N{COPYRIGHT SIGN} ALIF Semiconductor, 2023")
|
|
parser.add_argument("-f", "--filename", type=str,
|
|
default="build/config/app-cfg.json",
|
|
help="input file (check build/config/app-cfg.json as an example")
|
|
parser.add_argument("-o", "--output", type=str,
|
|
default="build/AppTocPackage.bin",
|
|
help="output file (default is build/AppTocPackage.bin")
|
|
parser.add_argument("-V", "--version", help="Display Version Number", action="store_true")
|
|
parser.add_argument("-c" ,"--clean", help="Clean build workspace (restore initial state)", action="store_true")
|
|
parser.add_argument("-v" , "--verbose", help="verbosity mode", action="store_true")
|
|
|
|
args = parser.parse_args()
|
|
|
|
if args.version:
|
|
print(TOOL_VERSION)
|
|
sys.exit()
|
|
|
|
if args.clean:
|
|
cleanBuild(['build/AppTocPackage.bin', 'build/App-package-map.txt', 'build/images/*_enc.bin', 'build/images/*.lzf', 'cert/SB*.crt'])
|
|
sys.exit()
|
|
|
|
# set verbose option
|
|
verboseModeSet(args.verbose)
|
|
|
|
# memory defines for Alif/OEM MRAM Addresses and Sizes
|
|
load_global_config()
|
|
DEVICE_PART_NUMBER = utils.config.DEVICE_PART_NUMBER
|
|
DEVICE_REVISION = utils.config.DEVICE_REVISION
|
|
ALIF_BASE_ADDRESS = utils.config.ALIF_BASE_ADDRESS
|
|
MRAM_BASE_ADDRESS = utils.config.MRAM_BASE_ADDRESS
|
|
OEM_BASE_ADDRESS = utils.config.APP_BASE_ADDRESS
|
|
APP_MRAM_SIZE = utils.config.APP_MRAM_SIZE
|
|
|
|
print('Generating APP Package with:')
|
|
print('Device Part# ' + DEVICE_PART_NUMBER + ' - Rev: ' + DEVICE_REVISION)
|
|
|
|
print('- System MRAM Base Address: ' + hex(ALIF_BASE_ADDRESS))
|
|
print('- APP MRAM Base Address: ' + hex(OEM_BASE_ADDRESS))
|
|
print('- APP MRAM Size: ' + str(APP_MRAM_SIZE))
|
|
print('- Configuration file: ' + args.filename)
|
|
print('- Output file: ' + args.output)
|
|
print('')
|
|
fwsections = read_json_file(args.filename, SUPPORTED_ATTRIBUTES, SUPPORTED_FLAGS, SUPPORTED_CPU_ID)
|
|
|
|
validateOptions(fwsections)
|
|
|
|
for sec in fwsections:
|
|
# check if entry is disabled
|
|
if sec['disabled'] is True:
|
|
print('Entry disabled:' + sec['identifier'])
|
|
continue
|
|
|
|
# check version string (format 'xx.yy.zz' where each item should be between 0 and 255)
|
|
validateVersAttr(sec['version'])
|
|
|
|
# update the size and padding information
|
|
if sec['identifier'].strip('\0') != 'DEVICE':
|
|
continue
|
|
|
|
print('Generating Device Configuration for: ' + sec['binary'])
|
|
updateDeviceConfig(sec['binary'])
|
|
gen_device_config(sec['binary'], False)
|
|
sec['binary'] = sec['binary'][:-5] + '.bin'
|
|
|
|
# also check unmanaged images (mramAddress != 0) are between boundaries (OEM_BASE_ADDRESS - only in Rev_A as in Rev_B will be 0)
|
|
# and images don't overlap... Also, advice is GAPs (big ones) exist - especially if tool can't create the layout...
|
|
calcOemManagedArea(fwsections)
|
|
|
|
printInfo(f"Images: {numImages}")
|
|
|
|
#for sec in fwsections:
|
|
# print(sec)
|
|
|
|
createContentCerts(fwsections, 'OEM')
|
|
|
|
createOemTocPackage(fwsections, args.output)
|
|
|
|
# checking the OEM TOC Package size
|
|
try:
|
|
fsize = os.path.getsize(args.output)
|
|
print("APP TOC Package size: " + str(fsize) + " bytes")
|
|
except:
|
|
print(sys.exc_info()[0])
|
|
print("ERROR: veryfing APP TOC Package size")
|
|
sys.exit(EXIT_WITH_ERROR)
|
|
|
|
sign_image(args.output, oemManagedAreaStartAddress, 0xFFFFFFFF, "OEM")
|
|
|
|
print("Done!")
|
|
return 0
|
|
|
|
if __name__ == "__main__":
|
|
main()
|