Merge pull request #2393 from openmv/alif_tools

tools/Alif: Add Alif tools.
This commit is contained in:
Ibrahim Abdelkader 2024-08-28 21:08:58 +03:00 committed by GitHub
commit 4e4f9ba377
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
186 changed files with 13102 additions and 0 deletions

8
.gitignore vendored
View File

@ -47,3 +47,11 @@ openmv.creator
openmv.creator.user
openmv.files
openmv.includes
# Alif tools temp files
######################
tools/alif/**/*.cfg
tools/alif/**/*.crt
tools/alif/**/*.ds
tools/alif/**/*.bin.sign
tools/alif/**/*map.txt

131
tools/alif/LICENSE Normal file
View File

@ -0,0 +1,131 @@
Alif Semiconductor Software License Agreement
=============================================
IMPORTANT: PLEASE READ CAREFULLY THE FOLLOWING ALIF SEMICONDUCTOR SINGAPORE
PTE. LTD. ("ALIF") SOFTWARE LICENSE AGREEMENT ("AGREEMENT").
BY INSTALLING, COPYING, DOWNLOADING, ACCESSING OR OTHERWISE USING THIS
SOFTWARE PACKAGE OR ANY PART THEREOF (AND THE RELATED DOCUMENTATION) FROM
Alif SEMICONDUCTOR, YOU AGREE ON BEHALF OF YOURSELF OR ON BEHALF OF ANY
ENTITY BY WHICH YOU ARE EMPLOYED TO BE BOUND BY THIS AGREEMENT.
Under Alif Semiconductors' intellectual property rights and subject to
applicable licensing terms for any third-party software incorporated in this
software package and applicable Open Source Terms (as defined here below),
You may use and redistribute the Software, in source and binary forms, with
or without modification, provided that the following conditions are met:
1. Redistributions in source form (including any additions or modifications
to or derivative works of the Software) must retain Alif's copyright notice
and all other copyright notices, this list of conditions and the following
disclaimers and terms.
2. Redistributions in binary form, except as embedded into microcontroller
or microprocessor device manufactured by or for Alif Semiconductor, or a
software update for such device, must reproduce Alif's copyright notice, this
list of conditions and the following disclaimers and terms in the Software
and in the documentation and any other materials provided with the
distribution.
3. Neither the name of Alif nor the names of its suppliers may be used to
endorse or promote products derived from this Software without specific prior
written permission.
4. The Software (including any additions or modifications to or derivative
works of the Software) may only be used with and executed on Alif
Semiconductors microcontroller, integrated circuits and SOC products.
5. Any use, reproduction, or redistribution of the Software (including any
derivative works thereof) may not be done in a manner or way that would
subject the Software to any "copyleft" license or other similar licensing
or distribution model, including any which would require the Software be
licensed under any such license. "Copyleft" license includes the GNU
General Public License, the GNU Library General Public License, the GNU
Lesser General Public License, the Affero General Public License, the
Mozilla Public License, the Common Development and Distribution License,
the Eclipse Public License, and any Creative Commons "sharealike" license.
6. You shall comply with all laws and regulations applicable to your use,
transfer, import or export of the Software (including any derivative works
thereof), including any applicable export control law or regulation.
Alif and its suppliers own all right, title and interest in and to the
Software, including all copies thereof. Except as provided in the preceding
section, Alif grants no licenses or other rights by implication, estoppel or
otherwise to, any patent, copyright, trademark, trade name, service mark or
other intellectual property licenses or rights of Alif. All rights not
expressly granted by Alif are hereby reserved. There are no implied rights.
This Agreement will automatically terminate if you fail to comply with any
terms or conditions of this Agreement, including any of the above conditions.
Your license to use the Software immediately terminates if you breach this
Agreement.
Alif may make changes to the Software, at any time without notice. Alif has
no obligation to update, support, or provide training for the Software.
The Software may contain open source software, third party software, or other
Alif software, including any that may be identified in the Software itself or
in the files (if any) accompanying the Software as licensed separately under
the terms of another license or agreement (collectively, the "Other
Software"). The Other Software is not licensed under this Agreement. Rather,
it is licensed to you under the terms of the applicable open source licenses,
third party license or other Alif license agreements (the "Other Software
Terms"), including any that may accompany the Software. Copyrights to the
Other Software are held by copyright holders indicated in the Other Software
Terms. To the extent required by the Other Software Terms, Alif will make
such open source software available upon written request to Alif.
ALIF PROVIDES THE SOFTWARE "AS-IS." TO THE MAXIMUM EXTENT PERMITTED BY
APPLICABLE LAW, ALIF DISCLAIMS AND EXCLUDES ALL WARRANTIES AND CONDITIONS,
WHETHER STATUTORY, EXPRESS OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE
IMPLIED WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE,
TITLE, QUIET ENJOYMENT, ACCURACY, AND NON-INFRINGEMENT OF THIRD-PARTY RIGHTS.
The Software is not intended for use in nuclear power, military, emergency,
or medical settings or applications or any life safety, critical purpose, or
other systems or applications where the use or failure of the Software may
lead to death, bodily injury, damage to person or property or environmental
damage. You agree that you are fully responsible for any claims, costs,
damages, expenses, and attorneys' fees arising out of any such use, even if
any claim alleges that Alif was negligent regarding the design or manufacture
of the Software.
IN NO EVENT SHALL ALIF OR ITS SUPPLIERS BE LIABLE FOR ANY DIRECT, INDIRECT,
INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES OR FOR ANY COST OF
COVER, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES, LOSS OF USE, DATA, OR
PROFITS, BUSINESS INTERRUPTION, OR OTHER LOSS ARISING OUT OF OR IN CONNECTION
WITH THE SOFTWARE, HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER
SOUNDING IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
OTHERWISE), EVEN IF ALIF HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGES,
NOTWITHSTANDING ANY FAILURE OF THE ESSENTIAL PURPOSE OF THIS AGREEMENT OR ANY
LIMITED REMEDY HEREUNDER.
If you provide Alif with any feedback, suggestions, comments, modifications,
corrections, enhancements or other input relating to the Software
("Feedback"), Alif will be free to use, disclose, reproduce, license,
distribute and otherwise exploit the Feedback in its sole discretion without
any obligations or restrictions of any kind, including without limitation,
intellectual property rights or licensing obligations. Alif has no obligation
to use any Feedback.
The laws of the State of California and the United States govern all matters
arising out of this Agreement, excluding their conflicts of laws principles.
All disputes will be brought exclusively in the state or federal courts in
the Northern District of California, except Alif may bring an action, suit
or proceeding anywhere as needed to protect its technology and intellectual
property rights. Each party agrees that it submits to the personal
jurisdiction and venue of the state or federal courts in the Northern
District of California and waives any objections. The United Nations
Convention on Contracts for the International Sale of Goods (1980) is hereby
excluded in its entirety from Software to this Agreement.
If any provision of this Agreement is found to be invalid, illegal or
unenforceable, the validity, legality and enforceability of any of the
remaining provisions shall not in any way be affected or impaired and a
valid, legal and enforceable provision of similar intent and economic impact
shall be substituted therefore. This Agreement sets forth the entire
understanding and agreement between you and Alif, supersedes all prior
agreements, whether written or oral, with respect to the Software, and may
be amended only in a writing signed by both parties that identifies itself
as an amendment to this Agreement.
Rev. 10/2022

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

202
tools/alif/app-assets-gen.py Executable file
View File

@ -0,0 +1,202 @@
#!/usr/bin/env python3
import sys
import os
import struct
import argparse
from utils.config import *
from utils.toc_common import *
import json
from json.decoder import JSONDecodeError
# Define Version constant for each separate tool
#0.01.000 Initial version
#0.02.000 added checksum for integrity
# passed ASSET_TYPE as a flag and used this placeholder for checksum
TOOL_VERSION ="0.02.000"
EXIT_WITH_ERROR = 1
#OUTPUT_FILE = 'build/assets-rev-b0.bin'
ASSET_ID = "APPASSET"
ASSET_VER = 1
CHECK_SUM = 0x00
HBK0_KEY = 'utils/key/hbk1.bin'
PROV_KEY = 'utils/key/oem_prov_asset.bin'
ENC_KEY = 'utils/key/oem_enc_asset.bin'
# DO NOT Alter the sequence of the following items in the list as it determines
# the bit position in the final value
OPTIONS = ['ENCRYPTED_ASSETS','TEST_MODE']
OPTION_FLAGS = 0x00
def read_asset_config(cfgFile):
f = open(cfgFile, 'r')
try:
cfg = json.load(f)
except JSONDecodeError as e:
print("ERROR in JSON file.")
print(str(e))
sys.exit(EXIT_WITH_ERROR)
except ValueError as v:
print("ERROR in JSON file:")
print(str(v))
sys.exit(EXIT_WITH_ERROR)
except:
print("ERROR: Unknown error loading JSON file")
sys.exit(EXIT_WITH_ERROR)
f.close()
return cfg
def create_package(outFile):
print('Creating Assets Package...')
with open(outFile, 'wb') as f:
f.write(ASSET_ID.encode('utf8'))
f.write(struct.pack("H", ASSET_VER))
f.write(struct.pack("H", CHECK_SUM))
f.write(struct.pack("I", OPTION_FLAGS))
with open(HBK0_KEY, 'rb') as i:
f.write(i.read())
with open(PROV_KEY, 'rb') as i:
f.write(i.read())
f.write(('\0' * 48).encode('utf8'))
with open(ENC_KEY, 'rb') as i:
f.write(i.read())
f.write(('\0' * 48).encode('utf8'))
def decodeFlags(assetFlags):
print('')
print('Provisioning Options:')
for option in OPTIONS:
fill = 20 - len(option)
label = option + (fill * ' ')
if assetFlags & (1<<OPTIONS.index(option)):
print(label + 'ON')
else:
print(label + '\tOFF')
def check_package(outFile):
print('Checking Assets Package...')
# check integrity
total = getChecksum(outFile)
if total != 0:
print('ERROR: Package integrity')
sys.exit(EXIT_WITH_ERROR)
else:
print('Package integrity Ok!')
with open(outFile, 'rb') as f:
assetID = f.read(8).decode("utf-8").rstrip('\0')
assetVer = int.from_bytes(f.read(2),"little", signed=False)
assetType = int.from_bytes(f.read(2),"little", signed=False)
assetFlags = int.from_bytes(f.read(4),"little", signed=False)
print('AssetID: ' + assetID)
print('Asset Version: ' + str(assetVer))
decodeFlags(assetFlags)
print('')
def sum_list(l):
sum = 0
for x in l:
sum += x
return sum
def getChecksum(outFile):
with open(outFile, 'rb') as f:
data = f.read()
# convert byte array to list of shorts (16-bit)
bList = [int.from_bytes(data[i:i+2], "little") for i in range(0, len(data), 2)]
# calculate sum
total = sum_list(bList)&0xFFFF
# calculate complement
total = 0x10000 - total
return total&0xFFFF
def addChecksum(outFile):
total = getChecksum(outFile)
with open(outFile, 'r+b') as f:
f.seek(10)
f.write(struct.pack("H", total))
def main():
global OPTION_FLAGS
if sys.version_info.major == 2:
print("You need Python 3 for this application!")
return 0
parser = argparse.ArgumentParser(description='Generate ICV External Assets',
epilog="\N{COPYRIGHT SIGN} ALIF Semiconductor, 2023")
parser.add_argument("-v" ,"--version", help="Display Version Number", action="store_true")
parser.add_argument("-f", "--filename",
type=str,
help="input file (default: build/config/assets-app-cfg.json")
parser.add_argument("-c" ,"--check",
help="Check asset package (skip generation)",
action="store_true")
args = parser.parse_args()
if args.version:
print(TOOL_VERSION)
sys.exit()
# 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
print('Generating APP assets with:')
print('- Device Part# ' + DEVICE_PART_NUMBER + ' - Rev: ' + DEVICE_REVISION)
configFile = args.filename
if configFile == None:
configFile = "build/config/assets-app-cfg.json"
fileToCheck = configFile
outFile = 'build/' + os.path.basename(configFile)[:-4] + 'bin'
if args.check:
# check binary file (check build options - NO Generation)
if args.filename:
outFile = args.filename
fileToCheck = outFile
else:
print('- Configuration file: ' + configFile)
print('- Output file: ' + outFile)
print('')
# verify the input file (config or binary) exists
if not os.path.isfile(fileToCheck):
print('File ' + fileToCheck + ' does not exist!')
sys.exit()
if args.check == False:
cfg = read_asset_config(configFile)
for option in cfg:
if option not in OPTIONS:
print('ERROR: option ' + option + ' not supported!')
sys.exit()
else:
if cfg[option].upper() == "ON":
OPTION_FLAGS |= (1<<OPTIONS.index(option) )
if option == 'ENCRYPTED_ASSETS':
print('ENCRYPTED ASSETS Option is not supported yet')
sys.exit(EXIT_WITH_ERROR)
create_package(outFile)
addChecksum(outFile)
check_package(outFile)
print("Done!")
return 0
if __name__ == "__main__":
main()

164
tools/alif/app-gen-rot.py Executable file
View File

@ -0,0 +1,164 @@
#!/usr/bin/env python3
import sys
import os
import glob
import argparse
import string
import random
from utils import rsa_keygen
from utils import hbk_gen_util
from utils import cert_key_util
# Define Version constant for each separate tool
TOOL_VERSION ="0.06.000"
PASS_FILENAME = "utils/key/oem_keys_pass.pwd"
EXIT_WITH_ERROR = 1
def createTextFormat(fileName, data):
f = open(fileName, 'w')
str = ''
for i in data:
if str != '':
str += ','
str += hex(i)
f.write(str)
f.close()
def createBinaryFile(fileName, data):
f = open(fileName, 'wb')
f.write(data)
f.close()
def convertToBinary(inputFile, outputFile):
f = open(inputFile, 'r')
array = f.read().split(',')
f.close()
print(array)
out = open(outputFile, 'wb')
for s in array:
n = int(s, 16)
b = n.to_bytes(4, byteorder='little', signed = False)
out.write(b)
out.close()
def gen_AES():
return os.urandom(16)
def confirmString_generator(size=6, chars=string.ascii_uppercase + string.digits):
return ''.join(random.choice(chars) for _ in range(size))
def cleanRoT():
dirs = ['utils/key/','cert/']
for i in range(len(dirs)):
for filename in os.listdir(dirs[i]):
f = os.path.join(dirs[i], filename)
# checking if it is a file
if os.path.isfile(f):
print(f)
try:
os.remove(f)
except OSError as e:
print('Error: ' + str(e))
def confirm_clean():
print("************************************************************************")
print(" WARNING!!! This action will permanently delete the APP Root of Trust!!!\n","Please enter the following confirmation string followed by Enter to continue,\n or just press any key to abandon this action ")
print("************************************************************************")
confirmRequest = confirmString_generator(6)
print("Confirmation string: ", confirmRequest)
confirmResponse = input("> ")
if confirmResponse == confirmRequest:
print("The APP RoT WILL BE DELETED!!!. Enter Yes to continue (or any key to abort)")
continueConfirmation = input('> ')
if continueConfirmation.upper() == 'YES':
cleanRoT()
print('\nThe RoT was deleted!')
return
print('Operation aborted!')
sys.exit(EXIT_WITH_ERROR)
def main():
if sys.version_info.major == 2:
print("You need Python 3 for this application!")
return 0
parser = argparse.ArgumentParser(description='Generate Application Root of Trust',
epilog="\N{COPYRIGHT SIGN} ALIF Semiconductor, 2021")
parser.add_argument("-v" ,"--version", help="Display Version Number", action="store_true")
parser.add_argument("-c" ,"--clean", help="Clean (delete) the APP RoT", action="store_true")
parser.add_argument("-o" ,"--overwrite", help="Overwrite the existing APP RoT", action="store_true")
args = parser.parse_args()
if args.version:
print(TOOL_VERSION)
sys.exit()
if args.clean:
confirm_clean()
sys.exit()
if os.path.isfile('utils/key/OEMRoT.pem') == True and args.overwrite == False:
print('APP Root of Trust already exist!')
print('If you want to overwrite the existing RoT, please use the --overwrite flag ')
sys.exit()
# we continue generating a new RoT
# (but first, we delete the current one if it exists)
if os.path.isfile('utils/key/OEMRoT.pem') == True:
confirm_clean()
if os.path.isfile(PASS_FILENAME) == False:
keysPwd = input("Please enter a new password for the keys to generate:")
f = open(PASS_FILENAME, 'w')
f.write(keysPwd)
f.close()
else:
print("File " + PASS_FILENAME + " with 'keys password' already exist and it will be used. If new password is required, delete this file and run again!")
print("Generating APP RoT keys (to be used in Key 1 Certificate)")
rsa_keygen.main(['utils/key/OEMRoT.pem', "-p", 'utils/key/oem_keys_pass.pwd', "-k", 'utils/key/OEMRoTPublic.pem', "-l", 'build/logs/key_gen_log.log'])
print("Generating APP SB Key keys (to be used in Key 2 Certificate)")
rsa_keygen.main(['utils/key/OEMSBKey.pem', "-p", 'utils/key/oem_keys_pass.pwd', "-k", 'utils/key/OEMSBKeyPublic.pem', "-l", 'build/logs/key_gen_log.log'])
print("Generating APP SB Content keys (to be used in Content Certificates)")
rsa_keygen.main(['utils/key/OEMSBContent.pem', "-p", 'utils/key/oem_keys_pass.pwd', "-k", 'utils/key/OEMSBContentPublic.pem', "-l", 'build/logs/key_gen_log.log'])
print("Generating APP Hbk1")
hbk_gen_util.main(["-f", 'SHA256_TRUNC', "-k", 'utils/key/OEMRoTPublic.pem', "-o", 'utils/key/hbk1_hash.txt', "-l", 'build/logs/gen_hbk_log.log'])
# create Hbk1 in binary format (required by dmpu_asset_util.py)
convertToBinary('utils/key/hbk1_hash.txt', 'utils/key/hbk1.bin')
# generate Encryption key (Kce)
# - text format: required by OEM SB Content Certificate generator to encrypt images
# - binary format: required by dmpu_asset_util.py to create Asset Package (for key injection)
print("Generating OEM kce")
kce = gen_AES()
createTextFormat('utils/key/kce.txt', kce)
createBinaryFile('utils/key/oem_enc_asset.bin', kce)
# generate Provision key (Kcp)
# - binary format: required by dmpu_asset_util.py to create Asset Package (for key injection)
print("Generating OEM kcp")
kcp = gen_AES()
createBinaryFile('utils/key/oem_prov_asset.bin', kcp)
print("Generating APP SB Key 1 Certificate")
cert_key_util.main(['utils/cfg/OEMSBKey1.cfg', 'build/logs/OEMSBKey1.log'])
print("Generating APP SB Key 2 Certificate")
cert_key_util.main(['utils/cfg/OEMSBKey2.cfg', 'build/logs/OEMSBKey2.log'])
print("\nCheck logs in build/logs/ directory")
print("Done!")
return 0
if __name__ == "__main__":
main()

689
tools/alif/app-gen-toc.py Executable file
View File

@ -0,0 +1,689 @@
#!/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
TOOL_VERSION = "0.32.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
# Default metadata flags when there is no OEM
METADATA_FLAGS_DEFAULT = 0x3
# 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, metadata_flags, 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'])
#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'])
#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))
# HFXO/LFXO presence flags
outf.write(struct.pack("I", metadata_flags))
# pad to 16 bytes with 00s
outf.write(('\0' * 12).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:
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()
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)
metadata_flags = METADATA_FLAGS_DEFAULT
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'])
metadata_flags = gen_device_config(sec['binary'], False)
sec['binary'] = sec['binary'][:-5] + '.bin'
if metadata_flags == None:
metadata_flags = METADATA_FLAGS_DEFAULT
# 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, metadata_flags, 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()

129
tools/alif/app-provision.py Executable file
View File

@ -0,0 +1,129 @@
#!/usr/bin/env python3
"""
Test file for the DMPU function in SERAM
__author__ = ""
__copyright__ = "ALIF Seminconductor"
__version__ = "0.1.0"
__status__ = "Dev"
"""
# pylint: disable=unused-argument, invalid-name, bare-except
import os
import sys
import signal
import argparse
sys.path.append("./isp")
import subprocess
from serialport import serialPort
import utils.config
from utils.config import *
from utils.user_validations import validateArgList
from isp_core import *
from isp_util import *
TOOL_VERSION ="0.1.000" # Define Version constant for each separate tool
def run_dmpu(isp, fileName):
"""
run_dmpu
"""
if sys.platform == "linux" or sys.platform == "darwin":
fileName = fileName.replace('\\','/')
else:
fileName = fileName.replace('/','\\')
fileName = fileName.replace('..\\','')
try:
f = open(fileName, 'rb')
except IOError as e:
print('[ERROR] {0}'.format(e))
sys.exit(1)
print("[INFO] Running APP Provisioning code...")
with f:
fileSize = file_get_size(f)
offset = 0
data_size = DATA_CHUNK_SIZE
if fileSize < data_size: # Deal with small ones
data_size = 16 # CHUNK_SIZE
isp_build_packet(isp, ISP_COMMAND_DMPU)
while offset < fileSize:
f.seek(offset)
data_line = f.read(data_size)
if isp_download_data(isp, data_line) == False:
break
offset = offset + data_size
isp_download_done(isp)
print("[INFO] Done")
def main():
"""
DMPU
"""
if sys.version_info.major == 2:
print("[ERROR] You need Python 3 for this application!")
sys.exit(1)
# Deal with Command Line
parser = argparse.ArgumentParser(description=
'APP Provision tool')
parser.add_argument("-d" , "--discover", action='store_true', \
default=False, help="(isp) COM port discovery")
parser.add_argument("-b", "--baudrate", help="serial port baud rate",
type=int)
parser.add_argument("-a", "--asset", type=str,
help='APP Provision Assets (default assets: build/assets-app-cfg.bin)', default='build/assets-app-cfg.bin')
parser.add_argument("-V" , "--version",
help="Display Version Number", 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(1)
load_global_config()
DEVICE_PART_NUMBER = utils.config.DEVICE_PART_NUMBER
DEVICE_REVISION = utils.config.DEVICE_REVISION
DEVICE_REV_BAUD_RATE = utils.config.DEVICE_REV_BAUD_RATE
print('APP Provision with parameters:')
print('Device Part# ' + DEVICE_PART_NUMBER + ' - Rev: ' + DEVICE_REVISION)
print('Assets file: ' + args.asset + '\n')
if args.asset == None:
print('[ERROR] No asset file specified')
sys.exit(1)
baud_rate = DEVICE_REV_BAUD_RATE[DEVICE_REVISION]
if args.baudrate is not None:
baud_rate = args.baudrate
isp = serialPort(baud_rate) # Serial dabbling open up port.
if args.discover: # discover the COM ports if requested
isp.discoverSerialPorts()
errorCode = isp.openSerial()
if errorCode is False:
print("[ERROR] isp openSerial failed for %s" %isp.getPort())
sys.exit(1)
print("[INFO] %s open Serial port success" %isp.getPort())
isp.setBaudRate(baud_rate)
isp.setVerbose(args.verbose)
isp_start(isp) # Begin the ISP sequence
asset_file = args.asset
run_dmpu(isp, asset_file)
isp_stop(isp)
isp.closeSerial()
if __name__ == "__main__":
main()

122
tools/alif/app-secure-debug.py Executable file
View File

@ -0,0 +1,122 @@
#!/usr/bin/env python3
"""
Perform Secure Debug unlocking
__author__ = ""
__copyright__ = "ALIF Seminconductor"
__version__ = "0.1.0"
__status__ = "Dev"
"""
# pylint: disable=unused-argument, invalid-name, bare-except
import os
import sys
import signal
import argparse
sys.path.append("./isp")
import subprocess
from serialport import serialPort
import utils.config
from utils.config import *
from utils.user_validations import validateArgList
from isp_core import *
from isp_util import *
from utils.sign_image_util import sign_image
#import gen_debug_certs
TOOL_VERSION ="0.1.000" # Define Version constant for each separate tool
def secure_debug_alif(isp, rma):
"""
secure_debug_alif - Secure Debug unlocking using Alif certificates
"""
print("[INFO] Alif secure debug")
message = isp_build_packet(isp, ISP_COMMAND_GET, [ISP_GET_SECURE_DEBUG_TOKENS])
if rma == False:
# DCU values - all 1's
secure_debug_content = [0xFF] * 16
else:
# Magic test pattern for RMA
secure_debug_content = [0xAA] * 16
# append the challenge bytes received by the device
secure_debug_content.extend(message[6:22])
fileName = "build/alif_secure_debug.bin"
f = open(fileName, 'wb')
f.write(bytes(secure_debug_content))
f.close()
address = int.from_bytes(message[2:6],"little")
#print("*** address: ", hex(address))
sign_image(fileName, address, 0xFFFFFFFF, 'OEM')
token = authenticate_image(isp, fileName)
isp_secure_debug(isp, token, secure_debug_content)
print("\r")
def main():
"""
secure debug
"""
if sys.version_info.major == 2:
print("[ERROR] You need Python 3 for this application!")
sys.exit(1)
# Deal with Command Line
parser = argparse.ArgumentParser(description=
'Secure Debug tool')
parser.add_argument("-d" , "--discover", action='store_true', \
default=False, help="(isp) COM port discovery")
parser.add_argument("-b", "--baudrate", help="serial port baud rate",
type=int)
parser.add_argument("-r", "--rma", default=False,
help="Perform RMA transition (test)", action="store_true")
parser.add_argument("-V" , "--version",
help="Display Version Number", 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(1)
load_global_config()
DEVICE_PART_NUMBER = utils.config.DEVICE_PART_NUMBER
DEVICE_REVISION = utils.config.DEVICE_REVISION
DEVICE_REV_BAUD_RATE = utils.config.DEVICE_REV_BAUD_RATE
print('Secure Debug with parameters:')
print('Device Part# ' + DEVICE_PART_NUMBER + ' - Rev: ' + DEVICE_REVISION)
baud_rate = DEVICE_REV_BAUD_RATE[DEVICE_REVISION]
if args.baudrate is not None:
baud_rate = args.baudrate
isp = serialPort(baud_rate) # Serial dabbling open up port.
if args.discover: # discover the COM ports if requested
isp.discoverSerialPorts()
errorCode = isp.openSerial()
if errorCode is False:
print("[ERROR] isp openSerial failed for %s" %isp.getPort())
sys.exit(1)
print("[INFO] %s open Serial port success" %isp.getPort())
isp.setBaudRate(baud_rate)
isp.setVerbose(args.verbose)
isp_start(isp) # Begin the ISP sequence
secure_debug_alif(isp, args.rma)
isp_stop(isp)
isp.closeSerial()
if __name__ == "__main__":
main()

76
tools/alif/app-sign-image.py Executable file
View File

@ -0,0 +1,76 @@
#!/usr/bin/env python3
"""
Perform Image signing
__author__ = ""
__copyright__ = "ALIF Seminconductor"
__version__ = "0.1.0"
__status__ = "Dev"
"""
# pylint: disable=unused-argument, invalid-name, bare-except
import sys
import argparse
import utils.config
from utils.config import *
from utils.sign_image_util import sign_image
# 0.3.000 - added support for Azure Storage (Public Keys and Certs)
# 0.4.000 - split image signature functionality
# 0.5.000 - verbosity removed (it only applies to ISP-related tools)
TOOL_VERSION ="0.5.000" # Define Version constant for each separate tool
def main():
"""
sign an image
"""
if sys.version_info.major == 2:
print("[ERROR] You need Python 3 for this application!")
sys.exit(EXIT_WITH_ERROR)
# Deal with Command Line
parser = argparse.ArgumentParser(description=
'Image Signature tool')
parser.add_argument("-i", "--images", type=str,
help='Images to sign\
("/path/image1.bin 0x30020000")')
parser.add_argument("-V" , "--version",
help="Display Version Number", action="store_true")
args = parser.parse_args()
if args.version:
print(TOOL_VERSION)
sys.exit()
if args.images == None:
print('No image list provided')
sys.exit(EXIT_WITH_ERROR)
load_global_config()
DEVICE_PART_NUMBER = utils.config.DEVICE_PART_NUMBER
DEVICE_REVISION = utils.config.DEVICE_REVISION
print('Signing images with parameters:')
print('Device Part# ' + DEVICE_PART_NUMBER + ' - Rev: ' + DEVICE_REVISION)
argList = args.images
if sys.platform == "linux":
argList = argList.replace('\\','/')
else:
argList = argList.replace('/','\\')
items = argList.split(' ')
for e in range(1, len(items),2):
addr = items[e]
address = int(addr,base=16)
fileName = items[e-1]
fileName = fileName.replace('..\\','')
sign_image(fileName, address, 0xFFFFFFFF, "OEM")
if __name__ == "__main__":
main()

375
tools/alif/app-write-mram.py Executable file
View File

@ -0,0 +1,375 @@
#!/usr/bin/env python3
"""
MRAM (NVM) burning / writing utility
Support
- APPLICATION TOC package writing
- image write at any address in NVM (MRAM)
- image erase of any | range of addresses in NVM (MRAM)
__author__ = ""
__copyright__ = "ALIF Seminconductor"
__version__ = "0.16.0"
__status__ = "Dev" "
"""
import os
import sys
import signal
import argparse
from utils.discover import getValues, getJlinkSN
import utils.config
from utils.config import *
from utils.user_validations import validateArgList
from _ast import Or
from _operator import or_
from cgitb import handler
sys.path.append("./isp")
from serialport import serialPort
from serialport import COM_BAUD_RATE_MAXIMUM
#import ispcommands
from isp_core import *
from isp_util import *
import pylink
import datetime
#from array import array
# Version Feature
# 0.22.000 Added support for MAC OS (J-Link not included yet)
# 0.21.000 get baudrate from DBs
# 0.20.007 Added padding option for binaries not multiple of 16
# 0.20.006 Added Python error exit code
# 0.20.005 Fixed J-Link+Pylink issue writing binaries
# 0.20.004 REV_A0 dynamic baud rate support
# 0.20.003 remove maintenance mode output unless -v is used)
# 0.20.002 Reset option set as default
# 0.20.001 Added Erase option
# 0.20.000 Added option to skip user managed images
# 0.19.000 Removed JTAG access
# 0.16.000 Addition of baud rate increase for bulk transfer
# 0.15.000 Fixes for Block sizes and left overs
TOOL_VERSION ="0.22.000" # Define Version constant for each separate tool
EXIT_WITH_ERROR = 1
def readImageList(dsFile):
"""
readImageList = read images from arm-ds command file
"""
try:
f = open(dsFile, 'r')
imageList = f.read()
f.close()
# search for image list
start = imageList.find('args')
end = imageList.find('continue')
if start == -1 or end == -1:
print('[ERROR] There is a problem with the Debug Script information')
sys.exit(EXIT_WITH_ERROR)
imageList = imageList[start + 5: end]
except:
print('[ERROR] opening Debug Script file',dsFile)
sys.exit(EXIT_WITH_ERROR)
return imageList
def app_mram_erase(isp,args, ALIF_BASE_ADDRESS, ALIF_MRAM_SIZE):
"""
app_mram_erase
- erase the Application are of MRAM
args
argv[0] 'erase' Operation, can be ignored
argv[1] <address> Starting address
argv{2] <size> Length of bytes to erase
argv[3] <pattern> Optional pattern to erase with
argc Checked before this is called
"""
argv = args.split()
argc = len(argv)
# nombres magiques, maybe not needed?
address = 0x80000000
erase_len = 16
pattern = 0x00000000
if argc >= 3:
address = int(argv[1],base=16)
erase_len = int(argv[2],base=16)
erase_len_fmt = "{:,}".format(erase_len)
if argc == 4:
pattern = int(argv[3],base=16)
print("[INFO] %s 0x%x %d (%s)" %(argv[0],address,erase_len,
erase_len_fmt))
# Validate user request for erasing is in OEM
if (address > ALIF_BASE_ADDRESS or
address + erase_len > ALIF_BASE_ADDRESS):
if address + erase_len > ALIF_BASE_ADDRESS:
print("[ERROR] illegal address " + hex(address+erase_len) +
" (" + hex(address) + " + " + hex(erase_len) + ")")
else:
print("[ERROR] illegal address " + hex(address))
return
isp_mram_erase(isp,address,erase_len,pattern)
def main():
if sys.version_info.major == 2:
print("[ERROR] You need Python 3 for this application!")
sys.exit(EXIT_WITH_ERROR)
# Deal with Command Line
parser = argparse.ArgumentParser(description=
'NVM Burner for Application TOC Package')
parser.add_argument("-d" , "--discover", action='store_true', \
default=False, help="COM port discovery")
parser.add_argument("-b", "--baudrate", help="serial port baud rate",
type=int)
parser.add_argument("-e", "--erase", type=str,
help='ERASE [APP | <start address> <size> [<pattern>] ]')
# creating a mutually exclusive group for -i IMAGES and -S
# (skip option doesn't make sense in a user provided list...)
group = parser.add_mutually_exclusive_group()
group.add_argument("-i", "--images", type=str,
default="Application TOC Package",
help='images list to burn into NVM \
("/path/image1.bin 0x80001000 /path/image2.bin 0x80003000")')
parser.add_argument("-a", "--auth_image", action='store_true',
help="authenticate the image by sending its signature file",
default=False)
parser.add_argument("-m", "--method", type=str,
help="loading method [JTAG | ISP]")
group.add_argument("-S", "--skip",
help='write ATOC only - skip user managed images',
action="store_true")
parser.add_argument("-s", "--switch",
help="dynamic baud rate switch toggle, default=on",
action="store_false")
parser.add_argument("-p", "--pad",
help="pad the binary if size is not multiple of 16", action="store_true")
parser.add_argument("-nr", "--no_reset", default=False,
help="do not reset target before operation", action="store_true")
parser.add_argument("-V" , "--version",
help="Display Version Number", 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()
# 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
DEVICE_REV_BAUD_RATE = utils.config.DEVICE_REV_BAUD_RATE
MRAM_BASE_ADDRESS = utils.config.MRAM_BASE_ADDRESS
ALIF_BASE_ADDRESS = utils.config.ALIF_BASE_ADDRESS
OEM_BASE_ADDRESS = utils.config.APP_BASE_ADDRESS
MRAM_SIZE = utils.config.MRAM_SIZE
ALIF_MRAM_SIZE = utils.config.ALIF_MRAM_SIZE
OEM_MRAM_SIZE = utils.config.APP_MRAM_SIZE
MRAM_BURN_INTERFACE = utils.config.MRAM_BURN_INTERFACE
JTAG_ADAPTER = utils.config.JTAG_ADAPTER
os.system('') # Help MS-DOS window with ESC sequences
print('Writing MRAM with parameters:')
print('Device Part# ' + DEVICE_PART_NUMBER + ' - Rev: ' + DEVICE_REVISION)
print('- Available MRAM: ' + str(OEM_MRAM_SIZE) + ' bytes')
# baud_rate = args.baudrate
# if DEVICE_REVISION == 'A0':
# """
# For REV_A0 we need to change the default used by ALL other devices
# """
# default_baud_rate = COM_BAUD_RATE_REV_A0
# if baud_rate == COM_BAUD_RATE_DEFAULT:
# baud_rate = default_baud_rate
# else:
# default_baud_rate = COM_BAUD_RATE_DEFAULT
# baud_rate = args.baudrate
# if baud_rate != default_baud_rate:
# dynamic_baud_rate_switch = False
# else:
# dynamic_baud_rate_switch = args.switch
baud_rate = DEVICE_REV_BAUD_RATE[DEVICE_REVISION]
if args.baudrate is not None:
baud_rate = args.baudrate
dynamic_baud_rate_switch = args.switch
argList = ''
action = 'Burning: '
method = None
if args.method == None:
method = MRAM_BURN_INTERFACE
elif args.method.upper() == 'ISP':
method = 'isp'
elif args.method.upper() == 'JTAG':
method = 'jtag'
else:
print("[ERROR] Unknown connection method", args.method)
sys.exit(EXIT_WITH_ERROR)
if args.erase:
action = 'Erasing: '
argList = 'erase '
if args.erase.upper() == 'APP':
argList += hex(OEM_BASE_ADDRESS) + ' ' + hex(OEM_MRAM_SIZE)
else:
if args.erase.strip() == '':
print("[ERROR] erase arguments are empty")
sys.exit(EXIT_WITH_ERROR)
argList += args.erase
elif args.images != "Application TOC Package":
argList = args.images
else:
dsFile = 'bin/application_package.ds'
argList = readImageList(dsFile)
if args.skip:
idx = argList.find('../build/AppTocPackage.bin 0x')
argList = argList[idx: idx + 37]
# validate all parameters
argList = validateArgList(action, argList.strip(), args.pad)
if sys.platform == "linux" or sys.platform == "darwin":
argList = argList.replace('../','')
print("[INFO]", action + argList)
if method == 'jtag' and not args.erase: # erase via jtag not yet supported!
jlinkSN = getJlinkSN()
if jlinkSN == -1:
print('J-Link device not found!')
sys.exit(EXIT_WITH_ERROR)
print('J-Link SN: ' + jlinkSN)
jlink = pylink.JLink()
jlink.open(serial_no=int(jlinkSN))
print(jlink.product_name)
if not jlink.opened():
print('Error opening J-Link')
sys.exit(EXIT_WITH_ERROR)
if not jlink.connected():
print('Error connecting J-Link')
sys.exit(EXIT_WITH_ERROR)
print("about to connect to M0+..")
jlink.connect("CORTEX-M0+", verbose=True)
#jlink.connect('AC302F8A82562_HE', verbose=True)
if not jlink.target_connected():
print('Error connecting target')
print('Please, power-cycle the board')
sys.exit(EXIT_WITH_ERROR)
argParams = argList.strip().split(" ")
lenParams = len(argParams)
i = 0
while i < lenParams:
f = argParams[i][3:]
if sys.platform == "linux":
f = argParams[i][:]
print('File name: ' + f)
file_size = os.path.getsize(f)
print("File Size is :", file_size, "bytes")
print('MRAM starting address: ' + argParams[i+1])
addr = globalToLocalAddress(argParams[i+1])
print("Writing the file to MRAM...")
# read the file
f = open(f,"rb")
#fileData = array("I")
#fileData.fromfile(f, int(file_size/4))
fileData = list(f.read(file_size))
f.close()
# write the data to MRAM
t1 = datetime.datetime.now()
#jlink.memory_write32(int(addr, 16), fileData)
jlink.memory_write8(int(addr, 16), fileData)
t2 = datetime.datetime.now()
print('Done in ' + str(t2-t1))
i += 2
#jlink.reset() # the reset causes an issue and the board will need to power cycle...
return # end jlink tests
if method == 'jtag' and args.erase: # erase via jtag not yet supported!
print('[INFO] Erase is only supported via ISP')
dynamic_string = "Enabled" if dynamic_baud_rate_switch else "Disabled"
print("[INFO] baud rate ", baud_rate)
print("[INFO] dynamic baud rate change ", dynamic_string)
handler = CtrlCHandler()
isp = serialPort(baud_rate) # Serial dabbling open up port.
if args.discover: # discover the COM ports if requested
isp.discoverSerialPorts()
errorCode = isp.openSerial()
if errorCode is False:
print("[ERROR] isp openSerial failed for %s" %isp.getPort())
sys.exit(EXIT_WITH_ERROR)
print("[INFO] %s open Serial port success" %isp.getPort())
isp.setBaudRate(baud_rate)
isp.setVerbose(args.verbose)
if not args.no_reset:
put_target_in_maintenance_mode(isp, baud_rate, args.verbose)
if sys.platform == "linux" or sys.platform == "darwin":
argList = argList.replace('\\','/')
else:
argList = argList.replace('/','\\')
items = argList.split(' ')
isp_start(isp) # Start ISP Sequence
if args.erase:
app_mram_erase(isp,argList,ALIF_BASE_ADDRESS, ALIF_MRAM_SIZE)
else:
if dynamic_baud_rate_switch:
isp_set_baud_rate(isp,COM_BAUD_RATE_MAXIMUM) # Jack up Baud rate
isp.setBaudRate(COM_BAUD_RATE_MAXIMUM) # Sets the HOST baud rate
# issue enquiry command to check if SERAM is in Maintenance Mode
mode = isp_get_maintenance_status(isp)
isp_show_maintenance_mode(isp, mode)
for e in range(1, len(items),2):
addr = items[e]
address = int(addr,base=16)
fileName = items[e-1]
fileName = fileName.replace('..\\','')
if burn_mram_isp(isp, handler, fileName, address,
args.verbose, args.auth_image) == False:
break
# Restore the default Baud rate
if dynamic_baud_rate_switch:
isp_set_baud_rate(isp,baud_rate)
isp.setBaudRate(baud_rate)
isp_stop(isp) # Stop ISP Sequence
isp_reset(isp)
isp.closeSerial()
if __name__ == "__main__":
main()

Binary file not shown.

View File

@ -0,0 +1,17 @@
{
"DEVICE": {
"disabled": false,
"binary": "app-device-config.json",
"version" : "0.5.00",
"signed": true
},
"BLINK-HE": {
"disabled": false,
"binary": "m55_blink_he.bin",
"version" : "1.0.0",
"signed": true,
"cpu_id": "M55_HE",
"loadAddress": "0x58000000",
"flags": ["load", "boot"]
}
}

View File

@ -0,0 +1,35 @@
{
"DEVICE": {
"disabled" : false,
"binary": "app-device-config.json",
"version" : "0.5.00",
"signed": true
},
"A32_APP": {
"disabled": false,
"binary": "a32_stub_0.bin",
"version" : "1.0.0",
"signed": true,
"loadAddress": "0x02000000",
"cpu_id": "A32_0",
"flags": ["load","boot"]
},
"HP_APP": {
"disabled": false,
"binary": "m55_stub_hp.bin",
"version" : "1.0.0",
"signed": true,
"loadAddress": "0x50000000",
"cpu_id": "M55_HP",
"flags": ["load","boot"]
},
"HE_APP": {
"disabled": false,
"binary": "m55_stub_he.bin",
"version" : "1.0.0",
"signed": true,
"loadAddress": "0x58000000",
"cpu_id": "M55_HE",
"flags": ["load", "boot"]
}
}

Some files were not shown because too many files have changed in this diff Show More