initial commit
This commit is contained in:
@@ -0,0 +1,56 @@
|
||||
#******************************************************************************
|
||||
#
|
||||
# Makefile - Rules for building the libraries, examples and docs.
|
||||
#
|
||||
# Copyright (c) 2020, Ambiq Micro
|
||||
# All rights reserved.
|
||||
#
|
||||
# Redistribution and use in source and binary forms, with or without
|
||||
# modification, are permitted provided that the following conditions are met:
|
||||
#
|
||||
# 1. Redistributions of source code must retain the above copyright notice,
|
||||
# this list of conditions and the following disclaimer.
|
||||
#
|
||||
# 2. Redistributions in binary form must reproduce the above copyright
|
||||
# notice, this list of conditions and the following disclaimer in the
|
||||
# documentation and/or other materials provided with the distribution.
|
||||
#
|
||||
# 3. Neither the name of the copyright holder nor the names of its
|
||||
# contributors may be used to endorse or promote products derived from this
|
||||
# software without specific prior written permission.
|
||||
#
|
||||
# Third party software included in this distribution is subject to the
|
||||
# additional license terms as defined in the /docs/licenses directory.
|
||||
#
|
||||
# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
|
||||
# AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||
# IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
||||
# ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
|
||||
# LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
|
||||
# CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
|
||||
# SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
|
||||
# INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
|
||||
# CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
|
||||
# ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
|
||||
# POSSIBILITY OF SUCH DAMAGE.
|
||||
#
|
||||
# This is part of revision 2.4.2 of the AmbiqSuite Development Package.
|
||||
#
|
||||
#******************************************************************************
|
||||
|
||||
SUBDIRS=${wildcard */}
|
||||
|
||||
all:
|
||||
@for i in ${SUBDIRS}; \
|
||||
do \
|
||||
if [ -f $${i}/Makefile ]; then \
|
||||
$(MAKE) -C $${i} || exit $$?; fi; \
|
||||
done
|
||||
|
||||
clean:
|
||||
@for i in ${SUBDIRS}; \
|
||||
do \
|
||||
if [ -f $${i}/Makefile ]; then \
|
||||
$(MAKE) -C $${i} clean; fi; \
|
||||
done
|
||||
|
||||
Binary file not shown.
@@ -0,0 +1,38 @@
|
||||
#*******************************************************************************
|
||||
#
|
||||
# Simple Makefile to prepare binaries for AMOTA.
|
||||
#
|
||||
#*******************************************************************************
|
||||
|
||||
FLAG_ADDR_APOLLO2 = 0x6000
|
||||
LOAD_ADDR_APOLLO2 = 0x8000
|
||||
BOOTBIN_APOLLO2 =../../../boards/apollo2_evb/examples/multi_boot/iar/bin/multi_boot.bin
|
||||
|
||||
# Apollo2-BLUE EVB
|
||||
UPDATEBIN_APOLLO2_BLUE =../../../boards/apollo2_blue_evb/examples/ble_freertos_amota_blinky/iar/bin/ble_freertos_amota_blinky.bin
|
||||
APPBIN_APOLLO2_BLUE =../../../boards/apollo2_blue_evb/examples/ble_freertos_amota/iar/bin/ble_freertos_amota.bin
|
||||
APPBIN_APOLLO2_BLUE_ETHERMIND =../../../boards/apollo2_blue_evb/examples/mindtree_amota/iar/bin/mindtree_amota.bin
|
||||
|
||||
all: $(BOOTBIN_APOLLO2) \
|
||||
$(APPBIN_APOLLO2_BLUE) $(UPDATEBIN_APOLLO2_BLUE) \
|
||||
|
||||
python3 bootloader_binary_combiner.py --bootbin "${BOOTBIN_APOLLO2}" --appbin "${APPBIN_APOLLO2_BLUE}" --flag-addr ${FLAG_ADDR_APOLLO2} --load-address ${LOAD_ADDR_APOLLO2} -o starter_binary_apollo2_blue
|
||||
python3 ota_binary_converter.py --appbin "${UPDATEBIN_APOLLO2_BLUE}" --load-address ${LOAD_ADDR_APOLLO2} -o update_binary_apollo2_blue
|
||||
|
||||
|
||||
$(BOOTBIN_APOLLO2):
|
||||
$(MAKE) -C ../../../boards/apollo2_evb/examples/multi_boot/iar/ $(MAKECMDGOALS)
|
||||
|
||||
$(APPBIN_APOLLO2_BLUE):
|
||||
$(MAKE) -C ../../../boards/apollo2_blue_evb/examples/ble_freertos_amota/iar/ $(MAKECMDGOALS)
|
||||
|
||||
$(UPDATEBIN_APOLLO2_BLUE):
|
||||
$(MAKE) -C ../../../boards/apollo2_blue_evb/examples/ble_freertos_amota_blinky/iar/ $(MAKECMDGOALS)
|
||||
|
||||
|
||||
clean:
|
||||
rm -rf *.bin
|
||||
$(MAKE) -C ../../../boards/apollo2_evb/examples/multi_boot/iar/ $(MAKECMDGOALS)
|
||||
$(MAKE) -C ../../../boards/apollo2_blue_evb/examples/ble_freertos_amota/iar/ $(MAKECMDGOALS)
|
||||
$(MAKE) -C ../../../boards/apollo2_blue_evb/examples/ble_freertos_amota_blinky/iar/ $(MAKECMDGOALS)
|
||||
|
||||
@@ -0,0 +1,265 @@
|
||||
#!/usr/bin/env python3
|
||||
|
||||
import argparse
|
||||
|
||||
|
||||
#******************************************************************************
|
||||
#
|
||||
# CRC function that matches the CRC used by the Apollo bootloader.
|
||||
#
|
||||
#******************************************************************************
|
||||
poly32 = 0x1EDC6F41
|
||||
def crc32(L):
|
||||
rem = 0
|
||||
for b in L:
|
||||
rem = rem ^ (b << 24)
|
||||
for i in range(8):
|
||||
if rem & 0x80000000:
|
||||
rem = ((rem << 1) ^ poly32)
|
||||
else:
|
||||
rem = (rem << 1)
|
||||
|
||||
rem = rem & 0xFFFFFFFF
|
||||
return rem
|
||||
|
||||
#******************************************************************************
|
||||
#
|
||||
# Read in the binary files and output the merged binary
|
||||
#
|
||||
#******************************************************************************
|
||||
def process(boot_loader_filename, app_filename, output, loadaddr, overridegpio,
|
||||
overridepolarity, flagtype, flagaddr):
|
||||
|
||||
# Open the file, and read it into an array of integers.
|
||||
with open(boot_loader_filename, mode = 'rb') as f_bl:
|
||||
boot_loader_binarray = f_bl.read()
|
||||
f_bl.close()
|
||||
|
||||
# Open the file, and read it into an array of integers.
|
||||
with open(app_filename, mode = 'rb') as f_app:
|
||||
app_binarray = f_app.read()
|
||||
f_app.close()
|
||||
|
||||
boot_length = len(boot_loader_binarray)
|
||||
flag_address = int(flagaddr, 16)
|
||||
print("boot size ",boot_length)
|
||||
# Make sure bootloader does not overlap with flag page
|
||||
if boot_length >= flag_address:
|
||||
print("ERROR boot loader image is too big");
|
||||
return
|
||||
|
||||
app_length = len(app_binarray)
|
||||
|
||||
load_address = int(loadaddr, 16)
|
||||
pad_length = load_address - len(boot_loader_binarray)
|
||||
|
||||
print("pad_length ",pad_length);
|
||||
|
||||
# generate mutable byte array for the boot loader
|
||||
pad_binarray = bytearray([0]*pad_length);
|
||||
|
||||
flag_type = int(flagtype, 16)
|
||||
|
||||
# check flash flag storage type
|
||||
if flag_type == 0:
|
||||
# flag stored before application (usually 0x3c00)
|
||||
|
||||
# this is where we will write the flash flag page info
|
||||
flag_page_location = flag_address - len(boot_loader_binarray)
|
||||
|
||||
# Insert the application binary load address.
|
||||
print("load_address ",hex(load_address), "(",load_address,")")
|
||||
pad_binarray[flag_page_location + 0] = (load_address >> 0) & 0x000000ff;
|
||||
pad_binarray[flag_page_location + 1] = (load_address >> 8) & 0x000000ff;
|
||||
pad_binarray[flag_page_location + 2] = (load_address >> 16) & 0x000000ff;
|
||||
pad_binarray[flag_page_location + 3] = (load_address >> 24) & 0x000000ff;
|
||||
|
||||
# put the application binary size into the padding array @ 0x3c04
|
||||
app_length = len(app_binarray)
|
||||
print("app_size ",hex(app_length), "(",app_length,")")
|
||||
pad_binarray[flag_page_location + 4] = (app_length >> 0) & 0x000000ff
|
||||
pad_binarray[flag_page_location + 5] = (app_length >> 8) & 0x000000ff
|
||||
pad_binarray[flag_page_location + 6] = (app_length >> 16) & 0x000000ff
|
||||
pad_binarray[flag_page_location + 7] = (app_length >> 24) & 0x000000ff
|
||||
|
||||
# compute the CRC for the application and write it to 0x3c08
|
||||
app_crc = crc32(app_binarray)
|
||||
print("crc = ",hex(app_crc));
|
||||
pad_binarray[flag_page_location + 8] = (app_crc >> 0) & 0x000000ff
|
||||
pad_binarray[flag_page_location + 9] = (app_crc >> 8) & 0x000000ff
|
||||
pad_binarray[flag_page_location + 10] = (app_crc >> 16) & 0x000000ff
|
||||
pad_binarray[flag_page_location + 11] = (app_crc >> 24) & 0x000000ff
|
||||
|
||||
# override gpio. default 0
|
||||
override_gpio = int(overridegpio, 16)
|
||||
pad_binarray[flag_page_location + 12] = (override_gpio >> 0) & 0x000000ff
|
||||
pad_binarray[flag_page_location + 13] = (override_gpio >> 8) & 0x000000ff
|
||||
pad_binarray[flag_page_location + 14] = (override_gpio >> 16) & 0x000000ff
|
||||
pad_binarray[flag_page_location + 15] = (override_gpio >> 24) & 0x000000ff
|
||||
|
||||
# override polarity. default 0
|
||||
override_polarity = int(overridepolarity)
|
||||
pad_binarray[flag_page_location + 16] = (override_polarity >> 0) & 0x000000ff
|
||||
pad_binarray[flag_page_location + 17] = (override_polarity >> 8) & 0x000000ff
|
||||
pad_binarray[flag_page_location + 18] = (override_polarity >> 16) & 0x000000ff
|
||||
pad_binarray[flag_page_location + 19] = (override_polarity >> 24) & 0x000000ff
|
||||
|
||||
# copy the reset vector stack pointer (SP) from the application binary to pad_binary
|
||||
pad_binarray[flag_page_location + 20] = app_binarray[0];
|
||||
pad_binarray[flag_page_location + 21] = app_binarray[1];
|
||||
pad_binarray[flag_page_location + 22] = app_binarray[2];
|
||||
pad_binarray[flag_page_location + 23] = app_binarray[3];
|
||||
|
||||
# copy the reset vector program counter (PC) from the application binary to pad_binary
|
||||
pad_binarray[flag_page_location + 24] = app_binarray[4];
|
||||
pad_binarray[flag_page_location + 25] = app_binarray[5];
|
||||
pad_binarray[flag_page_location + 26] = app_binarray[6];
|
||||
pad_binarray[flag_page_location + 27] = app_binarray[7];
|
||||
|
||||
# bEncrypted
|
||||
pad_binarray[flag_page_location + 28] = 0x00
|
||||
pad_binarray[flag_page_location + 29] = 0x00
|
||||
pad_binarray[flag_page_location + 30] = 0x00
|
||||
pad_binarray[flag_page_location + 31] = 0x00
|
||||
|
||||
# CRC
|
||||
crc_flag = crc32(pad_binarray[flag_page_location:(flag_page_location + 32)])
|
||||
print("info crc = ",hex(crc_flag));
|
||||
pad_binarray[flag_page_location + 32] = (crc_flag >> 0) & 0x000000ff
|
||||
pad_binarray[flag_page_location + 33] = (crc_flag >> 8) & 0x000000ff
|
||||
pad_binarray[flag_page_location + 34] = (crc_flag >> 16) & 0x000000ff
|
||||
pad_binarray[flag_page_location + 35] = (crc_flag >> 24) & 0x000000ff
|
||||
|
||||
# now output all three binary arrays in the proper order
|
||||
with open(output + '.bin', mode = 'wb') as out:
|
||||
out.write(boot_loader_binarray)
|
||||
out.write(pad_binarray)
|
||||
out.write(app_binarray)
|
||||
else:
|
||||
# flag stored after application (usually last page of the internal flash, e.g. 0x7F800 for 512KB flash)
|
||||
page_length = 56; #fixed page length
|
||||
|
||||
#generate mutable byte array for the boot loader
|
||||
page_binarray = bytearray([0]*page_length);
|
||||
|
||||
# Insert the application binary load address.
|
||||
print("load_address ",hex(load_address), "(",load_address,")")
|
||||
page_binarray[0] = (load_address >> 0) & 0x000000ff;
|
||||
page_binarray[1] = (load_address >> 8) & 0x000000ff;
|
||||
page_binarray[2] = (load_address >> 16) & 0x000000ff;
|
||||
page_binarray[3] = (load_address >> 24) & 0x000000ff;
|
||||
|
||||
# put the application binary size into the padding array @ 0x3c04
|
||||
app_length = len(app_binarray)
|
||||
print("app_size ",hex(app_length), "(",app_length,")")
|
||||
page_binarray[4] = (app_length >> 0) & 0x000000ff
|
||||
page_binarray[5] = (app_length >> 8) & 0x000000ff
|
||||
page_binarray[6] = (app_length >> 16) & 0x000000ff
|
||||
page_binarray[7] = (app_length >> 24) & 0x000000ff
|
||||
|
||||
# compute the CRC for the application and write it to 0x3c08
|
||||
app_crc = crc32(app_binarray)
|
||||
print("crc = ",hex(app_crc));
|
||||
page_binarray[8] = (app_crc >> 0) & 0x000000ff
|
||||
page_binarray[9] = (app_crc >> 8) & 0x000000ff
|
||||
page_binarray[10] = (app_crc >> 16) & 0x000000ff
|
||||
page_binarray[11] = (app_crc >> 24) & 0x000000ff
|
||||
|
||||
# override gpio. default 0
|
||||
override_gpio = int(overridegpio, 16)
|
||||
page_binarray[12] = (override_gpio >> 0) & 0x000000ff
|
||||
page_binarray[13] = (override_gpio >> 8) & 0x000000ff
|
||||
page_binarray[14] = (override_gpio >> 16) & 0x000000ff
|
||||
page_binarray[15] = (override_gpio >> 24) & 0x000000ff
|
||||
|
||||
# override polarity. default 0
|
||||
override_polarity = int(overridepolarity)
|
||||
page_binarray[16] = (override_polarity >> 0) & 0x000000ff
|
||||
page_binarray[17] = (override_polarity >> 8) & 0x000000ff
|
||||
page_binarray[18] = (override_polarity >> 16) & 0x000000ff
|
||||
page_binarray[19] = (override_polarity >> 24) & 0x000000ff
|
||||
|
||||
# copy the reset vector stack pointer (SP) from the application binary to pad_binary
|
||||
page_binarray[20] = app_binarray[0];
|
||||
page_binarray[21] = app_binarray[1];
|
||||
page_binarray[22] = app_binarray[2];
|
||||
page_binarray[23] = app_binarray[3];
|
||||
|
||||
# copy the reset vector program counter (PC) from the application binary to pad_binary
|
||||
page_binarray[24] = app_binarray[4];
|
||||
page_binarray[25] = app_binarray[5];
|
||||
page_binarray[26] = app_binarray[6];
|
||||
page_binarray[27] = app_binarray[7];
|
||||
|
||||
# bEncrypted
|
||||
page_binarray[28] = 0x00
|
||||
page_binarray[29] = 0x00
|
||||
page_binarray[30] = 0x00
|
||||
page_binarray[31] = 0x00
|
||||
|
||||
# CRC
|
||||
crc_flag = crc32(pad_binarray[flag_page_location:(flag_page_location + 32)])
|
||||
page_binarray[32] = (crc_flag >> 0) & 0x000000ff
|
||||
page_binarray[33] = (crc_flag >> 8) & 0x000000ff
|
||||
page_binarray[34] = (crc_flag >> 16) & 0x000000ff
|
||||
page_binarray[35] = (crc_flag >> 24) & 0x000000ff
|
||||
|
||||
#generate a mutable fill array between application end and flag page start
|
||||
fill_binarray = bytearray([0xff]*(flag_address - app_length - load_address));
|
||||
|
||||
# now output all three binary arrays in the proper order
|
||||
with open(output + '.bin', mode = 'wb') as out:
|
||||
out.write(boot_loader_binarray)
|
||||
out.write(pad_binarray)
|
||||
out.write(app_binarray)
|
||||
out.write(fill_binarray)
|
||||
out.write(page_binarray)
|
||||
|
||||
def parse_arguments():
|
||||
parser = argparse.ArgumentParser(description =
|
||||
'Combine Bootloader & main image in to a single download, with flag page.')
|
||||
|
||||
parser.add_argument('--bootbin', dest='bootbin', default='../../../boards/apollo2_evb/examples/multi_boot/keil/bin/multi_boot.bin',
|
||||
help='Bootloader binary file (multi_boot.bin)')
|
||||
|
||||
parser.add_argument('--appbin', dest='appbin', default='../../../boards/apollo2_evb_em9304/examples/freertos_amota/keil/bin/freertos_amota.bin',
|
||||
help='Application binary file (app.bin)')
|
||||
|
||||
parser.add_argument('--load-address', dest='loadaddress', default='0x4000',
|
||||
help='Load address of the application. Default = 0x4000 (for Apollo), set to 0x6000 for Apollo2')
|
||||
|
||||
parser.add_argument('--override-gpio', dest='overridegpio', default='0xffffffff',
|
||||
help = 'Override GPIO number in hex. (Can be used to force a new image load)\n(0xffffffff to disable)')
|
||||
|
||||
parser.add_argument('--override-polarity', dest='overridepolarity', default=0, type=int,
|
||||
help = 'Polarity for the override pin.')
|
||||
|
||||
#rma: add arg flag page address
|
||||
parser.add_argument('--flag-type', dest='flagtype', default='0x0',
|
||||
help = 'User specified flash flag page placement type. (0 = before application; 1 = after application)')
|
||||
#rma: add arg flag page address
|
||||
parser.add_argument('--flag-address', dest='flagaddress', default='0x3c00',
|
||||
help = 'User specified flash flag page address, 0x3c00 as default (input 0x7f800 for last page of a 512KB flash Apollo device).')
|
||||
|
||||
parser.add_argument('-o', dest = 'output', default = 'binary_array',
|
||||
help = 'Output filename (without the extension)')
|
||||
|
||||
args = parser.parse_args()
|
||||
|
||||
return args
|
||||
|
||||
#******************************************************************************
|
||||
#
|
||||
# Main function.
|
||||
#
|
||||
#******************************************************************************
|
||||
def main():
|
||||
# Read the arguments.
|
||||
args = parse_arguments()
|
||||
|
||||
process(args.bootbin, args.appbin, args.output, args.loadaddress,
|
||||
args.overridegpio, args.overridepolarity,
|
||||
args.flagtype, args.flagaddress)
|
||||
|
||||
if __name__ == '__main__':
|
||||
main()
|
||||
@@ -0,0 +1,214 @@
|
||||
#!/usr/bin/env python3
|
||||
|
||||
import argparse
|
||||
|
||||
|
||||
#******************************************************************************
|
||||
#
|
||||
# CRC function that matches the CRC used by the Apollo bootloader.
|
||||
#
|
||||
#******************************************************************************
|
||||
poly32 = 0x1EDC6F41
|
||||
def crc32(L):
|
||||
rem = 0
|
||||
for b in L:
|
||||
rem = rem ^ (b << 24)
|
||||
for i in range(8):
|
||||
if rem & 0x80000000:
|
||||
rem = ((rem << 1) ^ poly32)
|
||||
else:
|
||||
rem = (rem << 1)
|
||||
|
||||
rem = rem & 0xFFFFFFFF
|
||||
return rem
|
||||
|
||||
#******************************************************************************
|
||||
#
|
||||
# Read in the binary files and output the merged binary
|
||||
#
|
||||
#******************************************************************************
|
||||
#def process(boot_loader_filename, app_filename, output):
|
||||
def process(load_address, app_filename, secinfo_file_name, app_ver, bin_type, str_type, output, align):
|
||||
|
||||
# Open the file, and read it into an array of integers.
|
||||
with open(app_filename, mode = 'rb') as f_app:
|
||||
app_binarray = f_app.read()
|
||||
f_app.close()
|
||||
|
||||
sec_binarray = bytearray([])
|
||||
seclen = 0
|
||||
# Open the file, and read it into an array of integers.
|
||||
if len(secinfo_file_name) > 0:
|
||||
with open(secinfo_file_name, mode='rb') as f_sec:
|
||||
sec_binarray= f_sec.read()
|
||||
seclen = len(sec_binarray)
|
||||
|
||||
app_length = len(app_binarray)
|
||||
|
||||
hdr_length = 48; #fixed header length
|
||||
print("hdr_length ",hdr_length);
|
||||
|
||||
#generate mutable byte array for the boot loader
|
||||
hdr_binarray = bytearray([0]*hdr_length);
|
||||
|
||||
# Insert encryption flag, always 0
|
||||
hdr_binarray[0] = 0x00;
|
||||
hdr_binarray[1] = 0x00;
|
||||
hdr_binarray[2] = 0x00;
|
||||
hdr_binarray[3] = 0x00;
|
||||
|
||||
# Insert the application binary load address.
|
||||
loadaddress = int(load_address,16)
|
||||
print("load_address ",hex(loadaddress), "(",load_address,")")
|
||||
hdr_binarray[4] = (loadaddress >> 0) & 0x000000ff;
|
||||
hdr_binarray[5] = (loadaddress >> 8) & 0x000000ff;
|
||||
hdr_binarray[6] = (loadaddress >> 16) & 0x000000ff;
|
||||
hdr_binarray[7] = (loadaddress >> 24) & 0x000000ff;
|
||||
|
||||
|
||||
app_length = len(app_binarray)
|
||||
print("app_size ",hex(app_length), "(",app_length,")")
|
||||
app_crc = crc32(app_binarray)
|
||||
print("app_crc = ",hex(app_crc));
|
||||
print("Security Info Length", hex(seclen))
|
||||
|
||||
pad_binarray = bytearray([])
|
||||
pad_size = 0
|
||||
if (seclen > 0):
|
||||
if (seclen % int(align) != 0):
|
||||
# Add Padding
|
||||
pad_size = int(align) - (seclen % int(align))
|
||||
pad_binarray = bytearray([0]*pad_size);
|
||||
|
||||
# put the application binary size
|
||||
# Total blob length
|
||||
hdr_binarray[8] = ((app_length + pad_size + seclen) >> 0) & 0x000000ff
|
||||
hdr_binarray[9] = ((app_length + pad_size + seclen) >> 8) & 0x000000ff
|
||||
hdr_binarray[10] = ((app_length + pad_size + seclen) >> 16) & 0x000000ff
|
||||
hdr_binarray[11] = ((app_length + pad_size + seclen) >> 24) & 0x000000ff
|
||||
|
||||
# compute the CRC for the blob
|
||||
crc = crc32(sec_binarray + pad_binarray + app_binarray)
|
||||
print("blob crc = ",hex(crc));
|
||||
hdr_binarray[12] = (crc >> 0) & 0x000000ff
|
||||
hdr_binarray[13] = (crc >> 8) & 0x000000ff
|
||||
hdr_binarray[14] = (crc >> 16) & 0x000000ff
|
||||
hdr_binarray[15] = (crc >> 24) & 0x000000ff
|
||||
|
||||
hdr_binarray[16] = ((seclen + pad_size) >> 0) & 0x000000ff
|
||||
hdr_binarray[17] = ((seclen + pad_size) >> 8) & 0x000000ff
|
||||
hdr_binarray[18] = ((seclen + pad_size) >> 16) & 0x000000ff
|
||||
hdr_binarray[19] = ((seclen + pad_size) >> 24) & 0x000000ff
|
||||
|
||||
# word RFU
|
||||
hdr_binarray[20] = 0xff
|
||||
hdr_binarray[21] = 0xff
|
||||
hdr_binarray[22] = 0xff
|
||||
hdr_binarray[23] = 0xff
|
||||
|
||||
# word RFU
|
||||
hdr_binarray[24] = 0xFF
|
||||
hdr_binarray[25] = 0xFF
|
||||
hdr_binarray[26] = 0xFF
|
||||
hdr_binarray[27] = 0xFF
|
||||
|
||||
# word RFU
|
||||
hdr_binarray[28] = 0xFF
|
||||
hdr_binarray[29] = 0xFF
|
||||
hdr_binarray[30] = 0xFF
|
||||
hdr_binarray[31] = 0xFF
|
||||
|
||||
# application software version here
|
||||
print("app_ver",int(app_ver,16), "(",app_ver,")")
|
||||
appver = int(app_ver,16)
|
||||
hdr_binarray[32] = (appver >> 0) & 0x000000ff;
|
||||
hdr_binarray[33] = (appver >> 8) & 0x000000ff;
|
||||
hdr_binarray[34] = (appver >> 16) & 0x000000ff;
|
||||
hdr_binarray[35] = (appver >> 24) & 0x000000ff;
|
||||
|
||||
# binary type here
|
||||
print("bin_type",int(bin_type,16), "(",bin_type,")")
|
||||
bintype = int(bin_type,16)
|
||||
hdr_binarray[36] = (bintype >> 0) & 0x000000ff;
|
||||
hdr_binarray[37] = (bintype >> 8) & 0x000000ff;
|
||||
hdr_binarray[38] = (bintype >> 16) & 0x000000ff;
|
||||
hdr_binarray[39] = (bintype >> 24) & 0x000000ff;
|
||||
|
||||
# storage type here, 0 = internal, 1 = external
|
||||
print("str_type",int(str_type,16), "(",str_type,")")
|
||||
strtype = int(str_type,16)
|
||||
if strtype != 0:
|
||||
strtype = 1
|
||||
hdr_binarray[40] = (strtype >> 0) & 0x000000ff;
|
||||
hdr_binarray[41] = (strtype >> 8) & 0x000000ff;
|
||||
hdr_binarray[42] = (strtype >> 16) & 0x000000ff;
|
||||
hdr_binarray[43] = (strtype >> 24) & 0x000000ff;
|
||||
|
||||
# word RFU
|
||||
hdr_binarray[44] = 0xff
|
||||
hdr_binarray[45] = 0xff
|
||||
hdr_binarray[46] = 0xff
|
||||
hdr_binarray[47] = 0xff
|
||||
|
||||
|
||||
# now output all three binary arrays in the proper order
|
||||
with open(output + '.bin', mode = 'wb') as out:
|
||||
out.write(hdr_binarray)
|
||||
if (seclen > 0):
|
||||
print('Adding Security Info of {} bytes...'.format(seclen), flush=True)
|
||||
out.write(sec_binarray)
|
||||
if (pad_size != 0):
|
||||
# Add Padding
|
||||
print('Adding padding of {} bytes...'.format(pad_size), flush=True)
|
||||
out.write(pad_binarray)
|
||||
out.write(app_binarray)
|
||||
|
||||
def parse_arguments():
|
||||
parser = argparse.ArgumentParser(description =
|
||||
'Combine two binary files in to a single download.')
|
||||
|
||||
parser.add_argument('--load-address', dest='loadaddress', default='0x4000',
|
||||
help='Load address of the application.')
|
||||
|
||||
parser.add_argument('--appbin', dest='appbin', default='../keil/bin/freertos_fit_amota.bin',
|
||||
help='Application binary file (app.bin)')
|
||||
|
||||
parser.add_argument('--secbin', dest = 'secbin', default='',
|
||||
help = 'Binary file for (optional) security information')
|
||||
|
||||
# add arg version
|
||||
parser.add_argument('--version', dest='app_ver', default='0x0',
|
||||
help = 'Software version of the OTA image.')
|
||||
|
||||
# add arg binary type
|
||||
parser.add_argument('--binary-type', dest='bin_type', default='0x0',
|
||||
help = 'Binary type (0 = Firmware, 1 = Data) to be tranferred OTA')
|
||||
|
||||
# add arg binary type
|
||||
parser.add_argument('--storage-type', dest='str_type', default='0x0',
|
||||
help = 'Storage type to for the image OTA.')
|
||||
|
||||
parser.add_argument('-o', dest = 'output', default = 'binary_array',
|
||||
help = 'Output filename (without the extension)')
|
||||
|
||||
parser.add_argument('-a', dest = 'alignment', default=4,
|
||||
help = 'Desired alignment for appbin in image blob')
|
||||
|
||||
|
||||
args = parser.parse_args()
|
||||
|
||||
return args
|
||||
|
||||
#******************************************************************************
|
||||
#
|
||||
# Main function.
|
||||
#
|
||||
#******************************************************************************
|
||||
def main():
|
||||
# Read the arguments.
|
||||
args = parse_arguments()
|
||||
|
||||
process(args.loadaddress, args.appbin, args.secbin, args.app_ver, args.bin_type, args.str_type, args.output, args.alignment)
|
||||
|
||||
if __name__ == '__main__':
|
||||
main()
|
||||
Binary file not shown.
@@ -0,0 +1,27 @@
|
||||
#*******************************************************************************
|
||||
#
|
||||
# Simple Makefile to prepare binaries for AMOTA for Apollo3.
|
||||
#
|
||||
#*******************************************************************************
|
||||
|
||||
TOOL_CHAIN?=iar
|
||||
|
||||
# Apollo3-BLUE EVB
|
||||
UPDATEBIN_APOLLO3_BLUE =../../../boards/apollo3_evb/examples/ble_freertos_amota/$(TOOL_CHAIN)/bin/ble_freertos_amota.bin
|
||||
APPBIN_APOLLO3_BLUE =../../../boards/apollo3_evb/examples/ble_freertos_amota/$(TOOL_CHAIN)/bin/ble_freertos_amota.bin
|
||||
|
||||
all: $(APPBIN_APOLLO3_BLUE) $(UPDATEBIN_APOLLO3_BLUE) $(UPDATEBIN_APOLLO3_BLUE_ETHERMIND) $(APPBIN_APOLLO3_BLUE_ETHERMIND)
|
||||
# Apollo3 Cordio
|
||||
cp $(APPBIN_APOLLO3_BLUE) starter_binary_apollo3_blue.bin
|
||||
cp ../../apollo3_scripts/keys_info0.py ../../apollo3_scripts/keys_info.py
|
||||
python3 ../../apollo3_scripts/create_cust_image_blob.py --bin $(APPBIN_APOLLO3_BLUE) --load-address 0xc000 --magic-num 0xcb -o ../../apollo3_scripts/temp_main_nosecure_ota --version 0x0
|
||||
python3 ota_binary_converter.py --appbin ../../apollo3_scripts/temp_main_nosecure_ota.bin -o update_binary_apollo3_blue
|
||||
@rm -rf ../../apollo3_scripts/temp_main_nosecure_ota.bin
|
||||
|
||||
$(APPBIN_APOLLO3_BLUE):
|
||||
$(MAKE) -C ../../../boards/apollo3_evb/examples/ble_freertos_amota/$(TOOL_CHAIN)/ $(MAKECMDGOALS)
|
||||
|
||||
clean:
|
||||
rm -rf *.bin
|
||||
rm -rf $(APPBIN_APOLLO3_BLUE)
|
||||
|
||||
@@ -0,0 +1,214 @@
|
||||
#!/usr/bin/env python3
|
||||
|
||||
import argparse
|
||||
|
||||
|
||||
#******************************************************************************
|
||||
#
|
||||
# CRC function that matches the CRC used by the Apollo bootloader.
|
||||
#
|
||||
#******************************************************************************
|
||||
poly32 = 0x1EDC6F41
|
||||
def crc32(L):
|
||||
rem = 0
|
||||
for b in L:
|
||||
rem = rem ^ (b << 24)
|
||||
for i in range(8):
|
||||
if rem & 0x80000000:
|
||||
rem = ((rem << 1) ^ poly32)
|
||||
else:
|
||||
rem = (rem << 1)
|
||||
|
||||
rem = rem & 0xFFFFFFFF
|
||||
return rem
|
||||
|
||||
#******************************************************************************
|
||||
#
|
||||
# Read in the binary files and output the merged binary
|
||||
#
|
||||
#******************************************************************************
|
||||
#def process(boot_loader_filename, app_filename, output):
|
||||
def process(load_address, app_filename, secinfo_file_name, app_ver, bin_type, str_type, output, align):
|
||||
|
||||
# Open the file, and read it into an array of integers.
|
||||
with open(app_filename, mode = 'rb') as f_app:
|
||||
app_binarray = f_app.read()
|
||||
f_app.close()
|
||||
|
||||
sec_binarray = bytearray([])
|
||||
seclen = 0
|
||||
# Open the file, and read it into an array of integers.
|
||||
if len(secinfo_file_name) > 0:
|
||||
with open(secinfo_file_name, mode='rb') as f_sec:
|
||||
sec_binarray= f_sec.read()
|
||||
seclen = len(sec_binarray)
|
||||
|
||||
app_length = len(app_binarray)
|
||||
|
||||
hdr_length = 48; #fixed header length
|
||||
print("hdr_length ",hdr_length);
|
||||
|
||||
#generate mutable byte array for the boot loader
|
||||
hdr_binarray = bytearray([0]*hdr_length);
|
||||
|
||||
# Insert encryption flag, always 0
|
||||
hdr_binarray[0] = 0x00;
|
||||
hdr_binarray[1] = 0x00;
|
||||
hdr_binarray[2] = 0x00;
|
||||
hdr_binarray[3] = 0x00;
|
||||
|
||||
# Insert the application binary load address.
|
||||
loadaddress = int(load_address,16)
|
||||
print("load_address ",hex(loadaddress), "(",load_address,")")
|
||||
hdr_binarray[4] = (loadaddress >> 0) & 0x000000ff;
|
||||
hdr_binarray[5] = (loadaddress >> 8) & 0x000000ff;
|
||||
hdr_binarray[6] = (loadaddress >> 16) & 0x000000ff;
|
||||
hdr_binarray[7] = (loadaddress >> 24) & 0x000000ff;
|
||||
|
||||
|
||||
app_length = len(app_binarray)
|
||||
print("app_size ",hex(app_length), "(",app_length,")")
|
||||
app_crc = crc32(app_binarray)
|
||||
print("app_crc = ",hex(app_crc));
|
||||
print("Security Info Length", hex(seclen))
|
||||
|
||||
pad_binarray = bytearray([])
|
||||
pad_size = 0
|
||||
if (seclen > 0):
|
||||
if (seclen % int(align) != 0):
|
||||
# Add Padding
|
||||
pad_size = int(align) - (seclen % int(align))
|
||||
pad_binarray = bytearray([0]*pad_size);
|
||||
|
||||
# put the application binary size
|
||||
# Total blob length
|
||||
hdr_binarray[8] = ((app_length + pad_size + seclen) >> 0) & 0x000000ff
|
||||
hdr_binarray[9] = ((app_length + pad_size + seclen) >> 8) & 0x000000ff
|
||||
hdr_binarray[10] = ((app_length + pad_size + seclen) >> 16) & 0x000000ff
|
||||
hdr_binarray[11] = ((app_length + pad_size + seclen) >> 24) & 0x000000ff
|
||||
|
||||
# compute the CRC for the blob
|
||||
crc = crc32(sec_binarray + pad_binarray + app_binarray)
|
||||
print("blob crc = ",hex(crc));
|
||||
hdr_binarray[12] = (crc >> 0) & 0x000000ff
|
||||
hdr_binarray[13] = (crc >> 8) & 0x000000ff
|
||||
hdr_binarray[14] = (crc >> 16) & 0x000000ff
|
||||
hdr_binarray[15] = (crc >> 24) & 0x000000ff
|
||||
|
||||
hdr_binarray[16] = ((seclen + pad_size) >> 0) & 0x000000ff
|
||||
hdr_binarray[17] = ((seclen + pad_size) >> 8) & 0x000000ff
|
||||
hdr_binarray[18] = ((seclen + pad_size) >> 16) & 0x000000ff
|
||||
hdr_binarray[19] = ((seclen + pad_size) >> 24) & 0x000000ff
|
||||
|
||||
# word RFU
|
||||
hdr_binarray[20] = 0xff
|
||||
hdr_binarray[21] = 0xff
|
||||
hdr_binarray[22] = 0xff
|
||||
hdr_binarray[23] = 0xff
|
||||
|
||||
# word RFU
|
||||
hdr_binarray[24] = 0xFF
|
||||
hdr_binarray[25] = 0xFF
|
||||
hdr_binarray[26] = 0xFF
|
||||
hdr_binarray[27] = 0xFF
|
||||
|
||||
# word RFU
|
||||
hdr_binarray[28] = 0xFF
|
||||
hdr_binarray[29] = 0xFF
|
||||
hdr_binarray[30] = 0xFF
|
||||
hdr_binarray[31] = 0xFF
|
||||
|
||||
# application software version here
|
||||
print("app_ver",int(app_ver,16), "(",app_ver,")")
|
||||
appver = int(app_ver,16)
|
||||
hdr_binarray[32] = (appver >> 0) & 0x000000ff;
|
||||
hdr_binarray[33] = (appver >> 8) & 0x000000ff;
|
||||
hdr_binarray[34] = (appver >> 16) & 0x000000ff;
|
||||
hdr_binarray[35] = (appver >> 24) & 0x000000ff;
|
||||
|
||||
# binary type here
|
||||
print("bin_type",int(bin_type,16), "(",bin_type,")")
|
||||
bintype = int(bin_type,16)
|
||||
hdr_binarray[36] = (bintype >> 0) & 0x000000ff;
|
||||
hdr_binarray[37] = (bintype >> 8) & 0x000000ff;
|
||||
hdr_binarray[38] = (bintype >> 16) & 0x000000ff;
|
||||
hdr_binarray[39] = (bintype >> 24) & 0x000000ff;
|
||||
|
||||
# storage type here, 0 = internal, 1 = external
|
||||
print("str_type",int(str_type,16), "(",str_type,")")
|
||||
strtype = int(str_type,16)
|
||||
if strtype != 0:
|
||||
strtype = 1
|
||||
hdr_binarray[40] = (strtype >> 0) & 0x000000ff;
|
||||
hdr_binarray[41] = (strtype >> 8) & 0x000000ff;
|
||||
hdr_binarray[42] = (strtype >> 16) & 0x000000ff;
|
||||
hdr_binarray[43] = (strtype >> 24) & 0x000000ff;
|
||||
|
||||
# word RFU
|
||||
hdr_binarray[44] = 0xff
|
||||
hdr_binarray[45] = 0xff
|
||||
hdr_binarray[46] = 0xff
|
||||
hdr_binarray[47] = 0xff
|
||||
|
||||
|
||||
# now output all three binary arrays in the proper order
|
||||
with open(output + '.bin', mode = 'wb') as out:
|
||||
out.write(hdr_binarray)
|
||||
if (seclen > 0):
|
||||
print('Adding Security Info of {} bytes...'.format(seclen), flush=True)
|
||||
out.write(sec_binarray)
|
||||
if (pad_size != 0):
|
||||
# Add Padding
|
||||
print('Adding padding of {} bytes...'.format(pad_size), flush=True)
|
||||
out.write(pad_binarray)
|
||||
out.write(app_binarray)
|
||||
|
||||
def parse_arguments():
|
||||
parser = argparse.ArgumentParser(description =
|
||||
'Combine two binary files in to a single download.')
|
||||
|
||||
parser.add_argument('--load-address', dest='loadaddress', default='0x4000',
|
||||
help='Load address of the application.')
|
||||
|
||||
parser.add_argument('--appbin', dest='appbin', default='../keil/bin/freertos_fit_amota.bin',
|
||||
help='Application binary file (app.bin)')
|
||||
|
||||
parser.add_argument('--secbin', dest = 'secbin', default='',
|
||||
help = 'Binary file for (optional) security information')
|
||||
|
||||
# add arg version
|
||||
parser.add_argument('--version', dest='app_ver', default='0x0',
|
||||
help = 'Software version of the OTA image.')
|
||||
|
||||
# add arg binary type
|
||||
parser.add_argument('--binary-type', dest='bin_type', default='0x0',
|
||||
help = 'Binary type (0 = Firmware, 1 = Data) to be tranferred OTA')
|
||||
|
||||
# add arg binary type
|
||||
parser.add_argument('--storage-type', dest='str_type', default='0x0',
|
||||
help = 'Storage type to for the image OTA.')
|
||||
|
||||
parser.add_argument('-o', dest = 'output', default = 'binary_array',
|
||||
help = 'Output filename (without the extension)')
|
||||
|
||||
parser.add_argument('-a', dest = 'alignment', default=4,
|
||||
help = 'Desired alignment for appbin in image blob')
|
||||
|
||||
|
||||
args = parser.parse_args()
|
||||
|
||||
return args
|
||||
|
||||
#******************************************************************************
|
||||
#
|
||||
# Main function.
|
||||
#
|
||||
#******************************************************************************
|
||||
def main():
|
||||
# Read the arguments.
|
||||
args = parse_arguments()
|
||||
|
||||
process(args.loadaddress, args.appbin, args.secbin, args.app_ver, args.bin_type, args.str_type, args.output, args.alignment)
|
||||
|
||||
if __name__ == '__main__':
|
||||
main()
|
||||
@@ -0,0 +1,209 @@
|
||||
/*********************************************************************
|
||||
* (c) SEGGER Microcontroller GmbH & Co. KG *
|
||||
* The Embedded Experts *
|
||||
* www.segger.com *
|
||||
**********************************************************************
|
||||
|
||||
-------------------------- END-OF-HEADER -----------------------------
|
||||
|
||||
File : AMA3B2KK-KBR.JLinkScript
|
||||
Purpose : Handle reset for AmbiqMicro AMA3B2KK series of MCUs
|
||||
Literature:
|
||||
[1] J-Link User Guide (UM08001_JLink.pdf)
|
||||
|
||||
Additional information:
|
||||
For more information about public functions that can be implemented
|
||||
in order to customize J-Link actions, please refer to [1]
|
||||
*********************************************************************/
|
||||
|
||||
/*********************************************************************
|
||||
*
|
||||
* ResetTarget()
|
||||
* Reset and wait until CPU is halted.
|
||||
*********************************************************************/
|
||||
void ResetTarget(void) {
|
||||
|
||||
// Register Address Values
|
||||
int AIRCR_ADDR ;
|
||||
int DHCSR_ADDR ;
|
||||
int DEMCR_ADDR ;
|
||||
int AHBAP_REG_CTRL ;
|
||||
int AHBAP_REG_ADDR ;
|
||||
int AHBAP_REG_DATA ;
|
||||
int DP_REG_SELECT ;
|
||||
int MCUCTRL_SCRATCH0 ;
|
||||
int MCUCTRL_BOOTLDR ;
|
||||
int JDEC_PID ;
|
||||
|
||||
// Internal Variables
|
||||
int Ctrl;
|
||||
int demcr;
|
||||
int scratch0;
|
||||
int bootldr;
|
||||
int jdecpid;
|
||||
int v;
|
||||
int Tries;
|
||||
int Done;
|
||||
int nonsecure;
|
||||
int timeout;
|
||||
|
||||
// Initialize the Register Address and Internal vars.
|
||||
AIRCR_ADDR = 0xE000ED0C;
|
||||
DHCSR_ADDR = 0xE000EDF0;
|
||||
DEMCR_ADDR = 0xE000EDFC;
|
||||
MCUCTRL_SCRATCH0 = 0x400401B0;
|
||||
MCUCTRL_BOOTLDR = 0x400401A0;
|
||||
JDEC_PID = 0xF0000FE0;
|
||||
AHBAP_REG_CTRL = 0;
|
||||
AHBAP_REG_ADDR = 1;
|
||||
AHBAP_REG_DATA = 3;
|
||||
DP_REG_SELECT = 2;
|
||||
nonsecure = 1;
|
||||
timeout = 0;
|
||||
|
||||
|
||||
// Check global variable to detect whether debugger is using JTAG or SWO and configure JTAG is necessary.
|
||||
if (MAIN_ActiveTIF == JLINK_TIF_JTAG) {
|
||||
JLINK_CORESIGHT_Configure("IRPre=0;DRPre=0;IRPost=0;DRPost=0;IRLenDevice=4");
|
||||
} else {
|
||||
JLINK_CORESIGHT_Configure(""); // For SWD, no special setup is needed, just output the switching sequence
|
||||
}
|
||||
|
||||
// Power-up complete DAP
|
||||
Ctrl = 0
|
||||
| (1 << 30) // System power-up
|
||||
| (1 << 28) // Debug popwer-up
|
||||
| (1 << 5) // Clear STICKYERR
|
||||
;
|
||||
JLINK_CORESIGHT_WriteDP(1, Ctrl);
|
||||
|
||||
// Select AHB-AP and configure it
|
||||
JLINK_CORESIGHT_WriteDP(DP_REG_SELECT, (0 << 4) | (0 << 24)); // Select AP[0] (AHB-AP) bank 0
|
||||
JLINK_CORESIGHT_WriteAP(AHBAP_REG_CTRL, (1 << 4) | (1 << 24) | (1 << 25) | (1 << 29) | (2 << 0)); // Auto-increment, Private access, HMASTER = DEBUG, Access size: word
|
||||
|
||||
// Enable Debug and Halt the MCU Core.
|
||||
JLINK_CORESIGHT_WriteAP(AHBAP_REG_ADDR, DHCSR_ADDR);
|
||||
v = JLINK_CORESIGHT_ReadAP(AHBAP_REG_DATA);
|
||||
v &= 0x3F; // Mask out "debug" bits
|
||||
v |= 0xA05F0000; // Debug key to make a write to the DHCSR a valid one
|
||||
v |= 0x00000002; // Halt the core
|
||||
v |= 0x00000001; // Enable debug functionalities of the core
|
||||
JLINK_CORESIGHT_WriteAP(AHBAP_REG_ADDR, DHCSR_ADDR);
|
||||
JLINK_CORESIGHT_WriteAP(AHBAP_REG_DATA, v);
|
||||
|
||||
// Read the Peripheral ID.
|
||||
JLINK_CORESIGHT_WriteAP(AHBAP_REG_ADDR, JDEC_PID);
|
||||
jdecpid = JLINK_CORESIGHT_ReadAP(AHBAP_REG_DATA);
|
||||
Report1("JDEC PID ", jdecpid);
|
||||
|
||||
// Is this Apollo3-Blue or Apollo3-Blue-Plus MCU?
|
||||
if ((jdecpid & 0xF0) == 0xC0)
|
||||
{
|
||||
// Apollo3-Blue or Apollo3-Blue-Plus
|
||||
Report("Ambiq Apollo3-Blue ResetTarget");
|
||||
|
||||
// Read MCUCTRL_BOOTLDR to determine if it is a secure or non-secure chip
|
||||
JLINK_CORESIGHT_WriteAP(AHBAP_REG_ADDR, MCUCTRL_BOOTLDR);
|
||||
bootldr = JLINK_CORESIGHT_ReadAP(AHBAP_REG_DATA);
|
||||
Report1("Bootldr = ", bootldr);
|
||||
if ((bootldr & 0x0C000000) == 0x04000000)
|
||||
{
|
||||
Report("Secure Part.");
|
||||
nonsecure = 0;
|
||||
}
|
||||
}
|
||||
|
||||
if (nonsecure == 0)
|
||||
{
|
||||
// Set MCUCTRL Scratch0, indicating that the Bootloader needs to run, then halt when it is finished.
|
||||
Report("Secure Chip. Bootloader needs to run which will then halt when finish.");
|
||||
JLINK_CORESIGHT_WriteAP(AHBAP_REG_ADDR, MCUCTRL_SCRATCH0);
|
||||
scratch0 = JLINK_CORESIGHT_ReadAP(AHBAP_REG_DATA);
|
||||
JLINK_CORESIGHT_WriteAP(AHBAP_REG_ADDR, MCUCTRL_SCRATCH0);
|
||||
JLINK_CORESIGHT_WriteAP(AHBAP_REG_DATA, scratch0 | 0x1);
|
||||
} else
|
||||
{
|
||||
// Set VC_CORERESET in the DEMCR.
|
||||
Report("Non-Secure Chip. Following normal Reset procedure.");
|
||||
JLINK_CORESIGHT_WriteAP(AHBAP_REG_ADDR, DEMCR_ADDR);
|
||||
demcr = JLINK_CORESIGHT_ReadAP(AHBAP_REG_DATA);
|
||||
JLINK_CORESIGHT_WriteAP(AHBAP_REG_ADDR, DEMCR_ADDR);
|
||||
JLINK_CORESIGHT_WriteAP(AHBAP_REG_DATA, demcr | 0x00000001);
|
||||
}
|
||||
|
||||
// Set the SYSRESETREQ bit in the AIRCR.
|
||||
// This will request the MCU Core to reset.
|
||||
JLINK_CORESIGHT_WriteAP(AHBAP_REG_ADDR, AIRCR_ADDR);
|
||||
JLINK_CORESIGHT_WriteAP(AHBAP_REG_DATA, 0x05FA0004);
|
||||
|
||||
// Wait until CPU is halted
|
||||
Tries = 0;
|
||||
Done = 0;
|
||||
do {
|
||||
JLINK_CORESIGHT_WriteAP(AHBAP_REG_ADDR, DHCSR_ADDR);
|
||||
v = JLINK_CORESIGHT_ReadAP(AHBAP_REG_DATA);
|
||||
// Check if CPU is halted. If so, we are done
|
||||
if (Tries >= 25) // wait for up to 2.5 seconds.
|
||||
{
|
||||
Report("Apollo3 (connect): Timeout while waiting for CPU to halt after reset. Manually halting CPU.");
|
||||
Done = 1;
|
||||
timeout = 1;
|
||||
}
|
||||
else if ((v != 0xFFFFFFFF) && (v & 0x00020000)) // Bit 17: S_HALT in the DHCSR.
|
||||
{
|
||||
Report1("CPU halted after reset. Num Tries = ", Tries);
|
||||
Done = 1;
|
||||
}
|
||||
Tries = Tries + 1;
|
||||
SYS_Sleep(100); // Go to sleep for 100 msec.
|
||||
} while(Done == 0);
|
||||
|
||||
// Let's try one more time using regular reset method
|
||||
if ((timeout == 1) && (nonsecure == 0))
|
||||
{
|
||||
// Set VC_CORERESET
|
||||
Report("Secure Part Reset timed out. Reverting to normal Reset procedure.");
|
||||
JLINK_CORESIGHT_WriteAP(AHBAP_REG_ADDR, DEMCR_ADDR);
|
||||
demcr = JLINK_CORESIGHT_ReadAP(AHBAP_REG_DATA);
|
||||
JLINK_CORESIGHT_WriteAP(AHBAP_REG_ADDR, DEMCR_ADDR);
|
||||
JLINK_CORESIGHT_WriteAP(AHBAP_REG_DATA, demcr | 0x00000001);
|
||||
// SYSRESETREQ
|
||||
JLINK_CORESIGHT_WriteAP(AHBAP_REG_ADDR, AIRCR_ADDR);
|
||||
JLINK_CORESIGHT_WriteAP(AHBAP_REG_DATA, 0x05FA0004);
|
||||
//
|
||||
// Wait until CPU is halted
|
||||
//
|
||||
Tries = 0;
|
||||
Done = 0;
|
||||
do {
|
||||
JLINK_CORESIGHT_WriteAP(AHBAP_REG_ADDR, DHCSR_ADDR);
|
||||
v = JLINK_CORESIGHT_ReadAP(AHBAP_REG_DATA);
|
||||
// Check if CPU is halted. If so, we are done
|
||||
if (Tries >= 25) // wait for up to 2.5 seconds.
|
||||
{
|
||||
Report("Apollo3 (connect): Timeout while waiting for CPU to halt after reset. Manually halting CPU.");
|
||||
Done = 1;
|
||||
timeout = 1;
|
||||
}
|
||||
else if ((v != 0xFFFFFFFF) && (v & 0x00020000)) // Bit 17: S_HALT in the DHCSR.
|
||||
{
|
||||
Report1("CPU halted after reset. Num Tries = ", Tries);
|
||||
Done = 1;
|
||||
}
|
||||
Tries = Tries + 1;
|
||||
SYS_Sleep(100); // Go to sleep for 100 msec.
|
||||
} while(Done == 0);
|
||||
}
|
||||
|
||||
// If non-secure part,...
|
||||
if (nonsecure == 1)
|
||||
{
|
||||
// Clear VC_CORERESET in the DEMCR.
|
||||
JLINK_CORESIGHT_WriteAP(AHBAP_REG_ADDR, DEMCR_ADDR);
|
||||
demcr = JLINK_CORESIGHT_ReadAP(AHBAP_REG_DATA);
|
||||
JLINK_CORESIGHT_WriteAP(AHBAP_REG_ADDR, DEMCR_ADDR);
|
||||
JLINK_CORESIGHT_WriteAP(AHBAP_REG_DATA, (demcr & 0xFFFFFFFE));
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
@@ -0,0 +1,357 @@
|
||||
#!/usr/bin/env python3
|
||||
# Utility functioins
|
||||
|
||||
import sys
|
||||
from Crypto.Cipher import AES
|
||||
from Crypto.PublicKey import RSA
|
||||
from Crypto.Signature import PKCS1_v1_5
|
||||
from Crypto.Hash import SHA256
|
||||
import array
|
||||
import hashlib
|
||||
import hmac
|
||||
import os
|
||||
import binascii
|
||||
|
||||
|
||||
ivVal0 = [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]
|
||||
|
||||
FLASH_PAGE_SIZE = 0x2000 # 8K
|
||||
MAX_DOWNLOAD_SIZE = 0x48000 # 288K
|
||||
AM_SECBOOT_DEFAULT_NONSECURE_MAIN = 0xC000
|
||||
|
||||
AM_SECBOOT_AESCBC_BLOCK_SIZE_WORDS = 4
|
||||
AM_SECBOOT_AESCBC_BLOCK_SIZE_BYTES = 4*AM_SECBOOT_AESCBC_BLOCK_SIZE_WORDS
|
||||
|
||||
AM_SECBOOT_MIN_KEYIDX_INFO0 = 8 ## KeyIdx 8 - 15
|
||||
AM_SECBOOT_MAX_KEYIDX_INFO0 = 15
|
||||
AM_SECBOOT_MIN_KEYIDX_INFO1 = 0 ## KeyIdx 0 - 7
|
||||
AM_SECBOOT_MAX_KEYIDX_INFO1 = 7
|
||||
AM_SECBOOT_KEYIDX_BYTES = 16
|
||||
|
||||
# Encryption Algorithm
|
||||
AM_SECBOOT_ENC_ALGO_NONE = 0
|
||||
AM_SECBOOT_ENC_ALGO_AES128 = 1
|
||||
AM_SECBOOT_ENC_ALGO_MAX = AM_SECBOOT_ENC_ALGO_AES128
|
||||
# String constants
|
||||
helpEncAlgo = 'Encryption Algo? (0(default) = none, 1 = AES128)'
|
||||
|
||||
# Authentication Algorithm
|
||||
AM_SECBOOT_AUTH_ALGO_NONE = 0
|
||||
AM_SECBOOT_AUTH_ALGO_SHA256HMAC = 1
|
||||
AM_SECBOOT_AUTH_ALGO_MAX = AM_SECBOOT_AUTH_ALGO_SHA256HMAC
|
||||
# String constants
|
||||
helpAuthAlgo = 'Authentication Algo? (0(default) = none, 1 = SHA256)'
|
||||
|
||||
|
||||
FLASH_INVALID = 0xFFFFFFFF
|
||||
|
||||
# KeyWrap Mode
|
||||
AM_SECBOOT_KEYWRAP_NONE = 0
|
||||
AM_SECBOOT_KEYWRAP_XOR = 1
|
||||
AM_SECBOOT_KEYWRAP_AES128 = 2
|
||||
AM_SECBOOT_KEYWRAP_MAX = AM_SECBOOT_KEYWRAP_AES128
|
||||
|
||||
#******************************************************************************
|
||||
#
|
||||
# Magic Numbers
|
||||
#
|
||||
#******************************************************************************
|
||||
AM_IMAGE_MAGIC_MAIN = 0xC0
|
||||
AM_IMAGE_MAGIC_CHILD = 0xCC
|
||||
AM_IMAGE_MAGIC_NONSECURE = 0xCB
|
||||
AM_IMAGE_MAGIC_INFO0 = 0xCF
|
||||
|
||||
# Dummy for creating images for customer - not understood by SBL
|
||||
# This could be any value from the definition:
|
||||
# #define AM_IMAGE_MAGIC_CUST(x) ((((x) & 0xF0) == 0xC0) && ((x) != 0xC0) && ((x) != 0xCC) && ((x) != 0xCB) && ((x) != 0xCF))
|
||||
AM_IMAGE_MAGIC_CUSTPATCH = 0xC1
|
||||
|
||||
#******************************************************************************
|
||||
#
|
||||
# Image Types
|
||||
#
|
||||
#******************************************************************************
|
||||
AM_SECBOOT_WIRED_IMAGETYPE_SBL = 0
|
||||
AM_SECBOOT_WIRED_IMAGETYPE_AM3P = 1
|
||||
AM_SECBOOT_WIRED_IMAGETYPE_PATCH = 2
|
||||
AM_SECBOOT_WIRED_IMAGETYPE_MAIN = 3
|
||||
AM_SECBOOT_WIRED_IMAGETYPE_CHILD = 4
|
||||
AM_SECBOOT_WIRED_IMAGETYPE_CUSTPATCH = 5
|
||||
AM_SECBOOT_WIRED_IMAGETYPE_NONSECURE = 6
|
||||
AM_SECBOOT_WIRED_IMAGETYPE_INFO0 = 7
|
||||
AM_SECBOOT_WIRED_IMAGETYPE_INFO0_NOOTA = 32
|
||||
AM_SECBOOT_WIRED_IMAGETYPE_INVALID = 0xFF
|
||||
|
||||
|
||||
#******************************************************************************
|
||||
#
|
||||
# Wired Message Types
|
||||
#
|
||||
#******************************************************************************
|
||||
AM_SECBOOT_WIRED_MSGTYPE_HELLO = 0
|
||||
AM_SECBOOT_WIRED_MSGTYPE_STATUS = 1
|
||||
AM_SECBOOT_WIRED_MSGTYPE_OTADESC = 2
|
||||
AM_SECBOOT_WIRED_MSGTYPE_UPDATE = 3
|
||||
AM_SECBOOT_WIRED_MSGTYPE_ABORT = 4
|
||||
AM_SECBOOT_WIRED_MSGTYPE_RECOVER = 5
|
||||
AM_SECBOOT_WIRED_MSGTYPE_RESET = 6
|
||||
AM_SECBOOT_WIRED_MSGTYPE_ACK = 7
|
||||
AM_SECBOOT_WIRED_MSGTYPE_DATA = 8
|
||||
|
||||
|
||||
#******************************************************************************
|
||||
#
|
||||
# Wired Message ACK Status
|
||||
#
|
||||
#******************************************************************************
|
||||
AM_SECBOOT_WIRED_ACK_STATUS_SUCCESS = 0
|
||||
AM_SECBOOT_WIRED_ACK_STATUS_FAILURE = 1
|
||||
AM_SECBOOT_WIRED_ACK_STATUS_INVALID_INFO0 = 2
|
||||
AM_SECBOOT_WIRED_ACK_STATUS_CRC = 3
|
||||
AM_SECBOOT_WIRED_ACK_STATUS_SEC = 4
|
||||
AM_SECBOOT_WIRED_ACK_STATUS_MSG_TOO_BIG = 5
|
||||
AM_SECBOOT_WIRED_ACK_STATUS_UNKNOWN_MSGTYPE = 6
|
||||
AM_SECBOOT_WIRED_ACK_STATUS_INVALID_ADDR = 7
|
||||
AM_SECBOOT_WIRED_ACK_STATUS_INVALID_OPERATION = 8
|
||||
AM_SECBOOT_WIRED_ACK_STATUS_INVALID_PARAM = 9
|
||||
AM_SECBOOT_WIRED_ACK_STATUS_SEQ = 10
|
||||
AM_SECBOOT_WIRED_ACK_STATUS_TOO_MUCH_DATA = 11
|
||||
|
||||
#******************************************************************************
|
||||
#
|
||||
# Definitions related to Image Headers
|
||||
#
|
||||
#******************************************************************************
|
||||
AM_HMAC_SIG_SIZE = 32
|
||||
AM_KEK_SIZE = 16
|
||||
AM_CRC_SIZE = 4
|
||||
|
||||
AM_MAX_UART_MSG_SIZE = 8192 # 8K buffer in SBL
|
||||
|
||||
# Wiredupdate Image Header
|
||||
AM_WU_IMAGEHDR_OFFSET_SIG = 16
|
||||
AM_WU_IMAGEHDR_OFFSET_IV = 48
|
||||
AM_WU_IMAGEHDR_OFFSET_KEK = 64
|
||||
AM_WU_IMAGEHDR_OFFSET_IMAGETYPE = (AM_WU_IMAGEHDR_OFFSET_KEK + AM_KEK_SIZE)
|
||||
AM_WU_IMAGEHDR_OFFSET_OPTIONS = (AM_WU_IMAGEHDR_OFFSET_IMAGETYPE + 1)
|
||||
AM_WU_IMAGEHDR_OFFSET_KEY = (AM_WU_IMAGEHDR_OFFSET_IMAGETYPE + 4)
|
||||
AM_WU_IMAGEHDR_OFFSET_ADDR = (AM_WU_IMAGEHDR_OFFSET_KEY + 4)
|
||||
AM_WU_IMAGEHDR_OFFSET_SIZE = (AM_WU_IMAGEHDR_OFFSET_ADDR + 4)
|
||||
|
||||
AM_WU_IMAGEHDR_START_HMAC = (AM_WU_IMAGEHDR_OFFSET_SIG + AM_HMAC_SIG_SIZE)
|
||||
AM_WU_IMAGEHDR_START_ENCRYPT = (AM_WU_IMAGEHDR_OFFSET_KEK + AM_KEK_SIZE)
|
||||
AM_WU_IMAGEHDR_SIZE = (AM_WU_IMAGEHDR_OFFSET_KEK + AM_KEK_SIZE + 16)
|
||||
|
||||
|
||||
# Image Header
|
||||
AM_IMAGEHDR_SIZE_MAIN = 256
|
||||
AM_IMAGEHDR_SIZE_AUX = (112 + AM_KEK_SIZE)
|
||||
|
||||
AM_IMAGEHDR_OFFSET_CRC = 4
|
||||
AM_IMAGEHDR_OFFSET_SIG = 16
|
||||
AM_IMAGEHDR_OFFSET_IV = 48
|
||||
AM_IMAGEHDR_OFFSET_KEK = 64
|
||||
AM_IMAGEHDR_OFFSET_SIGCLR = (AM_IMAGEHDR_OFFSET_KEK + AM_KEK_SIZE)
|
||||
AM_IMAGEHDR_START_CRC = (AM_IMAGEHDR_OFFSET_CRC + AM_CRC_SIZE)
|
||||
AM_IMAGEHDR_START_HMAC_INST = (AM_IMAGEHDR_OFFSET_SIG + AM_HMAC_SIG_SIZE)
|
||||
AM_IMAGEHDR_START_ENCRYPT = (AM_IMAGEHDR_OFFSET_KEK + AM_KEK_SIZE)
|
||||
AM_IMAGEHDR_START_HMAC = (AM_IMAGEHDR_OFFSET_SIGCLR + AM_HMAC_SIG_SIZE)
|
||||
AM_IMAGEHDR_OFFSET_ADDR = AM_IMAGEHDR_START_HMAC
|
||||
AM_IMAGEHDR_OFFSET_VERKEY = (AM_IMAGEHDR_OFFSET_ADDR + 4)
|
||||
AM_IMAGEHDR_OFFSET_CHILDPTR = (AM_IMAGEHDR_OFFSET_VERKEY + 4)
|
||||
|
||||
# Recover message
|
||||
AM_WU_RECOVERY_HDR_SIZE = 44
|
||||
AM_WU_RECOVERY_HDR_OFFSET_CUSTID = 8
|
||||
AM_WU_RECOVERY_HDR_OFFSET_RECKEY = (AM_WU_RECOVERY_HDR_OFFSET_CUSTID + 4)
|
||||
AM_WU_RECOVERY_HDR_OFFSET_NONCE = (AM_WU_RECOVERY_HDR_OFFSET_RECKEY + 16)
|
||||
AM_WU_RECOVERY_HDR_OFFSET_RECBLOB = (AM_WU_RECOVERY_HDR_OFFSET_NONCE + 16)
|
||||
|
||||
|
||||
#******************************************************************************
|
||||
#
|
||||
# INFOSPACE related definitions
|
||||
#
|
||||
#******************************************************************************
|
||||
AM_SECBOOT_INFO0_SIGN_PROGRAMMED0 = 0x48EAAD88
|
||||
AM_SECBOOT_INFO0_SIGN_PROGRAMMED1 = 0xC9705737
|
||||
AM_SECBOOT_INFO0_SIGN_PROGRAMMED2 = 0x0A6B8458
|
||||
AM_SECBOOT_INFO0_SIGN_PROGRAMMED3 = 0xE41A9D74
|
||||
|
||||
AM_SECBOOT_INFO0_SIGN_UINIT0 = 0x5B75A5FA
|
||||
AM_SECBOOT_INFO0_SIGN_UINIT1 = 0x7B9C8674
|
||||
AM_SECBOOT_INFO0_SIGN_UINIT2 = 0x869A96FE
|
||||
AM_SECBOOT_INFO0_SIGN_UINIT3 = 0xAEC90860
|
||||
|
||||
INFO_SIZE_BYTES = (8 * 1024)
|
||||
INFO_MAX_AUTH_KEY_WORDS = 32
|
||||
INFO_MAX_ENC_KEY_WORDS = 32
|
||||
|
||||
INFO_MAX_AUTH_KEYS = (INFO_MAX_AUTH_KEY_WORDS*4//AM_SECBOOT_KEYIDX_BYTES)
|
||||
INFO_MAX_ENC_KEYS = (INFO_MAX_ENC_KEY_WORDS*4//AM_SECBOOT_KEYIDX_BYTES)
|
||||
|
||||
|
||||
#******************************************************************************
|
||||
#
|
||||
# CRC using ethernet poly, as used by Corvette hardware for validation
|
||||
#
|
||||
#******************************************************************************
|
||||
def crc32(L):
|
||||
return (binascii.crc32(L) & 0xFFFFFFFF)
|
||||
|
||||
#******************************************************************************
|
||||
#
|
||||
# Pad the text to the block_size. bZeroPad determines how to handle text which
|
||||
# is already multiple of block_size
|
||||
#
|
||||
#******************************************************************************
|
||||
def pad_to_block_size(text, block_size, bZeroPad):
|
||||
text_length = len(text)
|
||||
amount_to_pad = block_size - (text_length % block_size)
|
||||
if (amount_to_pad == block_size):
|
||||
if (bZeroPad == 0):
|
||||
amount_to_pad = 0
|
||||
for i in range(0, amount_to_pad, 1):
|
||||
text += bytes(chr(amount_to_pad), 'ascii')
|
||||
return text
|
||||
|
||||
|
||||
#******************************************************************************
|
||||
#
|
||||
# AES CBC encryption
|
||||
#
|
||||
#******************************************************************************
|
||||
def encrypt_app_aes(cleartext, encKey, iv):
|
||||
key = array.array('B', encKey).tostring()
|
||||
ivVal = array.array('B', iv).tostring()
|
||||
plaintext = array.array('B', cleartext).tostring()
|
||||
|
||||
encryption_suite = AES.new(key, AES.MODE_CBC, ivVal)
|
||||
cipher_text = encryption_suite.encrypt(plaintext)
|
||||
|
||||
return cipher_text
|
||||
|
||||
#******************************************************************************
|
||||
#
|
||||
# AES 128 CBC encryption
|
||||
#
|
||||
#******************************************************************************
|
||||
def encrypt_app_aes128(cleartext, encKey, iv):
|
||||
key = array.array('B', encKey).tostring()
|
||||
ivVal = array.array('B', iv).tostring()
|
||||
plaintext = array.array('B', cleartext).tostring()
|
||||
|
||||
encryption_suite = AES.new(key, AES.MODE_CBC, ivVal)
|
||||
cipher_text = encryption_suite.encrypt(plaintext)
|
||||
|
||||
return cipher_text
|
||||
|
||||
#******************************************************************************
|
||||
#
|
||||
# SHA256 HMAC
|
||||
#
|
||||
#******************************************************************************
|
||||
def compute_hmac(key, data):
|
||||
sig = hmac.new(array.array('B', key).tostring(), array.array('B', data).tostring(), hashlib.sha256).digest()
|
||||
return sig
|
||||
|
||||
#******************************************************************************
|
||||
#
|
||||
# RSA PKCS1_v1_5 sign
|
||||
#
|
||||
#******************************************************************************
|
||||
def compute_rsa_sign(prvKeyFile, data):
|
||||
key = open(prvKeyFile, "r").read()
|
||||
rsakey = RSA.importKey(key)
|
||||
signer = PKCS1_v1_5.new(rsakey)
|
||||
digest = SHA256.new()
|
||||
digest.update(bytes(data))
|
||||
sign = signer.sign(digest)
|
||||
return sign
|
||||
|
||||
#******************************************************************************
|
||||
#
|
||||
# RSA PKCS1_v1_5 sign verification
|
||||
#
|
||||
#******************************************************************************
|
||||
def verify_rsa_sign(pubKeyFile, data, sign):
|
||||
key = open(pubKeyFile, "r").read()
|
||||
rsakey = RSA.importKey(key)
|
||||
#print(hex(rsakey.n))
|
||||
verifier = PKCS1_v1_5.new(rsakey)
|
||||
digest = SHA256.new()
|
||||
digest.update(bytes(data))
|
||||
return verifier.verify(digest, sign)
|
||||
|
||||
#******************************************************************************
|
||||
#
|
||||
# Fill one word in bytearray
|
||||
#
|
||||
#******************************************************************************
|
||||
def fill_word(barray, offset, w):
|
||||
barray[offset + 0] = (w >> 0) & 0x000000ff;
|
||||
barray[offset + 1] = (w >> 8) & 0x000000ff;
|
||||
barray[offset + 2] = (w >> 16) & 0x000000ff;
|
||||
barray[offset + 3] = (w >> 24) & 0x000000ff;
|
||||
|
||||
|
||||
#******************************************************************************
|
||||
#
|
||||
# Turn a 32-bit number into a series of bytes for transmission.
|
||||
#
|
||||
# This command will split a 32-bit integer into an array of bytes, ordered
|
||||
# LSB-first for transmission over the UART.
|
||||
#
|
||||
#******************************************************************************
|
||||
def int_to_bytes(n):
|
||||
A = [n & 0xFF,
|
||||
(n >> 8) & 0xFF,
|
||||
(n >> 16) & 0xFF,
|
||||
(n >> 24) & 0xFF]
|
||||
|
||||
return A
|
||||
|
||||
#******************************************************************************
|
||||
#
|
||||
# Extract a word from a byte array
|
||||
#
|
||||
#******************************************************************************
|
||||
def word_from_bytes(B, n):
|
||||
return (B[n] + (B[n + 1] << 8) + (B[n + 2] << 16) + (B[n + 3] << 24))
|
||||
|
||||
|
||||
#******************************************************************************
|
||||
#
|
||||
# automatically figure out the integer format (base 10 or 16)
|
||||
#
|
||||
#******************************************************************************
|
||||
def auto_int(x):
|
||||
return int(x, 0)
|
||||
|
||||
#******************************************************************************
|
||||
#
|
||||
# User controllable Prints control
|
||||
#
|
||||
#******************************************************************************
|
||||
# Defined print levels
|
||||
AM_PRINT_LEVEL_MIN = 0
|
||||
AM_PRINT_LEVEL_NONE = AM_PRINT_LEVEL_MIN
|
||||
AM_PRINT_LEVEL_ERROR = 1
|
||||
AM_PRINT_LEVEL_INFO = 2
|
||||
AM_PRINT_LEVEL_VERBOSE = 4
|
||||
AM_PRINT_LEVEL_DEBUG = 5
|
||||
AM_PRINT_LEVEL_MAX = AM_PRINT_LEVEL_DEBUG
|
||||
|
||||
# Global variable to control the prints
|
||||
AM_PRINT_VERBOSITY = AM_PRINT_LEVEL_INFO
|
||||
|
||||
helpPrintLevel = 'Set Log Level (0: None), (1: Error), (2: INFO), (4: Verbose), (5: Debug) [Default = Info]'
|
||||
|
||||
def am_set_print_level(level):
|
||||
global AM_PRINT_VERBOSITY
|
||||
AM_PRINT_VERBOSITY = level
|
||||
|
||||
def am_print(*args, level=AM_PRINT_LEVEL_INFO, **kwargs):
|
||||
global AM_PRINT_VERBOSITY
|
||||
if (AM_PRINT_VERBOSITY >= level):
|
||||
print(*args, **kwargs)
|
||||
@@ -0,0 +1,178 @@
|
||||
from am_defines import *
|
||||
|
||||
#******************************************************************************
|
||||
#
|
||||
# INFOSPACE related definitions
|
||||
#
|
||||
#******************************************************************************
|
||||
INFO0_SIGNATURE0_O = 0x00000000
|
||||
INFO0_SIGNATURE1_O = 0x00000004
|
||||
INFO0_SIGNATURE2_O = 0x00000008
|
||||
INFO0_SIGNATURE3_O = 0x0000000c
|
||||
INFO0_SECURITY_O = 0x00000010
|
||||
INFO0_CUSTOMER_TRIM_O = 0x00000014
|
||||
INFO0_CUSTOMER_TRIM2_O = 0x00000018
|
||||
INFO0_SECURITY_OVR_O = 0x00000020
|
||||
INFO0_SECURITY_WIRED_CFG_O = 0x00000024
|
||||
INFO0_SECURITY_WIRED_IFC_CFG0_O = 0x00000028
|
||||
INFO0_SECURITY_WIRED_IFC_CFG1_O = 0x0000002C
|
||||
INFO0_SECURITY_WIRED_IFC_CFG2_O = 0x00000030
|
||||
INFO0_SECURITY_WIRED_IFC_CFG3_O = 0x00000034
|
||||
INFO0_SECURITY_WIRED_IFC_CFG4_O = 0x00000038
|
||||
INFO0_SECURITY_WIRED_IFC_CFG5_O = 0x0000003C
|
||||
INFO0_SECURITY_VERSION_O = 0x00000040
|
||||
INFO0_SECURITY_SRAM_RESV_O = 0x00000050
|
||||
AM_REG_INFO0_SECURITY_SRAM_RESV_SRAM_RESV_M = 0x0000FFFF
|
||||
INFO0_WRITE_PROTECT_L_O = 0x000001f8
|
||||
INFO0_WRITE_PROTECT_H_O = 0x000001fc
|
||||
INFO0_COPY_PROTECT_L_O = 0x00000200
|
||||
INFO0_COPY_PROTECT_H_O = 0x00000204
|
||||
INFO0_WRITE_PROTECT_SBL_L_O = 0x000009f8
|
||||
INFO0_WRITE_PROTECT_SBL_H_O = 0x000009fc
|
||||
INFO0_COPY_PROTECT_SBL_L_O = 0x00000A00
|
||||
INFO0_COPY_PROTECT_SBL_H_O = 0x00000A04
|
||||
INFO0_MAIN_PTR1_O = 0x00000C00
|
||||
INFO0_MAIN_PTR2_O = 0x00000C04
|
||||
INFO0_KREVTRACK_O = 0x00000C08
|
||||
INFO0_AREVTRACK_O = 0x00000C0C
|
||||
INFO0_MAIN_CNT0_O = 0x00000FF8
|
||||
INFO0_MAIN_CNT1_O = 0x00000FFC
|
||||
|
||||
INFO0_CUST_KEK_W0_O = 0x00001800
|
||||
INFO0_CUST_KEK_W1_O = 0x00001804
|
||||
INFO0_CUST_KEK_W2_O = 0x00001808
|
||||
INFO0_CUST_KEK_W3_O = 0x0000180c
|
||||
INFO0_CUST_KEK_W4_O = 0x00001810
|
||||
INFO0_CUST_KEK_W5_O = 0x00001814
|
||||
INFO0_CUST_KEK_W6_O = 0x00001818
|
||||
INFO0_CUST_KEK_W7_O = 0x0000181c
|
||||
INFO0_CUST_KEK_W8_O = 0x00001820
|
||||
INFO0_CUST_KEK_W9_O = 0x00001824
|
||||
INFO0_CUST_KEK_W10_O = 0x00001828
|
||||
INFO0_CUST_KEK_W11_O = 0x0000182c
|
||||
INFO0_CUST_KEK_W12_O = 0x00001830
|
||||
INFO0_CUST_KEK_W13_O = 0x00001834
|
||||
INFO0_CUST_KEK_W14_O = 0x00001838
|
||||
INFO0_CUST_KEK_W15_O = 0x0000183c
|
||||
INFO0_CUST_KEK_W16_O = 0x00001840
|
||||
INFO0_CUST_KEK_W17_O = 0x00001844
|
||||
INFO0_CUST_KEK_W18_O = 0x00001848
|
||||
INFO0_CUST_KEK_W19_O = 0x0000184c
|
||||
INFO0_CUST_KEK_W20_O = 0x00001850
|
||||
INFO0_CUST_KEK_W21_O = 0x00001854
|
||||
INFO0_CUST_KEK_W22_O = 0x00001858
|
||||
INFO0_CUST_KEK_W23_O = 0x0000185c
|
||||
INFO0_CUST_KEK_W24_O = 0x00001860
|
||||
INFO0_CUST_KEK_W25_O = 0x00001864
|
||||
INFO0_CUST_KEK_W26_O = 0x00001868
|
||||
INFO0_CUST_KEK_W27_O = 0x0000186c
|
||||
INFO0_CUST_KEK_W28_O = 0x00001870
|
||||
INFO0_CUST_KEK_W29_O = 0x00001874
|
||||
INFO0_CUST_KEK_W30_O = 0x00001878
|
||||
INFO0_CUST_KEK_W31_O = 0x0000187c
|
||||
INFO0_CUST_AUTH_W0_O = 0x00001880
|
||||
INFO0_CUST_AUTH_W1_O = 0x00001884
|
||||
INFO0_CUST_AUTH_W2_O = 0x00001888
|
||||
INFO0_CUST_AUTH_W3_O = 0x0000188c
|
||||
INFO0_CUST_AUTH_W4_O = 0x00001890
|
||||
INFO0_CUST_AUTH_W5_O = 0x00001894
|
||||
INFO0_CUST_AUTH_W6_O = 0x00001898
|
||||
INFO0_CUST_AUTH_W7_O = 0x0000189c
|
||||
INFO0_CUST_AUTH_W8_O = 0x000018a0
|
||||
INFO0_CUST_AUTH_W9_O = 0x000018a4
|
||||
INFO0_CUST_AUTH_W10_O = 0x000018a8
|
||||
INFO0_CUST_AUTH_W11_O = 0x000018ac
|
||||
INFO0_CUST_AUTH_W12_O = 0x000018b0
|
||||
INFO0_CUST_AUTH_W13_O = 0x000018b4
|
||||
INFO0_CUST_AUTH_W14_O = 0x000018b8
|
||||
INFO0_CUST_AUTH_W15_O = 0x000018bc
|
||||
INFO0_CUST_AUTH_W16_O = 0x000018c0
|
||||
INFO0_CUST_AUTH_W17_O = 0x000018c4
|
||||
INFO0_CUST_AUTH_W18_O = 0x000018c8
|
||||
INFO0_CUST_AUTH_W19_O = 0x000018cc
|
||||
INFO0_CUST_AUTH_W20_O = 0x000018d0
|
||||
INFO0_CUST_AUTH_W21_O = 0x000018d4
|
||||
INFO0_CUST_AUTH_W22_O = 0x000018d8
|
||||
INFO0_CUST_AUTH_W23_O = 0x000018dc
|
||||
INFO0_CUST_AUTH_W24_O = 0x000018e0
|
||||
INFO0_CUST_AUTH_W25_O = 0x000018e4
|
||||
INFO0_CUST_AUTH_W26_O = 0x000018e8
|
||||
INFO0_CUST_AUTH_W27_O = 0x000018ec
|
||||
INFO0_CUST_AUTH_W28_O = 0x000018f0
|
||||
INFO0_CUST_AUTH_W29_O = 0x000018f4
|
||||
INFO0_CUST_AUTH_W30_O = 0x000018f8
|
||||
INFO0_CUST_AUTH_W31_O = 0x000018fc
|
||||
INFO0_CUST_PUBKEY_W0_O = 0x00001900
|
||||
INFO0_CUST_PUBKEY_W1_O = 0x00001904
|
||||
INFO0_CUST_PUBKEY_W2_O = 0x00001908
|
||||
INFO0_CUST_PUBKEY_W3_O = 0x0000190c
|
||||
INFO0_CUST_PUBKEY_W4_O = 0x00001910
|
||||
INFO0_CUST_PUBKEY_W5_O = 0x00001914
|
||||
INFO0_CUST_PUBKEY_W6_O = 0x00001918
|
||||
INFO0_CUST_PUBKEY_W7_O = 0x0000191c
|
||||
INFO0_CUST_PUBKEY_W8_O = 0x00001920
|
||||
INFO0_CUST_PUBKEY_W9_O = 0x00001924
|
||||
INFO0_CUST_PUBKEY_W10_O = 0x00001928
|
||||
INFO0_CUST_PUBKEY_W11_O = 0x0000192c
|
||||
INFO0_CUST_PUBKEY_W12_O = 0x00001930
|
||||
INFO0_CUST_PUBKEY_W13_O = 0x00001934
|
||||
INFO0_CUST_PUBKEY_W14_O = 0x00001938
|
||||
INFO0_CUST_PUBKEY_W15_O = 0x0000193c
|
||||
INFO0_CUST_PUBKEY_W16_O = 0x00001940
|
||||
INFO0_CUST_PUBKEY_W17_O = 0x00001944
|
||||
INFO0_CUST_PUBKEY_W18_O = 0x00001948
|
||||
INFO0_CUST_PUBKEY_W19_O = 0x0000194c
|
||||
INFO0_CUST_PUBKEY_W20_O = 0x00001950
|
||||
INFO0_CUST_PUBKEY_W21_O = 0x00001954
|
||||
INFO0_CUST_PUBKEY_W22_O = 0x00001958
|
||||
INFO0_CUST_PUBKEY_W23_O = 0x0000195c
|
||||
INFO0_CUST_PUBKEY_W24_O = 0x00001960
|
||||
INFO0_CUST_PUBKEY_W25_O = 0x00001964
|
||||
INFO0_CUST_PUBKEY_W26_O = 0x00001968
|
||||
INFO0_CUST_PUBKEY_W27_O = 0x0000196c
|
||||
INFO0_CUST_PUBKEY_W28_O = 0x00001970
|
||||
INFO0_CUST_PUBKEY_W29_O = 0x00001974
|
||||
INFO0_CUST_PUBKEY_W30_O = 0x00001978
|
||||
INFO0_CUST_PUBKEY_W31_O = 0x0000197c
|
||||
INFO0_CUST_PUBKEY_W32_O = 0x00001980
|
||||
INFO0_CUST_PUBKEY_W33_O = 0x00001984
|
||||
INFO0_CUST_PUBKEY_W34_O = 0x00001988
|
||||
INFO0_CUST_PUBKEY_W35_O = 0x0000198c
|
||||
INFO0_CUST_PUBKEY_W36_O = 0x00001990
|
||||
INFO0_CUST_PUBKEY_W37_O = 0x00001994
|
||||
INFO0_CUST_PUBKEY_W38_O = 0x00001998
|
||||
INFO0_CUST_PUBKEY_W39_O = 0x0000199c
|
||||
INFO0_CUST_PUBKEY_W40_O = 0x000019a0
|
||||
INFO0_CUST_PUBKEY_W41_O = 0x000019a4
|
||||
INFO0_CUST_PUBKEY_W42_O = 0x000019a8
|
||||
INFO0_CUST_PUBKEY_W43_O = 0x000019ac
|
||||
INFO0_CUST_PUBKEY_W44_O = 0x000019b0
|
||||
INFO0_CUST_PUBKEY_W45_O = 0x000019b4
|
||||
INFO0_CUST_PUBKEY_W46_O = 0x000019b8
|
||||
INFO0_CUST_PUBKEY_W47_O = 0x000019bc
|
||||
INFO0_CUST_PUBKEY_W48_O = 0x000019c0
|
||||
INFO0_CUST_PUBKEY_W49_O = 0x000019c4
|
||||
INFO0_CUST_PUBKEY_W50_O = 0x000019c8
|
||||
INFO0_CUST_PUBKEY_W51_O = 0x000019cc
|
||||
INFO0_CUST_PUBKEY_W52_O = 0x000019d0
|
||||
INFO0_CUST_PUBKEY_W53_O = 0x000019d4
|
||||
INFO0_CUST_PUBKEY_W54_O = 0x000019d8
|
||||
INFO0_CUST_PUBKEY_W55_O = 0x000019dc
|
||||
INFO0_CUST_PUBKEY_W56_O = 0x000019e0
|
||||
INFO0_CUST_PUBKEY_W57_O = 0x000019e4
|
||||
INFO0_CUST_PUBKEY_W58_O = 0x000019e8
|
||||
INFO0_CUST_PUBKEY_W59_O = 0x000019ec
|
||||
INFO0_CUST_PUBKEY_W60_O = 0x000019f0
|
||||
INFO0_CUST_PUBKEY_W61_O = 0x000019f4
|
||||
INFO0_CUST_PUBKEY_W62_O = 0x000019f8
|
||||
INFO0_CUST_PUBKEY_W63_O = 0x000019fc
|
||||
INFO0_CUSTOMER_KEY0_O = 0x00001a00
|
||||
INFO0_CUSTOMER_KEY1_O = 0x00001a04
|
||||
INFO0_CUSTOMER_KEY2_O = 0x00001a08
|
||||
INFO0_CUSTOMER_KEY3_O = 0x00001a0c
|
||||
INFO0_CUST_PUBHASH_W0_O = 0x00001a10
|
||||
INFO0_CUST_PUBHASH_W1_O = 0x00001a14
|
||||
INFO0_CUST_PUBHASH_W2_O = 0x00001a18
|
||||
INFO0_CUST_PUBHASH_W3_O = 0x00001a1c
|
||||
|
||||
|
||||
@@ -0,0 +1,180 @@
|
||||
#from am_defines import *
|
||||
INFO0_SIGNATURE0_O = 0x00000000
|
||||
INFO0_SIGNATURE1_O = 0x00000004
|
||||
INFO0_SIGNATURE2_O = 0x00000008
|
||||
INFO0_SIGNATURE3_O = 0x0000000c
|
||||
INFO0_SECURITY_O = 0x00000010
|
||||
INFO0_CUSTOMER_TRIM_O = 0x00000014
|
||||
INFO0_CUSTOMER_TRIM2_O = 0x00000018
|
||||
INFO0_SECURITY_OVR_O = 0x00000020
|
||||
INFO0_SECURITY_WIRED_CFG_O = 0x00000024
|
||||
INFO0_SECURITY_WIRED_IFC_CFG0_O = 0x00000028
|
||||
INFO0_SECURITY_WIRED_IFC_CFG1_O = 0x0000002C
|
||||
INFO0_SECURITY_WIRED_IFC_CFG2_O = 0x00000030
|
||||
INFO0_SECURITY_WIRED_IFC_CFG3_O = 0x00000034
|
||||
INFO0_SECURITY_WIRED_IFC_CFG4_O = 0x00000038
|
||||
INFO0_SECURITY_WIRED_IFC_CFG5_O = 0x0000003C
|
||||
INFO0_SECURITY_VERSION_O = 0x00000040
|
||||
INFO0_SECURITY_SRAM_RESV_O = 0x00000050
|
||||
AM_REG_INFO0_SECURITY_SRAM_RESV_SRAM_RESV_M = 0x0000FFFF
|
||||
INFO0_WRITE_PROTECT0_O = 0x000001f0
|
||||
INFO0_WRITE_PROTECT1_O = 0x000001f4
|
||||
INFO0_WRITE_PROTECT2_O = 0x000001f8
|
||||
INFO0_WRITE_PROTECT3_O = 0x000001fc
|
||||
INFO0_COPY_PROTECT0_O = 0x00000200
|
||||
INFO0_COPY_PROTECT1_O = 0x00000204
|
||||
INFO0_COPY_PROTECT2_O = 0x00000208
|
||||
INFO0_COPY_PROTECT3_O = 0x0000020C
|
||||
INFO0_WRITE_PROTECT0_SBL_O = 0x000009f0
|
||||
INFO0_WRITE_PROTECT1_SBL_O = 0x000009f4
|
||||
INFO0_WRITE_PROTECT2_SBL_O = 0x000009f8
|
||||
INFO0_WRITE_PROTECT3_SBL_O = 0x000009fc
|
||||
INFO0_COPY_PROTECT0_SBL_O = 0x00000A00
|
||||
INFO0_COPY_PROTECT1_SBL_O = 0x00000A04
|
||||
INFO0_COPY_PROTECT2_SBL_O = 0x00000A08
|
||||
INFO0_COPY_PROTECT3_SBL_O = 0x00000A0C
|
||||
INFO0_MAIN_PTR1_O = 0x00000C00
|
||||
INFO0_MAIN_PTR2_O = 0x00000C04
|
||||
INFO0_KREVTRACK_O = 0x00000C08
|
||||
INFO0_AREVTRACK_O = 0x00000C0C
|
||||
INFO0_MAIN_CNT0_O = 0x00000FF8
|
||||
INFO0_MAIN_CNT1_O = 0x00000FFC
|
||||
|
||||
INFO0_CUST_KEK_W0_O = 0x00001800
|
||||
INFO0_CUST_KEK_W1_O = 0x00001804
|
||||
INFO0_CUST_KEK_W2_O = 0x00001808
|
||||
INFO0_CUST_KEK_W3_O = 0x0000180c
|
||||
INFO0_CUST_KEK_W4_O = 0x00001810
|
||||
INFO0_CUST_KEK_W5_O = 0x00001814
|
||||
INFO0_CUST_KEK_W6_O = 0x00001818
|
||||
INFO0_CUST_KEK_W7_O = 0x0000181c
|
||||
INFO0_CUST_KEK_W8_O = 0x00001820
|
||||
INFO0_CUST_KEK_W9_O = 0x00001824
|
||||
INFO0_CUST_KEK_W10_O = 0x00001828
|
||||
INFO0_CUST_KEK_W11_O = 0x0000182c
|
||||
INFO0_CUST_KEK_W12_O = 0x00001830
|
||||
INFO0_CUST_KEK_W13_O = 0x00001834
|
||||
INFO0_CUST_KEK_W14_O = 0x00001838
|
||||
INFO0_CUST_KEK_W15_O = 0x0000183c
|
||||
INFO0_CUST_KEK_W16_O = 0x00001840
|
||||
INFO0_CUST_KEK_W17_O = 0x00001844
|
||||
INFO0_CUST_KEK_W18_O = 0x00001848
|
||||
INFO0_CUST_KEK_W19_O = 0x0000184c
|
||||
INFO0_CUST_KEK_W20_O = 0x00001850
|
||||
INFO0_CUST_KEK_W21_O = 0x00001854
|
||||
INFO0_CUST_KEK_W22_O = 0x00001858
|
||||
INFO0_CUST_KEK_W23_O = 0x0000185c
|
||||
INFO0_CUST_KEK_W24_O = 0x00001860
|
||||
INFO0_CUST_KEK_W25_O = 0x00001864
|
||||
INFO0_CUST_KEK_W26_O = 0x00001868
|
||||
INFO0_CUST_KEK_W27_O = 0x0000186c
|
||||
INFO0_CUST_KEK_W28_O = 0x00001870
|
||||
INFO0_CUST_KEK_W29_O = 0x00001874
|
||||
INFO0_CUST_KEK_W30_O = 0x00001878
|
||||
INFO0_CUST_KEK_W31_O = 0x0000187c
|
||||
INFO0_CUST_AUTH_W0_O = 0x00001880
|
||||
INFO0_CUST_AUTH_W1_O = 0x00001884
|
||||
INFO0_CUST_AUTH_W2_O = 0x00001888
|
||||
INFO0_CUST_AUTH_W3_O = 0x0000188c
|
||||
INFO0_CUST_AUTH_W4_O = 0x00001890
|
||||
INFO0_CUST_AUTH_W5_O = 0x00001894
|
||||
INFO0_CUST_AUTH_W6_O = 0x00001898
|
||||
INFO0_CUST_AUTH_W7_O = 0x0000189c
|
||||
INFO0_CUST_AUTH_W8_O = 0x000018a0
|
||||
INFO0_CUST_AUTH_W9_O = 0x000018a4
|
||||
INFO0_CUST_AUTH_W10_O = 0x000018a8
|
||||
INFO0_CUST_AUTH_W11_O = 0x000018ac
|
||||
INFO0_CUST_AUTH_W12_O = 0x000018b0
|
||||
INFO0_CUST_AUTH_W13_O = 0x000018b4
|
||||
INFO0_CUST_AUTH_W14_O = 0x000018b8
|
||||
INFO0_CUST_AUTH_W15_O = 0x000018bc
|
||||
INFO0_CUST_AUTH_W16_O = 0x000018c0
|
||||
INFO0_CUST_AUTH_W17_O = 0x000018c4
|
||||
INFO0_CUST_AUTH_W18_O = 0x000018c8
|
||||
INFO0_CUST_AUTH_W19_O = 0x000018cc
|
||||
INFO0_CUST_AUTH_W20_O = 0x000018d0
|
||||
INFO0_CUST_AUTH_W21_O = 0x000018d4
|
||||
INFO0_CUST_AUTH_W22_O = 0x000018d8
|
||||
INFO0_CUST_AUTH_W23_O = 0x000018dc
|
||||
INFO0_CUST_AUTH_W24_O = 0x000018e0
|
||||
INFO0_CUST_AUTH_W25_O = 0x000018e4
|
||||
INFO0_CUST_AUTH_W26_O = 0x000018e8
|
||||
INFO0_CUST_AUTH_W27_O = 0x000018ec
|
||||
INFO0_CUST_AUTH_W28_O = 0x000018f0
|
||||
INFO0_CUST_AUTH_W29_O = 0x000018f4
|
||||
INFO0_CUST_AUTH_W30_O = 0x000018f8
|
||||
INFO0_CUST_AUTH_W31_O = 0x000018fc
|
||||
INFO0_CUST_PUBKEY_W0_O = 0x00001900
|
||||
INFO0_CUST_PUBKEY_W1_O = 0x00001904
|
||||
INFO0_CUST_PUBKEY_W2_O = 0x00001908
|
||||
INFO0_CUST_PUBKEY_W3_O = 0x0000190c
|
||||
INFO0_CUST_PUBKEY_W4_O = 0x00001910
|
||||
INFO0_CUST_PUBKEY_W5_O = 0x00001914
|
||||
INFO0_CUST_PUBKEY_W6_O = 0x00001918
|
||||
INFO0_CUST_PUBKEY_W7_O = 0x0000191c
|
||||
INFO0_CUST_PUBKEY_W8_O = 0x00001920
|
||||
INFO0_CUST_PUBKEY_W9_O = 0x00001924
|
||||
INFO0_CUST_PUBKEY_W10_O = 0x00001928
|
||||
INFO0_CUST_PUBKEY_W11_O = 0x0000192c
|
||||
INFO0_CUST_PUBKEY_W12_O = 0x00001930
|
||||
INFO0_CUST_PUBKEY_W13_O = 0x00001934
|
||||
INFO0_CUST_PUBKEY_W14_O = 0x00001938
|
||||
INFO0_CUST_PUBKEY_W15_O = 0x0000193c
|
||||
INFO0_CUST_PUBKEY_W16_O = 0x00001940
|
||||
INFO0_CUST_PUBKEY_W17_O = 0x00001944
|
||||
INFO0_CUST_PUBKEY_W18_O = 0x00001948
|
||||
INFO0_CUST_PUBKEY_W19_O = 0x0000194c
|
||||
INFO0_CUST_PUBKEY_W20_O = 0x00001950
|
||||
INFO0_CUST_PUBKEY_W21_O = 0x00001954
|
||||
INFO0_CUST_PUBKEY_W22_O = 0x00001958
|
||||
INFO0_CUST_PUBKEY_W23_O = 0x0000195c
|
||||
INFO0_CUST_PUBKEY_W24_O = 0x00001960
|
||||
INFO0_CUST_PUBKEY_W25_O = 0x00001964
|
||||
INFO0_CUST_PUBKEY_W26_O = 0x00001968
|
||||
INFO0_CUST_PUBKEY_W27_O = 0x0000196c
|
||||
INFO0_CUST_PUBKEY_W28_O = 0x00001970
|
||||
INFO0_CUST_PUBKEY_W29_O = 0x00001974
|
||||
INFO0_CUST_PUBKEY_W30_O = 0x00001978
|
||||
INFO0_CUST_PUBKEY_W31_O = 0x0000197c
|
||||
INFO0_CUST_PUBKEY_W32_O = 0x00001980
|
||||
INFO0_CUST_PUBKEY_W33_O = 0x00001984
|
||||
INFO0_CUST_PUBKEY_W34_O = 0x00001988
|
||||
INFO0_CUST_PUBKEY_W35_O = 0x0000198c
|
||||
INFO0_CUST_PUBKEY_W36_O = 0x00001990
|
||||
INFO0_CUST_PUBKEY_W37_O = 0x00001994
|
||||
INFO0_CUST_PUBKEY_W38_O = 0x00001998
|
||||
INFO0_CUST_PUBKEY_W39_O = 0x0000199c
|
||||
INFO0_CUST_PUBKEY_W40_O = 0x000019a0
|
||||
INFO0_CUST_PUBKEY_W41_O = 0x000019a4
|
||||
INFO0_CUST_PUBKEY_W42_O = 0x000019a8
|
||||
INFO0_CUST_PUBKEY_W43_O = 0x000019ac
|
||||
INFO0_CUST_PUBKEY_W44_O = 0x000019b0
|
||||
INFO0_CUST_PUBKEY_W45_O = 0x000019b4
|
||||
INFO0_CUST_PUBKEY_W46_O = 0x000019b8
|
||||
INFO0_CUST_PUBKEY_W47_O = 0x000019bc
|
||||
INFO0_CUST_PUBKEY_W48_O = 0x000019c0
|
||||
INFO0_CUST_PUBKEY_W49_O = 0x000019c4
|
||||
INFO0_CUST_PUBKEY_W50_O = 0x000019c8
|
||||
INFO0_CUST_PUBKEY_W51_O = 0x000019cc
|
||||
INFO0_CUST_PUBKEY_W52_O = 0x000019d0
|
||||
INFO0_CUST_PUBKEY_W53_O = 0x000019d4
|
||||
INFO0_CUST_PUBKEY_W54_O = 0x000019d8
|
||||
INFO0_CUST_PUBKEY_W55_O = 0x000019dc
|
||||
INFO0_CUST_PUBKEY_W56_O = 0x000019e0
|
||||
INFO0_CUST_PUBKEY_W57_O = 0x000019e4
|
||||
INFO0_CUST_PUBKEY_W58_O = 0x000019e8
|
||||
INFO0_CUST_PUBKEY_W59_O = 0x000019ec
|
||||
INFO0_CUST_PUBKEY_W60_O = 0x000019f0
|
||||
INFO0_CUST_PUBKEY_W61_O = 0x000019f4
|
||||
INFO0_CUST_PUBKEY_W62_O = 0x000019f8
|
||||
INFO0_CUST_PUBKEY_W63_O = 0x000019fc
|
||||
INFO0_CUSTOMER_KEY0_O = 0x00001a00
|
||||
INFO0_CUSTOMER_KEY1_O = 0x00001a04
|
||||
INFO0_CUSTOMER_KEY2_O = 0x00001a08
|
||||
INFO0_CUSTOMER_KEY3_O = 0x00001a0c
|
||||
INFO0_CUST_PUBHASH_W0_O = 0x00001a10
|
||||
INFO0_CUST_PUBHASH_W1_O = 0x00001a14
|
||||
INFO0_CUST_PUBHASH_W2_O = 0x00001a18
|
||||
INFO0_CUST_PUBHASH_W3_O = 0x00001a1c
|
||||
|
||||
|
||||
@@ -0,0 +1,299 @@
|
||||
#!/usr/bin/env python3
|
||||
# Utility to create image blobs for Corvette Secure Boot
|
||||
|
||||
import argparse
|
||||
import sys
|
||||
from Crypto.Cipher import AES
|
||||
import array
|
||||
import hashlib
|
||||
import hmac
|
||||
import os
|
||||
import binascii
|
||||
import importlib
|
||||
|
||||
from am_defines import *
|
||||
#from keys_info import keyTblAes, keyTblHmac, minAesKeyIdx, maxAesKeyIdx, minHmacKeyIdx, maxHmacKeyIdx, INFO_KEY
|
||||
|
||||
|
||||
#******************************************************************************
|
||||
#
|
||||
# Generate the image blob as per command line parameters
|
||||
#
|
||||
#******************************************************************************
|
||||
def process(loadaddress, appFile, magicNum, crcI, crcB, authI, authB, protection, authKeyIdx, output, encKeyIdx, version, erasePrev, child0, child1, authalgo, encalgo, keyFile):
|
||||
|
||||
app_binarray = bytearray()
|
||||
# Open the file, and read it into an array of integers.
|
||||
with appFile as f_app:
|
||||
app_binarray.extend(f_app.read())
|
||||
f_app.close()
|
||||
|
||||
filenames = keyFile.split('.')
|
||||
keys = importlib.import_module(filenames[0])
|
||||
|
||||
encVal = 0
|
||||
if (encalgo != 0):
|
||||
encVal = 1
|
||||
if ((encKeyIdx < keys.minAesKeyIdx) or (encKeyIdx > keys.maxAesKeyIdx)):
|
||||
am_print("Invalid encKey Idx ", encKeyIdx, level=AM_PRINT_LEVEL_ERROR);
|
||||
return
|
||||
if (encalgo == 2):
|
||||
if (encKeyIdx & 0x1):
|
||||
am_print("Invalid encKey Idx ", encKeyIdx, level=AM_PRINT_LEVEL_ERROR);
|
||||
return
|
||||
keySize = 32
|
||||
else:
|
||||
keySize = 16
|
||||
if (authalgo != 0):
|
||||
if ((authKeyIdx < keys.minHmacKeyIdx) or (authKeyIdx > keys.maxHmacKeyIdx) or (authKeyIdx & 0x1)):
|
||||
am_print("Invalid authKey Idx ", authKeyIdx, level=AM_PRINT_LEVEL_ERROR);
|
||||
return
|
||||
|
||||
if (magicNum == AM_IMAGE_MAGIC_MAIN):
|
||||
hdr_length = AM_IMAGEHDR_SIZE_MAIN; #fixed header length
|
||||
elif ((magicNum == AM_IMAGE_MAGIC_CHILD) or (magicNum == AM_IMAGE_MAGIC_CUSTPATCH) or (magicNum == AM_IMAGE_MAGIC_NONSECURE) or (magicNum == AM_IMAGE_MAGIC_INFO0)):
|
||||
hdr_length = AM_IMAGEHDR_SIZE_AUX; #fixed header length
|
||||
else:
|
||||
am_print("magic number", hex(magicNum), " not supported", level=AM_PRINT_LEVEL_ERROR)
|
||||
return
|
||||
am_print("Header Size = ", hex(hdr_length))
|
||||
|
||||
#generate mutable byte array for the header
|
||||
hdr_binarray = bytearray([0x00]*hdr_length);
|
||||
|
||||
orig_app_length = (len(app_binarray))
|
||||
am_print("original app_size ",hex(orig_app_length), "(",orig_app_length,")")
|
||||
|
||||
am_print("load_address ",hex(loadaddress), "(",loadaddress,")")
|
||||
if (loadaddress & 0x3):
|
||||
am_print("load address needs to be word aligned", level=AM_PRINT_LEVEL_ERROR)
|
||||
return
|
||||
|
||||
if (loadaddress & (FLASH_PAGE_SIZE - 1)):
|
||||
am_print("WARNING!!! - load address is not page aligned", level=AM_PRINT_LEVEL_ERROR)
|
||||
|
||||
if (magicNum == AM_IMAGE_MAGIC_INFO0):
|
||||
if (orig_app_length & 0x3):
|
||||
am_print("INFO0 blob length needs to be multiple of 4", level=AM_PRINT_LEVEL_ERROR)
|
||||
return
|
||||
if ((loadaddress + orig_app_length) > INFO_SIZE_BYTES):
|
||||
am_print("INFO0 Offset and length exceed size", level=AM_PRINT_LEVEL_ERROR)
|
||||
return
|
||||
|
||||
if (encVal == 1):
|
||||
block_size = AM_SECBOOT_AESCBC_BLOCK_SIZE_BYTES
|
||||
app_binarray = pad_to_block_size(app_binarray, block_size, 1)
|
||||
else:
|
||||
# Add Padding
|
||||
app_binarray = pad_to_block_size(app_binarray, 4, 0)
|
||||
|
||||
app_length = (len(app_binarray))
|
||||
am_print("app_size ",hex(app_length), "(",app_length,")")
|
||||
|
||||
# Create Image blobs
|
||||
|
||||
# w0
|
||||
blobLen = hdr_length + app_length
|
||||
w0 = (magicNum << 24) | ((encVal & 0x1) << 23) | blobLen
|
||||
|
||||
am_print("w0 =", hex(w0))
|
||||
fill_word(hdr_binarray, 0, w0)
|
||||
|
||||
# w2
|
||||
securityVal = ((authI << 1) | crcI) << 4 | (authB << 1) | crcB
|
||||
am_print("Security Value ", hex(securityVal))
|
||||
w2 = ((securityVal << 24) & 0xff000000) | ((authalgo) & 0xf) | ((authKeyIdx << 4) & 0xf0) | ((encalgo << 8) & 0xf00) | ((encKeyIdx << 12) & 0xf000)
|
||||
fill_word(hdr_binarray, 8, w2)
|
||||
am_print("w2 = ",hex(w2))
|
||||
|
||||
|
||||
if (magicNum == AM_IMAGE_MAGIC_INFO0):
|
||||
# Insert the INFO0 size and offset
|
||||
addrWord = ((orig_app_length>>2) << 16) | ((loadaddress>>2) & 0xFFFF)
|
||||
versionKeyWord = keys.INFO_KEY
|
||||
else:
|
||||
# Insert the application binary load address.
|
||||
addrWord = loadaddress | (protection & 0x3)
|
||||
# Initialize versionKeyWord
|
||||
versionKeyWord = (version & 0x7FFF) | ((erasePrev & 0x1) << 15)
|
||||
|
||||
am_print("addrWord = ",hex(addrWord))
|
||||
fill_word(hdr_binarray, AM_IMAGEHDR_OFFSET_ADDR, addrWord)
|
||||
|
||||
am_print("versionKeyWord = ",hex(versionKeyWord))
|
||||
fill_word(hdr_binarray, AM_IMAGEHDR_OFFSET_VERKEY, versionKeyWord)
|
||||
|
||||
# Initialize child (Child Ptr/ Feature key)
|
||||
am_print("child0/feature = ",hex(child0))
|
||||
fill_word(hdr_binarray, AM_IMAGEHDR_OFFSET_CHILDPTR, child0)
|
||||
am_print("child1 = ",hex(child1))
|
||||
fill_word(hdr_binarray, AM_IMAGEHDR_OFFSET_CHILDPTR + 4, child1)
|
||||
|
||||
authKeyIdx = authKeyIdx - keys.minHmacKeyIdx
|
||||
if (authB != 0): # Authentication needed
|
||||
am_print("Boot Authentication Enabled")
|
||||
# am_print("Key used for HMAC")
|
||||
# am_print([hex(keys.keyTblHmac[authKeyIdx*AM_SECBOOT_KEYIDX_BYTES + n]) for n in range (0, AM_HMAC_SIG_SIZE)])
|
||||
# Initialize the clear image HMAC
|
||||
sigClr = compute_hmac(keys.keyTblHmac[authKeyIdx*AM_SECBOOT_KEYIDX_BYTES:(authKeyIdx*AM_SECBOOT_KEYIDX_BYTES+AM_HMAC_SIG_SIZE)], (hdr_binarray[AM_IMAGEHDR_START_HMAC:hdr_length] + app_binarray))
|
||||
am_print("HMAC Clear")
|
||||
am_print([hex(n) for n in sigClr])
|
||||
# Fill up the HMAC
|
||||
for x in range(0, AM_HMAC_SIG_SIZE):
|
||||
hdr_binarray[AM_IMAGEHDR_OFFSET_SIGCLR + x] = sigClr[x]
|
||||
|
||||
# All the header fields part of the encryption are now final
|
||||
if (encVal == 1):
|
||||
am_print("Encryption Enabled")
|
||||
encKeyIdx = encKeyIdx - keys.minAesKeyIdx
|
||||
ivValAes = os.urandom(AM_SECBOOT_AESCBC_BLOCK_SIZE_BYTES)
|
||||
am_print("Initialization Vector")
|
||||
am_print([hex(ivValAes[n]) for n in range (0, AM_SECBOOT_AESCBC_BLOCK_SIZE_BYTES)])
|
||||
keyAes = os.urandom(keySize)
|
||||
am_print("AES Key used for encryption")
|
||||
am_print([hex(keyAes[n]) for n in range (0, keySize)])
|
||||
# Encrypted Part
|
||||
am_print("Encrypting blob of size " , (hdr_length - AM_IMAGEHDR_START_ENCRYPT + app_length))
|
||||
enc_binarray = encrypt_app_aes((hdr_binarray[AM_IMAGEHDR_START_ENCRYPT:hdr_length] + app_binarray), keyAes, ivValAes)
|
||||
# am_print("Key used for encrypting AES Key")
|
||||
# am_print([hex(keys.keyTblAes[encKeyIdx*keySize + n]) for n in range (0, keySize)])
|
||||
# Encrypted Key
|
||||
enc_key = encrypt_app_aes(keyAes, keys.keyTblAes[encKeyIdx*keySize:encKeyIdx*keySize + keySize], ivVal0)
|
||||
am_print("Encrypted Key")
|
||||
am_print([hex(enc_key[n]) for n in range (0, keySize)])
|
||||
# Fill up the IV
|
||||
for x in range(0, AM_SECBOOT_AESCBC_BLOCK_SIZE_BYTES):
|
||||
hdr_binarray[AM_IMAGEHDR_OFFSET_IV + x] = ivValAes[x]
|
||||
# Fill up the Encrypted Key
|
||||
for x in range(0, keySize):
|
||||
hdr_binarray[AM_IMAGEHDR_OFFSET_KEK + x] = enc_key[x]
|
||||
else:
|
||||
enc_binarray = hdr_binarray[AM_IMAGEHDR_START_ENCRYPT:hdr_length] + app_binarray
|
||||
|
||||
|
||||
if (authI != 0): # Install Authentication needed
|
||||
am_print("Install Authentication Enabled")
|
||||
# am_print("Key used for HMAC")
|
||||
# am_print([hex(keys.keyTblHmac[authKeyIdx*AM_SECBOOT_KEYIDX_BYTES + n]) for n in range (0, AM_HMAC_SIG_SIZE)])
|
||||
# Initialize the top level HMAC
|
||||
sig = compute_hmac(keys.keyTblHmac[authKeyIdx*AM_SECBOOT_KEYIDX_BYTES:(authKeyIdx*AM_SECBOOT_KEYIDX_BYTES+AM_HMAC_SIG_SIZE)], (hdr_binarray[AM_IMAGEHDR_START_HMAC_INST:AM_IMAGEHDR_START_ENCRYPT] + enc_binarray))
|
||||
am_print("Generated Signature")
|
||||
am_print([hex(n) for n in sig])
|
||||
# Fill up the HMAC
|
||||
for x in range(0, AM_HMAC_SIG_SIZE):
|
||||
hdr_binarray[AM_IMAGEHDR_OFFSET_SIG + x] = sig[x]
|
||||
# compute the CRC for the blob - this is done on a clear image
|
||||
crc = crc32(hdr_binarray[AM_IMAGEHDR_START_CRC:hdr_length] + app_binarray)
|
||||
am_print("crc = ",hex(crc));
|
||||
w1 = crc
|
||||
fill_word(hdr_binarray, AM_IMAGEHDR_OFFSET_CRC, w1)
|
||||
|
||||
# now output all three binary arrays in the proper order
|
||||
output = output + '.bin'
|
||||
am_print("Writing to file ", output)
|
||||
with open(output, mode = 'wb') as out:
|
||||
out.write(hdr_binarray[0:AM_IMAGEHDR_START_ENCRYPT])
|
||||
out.write(enc_binarray)
|
||||
|
||||
|
||||
|
||||
def parse_arguments():
|
||||
parser = argparse.ArgumentParser(description =
|
||||
'Generate Corvette Image Blob')
|
||||
|
||||
parser.add_argument('--bin', dest='appFile', type=argparse.FileType('rb'),
|
||||
help='binary file (blah.bin)')
|
||||
|
||||
parser.add_argument('--load-address', dest='loadaddress', type=auto_int, default=hex(AM_SECBOOT_DEFAULT_NONSECURE_MAIN),
|
||||
help='Load address of the binary.')
|
||||
|
||||
parser.add_argument('--magic-num', dest='magic_num', default=hex(AM_IMAGE_MAGIC_NONSECURE),
|
||||
type=lambda x: x.lower(),
|
||||
# type = str.lower,
|
||||
choices = [
|
||||
hex(AM_IMAGE_MAGIC_MAIN),
|
||||
hex(AM_IMAGE_MAGIC_CHILD),
|
||||
hex(AM_IMAGE_MAGIC_CUSTPATCH),
|
||||
hex(AM_IMAGE_MAGIC_NONSECURE),
|
||||
hex(AM_IMAGE_MAGIC_INFO0)
|
||||
],
|
||||
help = 'Magic Num ('
|
||||
+ str(hex(AM_IMAGE_MAGIC_MAIN)) + ': Main, '
|
||||
+ str(hex(AM_IMAGE_MAGIC_CHILD)) + ': Child, '
|
||||
+ str(hex(AM_IMAGE_MAGIC_CUSTPATCH)) + ': CustOTA, '
|
||||
+ str(hex(AM_IMAGE_MAGIC_NONSECURE)) + ': NonSecure, '
|
||||
+ str(hex(AM_IMAGE_MAGIC_INFO0)) + ': Info0) '
|
||||
'- default[Main]'
|
||||
)
|
||||
|
||||
parser.add_argument('-o', dest = 'output', default='outimage',
|
||||
help = 'Output filename (without the extension)')
|
||||
|
||||
parser.add_argument('--authkey', dest = 'authkey', type=auto_int, default=(AM_SECBOOT_MIN_KEYIDX_INFO0), choices = range(AM_SECBOOT_MIN_KEYIDX_INFO0, AM_SECBOOT_MAX_KEYIDX_INFO0 + 1),
|
||||
help = 'Authentication Key Idx? (' + str(AM_SECBOOT_MIN_KEYIDX_INFO0) + ' to ' + str(AM_SECBOOT_MAX_KEYIDX_INFO0) + ')')
|
||||
|
||||
parser.add_argument('--kek', dest = 'kek', type=auto_int, default=(AM_SECBOOT_MIN_KEYIDX_INFO0), choices = range(AM_SECBOOT_MIN_KEYIDX_INFO0, AM_SECBOOT_MAX_KEYIDX_INFO0 + 1),
|
||||
help = 'KEK Index? (' + str(AM_SECBOOT_MIN_KEYIDX_INFO0) + ' to ' + str(AM_SECBOOT_MAX_KEYIDX_INFO0) + ')')
|
||||
|
||||
parser.add_argument('--authalgo', dest = 'authalgo', type=auto_int, default=0, choices=range(0, AM_SECBOOT_AUTH_ALGO_MAX+1),
|
||||
help = helpAuthAlgo)
|
||||
|
||||
parser.add_argument('--encalgo', dest = 'encalgo', type=auto_int, default=0, choices = range(0, AM_SECBOOT_ENC_ALGO_MAX+1),
|
||||
help = helpEncAlgo)
|
||||
|
||||
parser.add_argument('--child0', dest = 'child0', type=auto_int, default=hex(0xFFFFFFFF),
|
||||
help = 'child (blobPtr#0 for Main / feature key for AM3P)')
|
||||
|
||||
parser.add_argument('--child1', dest = 'child1', type=auto_int, default=hex(0xFFFFFFFF),
|
||||
help = 'child (blobPtr#1 for Main)')
|
||||
|
||||
parser.add_argument('--version', dest = 'version', type=auto_int, default=0,
|
||||
help = 'version (15 bit)')
|
||||
|
||||
parser.add_argument('--crcI', dest = 'crcI', type=auto_int, default=1, choices=[0,1],
|
||||
help = 'Install CRC check enabled (Default = Y)?')
|
||||
|
||||
parser.add_argument('--crcB', dest = 'crcB', type=auto_int, default=0, choices=[0,1],
|
||||
help = 'Boot CRC check enabled (Default = N)?')
|
||||
|
||||
parser.add_argument('--authI', dest = 'authI', type=auto_int, default=0, choices=[0,1],
|
||||
help = 'Install Authentication check enabled (Default = N)?')
|
||||
|
||||
parser.add_argument('--authB', dest = 'authB', type=auto_int, default=0, choices=[0,1],
|
||||
help = 'Boot Authentication check enabled (Default = N)?')
|
||||
|
||||
parser.add_argument('--erasePrev', dest = 'erasePrev', type=auto_int, default=0, choices=[0,1],
|
||||
help = 'erasePrev (Valid only for main)')
|
||||
|
||||
parser.add_argument('-p', dest = 'protection', type=auto_int, default=0, choices = [0x0, 0x1, 0x2, 0x3],
|
||||
help = 'protection info 2 bit C W')
|
||||
|
||||
parser.add_argument('-k', type=str, dest='keyFile', nargs='?', default='keys_info.py',
|
||||
help='key file in specified format [default = keys_info.py]')
|
||||
|
||||
parser.add_argument('--loglevel', dest='loglevel', type=auto_int, default=AM_PRINT_LEVEL_INFO,
|
||||
choices = range(AM_PRINT_LEVEL_MIN, AM_PRINT_LEVEL_MAX+1),
|
||||
help=helpPrintLevel)
|
||||
|
||||
|
||||
args = parser.parse_args()
|
||||
args.magic_num = int(args.magic_num, 16)
|
||||
|
||||
|
||||
return args
|
||||
|
||||
#******************************************************************************
|
||||
#
|
||||
# Main function.
|
||||
#
|
||||
#******************************************************************************
|
||||
def main():
|
||||
# Read the arguments.
|
||||
args = parse_arguments()
|
||||
am_set_print_level(args.loglevel)
|
||||
|
||||
|
||||
process(args.loadaddress, args.appFile, args.magic_num, args.crcI, args.crcB, args.authI, args.authB, args.protection, args.authkey, args.output, args.kek, args.version, args.erasePrev, args.child0, args.child1, args.authalgo, args.encalgo, args.keyFile)
|
||||
|
||||
if __name__ == '__main__':
|
||||
main()
|
||||
+241
@@ -0,0 +1,241 @@
|
||||
#!/usr/bin/env python3
|
||||
# Utility to generate image blobs for Corvette Bootloader assisted Wired updates
|
||||
|
||||
import argparse
|
||||
import sys
|
||||
from Crypto.Cipher import AES
|
||||
import array
|
||||
import hashlib
|
||||
import hmac
|
||||
import os
|
||||
import binascii
|
||||
import importlib
|
||||
|
||||
from am_defines import *
|
||||
#from keys_info import keyTblAes, keyTblHmac, minAesKeyIdx, maxAesKeyIdx, minHmacKeyIdx, maxHmacKeyIdx , INFO_KEY, FLASH_KEY
|
||||
|
||||
#******************************************************************************
|
||||
#
|
||||
# Generate the image blob as per command line parameters
|
||||
#
|
||||
#******************************************************************************
|
||||
def process(appFile, imagetype, loadaddress, authalgo, encalgo, authKeyIdx, encKeyIdx, optionsVal, maxSize, output, keyFile):
|
||||
|
||||
app_binarray = bytearray()
|
||||
# Open the file, and read it into an array of integers.
|
||||
with appFile as f_app:
|
||||
app_binarray.extend(f_app.read())
|
||||
f_app.close()
|
||||
|
||||
# Make sure it is page multiple
|
||||
if ((maxSize & (FLASH_PAGE_SIZE - 1)) != 0):
|
||||
am_print ("split needs to be multiple of flash page size", level=AM_PRINT_LEVEL_ERROR)
|
||||
return
|
||||
|
||||
filenames = keyFile.split('.')
|
||||
keys = importlib.import_module(filenames[0])
|
||||
|
||||
if (encalgo != 0):
|
||||
if ((encKeyIdx < keys.minAesKeyIdx) or (encKeyIdx > keys.maxAesKeyIdx)):
|
||||
am_print("Invalid encKey Idx ", encKeyIdx, level=AM_PRINT_LEVEL_ERROR)
|
||||
return
|
||||
if (encalgo == 2):
|
||||
if (encKeyIdx & 0x1):
|
||||
am_print("Invalid encKey Idx ", encKeyIdx, level=AM_PRINT_LEVEL_ERROR);
|
||||
return
|
||||
keySize = 32
|
||||
else:
|
||||
keySize = 16
|
||||
if (authalgo != 0):
|
||||
if ((authKeyIdx < keys.minHmacKeyIdx) or (authKeyIdx > keys.maxHmacKeyIdx) or (authKeyIdx & 0x1)):
|
||||
am_print("Invalid authKey Idx ", authKeyIdx, level=AM_PRINT_LEVEL_ERROR);
|
||||
return
|
||||
|
||||
hdr_length = AM_WU_IMAGEHDR_SIZE; #fixed header length
|
||||
am_print("Header Size = ", hex(hdr_length))
|
||||
|
||||
orig_app_length = (len(app_binarray))
|
||||
|
||||
if (encalgo != 0):
|
||||
block_size = keySize
|
||||
app_binarray = pad_to_block_size(app_binarray, block_size, 1)
|
||||
else:
|
||||
# Add Padding
|
||||
app_binarray = pad_to_block_size(app_binarray, 4, 0)
|
||||
|
||||
app_length = (len(app_binarray))
|
||||
am_print("app_size ",hex(app_length), "(",app_length,")")
|
||||
|
||||
if (app_length + hdr_length > maxSize):
|
||||
am_print("Image size bigger than max - Creating Split image")
|
||||
|
||||
start = 0
|
||||
# now output all three binary arrays in the proper order
|
||||
output = output + '.bin'
|
||||
out = open(output, mode = 'wb')
|
||||
|
||||
while (start < app_length):
|
||||
#generate mutable byte array for the header
|
||||
hdr_binarray = bytearray([0x00]*hdr_length);
|
||||
|
||||
if (app_length - start > maxSize):
|
||||
end = start + maxSize
|
||||
else:
|
||||
end = app_length
|
||||
|
||||
if (imagetype == AM_SECBOOT_WIRED_IMAGETYPE_INFO0_NOOTA):
|
||||
key = keys.INFO_KEY
|
||||
# word offset
|
||||
fill_word(hdr_binarray, AM_WU_IMAGEHDR_OFFSET_ADDR, loadaddress>>2)
|
||||
else:
|
||||
key = keys.FLASH_KEY
|
||||
# load address
|
||||
fill_word(hdr_binarray, AM_WU_IMAGEHDR_OFFSET_ADDR, loadaddress)
|
||||
if (loadaddress & (FLASH_PAGE_SIZE - 1)):
|
||||
am_print("WARNING!!! - load address is not page aligned", level=AM_PRINT_LEVEL_ERROR)
|
||||
|
||||
# Create imageType & options
|
||||
hdr_binarray[AM_WU_IMAGEHDR_OFFSET_IMAGETYPE] = imagetype
|
||||
# Set the options only for the first block
|
||||
if (start == 0):
|
||||
hdr_binarray[AM_WU_IMAGEHDR_OFFSET_OPTIONS] = optionsVal
|
||||
else:
|
||||
hdr_binarray[AM_WU_IMAGEHDR_OFFSET_OPTIONS] = 0
|
||||
|
||||
# Create Info0 Update Blob for wired update
|
||||
fill_word(hdr_binarray, AM_WU_IMAGEHDR_OFFSET_KEY, key)
|
||||
# update size
|
||||
fill_word(hdr_binarray, AM_WU_IMAGEHDR_OFFSET_SIZE, end-start)
|
||||
|
||||
w0 = ((authalgo & 0xf) | ((authKeyIdx << 8) & 0xf00) | ((encalgo << 16) & 0xf0000) | ((encKeyIdx << 24) & 0x0f000000))
|
||||
|
||||
fill_word(hdr_binarray, 0, w0)
|
||||
|
||||
if (encalgo != 0):
|
||||
keyIdx = encKeyIdx - keys.minAesKeyIdx
|
||||
ivValAes = os.urandom(AM_SECBOOT_AESCBC_BLOCK_SIZE_BYTES)
|
||||
am_print("Initialization Vector")
|
||||
am_print([hex(n) for n in ivValAes])
|
||||
keyAes = os.urandom(keySize)
|
||||
am_print("AES Key used for encryption")
|
||||
am_print([hex(keyAes[n]) for n in range (0, keySize)])
|
||||
# Encrypted Part - after security header
|
||||
enc_binarray = encrypt_app_aes((hdr_binarray[AM_WU_IMAGEHDR_START_ENCRYPT:hdr_length] + app_binarray[start:end]), keyAes, ivValAes)
|
||||
# am_print("Key used for encrypting AES Key")
|
||||
# am_print([hex(keys.keyTblAes[keyIdx*AM_SECBOOT_KEYIDX_BYTES + n]) for n in range (0, keySize)])
|
||||
# Encrypted Key
|
||||
enc_key = encrypt_app_aes(keyAes, keys.keyTblAes[keyIdx*AM_SECBOOT_KEYIDX_BYTES:(keyIdx*AM_SECBOOT_KEYIDX_BYTES + keySize)], ivVal0)
|
||||
am_print("Encrypted Key")
|
||||
am_print([hex(enc_key[n]) for n in range (0, keySize)])
|
||||
# Fill up the IV
|
||||
for x in range(0, AM_SECBOOT_AESCBC_BLOCK_SIZE_BYTES):
|
||||
hdr_binarray[AM_WU_IMAGEHDR_OFFSET_IV + x] = ivValAes[x]
|
||||
# Fill up the Encrypted Key
|
||||
for x in range(0, keySize):
|
||||
hdr_binarray[AM_WU_IMAGEHDR_OFFSET_KEK + x] = enc_key[x]
|
||||
else:
|
||||
enc_binarray = hdr_binarray[AM_WU_IMAGEHDR_START_ENCRYPT:hdr_length] + app_binarray[start:end]
|
||||
|
||||
|
||||
if (authalgo != 0): # Authentication needed
|
||||
keyIdx = authKeyIdx - keys.minHmacKeyIdx
|
||||
# am_print("Key used for HMAC")
|
||||
# am_print([hex(keys.keyTblHmac[keyIdx*AM_SECBOOT_KEYIDX_BYTES + n]) for n in range (0, AM_HMAC_SIG_SIZE)])
|
||||
# Initialize the HMAC - Sign is computed on image following the signature
|
||||
sig = compute_hmac(keys.keyTblHmac[keyIdx*AM_SECBOOT_KEYIDX_BYTES:(keyIdx*AM_SECBOOT_KEYIDX_BYTES+AM_HMAC_SIG_SIZE)], hdr_binarray[AM_WU_IMAGEHDR_START_HMAC:AM_WU_IMAGEHDR_START_ENCRYPT] + enc_binarray)
|
||||
am_print("HMAC")
|
||||
am_print([hex(n) for n in sig])
|
||||
# Fill up the HMAC
|
||||
for x in range(0, AM_HMAC_SIG_SIZE):
|
||||
hdr_binarray[AM_WU_IMAGEHDR_OFFSET_SIG + x] = sig[x]
|
||||
|
||||
am_print("Writing to file ", output)
|
||||
am_print("Image from ", str(hex(start)), " to ", str(hex(end)), " will be loaded at", str(hex(loadaddress)))
|
||||
out.write(hdr_binarray[0:AM_WU_IMAGEHDR_START_ENCRYPT])
|
||||
out.write(enc_binarray)
|
||||
|
||||
# Reset start for next chunk
|
||||
start = end
|
||||
loadaddress = loadaddress + maxSize
|
||||
|
||||
def parse_arguments():
|
||||
parser = argparse.ArgumentParser(description =
|
||||
'Generate Corvette Wired Update Blob')
|
||||
|
||||
parser.add_argument('--load-address', dest='loadaddress', type=auto_int, default=hex(0x60000),
|
||||
help='Load address of the binary - Where in flash the blob will be stored (could be different than install address of binary within).')
|
||||
|
||||
parser.add_argument('--bin', dest='appFile', type=argparse.FileType('rb'),
|
||||
help='binary file (blah.bin)')
|
||||
|
||||
parser.add_argument('-i', dest = 'imagetype', default=AM_SECBOOT_WIRED_IMAGETYPE_MAIN, type=int,
|
||||
choices = [
|
||||
(AM_SECBOOT_WIRED_IMAGETYPE_SBL),
|
||||
(AM_SECBOOT_WIRED_IMAGETYPE_AM3P),
|
||||
(AM_SECBOOT_WIRED_IMAGETYPE_PATCH),
|
||||
(AM_SECBOOT_WIRED_IMAGETYPE_MAIN),
|
||||
(AM_SECBOOT_WIRED_IMAGETYPE_CHILD),
|
||||
(AM_SECBOOT_WIRED_IMAGETYPE_CUSTPATCH),
|
||||
(AM_SECBOOT_WIRED_IMAGETYPE_NONSECURE),
|
||||
(AM_SECBOOT_WIRED_IMAGETYPE_INFO0),
|
||||
(AM_SECBOOT_WIRED_IMAGETYPE_INFO0_NOOTA)
|
||||
],
|
||||
help = 'ImageType ('
|
||||
+ str(AM_SECBOOT_WIRED_IMAGETYPE_SBL) + ': SBL, '
|
||||
+ str(AM_SECBOOT_WIRED_IMAGETYPE_AM3P) + ': AM3P, '
|
||||
+ str(AM_SECBOOT_WIRED_IMAGETYPE_PATCH) + ': Patch, '
|
||||
+ str(AM_SECBOOT_WIRED_IMAGETYPE_MAIN) + ': Main, '
|
||||
+ str(AM_SECBOOT_WIRED_IMAGETYPE_CHILD) + ': Child, '
|
||||
+ str(AM_SECBOOT_WIRED_IMAGETYPE_CUSTPATCH) + ': CustOTA, '
|
||||
+ str(AM_SECBOOT_WIRED_IMAGETYPE_NONSECURE) + ': NonSecure, '
|
||||
+ str(AM_SECBOOT_WIRED_IMAGETYPE_INFO0) + ': Info0, '
|
||||
+ str(AM_SECBOOT_WIRED_IMAGETYPE_INFO0_NOOTA) + ': Info0-NoOTA) '
|
||||
'- default[Main]')
|
||||
|
||||
parser.add_argument('--options', dest = 'options', type=auto_int, default=0x1,
|
||||
help = 'Options (16b hex value) - bit0 instructs to perform OTA of the image after wired download (set to 0 if only downloading & skipping OTA flow)')
|
||||
|
||||
parser.add_argument('-o', dest = 'output', default='wuimage',
|
||||
help = 'Output filename (without the extension)')
|
||||
|
||||
parser.add_argument('--authkey', dest = 'authkey', type=auto_int, default=(AM_SECBOOT_MIN_KEYIDX_INFO0), choices = range(AM_SECBOOT_MIN_KEYIDX_INFO0, AM_SECBOOT_MAX_KEYIDX_INFO0 + 1),
|
||||
help = 'Authentication Key Idx? (' + str(AM_SECBOOT_MIN_KEYIDX_INFO0) + ' to ' + str(AM_SECBOOT_MAX_KEYIDX_INFO0) + ')')
|
||||
|
||||
parser.add_argument('--kek', dest = 'kek', type=auto_int, default=(AM_SECBOOT_MIN_KEYIDX_INFO0), choices = range(AM_SECBOOT_MIN_KEYIDX_INFO0, AM_SECBOOT_MAX_KEYIDX_INFO0 + 1),
|
||||
help = 'KEK Index? (' + str(AM_SECBOOT_MIN_KEYIDX_INFO0) + ' to ' + str(AM_SECBOOT_MAX_KEYIDX_INFO0) + ')')
|
||||
|
||||
parser.add_argument('--authalgo', dest = 'authalgo', type=auto_int, default=0, choices=range(0, AM_SECBOOT_AUTH_ALGO_MAX+1),
|
||||
help = helpAuthAlgo)
|
||||
|
||||
parser.add_argument('--encalgo', dest = 'encalgo', type=auto_int, default=0, choices = range(0, AM_SECBOOT_ENC_ALGO_MAX+1),
|
||||
help = helpEncAlgo)
|
||||
|
||||
parser.add_argument('--split', dest='split', type=auto_int, default=hex(MAX_DOWNLOAD_SIZE),
|
||||
help='Specify the max block size if the image will be downloaded in pieces')
|
||||
|
||||
parser.add_argument('-k', type=str, dest='keyFile', nargs='?', default='keys_info.py',
|
||||
help='key file in specified format [default = keys_info.py]')
|
||||
|
||||
parser.add_argument('--loglevel', dest='loglevel', type=auto_int, default=AM_PRINT_LEVEL_INFO,
|
||||
choices = range(AM_PRINT_LEVEL_MIN, AM_PRINT_LEVEL_MAX+1),
|
||||
help=helpPrintLevel)
|
||||
|
||||
|
||||
args = parser.parse_args()
|
||||
|
||||
return args
|
||||
|
||||
#******************************************************************************
|
||||
#
|
||||
# Main function.
|
||||
#
|
||||
#******************************************************************************
|
||||
def main():
|
||||
# Read the arguments.
|
||||
args = parse_arguments()
|
||||
|
||||
am_set_print_level(args.loglevel)
|
||||
process(args.appFile, args.imagetype, args.loadaddress, args.authalgo, args.encalgo, args.authkey, args.kek, args.options, args.split, args.output, args.keyFile)
|
||||
|
||||
if __name__ == '__main__':
|
||||
main()
|
||||
@@ -0,0 +1,409 @@
|
||||
#!/usr/bin/env python3
|
||||
# Utility to create info0 for Apollo3
|
||||
|
||||
import argparse
|
||||
import sys
|
||||
from Crypto.Cipher import AES
|
||||
import array
|
||||
import hashlib
|
||||
import hmac
|
||||
import os
|
||||
import binascii
|
||||
import importlib
|
||||
|
||||
from am_defines import *
|
||||
#from keys_info import keyTblAes, keyTblHmac, custKey
|
||||
|
||||
def copy_keys(binarray, offset, key, size):
|
||||
for i in range (0, size):
|
||||
binarray[offset + i] = key[i]
|
||||
|
||||
#******************************************************************************
|
||||
#
|
||||
# Generate the info0 blob as per command line parameters
|
||||
#
|
||||
#******************************************************************************
|
||||
def process(valid, version, output, mainPtr, secPol, keyWrap, secBoot, secBootOnRst, plOnExit, sDbg, bEnErase, infoProg, bNoSramWipe, bSwoCtrl, bDbgAllowed, custTrim, custTrim2, overrideGpio, overridePol, wiredIfMask, wiredSlvInt, wiredI2cAddr, wiredTimeout, u0, u1, u2, u3, u4, u5, krev, arev, chipId0, chipId1, sresv, wprot0, wprot1, rprot0, rprot1, swprot0, swprot1, srprot0, srprot1, wprot2, wprot3, rprot2, rprot3, swprot2, swprot3, srprot2, srprot3, chip, keyFile):
|
||||
|
||||
|
||||
if (chip == 'apollo3'):
|
||||
import apollo3_info0 as info0
|
||||
am_print("Apollo3 INFO0")
|
||||
elif (chip == 'apollo3p'):
|
||||
import apollo3p_info0 as info0
|
||||
am_print("Apollo3P INFO0")
|
||||
|
||||
filenames = keyFile.split('.')
|
||||
keys = importlib.import_module(filenames[0])
|
||||
|
||||
#generate mutable byte array for the header
|
||||
hdr_binarray = bytearray([0xFF]*INFO_SIZE_BYTES);
|
||||
|
||||
# initialize signature
|
||||
if (valid == 1):
|
||||
fill_word(hdr_binarray, info0.INFO0_SIGNATURE0_O, AM_SECBOOT_INFO0_SIGN_PROGRAMMED0)
|
||||
fill_word(hdr_binarray, info0.INFO0_SIGNATURE1_O, AM_SECBOOT_INFO0_SIGN_PROGRAMMED1)
|
||||
fill_word(hdr_binarray, info0.INFO0_SIGNATURE2_O, AM_SECBOOT_INFO0_SIGN_PROGRAMMED2)
|
||||
fill_word(hdr_binarray, info0.INFO0_SIGNATURE3_O, AM_SECBOOT_INFO0_SIGN_PROGRAMMED3)
|
||||
elif (valid == 0):
|
||||
fill_word(hdr_binarray, info0.INFO0_SIGNATURE0_O, AM_SECBOOT_INFO0_SIGN_UINIT0)
|
||||
fill_word(hdr_binarray, info0.INFO0_SIGNATURE1_O, AM_SECBOOT_INFO0_SIGN_UINIT1)
|
||||
fill_word(hdr_binarray, info0.INFO0_SIGNATURE2_O, AM_SECBOOT_INFO0_SIGN_UINIT2)
|
||||
fill_word(hdr_binarray, info0.INFO0_SIGNATURE3_O, AM_SECBOOT_INFO0_SIGN_UINIT3)
|
||||
else:
|
||||
fill_word(hdr_binarray, info0.INFO0_SIGNATURE0_O, FLASH_INVALID)
|
||||
fill_word(hdr_binarray, info0.INFO0_SIGNATURE1_O, FLASH_INVALID)
|
||||
fill_word(hdr_binarray, info0.INFO0_SIGNATURE2_O, FLASH_INVALID)
|
||||
fill_word(hdr_binarray, info0.INFO0_SIGNATURE3_O, FLASH_INVALID)
|
||||
|
||||
am_print("info0 Signature...")
|
||||
am_print([hex(hdr_binarray[n]) for n in range(0, 16)])
|
||||
|
||||
# Flash wipe is no longer supported
|
||||
bNoFlashWipe = 1
|
||||
if (valid == 1):
|
||||
# Build Security word
|
||||
blAtReset = 1
|
||||
if (secBoot == 0):
|
||||
secBoot = 0x5
|
||||
else:
|
||||
secBoot = 0x2
|
||||
if (secBootOnRst == 0):
|
||||
secBootOnRst = 0x5
|
||||
else:
|
||||
secBootOnRst = 0x2
|
||||
|
||||
security = (((secPol & 0x7) << 24) | ((keyWrap & 0xf) << 20) | (secBootOnRst << 16) | (secBoot << 12) | ((plOnExit & 0x1) << 11) | ((sDbg & 0x1) << 10) | ((blAtReset & 0x1) << 9) | ((bEnErase & 0x1) << 8) | ((infoProg & 0xf) << 4) | ((bNoFlashWipe & 0x1) << 3) | ((bNoSramWipe & 0x1) << 2) | ((bSwoCtrl & 0x1) << 1) | ((bDbgAllowed & 0x1)))
|
||||
|
||||
am_print("Security Word = ", hex(security))
|
||||
fill_word(hdr_binarray, info0.INFO0_SECURITY_O, security)
|
||||
|
||||
# Customer trim
|
||||
am_print("Customer Trim = ", hex(custTrim))
|
||||
fill_word(hdr_binarray, info0.INFO0_CUSTOMER_TRIM_O, custTrim)
|
||||
|
||||
am_print("Customer Trim2 = ", hex(custTrim2))
|
||||
fill_word(hdr_binarray, info0.INFO0_CUSTOMER_TRIM2_O, custTrim2)
|
||||
|
||||
# Override
|
||||
override = ((overridePol & 0x1) << 7) | (overrideGpio & 0x7f)
|
||||
am_print("Override = ", hex(override))
|
||||
fill_word(hdr_binarray, info0.INFO0_SECURITY_OVR_O, override)
|
||||
|
||||
# Wired interface config
|
||||
wired = ((wiredIfMask & 0x7) | ((wiredSlvInt & 0x3f) << 3) | ((wiredI2cAddr & 0x7f) << 9) | ((wiredTimeout & 0xffff) << 16))
|
||||
am_print("WiredCfg = ", hex(wired))
|
||||
fill_word(hdr_binarray, info0.INFO0_SECURITY_WIRED_CFG_O, wired)
|
||||
|
||||
# Wired UART cfg
|
||||
if (wiredIfMask & 0x1): # UART
|
||||
am_print("UART Config ", hex(u0), hex(u1), hex(u2), hex(u3), hex(u4), hex(u5))
|
||||
fill_word(hdr_binarray, info0.INFO0_SECURITY_WIRED_IFC_CFG0_O, u0)
|
||||
fill_word(hdr_binarray, info0.INFO0_SECURITY_WIRED_IFC_CFG1_O, u1)
|
||||
fill_word(hdr_binarray, info0.INFO0_SECURITY_WIRED_IFC_CFG2_O, u2)
|
||||
fill_word(hdr_binarray, info0.INFO0_SECURITY_WIRED_IFC_CFG3_O, u3)
|
||||
fill_word(hdr_binarray, info0.INFO0_SECURITY_WIRED_IFC_CFG4_O, u4)
|
||||
fill_word(hdr_binarray, info0.INFO0_SECURITY_WIRED_IFC_CFG5_O, u5)
|
||||
|
||||
# version
|
||||
am_print("Version = ", hex(version))
|
||||
fill_word(hdr_binarray, info0.INFO0_SECURITY_VERSION_O, version)
|
||||
|
||||
# main ptr
|
||||
am_print("Main Ptr = ", hex(mainPtr))
|
||||
fill_word(hdr_binarray, info0.INFO0_MAIN_PTR1_O, mainPtr)
|
||||
|
||||
# SRAM Reservation
|
||||
am_print("SRAM Reservation = ", hex(sresv))
|
||||
fill_word(hdr_binarray, info0.INFO0_SECURITY_SRAM_RESV_O, sresv)
|
||||
|
||||
# Flash Protections
|
||||
if (chip == 'apollo3'):
|
||||
fill_word(hdr_binarray, info0.INFO0_WRITE_PROTECT_L_O, wprot0)
|
||||
fill_word(hdr_binarray, info0.INFO0_WRITE_PROTECT_H_O, wprot1)
|
||||
fill_word(hdr_binarray, info0.INFO0_COPY_PROTECT_L_O, rprot0)
|
||||
fill_word(hdr_binarray, info0.INFO0_COPY_PROTECT_H_O, rprot1)
|
||||
am_print("Permanent Write Protections = ", hex(wprot0), ":", hex(wprot1))
|
||||
am_print("Permanent Copy Protections = ", hex(rprot0), ":", hex(rprot1))
|
||||
elif (chip == 'apollo3p'):
|
||||
fill_word(hdr_binarray, info0.INFO0_WRITE_PROTECT0_O, wprot0)
|
||||
fill_word(hdr_binarray, info0.INFO0_WRITE_PROTECT1_O, wprot1)
|
||||
fill_word(hdr_binarray, info0.INFO0_COPY_PROTECT0_O, rprot0)
|
||||
fill_word(hdr_binarray, info0.INFO0_COPY_PROTECT1_O, rprot1)
|
||||
fill_word(hdr_binarray, info0.INFO0_WRITE_PROTECT2_O, wprot2)
|
||||
fill_word(hdr_binarray, info0.INFO0_WRITE_PROTECT3_O, wprot3)
|
||||
fill_word(hdr_binarray, info0.INFO0_COPY_PROTECT2_O, rprot2)
|
||||
fill_word(hdr_binarray, info0.INFO0_COPY_PROTECT3_O, rprot3)
|
||||
am_print("Permanent Write Protections = ", hex(wprot0), ":", hex(wprot1), ":", hex(wprot2), ":", hex(wprot3))
|
||||
am_print("Permanent Copy Protections = ", hex(rprot0), ":", hex(rprot1), ":", hex(rprot2), ":", hex(rprot3))
|
||||
|
||||
if (chip == 'apollo3'):
|
||||
fill_word(hdr_binarray, info0.INFO0_WRITE_PROTECT_SBL_L_O, swprot0)
|
||||
fill_word(hdr_binarray, info0.INFO0_WRITE_PROTECT_SBL_H_O, swprot1)
|
||||
fill_word(hdr_binarray, info0.INFO0_COPY_PROTECT_SBL_L_O, srprot0)
|
||||
fill_word(hdr_binarray, info0.INFO0_COPY_PROTECT_SBL_H_O, srprot1)
|
||||
am_print("SBL Overridable Write Protections = ", hex(swprot0), ":", hex(swprot1))
|
||||
am_print("SBL Overridable Copy Protections = ", hex(srprot0), ":", hex(srprot1))
|
||||
elif (chip == 'apollo3p'):
|
||||
fill_word(hdr_binarray, info0.INFO0_WRITE_PROTECT0_SBL_O, swprot0)
|
||||
fill_word(hdr_binarray, info0.INFO0_WRITE_PROTECT1_SBL_O, swprot1)
|
||||
fill_word(hdr_binarray, info0.INFO0_COPY_PROTECT0_SBL_O, srprot0)
|
||||
fill_word(hdr_binarray, info0.INFO0_COPY_PROTECT1_SBL_O, srprot1)
|
||||
fill_word(hdr_binarray, info0.INFO0_WRITE_PROTECT2_SBL_O, swprot2)
|
||||
fill_word(hdr_binarray, info0.INFO0_WRITE_PROTECT3_SBL_O, swprot3)
|
||||
fill_word(hdr_binarray, info0.INFO0_COPY_PROTECT2_SBL_O, srprot2)
|
||||
fill_word(hdr_binarray, info0.INFO0_COPY_PROTECT3_SBL_O, srprot3)
|
||||
am_print("SBL Overridable Write Protections = ", hex(swprot0), ":", hex(swprot1), ":", hex(swprot2), ":", hex(swprot3))
|
||||
am_print("SBL Overridable Copy Protections = ", hex(srprot0), ":", hex(srprot1), ":", hex(srprot2), ":", hex(srprot3))
|
||||
|
||||
# Customer Key
|
||||
am_print("Customer Key")
|
||||
am_print([hex(n) for n in keys.custKey])
|
||||
copy_keys(hdr_binarray, info0.INFO0_CUSTOMER_KEY0_O, keys.custKey, 16)
|
||||
|
||||
# Keys
|
||||
chipId = int_to_bytes(chipId0) + int_to_bytes(chipId1)
|
||||
while (len(chipId) != AM_SECBOOT_KEYIDX_BYTES):
|
||||
chipId = chipId + chipId
|
||||
am_print("chipID 16")
|
||||
am_print([hex(n) for n in chipId])
|
||||
|
||||
kekOffset = info0.INFO0_CUST_KEK_W0_O
|
||||
authKeyOffset = info0.INFO0_CUST_AUTH_W0_O
|
||||
|
||||
if (keyWrap == 0): ## None
|
||||
am_print("wrap mode 0")
|
||||
am_print("KEK")
|
||||
for i in range (0, INFO_MAX_ENC_KEYS):
|
||||
am_print([hex(n) for n in keys.keyTblAes[i*AM_SECBOOT_KEYIDX_BYTES:(i*AM_SECBOOT_KEYIDX_BYTES + AM_SECBOOT_KEYIDX_BYTES)]])
|
||||
copy_keys(hdr_binarray, kekOffset + i*AM_SECBOOT_KEYIDX_BYTES, keys.keyTblAes[i*AM_SECBOOT_KEYIDX_BYTES:(i*AM_SECBOOT_KEYIDX_BYTES + AM_SECBOOT_KEYIDX_BYTES)], AM_SECBOOT_KEYIDX_BYTES)
|
||||
am_print("AuthKey")
|
||||
for i in range (0, INFO_MAX_AUTH_KEYS):
|
||||
am_print([hex(n) for n in keys.keyTblHmac[i*AM_SECBOOT_KEYIDX_BYTES:(i*AM_SECBOOT_KEYIDX_BYTES + AM_SECBOOT_KEYIDX_BYTES)]])
|
||||
copy_keys(hdr_binarray, authKeyOffset + i*AM_SECBOOT_KEYIDX_BYTES, keys.keyTblHmac[i*AM_SECBOOT_KEYIDX_BYTES:(i*AM_SECBOOT_KEYIDX_BYTES + AM_SECBOOT_KEYIDX_BYTES)], AM_SECBOOT_KEYIDX_BYTES)
|
||||
elif (keyWrap == 1): ## XOR
|
||||
am_print("wrap mode 1")
|
||||
am_print("KEK")
|
||||
for i in range (0, INFO_MAX_ENC_KEYS):
|
||||
scrambledKey = keys.keyTblAes[i*AM_SECBOOT_KEYIDX_BYTES:(i*AM_SECBOOT_KEYIDX_BYTES + AM_SECBOOT_KEYIDX_BYTES)]
|
||||
for j in range (0, AM_SECBOOT_KEYIDX_BYTES):
|
||||
scrambledKey[j] = scrambledKey[j] ^ keys.custKey[j] ^ chipId[j]
|
||||
am_print([hex(n) for n in scrambledKey])
|
||||
copy_keys(hdr_binarray, kekOffset + i*AM_SECBOOT_KEYIDX_BYTES, scrambledKey, AM_SECBOOT_KEYIDX_BYTES)
|
||||
am_print("AuthKey")
|
||||
for i in range (0, INFO_MAX_AUTH_KEYS):
|
||||
scrambledKey = keys.keyTblHmac[i*AM_SECBOOT_KEYIDX_BYTES:(i*AM_SECBOOT_KEYIDX_BYTES + AM_SECBOOT_KEYIDX_BYTES)]
|
||||
for j in range (0, AM_SECBOOT_KEYIDX_BYTES):
|
||||
scrambledKey[j] = scrambledKey[j] ^ keys.custKey[j] ^ chipId[j]
|
||||
am_print([hex(n) for n in scrambledKey])
|
||||
copy_keys(hdr_binarray, authKeyOffset + i*AM_SECBOOT_KEYIDX_BYTES, scrambledKey, AM_SECBOOT_KEYIDX_BYTES)
|
||||
elif (keyWrap == 2): ## AES128
|
||||
am_print("wrap mode 2")
|
||||
am_print("KEK")
|
||||
for i in range (0, INFO_MAX_ENC_KEYS):
|
||||
scrambledKey = encrypt_app_aes(keys.keyTblAes[i*AM_SECBOOT_KEYIDX_BYTES:(i*AM_SECBOOT_KEYIDX_BYTES + AM_SECBOOT_KEYIDX_BYTES)], keys.custKey, chipId)
|
||||
am_print([hex(n) for n in scrambledKey])
|
||||
copy_keys(hdr_binarray, kekOffset + i*AM_SECBOOT_KEYIDX_BYTES, scrambledKey, AM_SECBOOT_KEYIDX_BYTES)
|
||||
am_print("AuthKey")
|
||||
for i in range (0, INFO_MAX_AUTH_KEYS):
|
||||
scrambledKey = encrypt_app_aes(keys.keyTblHmac[i*AM_SECBOOT_KEYIDX_BYTES:(i*AM_SECBOOT_KEYIDX_BYTES + AM_SECBOOT_KEYIDX_BYTES)], keys.custKey, chipId)
|
||||
am_print([hex(n) for n in scrambledKey])
|
||||
copy_keys(hdr_binarray, authKeyOffset + i*AM_SECBOOT_KEYIDX_BYTES, scrambledKey, AM_SECBOOT_KEYIDX_BYTES)
|
||||
else:
|
||||
am_print("Unknown wrap mode")
|
||||
|
||||
# Revocation Masks
|
||||
am_print("KREV Mask = ", hex(krev))
|
||||
fill_word(hdr_binarray, info0.INFO0_KREVTRACK_O, krev)
|
||||
am_print("AREV Mask = ", hex(arev))
|
||||
fill_word(hdr_binarray, info0.INFO0_AREVTRACK_O, arev)
|
||||
|
||||
|
||||
# now output all three binary arrays in the proper order
|
||||
with open(output + '.bin', mode = 'wb') as out:
|
||||
am_print("Writing to file ", output + '.bin')
|
||||
out.write(hdr_binarray)
|
||||
|
||||
def parse_arguments():
|
||||
parser = argparse.ArgumentParser(description =
|
||||
'Generate Corvette Info0 Blob')
|
||||
|
||||
parser.add_argument('output',
|
||||
help = 'Output filename (without the extension)')
|
||||
|
||||
parser.add_argument('--valid', dest = 'valid', type=auto_int, default=1, choices = [0,1,2],
|
||||
help = 'INFO0 Valid 0 = Uninitialized, 1 = Valid, 2 = Invalid (Default = 1)?')
|
||||
|
||||
parser.add_argument('--version', dest = 'version', type=auto_int, default=0,
|
||||
help = 'version (Default = 0)?')
|
||||
|
||||
parser.add_argument('--main', dest = 'mainPtr', type=auto_int, default=hex(AM_SECBOOT_DEFAULT_NONSECURE_MAIN),
|
||||
help = 'Main Firmware location (Default = ' + str(hex(AM_SECBOOT_DEFAULT_NONSECURE_MAIN)) + ')?')
|
||||
|
||||
parser.add_argument('--secpol', dest = 'secPol', type=auto_int, default=hex(0x0), choices = [0x0,0x1,0x2,0x3,0x4,0x5,0x6,0x7],
|
||||
help = 'Security Policy Bitmask (Default = 0)? (bit 0 = Auth, bit 1 = Enc, bit 2 = Version Rollback)')
|
||||
|
||||
parser.add_argument('--wrap', dest = 'keyWrap', type=auto_int, default=0, choices = [0,1,2],
|
||||
help = 'KeyWrap Algo (Default = 0)? (0 = none, 1 = XOR, 2 = AES128)')
|
||||
|
||||
parser.add_argument('--sRst', dest = 'secBootOnRst', type=auto_int, default=0, choices = [0,1],
|
||||
help = 'Secure Boot on Soft Reset (Default = 0) ?')
|
||||
|
||||
parser.add_argument('-s', dest = 'secBoot', type=auto_int, default=0, choices = [0,1],
|
||||
help = 'Secure Boot (Default = 0) ?')
|
||||
|
||||
parser.add_argument('--pl', dest = 'plOnExit', type=auto_int, default=0, choices = [0,1],
|
||||
help = 'Protection Lock Enabled (Default = 0) ?')
|
||||
|
||||
parser.add_argument('--sDbgAllowed', dest = 'sDbg', type=auto_int, default=1, choices = [0,1],
|
||||
help = 'Debugger allowed during (optional) Secondary Bootloader (Default = 1) ?')
|
||||
|
||||
parser.add_argument('--erase', dest = 'bEnErase', type=auto_int, default=1, choices = [0,1],
|
||||
help = 'Info0 Erase Allowed (Default = 1) ?')
|
||||
|
||||
parser.add_argument('--prog', dest = 'infoProg', type=auto_int, default=hex(0xf),
|
||||
help = 'INFO0 Program allowed (1 bit per quadrant) (Default = 0xf) ?')
|
||||
|
||||
parser.add_argument('--snowipe', dest = 'bNoSramWipe', type=auto_int, default=1, choices = [0,1],
|
||||
help = ' Do not wipe SRAM on debugger connection (Default = 1) ?')
|
||||
|
||||
parser.add_argument('--swo', dest = 'bSwoCtrl', type=auto_int, default=1, choices = [0,1],
|
||||
help = 'debugger connection allowed (Default = 1) ?')
|
||||
|
||||
parser.add_argument('--dbgprot', dest = 'bDbgAllowed', type=auto_int, default=1, choices = [0,1],
|
||||
help = 'Do not lock debugger (Default = 1) ?')
|
||||
|
||||
parser.add_argument('--trim', dest = 'custTrim', type=auto_int, default=hex(0xFFFFFFFF),
|
||||
help = 'customer trim ?')
|
||||
|
||||
parser.add_argument('--trim2', dest = 'custTrim2', type=auto_int, default=hex(0xFFFFFFFF),
|
||||
help = 'customer trim 2?')
|
||||
|
||||
parser.add_argument('--gpio', dest = 'overrideGpio', type=auto_int, default=hex(0x7f),
|
||||
help = 'Override GPIO (7 bit - in hex) - 0x7f for disabled (Default = 0x7f)')
|
||||
|
||||
parser.add_argument('--gpiolvl', dest = 'overridePol', type=auto_int, default=0, choices = [0,1],
|
||||
help = 'Override GPIO Polarity (0 = low, 1 = hi) (Default = 0)')
|
||||
|
||||
parser.add_argument('--wmask', dest = 'wiredIfMask', type=auto_int, default=0x1,
|
||||
help = 'Wired interface mask (bit 0 = UART, bit 1 = SPI, bit 2 = I2C) (default = UART)')
|
||||
|
||||
parser.add_argument('--wSlInt', dest = 'wiredSlvInt', type=auto_int, default=4,
|
||||
help = 'Wired IOS interface handshake pin (default = 4)')
|
||||
|
||||
parser.add_argument('--wI2c', dest = 'wiredI2cAddr', type=auto_int, default=hex(0x20),
|
||||
help = 'Wired IOS interface I2C Address (default = 0x20)')
|
||||
|
||||
parser.add_argument('--wTO', dest = 'wiredTimeout', type=auto_int, default=20000,
|
||||
help = 'Wired interface timeout in millisec (default = 20000)')
|
||||
|
||||
parser.add_argument('--u0', dest = 'u0', type=auto_int, default=hex(0xFFFFFFFF),
|
||||
help = 'UART Config 0 (default = 0xFFFFFFFF)')
|
||||
|
||||
parser.add_argument('--u1', dest = 'u1', type=auto_int, default=hex(0xFFFFFFFF),
|
||||
help = 'UART Config 1 (default = 0xFFFFFFFF)')
|
||||
|
||||
parser.add_argument('--u2', dest = 'u2', type=auto_int, default=hex(0xFFFFFFFF),
|
||||
help = 'UART Config 2 (default = 0xFFFFFFFF)')
|
||||
|
||||
parser.add_argument('--u3', dest = 'u3', type=auto_int, default=hex(0xFFFFFFFF),
|
||||
help = 'UART Config 3 (default = 0xFFFFFFFF)')
|
||||
|
||||
parser.add_argument('--u4', dest = 'u4', type=auto_int, default=hex(0xFFFFFFFF),
|
||||
help = 'UART Config 4 (default = 0xFFFFFFFF)')
|
||||
|
||||
parser.add_argument('--u5', dest = 'u5', type=auto_int, default=hex(0xFFFFFFFF),
|
||||
help = 'UART Config 5 (default = 0xFFFFFFFF)')
|
||||
|
||||
parser.add_argument('--krev', dest='krev', type=auto_int, default = hex(0xFFFFFFFF),
|
||||
help='KEK Revocation Mask (Default 0xFFFFFFFF)')
|
||||
|
||||
parser.add_argument('--arev', dest='arev', type=auto_int, default = hex(0xFFFFFFFF),
|
||||
help='AuthKey Revocation Mask (Default 0xFFFFFFFF)')
|
||||
|
||||
parser.add_argument('--sresv', dest='sresv', type=auto_int, default = hex(0x0),
|
||||
help='SRAM Reservation (Default 0x0)')
|
||||
|
||||
parser.add_argument('--chipid0', dest='chipId0', type=auto_int, default = 0,
|
||||
help='CHIPID0 for the device (Default 0)')
|
||||
|
||||
parser.add_argument('--chipid1', dest='chipId1', type=auto_int, default = 0,
|
||||
help='CHIPID1 for the device (Default 0)')
|
||||
|
||||
parser.add_argument('--wprot0', dest='wprot0', type=auto_int, default = hex(0xFFFFFFFF),
|
||||
help='Permanent Write Protections Mask for flash#0 (Default 0xFFFFFFFF)')
|
||||
|
||||
parser.add_argument('--wprot1', dest='wprot1', type=auto_int, default = hex(0xFFFFFFFF),
|
||||
help='Permanent Write Protections Mask for flash#1 (Default 0xFFFFFFFF)')
|
||||
|
||||
parser.add_argument('--rprot0', dest='rprot0', type=auto_int, default = hex(0xFFFFFFFF),
|
||||
help='Permanent Copy Protections Mask for flash#0 (Default 0xFFFFFFFF)')
|
||||
|
||||
parser.add_argument('--rprot1', dest='rprot1', type=auto_int, default = hex(0xFFFFFFFF),
|
||||
help='Permanent Copy Protections Mask for flash#1 (Default 0xFFFFFFFF)')
|
||||
|
||||
parser.add_argument('--swprot0', dest='swprot0', type=auto_int, default = hex(0xFFFFFFFF),
|
||||
help='SBL overridable Write Protections Mask for flash#0 (Default 0xFFFFFFFF)')
|
||||
|
||||
parser.add_argument('--swprot1', dest='swprot1', type=auto_int, default = hex(0xFFFFFFFF),
|
||||
help='SBL overridable Write Protections Mask for flash#1 (Default 0xFFFFFFFF)')
|
||||
|
||||
parser.add_argument('--srprot0', dest='srprot0', type=auto_int, default = hex(0xFFFFFFFF),
|
||||
help='SBL overridable Copy Protections Mask for flash#0 (Default 0xFFFFFFFF)')
|
||||
|
||||
parser.add_argument('--srprot1', dest='srprot1', type=auto_int, default = hex(0xFFFFFFFF),
|
||||
help='SBL overridable Copy Protections Mask for flash#1 (Default 0xFFFFFFFF)')
|
||||
|
||||
parser.add_argument('--wprot2', dest='wprot2', type=auto_int, default = hex(0xFFFFFFFF),
|
||||
help='Permanent Write Protections Mask for flash#2 (Default 0xFFFFFFFF)')
|
||||
|
||||
parser.add_argument('--wprot3', dest='wprot3', type=auto_int, default = hex(0xFFFFFFFF),
|
||||
help='Permanent Write Protections Mask for flash#3 (Default 0xFFFFFFFF)')
|
||||
|
||||
parser.add_argument('--rprot2', dest='rprot2', type=auto_int, default = hex(0xFFFFFFFF),
|
||||
help='Permanent Copy Protections Mask for flash#2 (Default 0xFFFFFFFF)')
|
||||
|
||||
parser.add_argument('--rprot3', dest='rprot3', type=auto_int, default = hex(0xFFFFFFFF),
|
||||
help='Permanent Copy Protections Mask for flash#3 (Default 0xFFFFFFFF)')
|
||||
|
||||
parser.add_argument('--swprot2', dest='swprot2', type=auto_int, default = hex(0xFFFFFFFF),
|
||||
help='SBL overridable Write Protections Mask for flash#2 (Default 0xFFFFFFFF)')
|
||||
|
||||
parser.add_argument('--swprot3', dest='swprot3', type=auto_int, default = hex(0xFFFFFFFF),
|
||||
help='SBL overridable Write Protections Mask for flash#3 (Default 0xFFFFFFFF)')
|
||||
|
||||
parser.add_argument('--srprot2', dest='srprot2', type=auto_int, default = hex(0xFFFFFFFF),
|
||||
help='SBL overridable Copy Protections Mask for flash#2 (Default 0xFFFFFFFF)')
|
||||
|
||||
parser.add_argument('--srprot3', dest='srprot3', type=auto_int, default = hex(0xFFFFFFFF),
|
||||
help='SBL overridable Copy Protections Mask for flash#3 (Default 0xFFFFFFFF)')
|
||||
|
||||
parser.add_argument('--chipType', dest='chip', type=str, required=True,
|
||||
choices = ['apollo3', 'apollo3p'],
|
||||
help='Chip Type: apollo3, apollo3p (default = apollo3)')
|
||||
|
||||
parser.add_argument('-k', type=str, dest='keyFile', nargs='?', default='keys_info.py',
|
||||
help='key file in specified format [default = keys_info.py]')
|
||||
|
||||
parser.add_argument('--loglevel', dest='loglevel', type=auto_int, default=AM_PRINT_LEVEL_INFO,
|
||||
choices = range(AM_PRINT_LEVEL_MIN, AM_PRINT_LEVEL_MAX+1),
|
||||
help=helpPrintLevel)
|
||||
|
||||
args = parser.parse_args()
|
||||
|
||||
return args
|
||||
|
||||
#******************************************************************************
|
||||
#
|
||||
# Main function.
|
||||
#
|
||||
#******************************************************************************
|
||||
def main():
|
||||
# Read the arguments.
|
||||
args = parse_arguments()
|
||||
am_set_print_level(args.loglevel)
|
||||
|
||||
process(args.valid, args.version, args.output, args.mainPtr, args.secPol, args.keyWrap, args.secBoot, args.secBootOnRst, args.plOnExit, args.sDbg, args.bEnErase, args.infoProg, args.bNoSramWipe, args.bSwoCtrl, args.bDbgAllowed, args.custTrim, args.custTrim2, args.overrideGpio, args.overridePol, args.wiredIfMask, args.wiredSlvInt, args.wiredI2cAddr, args.wiredTimeout, args.u0, args.u1, args.u2, args.u3, args.u4, args.u5, args.krev, args.arev, args.chipId0, args.chipId1, args.sresv, args.wprot0, args.wprot1, args.rprot0, args.rprot1, args.swprot0, args.swprot1, args.srprot0, args.srprot1, args.wprot2, args.wprot3, args.rprot2, args.rprot3, args.swprot2, args.swprot3, args.srprot2, args.srprot3, args.chip, args.keyFile)
|
||||
|
||||
if __name__ == '__main__':
|
||||
main()
|
||||
@@ -0,0 +1,133 @@
|
||||
#!/usr/bin/env python3
|
||||
|
||||
import argparse
|
||||
import sys
|
||||
from Crypto.Cipher import AES
|
||||
import array
|
||||
import os
|
||||
import binascii
|
||||
import importlib
|
||||
|
||||
from am_defines import *
|
||||
#from keys_info import keyTblAes, keyTblHmac, wrapKey, minWrapMode
|
||||
|
||||
|
||||
#******************************************************************************
|
||||
#
|
||||
# Generate the device keys for a given chipId based on well known keys and key Wrap mode
|
||||
#
|
||||
#******************************************************************************
|
||||
def process(wrapMode, chipId0, chipId1, inFile, keyFile):
|
||||
filenames = keyFile.split('.')
|
||||
keys = importlib.import_module(filenames[0])
|
||||
if (inFile is not None):
|
||||
for line in inFile:
|
||||
linecontent = line.rstrip()
|
||||
if linecontent:
|
||||
chipids = line.split(':')
|
||||
process_chip(wrapMode, int(chipids[0], 16), int(chipids[1], 16), keys)
|
||||
else:
|
||||
process_chip(wrapMode, chipId0, chipId1, keys)
|
||||
|
||||
def process_chip(wrapMode, chipId0, chipId1, keys):
|
||||
|
||||
output = str(hex(chipId0)) + '_' + str(hex(chipId1))
|
||||
chipId = int_to_bytes(chipId0) + int_to_bytes(chipId1)
|
||||
while (len(chipId) != AM_SECBOOT_KEYIDX_BYTES):
|
||||
chipId = chipId + chipId
|
||||
am_print("ChipID: ", [hex(n) for n in chipId], level=AM_PRINT_LEVEL_VERBOSE)
|
||||
|
||||
if (wrapMode < keys.minWrapMode):
|
||||
am_print("Invalid Wrap Mode", level=AM_PRINT_LEVEL_ERROR)
|
||||
return
|
||||
if (wrapMode == AM_SECBOOT_KEYWRAP_NONE): ## None
|
||||
am_print("wrap mode None")
|
||||
with open(output + '_info_kek.bin', mode = 'wb') as out_info_kek:
|
||||
am_print("writing to " + output + '_info_kek.bin')
|
||||
for i in range (0, INFO_MAX_ENC_KEYS):
|
||||
am_print([hex(n) for n in keys.keyTblAes[i*AM_SECBOOT_KEYIDX_BYTES:(i*AM_SECBOOT_KEYIDX_BYTES + AM_SECBOOT_KEYIDX_BYTES)]], level=AM_PRINT_LEVEL_DEBUG)
|
||||
out_info_kek.write(bytearray(keys.keyTblAes[i*AM_SECBOOT_KEYIDX_BYTES:(i*AM_SECBOOT_KEYIDX_BYTES + AM_SECBOOT_KEYIDX_BYTES)]))
|
||||
with open(output + '_info_authkey.bin', mode = 'wb') as out_info_authkey:
|
||||
am_print("writing to " + output + '_info_authkey.bin')
|
||||
for i in range (0, INFO_MAX_AUTH_KEYS):
|
||||
am_print([hex(n) for n in keys.keyTblHmac[i*AM_SECBOOT_KEYIDX_BYTES:(i*AM_SECBOOT_KEYIDX_BYTES + AM_SECBOOT_KEYIDX_BYTES)]], level=AM_PRINT_LEVEL_DEBUG)
|
||||
out_info_authkey.write(bytearray(keys.keyTblHmac[i*AM_SECBOOT_KEYIDX_BYTES:(i*AM_SECBOOT_KEYIDX_BYTES + AM_SECBOOT_KEYIDX_BYTES)]))
|
||||
elif (wrapMode == AM_SECBOOT_KEYWRAP_XOR): ## XOR
|
||||
am_print("wrap mode XOR")
|
||||
with open(output + '_info_kek.bin', mode = 'wb') as out_info_kek:
|
||||
am_print("writing to " + output + '_info_kek.bin')
|
||||
for i in range (0, INFO_MAX_ENC_KEYS):
|
||||
scrambledKey = keys.keyTblAes[i*AM_SECBOOT_KEYIDX_BYTES:(i*AM_SECBOOT_KEYIDX_BYTES + AM_SECBOOT_KEYIDX_BYTES)]
|
||||
for j in range (0, AM_SECBOOT_KEYIDX_BYTES):
|
||||
scrambledKey[j] = scrambledKey[j] ^ keys.wrapKey[j] ^ chipId[j]
|
||||
am_print([hex(n) for n in scrambledKey], level=AM_PRINT_LEVEL_DEBUG)
|
||||
out_info_kek.write(bytearray(scrambledKey))
|
||||
with open(output + '_info_authkey.bin', mode = 'wb') as out_info_authkey:
|
||||
am_print("writing to " + output + '_info_authkey.bin')
|
||||
for i in range (0, INFO_MAX_AUTH_KEYS):
|
||||
scrambledKey = keys.keyTblHmac[i*AM_SECBOOT_KEYIDX_BYTES:(i*AM_SECBOOT_KEYIDX_BYTES + AM_SECBOOT_KEYIDX_BYTES)]
|
||||
for j in range (0, AM_SECBOOT_KEYIDX_BYTES):
|
||||
scrambledKey[j] = scrambledKey[j] ^ keys.wrapKey[j] ^ chipId[j]
|
||||
am_print([hex(n) for n in scrambledKey], level=AM_PRINT_LEVEL_DEBUG)
|
||||
out_info_authkey.write(bytearray(scrambledKey))
|
||||
elif (wrapMode == AM_SECBOOT_KEYWRAP_AES128): ## AES128
|
||||
am_print("wrap mode AES128")
|
||||
with open(output + '_info_kek.bin', mode = 'wb') as out_info_kek:
|
||||
am_print("writing to " + output + '_info_kek.bin')
|
||||
for i in range (0, INFO_MAX_ENC_KEYS):
|
||||
scrambledKey = encrypt_app_aes(keys.keyTblAes[i*AM_SECBOOT_KEYIDX_BYTES:(i*AM_SECBOOT_KEYIDX_BYTES + AM_SECBOOT_KEYIDX_BYTES)], keys.wrapKey, chipId)
|
||||
am_print([hex(n) for n in scrambledKey], level=AM_PRINT_LEVEL_DEBUG)
|
||||
out_info_kek.write(bytearray(scrambledKey))
|
||||
with open(output + '_info_authkey.bin', mode = 'wb') as out_info_authkey:
|
||||
am_print("writing to " + output + '_info_authkey.bin')
|
||||
for i in range (0, INFO_MAX_AUTH_KEYS):
|
||||
scrambledKey = encrypt_app_aes(keys.keyTblHmac[i*AM_SECBOOT_KEYIDX_BYTES:(i*AM_SECBOOT_KEYIDX_BYTES + AM_SECBOOT_KEYIDX_BYTES)], keys.wrapKey, chipId)
|
||||
am_print([hex(n) for n in scrambledKey], level=AM_PRINT_LEVEL_DEBUG)
|
||||
out_info_authkey.write(bytearray(scrambledKey))
|
||||
else:
|
||||
am_print("Unknown wrap mode", level=AM_PRINT_LEVEL_ERROR)
|
||||
return
|
||||
|
||||
|
||||
def parse_arguments():
|
||||
parser = argparse.ArgumentParser(description =
|
||||
'Generate Corvette Device keys')
|
||||
|
||||
parser.add_argument('--wrap', dest='wrap', type=auto_int, default=AM_SECBOOT_KEYWRAP_NONE, choices = range(AM_SECBOOT_KEYWRAP_NONE, AM_SECBOOT_KEYWRAP_MAX+1),
|
||||
help='wrap mode (0 = None, 1 = XOR, 2 = AES128) [default ' + str(AM_SECBOOT_KEYWRAP_NONE) +'] ')
|
||||
|
||||
parser.add_argument('--chipid0', dest='chipId0', type=auto_int, default=0,
|
||||
help='CHIPID0 for the device')
|
||||
|
||||
parser.add_argument('--chipid1', dest='chipId1', type=auto_int, default=0,
|
||||
help='CHIPID1 for the device')
|
||||
|
||||
parser.add_argument('-k', type=str, dest='keyFile', nargs='?', default='keys_info.py',
|
||||
help='key file in specified format [default = keys_info.py]')
|
||||
|
||||
parser.add_argument('-f', type=argparse.FileType('r'), dest='inFile', nargs='?',
|
||||
help='Input text file with chip ID Tuples (chipID0:chipID1 in each line)')
|
||||
|
||||
parser.add_argument('--loglevel', dest='loglevel', type=auto_int, default=AM_PRINT_LEVEL_INFO,
|
||||
choices = range(AM_PRINT_LEVEL_MIN, AM_PRINT_LEVEL_MAX+1),
|
||||
help=helpPrintLevel)
|
||||
|
||||
args = parser.parse_args()
|
||||
|
||||
return args
|
||||
|
||||
|
||||
#******************************************************************************
|
||||
#
|
||||
# Main function.
|
||||
#
|
||||
#******************************************************************************
|
||||
def main():
|
||||
# Read the arguments.
|
||||
args = parse_arguments()
|
||||
|
||||
am_set_print_level(args.loglevel)
|
||||
process(args.wrap, args.chipId0, args.chipId1, args.inFile, args.keyFile)
|
||||
|
||||
if __name__ == '__main__':
|
||||
main()
|
||||
@@ -0,0 +1,107 @@
|
||||
#!/usr/bin/env python3
|
||||
# Utility to generate Recover Message for Corvette Bootloader assisted Wired updates
|
||||
|
||||
import argparse
|
||||
import sys
|
||||
from Crypto.Cipher import AES
|
||||
import array
|
||||
import hashlib
|
||||
import hmac
|
||||
import os
|
||||
import binascii
|
||||
import importlib
|
||||
|
||||
from am_defines import *
|
||||
#from keys_info import recoveryKey
|
||||
|
||||
#******************************************************************************
|
||||
#
|
||||
# Generate the image blob as per command line parameters
|
||||
#
|
||||
#******************************************************************************
|
||||
def process(binfile, n0, n1, n2, n3, custId, output, keyFile):
|
||||
|
||||
if (binfile != ''):
|
||||
# Read the binary file from the command line.
|
||||
with open(binfile, mode='rb') as binfile:
|
||||
blob = binfile.read()
|
||||
# Gather the important binary metadata.
|
||||
blobLen = len(blob)
|
||||
else:
|
||||
blob = bytearray()
|
||||
blobLen = 0
|
||||
|
||||
filenames = keyFile.split('.')
|
||||
keys = importlib.import_module(filenames[0])
|
||||
|
||||
# Send Recover command
|
||||
print('Building Recover Command.')
|
||||
|
||||
hdr_binarray = bytearray([0x00]*(AM_WU_RECOVERY_HDR_SIZE))
|
||||
fill_word(hdr_binarray, 4, (((blobLen + AM_WU_RECOVERY_HDR_SIZE) << 16) | AM_SECBOOT_WIRED_MSGTYPE_RECOVER))
|
||||
# CustId
|
||||
fill_word(hdr_binarray, AM_WU_RECOVERY_HDR_OFFSET_CUSTID, custId)
|
||||
# Recovery key
|
||||
for x in range(0, AM_SECBOOT_AESCBC_BLOCK_SIZE_BYTES):
|
||||
hdr_binarray[AM_WU_RECOVERY_HDR_OFFSET_RECKEY + x] = keys.recoveryKey[x]
|
||||
# Nonce
|
||||
fill_word(hdr_binarray, AM_WU_RECOVERY_HDR_OFFSET_NONCE + 0, n0)
|
||||
fill_word(hdr_binarray, AM_WU_RECOVERY_HDR_OFFSET_NONCE + 4, n1)
|
||||
fill_word(hdr_binarray, AM_WU_RECOVERY_HDR_OFFSET_NONCE + 8, n2)
|
||||
fill_word(hdr_binarray, AM_WU_RECOVERY_HDR_OFFSET_NONCE + 12, n3)
|
||||
|
||||
# Compute crc
|
||||
crc = crc32(hdr_binarray[4:AM_WU_RECOVERY_HDR_SIZE] + blob)
|
||||
fill_word(hdr_binarray, 0, crc)
|
||||
|
||||
# Write the message as a raw message
|
||||
with open(output + '.msg', mode = 'wb') as out:
|
||||
print("Writing to file ", output + '.msg')
|
||||
out.write(hdr_binarray + blob)
|
||||
|
||||
def parse_arguments():
|
||||
parser = argparse.ArgumentParser(description =
|
||||
'Generate Corvette Recovery Message')
|
||||
|
||||
parser.add_argument('-f', dest='binfile', default='',
|
||||
help = 'Binary file representing the raw Recovery Blob provided by Ambiq')
|
||||
|
||||
parser.add_argument('-o', dest = 'output',
|
||||
help = 'Output filename (without the extension)')
|
||||
|
||||
parser.add_argument('--n0', dest = 'n0', type=auto_int, default=0xFFFFFFFF,
|
||||
help = 'Nonce 0 - should correspond to the value provided to Ambiq (default = 0xFFFFFFFF)')
|
||||
|
||||
parser.add_argument('--n1', dest = 'n1', type=auto_int, default=0xFFFFFFFF,
|
||||
help = 'Nonce 1 - should correspond to the value provided to Ambiq (default = 0xFFFFFFFF)')
|
||||
|
||||
parser.add_argument('--n2', dest = 'n2', type=auto_int, default=0xFFFFFFFF,
|
||||
help = 'Nonce 2 - should correspond to the value provided to Ambiq (default = 0xFFFFFFFF)')
|
||||
|
||||
parser.add_argument('--n3', dest = 'n3', type=auto_int, default=0xFFFFFFFF,
|
||||
help = 'Nonce 3 - should correspond to the value provided to Ambiq (default = 0xFFFFFFFF)')
|
||||
|
||||
parser.add_argument('--custId', dest='custId', type=auto_int, default=0xFFFFFFFF,
|
||||
help='Customer ID - should correspond to the value provided to Ambiq (default = 0xFFFFFFFF)')
|
||||
|
||||
parser.add_argument('-k', type=str, dest='keyFile', nargs='?', default='keys_info.py',
|
||||
help='key file in specified format [default = keys_info.py]')
|
||||
|
||||
args = parser.parse_args()
|
||||
|
||||
return args
|
||||
|
||||
#******************************************************************************
|
||||
#
|
||||
# Main function.
|
||||
#
|
||||
#******************************************************************************
|
||||
def main():
|
||||
# Read the arguments.
|
||||
args = parse_arguments()
|
||||
|
||||
|
||||
process(args.binfile, args.n0, args.n1, args.n2, args.n3, args.custId, args.output, args.keyFile)
|
||||
|
||||
if __name__ == '__main__':
|
||||
main()
|
||||
@@ -0,0 +1,36 @@
|
||||
// connect to device
|
||||
// NEED to specify -device AMA3B2KK-KBR (for Apollo3P) or -device AMA3B1KK-KBR/KCR (for Apollo3) from command line
|
||||
si SWD
|
||||
speed 1000
|
||||
r
|
||||
sleep 10
|
||||
|
||||
//set C runtime environment
|
||||
wreg MSP, 0x10000100
|
||||
|
||||
// erase info0
|
||||
w4 0x10000000 0 // flash info instance
|
||||
w4 0x10000004 0xd894e09e // info 0 key
|
||||
w4 0x10000008 0xFFFFFFFF // clear return value
|
||||
setPC 0x08000085 // call the ROM helper function flash_info_erase_from_sram
|
||||
g
|
||||
sleep 50
|
||||
mem32 0x10000008 1 // dump return value for check
|
||||
|
||||
// program info0
|
||||
w4 0x10000000 0 // flash info instance
|
||||
w4 0x10000004 0 // offset
|
||||
w4 0x10000008 0x800 // length in words
|
||||
w4 0x1000000C 0xd894e09e // info 0 key
|
||||
w4 0x10000010 0xFFFFFFFF // clear return value
|
||||
loadbin info0.bin 0x10001000 //load the info0 binary into sram
|
||||
setPC 0x08000061 // call the ROM helper function flash_program_info_area_from_sram
|
||||
g
|
||||
sleep 50
|
||||
mem32 0x10000010 1 // dump return value for check
|
||||
|
||||
// perform software POI
|
||||
w4 0x40000004 0x1B
|
||||
|
||||
// quit
|
||||
qc
|
||||
@@ -0,0 +1,20 @@
|
||||
//connect to device
|
||||
// NEED to specify -device AMA3B2KK-KBR (for Apollo3P) or -device AMA3B1KK-KBR/KCR (for Apollo3) from command line
|
||||
si SWD
|
||||
speed 1000
|
||||
r
|
||||
sleep 10
|
||||
|
||||
// download image to 0x80000 - **** Change this based on device flashmap ****
|
||||
loadbin sbl.bin 0x80000 //load the SBL binary into temp location in flash
|
||||
// Set up OTA Descriptor at 0xF0000 // **** Change this based on device flashmap ****
|
||||
w4 0xF0000 0x80003
|
||||
w4 0xF0004 0xFFFFFFFF
|
||||
// Set up OTAPointer
|
||||
w4 0x40020264 0xF0003
|
||||
// Reset POI
|
||||
w4 0x40000004 0x1B
|
||||
|
||||
|
||||
// quit
|
||||
qc
|
||||
@@ -0,0 +1,25 @@
|
||||
//connect to device
|
||||
// NEED to specify -device AMA3B2KK-KBR (for Apollo3P) or -device AMA3B1KK-KBR/KCR (for Apollo3) from command line
|
||||
si SWD
|
||||
speed 1000
|
||||
r
|
||||
sleep 10
|
||||
|
||||
//set C runtime environment
|
||||
wreg MSP, 0x10000100
|
||||
|
||||
// unlock info0 access
|
||||
w4 0x40030078 1 // unlock the info0 secured portion
|
||||
w4 0x40030080 DEADBEEF DEADBEEF DEADBEEF DEADBEEF // write the unlock key
|
||||
// this should be replaced with actual customer key!!!
|
||||
mem32 0x4003007C 1 // dump the lock status for check
|
||||
|
||||
// read back info0 for verify
|
||||
verifybin info0.bin 0x50020000 // verify the info 0 content with the original source file
|
||||
savebin info0_dump.bin 0x50020000 0x2000 // read out the info 0 content for saving
|
||||
|
||||
w4 0x40030080 FFFFFFFF FFFFFFFF FFFFFFFF FFFFFFFF // lock the secured portion
|
||||
|
||||
// reset and quit
|
||||
r
|
||||
qc
|
||||
@@ -0,0 +1,46 @@
|
||||
#!/usr/bin/env python3
|
||||
from am_defines import *
|
||||
|
||||
minAesKeyIdx = 8
|
||||
maxAesKeyIdx = 15
|
||||
minHmacKeyIdx = 8
|
||||
maxHmacKeyIdx = 15
|
||||
|
||||
###### Following are just dummy keys - Should be substituted with real keys #######
|
||||
keyTblAes = [
|
||||
# Info0 Keys - Starting at index 8
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
|
||||
0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA,
|
||||
0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55,
|
||||
0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11,
|
||||
0xA5, 0xA5, 0xA5, 0xA5, 0xA5, 0xA5, 0xA5, 0xA5, 0xA5, 0xA5, 0xA5, 0xA5, 0xA5, 0xA5, 0xA5, 0xA5,
|
||||
0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66,
|
||||
0xEF, 0xBE, 0xAD, 0xDE, 0xEF, 0xBE, 0xAD, 0xDE, 0xEF, 0xBE, 0xAD, 0xDE, 0xEF, 0xBE, 0xAD, 0xDE,
|
||||
]
|
||||
|
||||
keyTblHmac = [
|
||||
# Info0 Keys - Starting at index 8
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
|
||||
0xAA, 0x55, 0xAA, 0x55, 0xAA, 0x55, 0xAA, 0x55, 0xAA, 0x55, 0xAA, 0x55, 0xAA, 0x55, 0xAA, 0x55, 0xAA, 0x55, 0xAA, 0x55, 0xAA, 0x55, 0xAA, 0x55, 0xAA, 0x55, 0xAA, 0x55, 0xAA, 0x55, 0xAA, 0x55,
|
||||
0xEF, 0xBE, 0xAD, 0xDE, 0xEF, 0xBE, 0xAD, 0xDE, 0xEF, 0xBE, 0xAD, 0xDE, 0xEF, 0xBE, 0xAD, 0xDE, 0xEF, 0xBE, 0xAD, 0xDE, 0xEF, 0xBE, 0xAD, 0xDE, 0xEF, 0xBE, 0xAD, 0xDE, 0xEF, 0xBE, 0xAD, 0xDE,
|
||||
]
|
||||
|
||||
custKey = [
|
||||
0xEF, 0xBE, 0xAD, 0xDE, 0xEF, 0xBE, 0xAD, 0xDE, 0xEF, 0xBE, 0xAD, 0xDE, 0xEF, 0xBE, 0xAD, 0xDE,
|
||||
]
|
||||
|
||||
# These are dummy values. Contact AMBIQ to get the real Recovery Key
|
||||
recoveryKey = [
|
||||
0xEF, 0xBE, 0xAD, 0xDE, 0xEF, 0xBE, 0xAD, 0xDE, 0xEF, 0xBE, 0xAD, 0xDE, 0xEF, 0xBE, 0xAD, 0xDE,
|
||||
]
|
||||
|
||||
###################################################################################
|
||||
|
||||
wrapKey = custKey
|
||||
minWrapMode = AM_SECBOOT_KEYWRAP_NONE
|
||||
|
||||
INFO_KEY = 0xd894e09e
|
||||
FLASH_KEY = 0x12344321
|
||||
|
||||
@@ -0,0 +1,11 @@
|
||||
@echo off
|
||||
|
||||
if [%1]==[] goto usage
|
||||
|
||||
jlink -device %1 -CommanderScript jlink-prog-info0.txt
|
||||
pause
|
||||
goto :eof
|
||||
|
||||
:usage
|
||||
@echo Usage: %0 ^<Chip Part#^>
|
||||
exit /B 1
|
||||
@@ -0,0 +1,9 @@
|
||||
sbl_v2_3_93e8 SBL v2 created on 7/26/2018. Change to disable Encap OTA Support.
|
||||
SBL_v2 Release candidate #2. Header version 3
|
||||
|
||||
sbl_v3_4_994c SBL v3 created on 2/19/2019. Adds IOS SPI and I2C support.
|
||||
Header version 4.
|
||||
|
||||
sbl_v3_5_99a0 SBL v4 created on 3/8/2019. Eliminates setting of HFADJ in
|
||||
am_secboot_config_wired_uart() for B0. Header version 5.
|
||||
|
||||
+5
@@ -0,0 +1,5 @@
|
||||
sbl3p_v2_2_a0a5 (OTA: 0xA3009400:0x53D5B051) - SBL v2
|
||||
enhancement for SRAM Reservation feature
|
||||
with fix to GPIO macro to allow GPIO>63 to be used
|
||||
Header Version 2
|
||||
|
||||
@@ -0,0 +1,345 @@
|
||||
#!/usr/bin/env python3
|
||||
# UART wired update host for Corvette Bootloader
|
||||
|
||||
import argparse
|
||||
import serial
|
||||
import sys
|
||||
import array
|
||||
import os
|
||||
import binascii
|
||||
|
||||
from am_defines import *
|
||||
|
||||
#******************************************************************************
|
||||
#
|
||||
# Main function
|
||||
#
|
||||
#******************************************************************************
|
||||
def main():
|
||||
|
||||
# Open a serial port, and communicate with Device
|
||||
#
|
||||
# We will use a UART timeout value of 12 second. This should be long
|
||||
# enough that the slave will respond to us, but short enough that a human
|
||||
# operator should see errors quickly..
|
||||
# Max flashing time depends on the amount of SRAM available.
|
||||
# For very large images, the flashing happens page by page.
|
||||
# However if the image can fit in the free SRAM, it could take a long time
|
||||
# for the whole image to be flashed at the end.
|
||||
# The largest image which can be stored depends on the max SRAM.
|
||||
# Assuming worst case ~100 ms/page of flashing time, and allowing for the
|
||||
# image to be close to occupying full SRAM (256K) which is 128 pages.
|
||||
|
||||
print('Connecting with Corvette over serial port {}...'.format(args.port), flush=True)
|
||||
|
||||
with serial.Serial(args.port, args.baud, timeout=12) as ser:
|
||||
connect_device(ser)
|
||||
|
||||
print('Done.')
|
||||
|
||||
#******************************************************************************
|
||||
#
|
||||
# Communicate with Device
|
||||
#
|
||||
# Given a serial port, connects to the target device using the
|
||||
# UART.
|
||||
#
|
||||
#******************************************************************************
|
||||
def connect_device(ser):
|
||||
|
||||
# Send Hello
|
||||
#generate mutable byte array for the header
|
||||
hello = bytearray([0x00]*4);
|
||||
|
||||
fill_word(hello, 0, ((8 << 16) | AM_SECBOOT_WIRED_MSGTYPE_HELLO))
|
||||
print('Sending Hello.')
|
||||
response = send_command(hello, 88, ser)
|
||||
print("Received response for Hello")
|
||||
word = word_from_bytes(response, 4)
|
||||
if ((word & 0xFFFF) == AM_SECBOOT_WIRED_MSGTYPE_STATUS):
|
||||
# Received Status
|
||||
print("Received Status")
|
||||
print("length = ", hex((word >> 16)))
|
||||
print("version = ", hex(word_from_bytes(response, 8)))
|
||||
print("Max Storage = ", hex(word_from_bytes(response, 12)))
|
||||
print("Status = ", hex(word_from_bytes(response, 16)))
|
||||
print("State = ", hex(word_from_bytes(response, 20)))
|
||||
print("AMInfo = ")
|
||||
for x in range(24, 88, 4):
|
||||
print(hex(word_from_bytes(response, x)))
|
||||
|
||||
abort = args.abort
|
||||
if (abort != -1):
|
||||
# Send OTA Desc
|
||||
print('Sending Abort command.')
|
||||
abortMsg = bytearray([0x00]*8);
|
||||
fill_word(abortMsg, 0, ((12 << 16) | AM_SECBOOT_WIRED_MSGTYPE_ABORT))
|
||||
fill_word(abortMsg, 4, abort)
|
||||
send_ackd_command(abortMsg, ser)
|
||||
|
||||
otadescaddr = args.otadesc
|
||||
if (otadescaddr != 0xFFFFFFFF):
|
||||
# Send OTA Desc
|
||||
print('Sending OTA Descriptor = ', hex(otadescaddr))
|
||||
otaDesc = bytearray([0x00]*8);
|
||||
fill_word(otaDesc, 0, ((12 << 16) | AM_SECBOOT_WIRED_MSGTYPE_OTADESC))
|
||||
fill_word(otaDesc, 4, otadescaddr)
|
||||
send_ackd_command(otaDesc, ser)
|
||||
|
||||
imageType = args.imagetype
|
||||
if (args.binfile != ''):
|
||||
|
||||
# Read the binary file from the command line.
|
||||
with open(args.binfile, mode='rb') as binfile:
|
||||
application = binfile.read()
|
||||
# Gather the important binary metadata.
|
||||
totalLen = len(application)
|
||||
# Send Update command
|
||||
print('Sending Update Command.')
|
||||
|
||||
# It is assumed that maxSize is 256b multiple
|
||||
maxImageSize = args.split
|
||||
if ((maxImageSize & (FLASH_PAGE_SIZE - 1)) != 0):
|
||||
print ("split needs to be multiple of flash page size")
|
||||
return
|
||||
|
||||
# Each Block of image consists of AM_WU_IMAGEHDR_SIZE Bytes Image header and the Image blob
|
||||
maxUpdateSize = AM_WU_IMAGEHDR_SIZE + maxImageSize
|
||||
numUpdates = (totalLen + maxUpdateSize - 1) // maxUpdateSize # Integer division
|
||||
print("number of updates needed = ", numUpdates)
|
||||
|
||||
end = totalLen
|
||||
for numUpdates in range(numUpdates, 0 , -1):
|
||||
start = (numUpdates-1)*maxUpdateSize
|
||||
crc = crc32(application[start:end])
|
||||
applen = end - start
|
||||
print("Sending block of size ", str(hex(applen)), " from ", str(hex(start)), " to ", str(hex(end)))
|
||||
end = end - applen
|
||||
|
||||
update = bytearray([0x00]*16);
|
||||
fill_word(update, 0, ((20 << 16) | AM_SECBOOT_WIRED_MSGTYPE_UPDATE))
|
||||
fill_word(update, 4, applen)
|
||||
fill_word(update, 8, crc)
|
||||
# Size = 0 => We're not piggybacking any data to IMAGE command
|
||||
fill_word(update, 12, 0)
|
||||
|
||||
send_ackd_command(update, ser)
|
||||
|
||||
# Loop over the bytes in the image, and send them to the target.
|
||||
resp = 0
|
||||
# Max chunk size is AM_MAX_UART_MSG_SIZE adjusted for the header for Data message
|
||||
maxChunkSize = AM_MAX_UART_MSG_SIZE - 12
|
||||
for x in range(0, applen, maxChunkSize):
|
||||
# Split the application into chunks of maxChunkSize bytes.
|
||||
# This is the max chunk size supported by the UART bootloader
|
||||
if ((x + maxChunkSize) > applen):
|
||||
chunk = application[start+x:start+applen]
|
||||
# print(str(hex(start+x)), " to ", str(hex(applen)))
|
||||
else:
|
||||
chunk = application[start+x:start+x+maxChunkSize]
|
||||
# print(str(hex(start+x)), " to ", str(hex(start + x + maxChunkSize)))
|
||||
|
||||
chunklen = len(chunk)
|
||||
|
||||
# Build a data packet with a "data command" a "length" and the actual
|
||||
# payload bytes, and send it to the target.
|
||||
dataMsg = bytearray([0x00]*8);
|
||||
fill_word(dataMsg, 0, (((chunklen + 12) << 16) | AM_SECBOOT_WIRED_MSGTYPE_DATA))
|
||||
# seqNo
|
||||
fill_word(dataMsg, 4, x)
|
||||
|
||||
print("Sending Data Packet of length ", chunklen)
|
||||
send_ackd_command(dataMsg + chunk, ser)
|
||||
|
||||
if (args.raw != ''):
|
||||
|
||||
# Read the binary file from the command line.
|
||||
with open(args.raw, mode='rb') as rawfile:
|
||||
blob = rawfile.read()
|
||||
# Send Raw command
|
||||
print('Sending Raw Command.')
|
||||
ser.write(blob)
|
||||
|
||||
if (args.reset != 0):
|
||||
# Send reset
|
||||
print('Sending Reset Command.')
|
||||
resetmsg = bytearray([0x00]*8);
|
||||
fill_word(resetmsg, 0, ((12 << 16) | AM_SECBOOT_WIRED_MSGTYPE_RESET))
|
||||
# options
|
||||
fill_word(resetmsg, 4, args.reset)
|
||||
send_ackd_command(resetmsg, ser)
|
||||
else:
|
||||
# Received Wrong message
|
||||
print("Received Unknown Message")
|
||||
word = word_from_bytes(response, 4)
|
||||
print("msgType = ", hex(word & 0xFFFF))
|
||||
print("Length = ", hex(word >> 16))
|
||||
print([hex(n) for n in response])
|
||||
print("!!!Wired Upgrade Unsuccessful!!!....Terminating the script")
|
||||
exit()
|
||||
|
||||
#******************************************************************************
|
||||
#
|
||||
# Send ACK'd command
|
||||
#
|
||||
# Sends a command, and waits for an ACK.
|
||||
#
|
||||
#******************************************************************************
|
||||
def send_ackd_command(command, ser):
|
||||
for numTries in range(1, 5 , 1):
|
||||
response = send_command(command, 20, ser)
|
||||
|
||||
word = word_from_bytes(response, 4)
|
||||
if ((word & 0xFFFF) == AM_SECBOOT_WIRED_MSGTYPE_ACK):
|
||||
# Received ACK
|
||||
if (word_from_bytes(response, 12) != AM_SECBOOT_WIRED_ACK_STATUS_SUCCESS):
|
||||
print("Received NACK")
|
||||
print("msgType = ", hex(word_from_bytes(response, 8)))
|
||||
print("error = ", hex(word_from_bytes(response, 12)))
|
||||
print("seqNo = ", hex(word_from_bytes(response, 16)))
|
||||
if (numTries < 4):
|
||||
print("Retry # ", numTries)
|
||||
else:
|
||||
print("Exceed number of retries")
|
||||
else:
|
||||
break
|
||||
else:
|
||||
print("!!!Wired Upgrade Unsuccessful!!!....unexpected respose - Terminating the script")
|
||||
exit()
|
||||
if (numTries == 4):
|
||||
print("!!!Wired Upgrade Unsuccessful!!!....numTries exceeded - Terminating the script")
|
||||
exit()
|
||||
|
||||
return response
|
||||
|
||||
#******************************************************************************
|
||||
#
|
||||
# Send command
|
||||
#
|
||||
# Sends a command, and waits for the response.
|
||||
#
|
||||
#******************************************************************************
|
||||
def send_command(params, response_len, ser):
|
||||
|
||||
# Compute crc
|
||||
crc = crc32(params)
|
||||
# print([hex(n) for n in int_to_bytes(crc)])
|
||||
# print([hex(n) for n in params])
|
||||
# send crc first
|
||||
ser.write(int_to_bytes(crc))
|
||||
|
||||
# Next, send the parameters.
|
||||
ser.write(params)
|
||||
|
||||
response = ''
|
||||
response = ser.read(response_len)
|
||||
|
||||
# Make sure we got the number of bytes we asked for.
|
||||
if len(response) != response_len:
|
||||
print('No response for command 0x{:08X}'.format(word_from_bytes(params, 0) & 0xFFFF))
|
||||
n = len(response)
|
||||
if (n != 0):
|
||||
print("received bytes ", len(response))
|
||||
print([hex(n) for n in response])
|
||||
raise NoResponseError
|
||||
|
||||
return response
|
||||
|
||||
#******************************************************************************
|
||||
#
|
||||
# Send a command that uses an array of bytes as its parameters.
|
||||
#
|
||||
#******************************************************************************
|
||||
def send_bytewise_command(command, params, response_len, ser):
|
||||
# Send the command first.
|
||||
ser.write(int_to_bytes(command))
|
||||
|
||||
# Next, send the parameters.
|
||||
ser.write(params)
|
||||
|
||||
response = ''
|
||||
response = ser.read(response_len)
|
||||
|
||||
# Make sure we got the number of bytes we asked for.
|
||||
if len(response) != response_len:
|
||||
print('No response for command 0x{:08X}'.format(command))
|
||||
raise NoResponseError
|
||||
|
||||
return response
|
||||
|
||||
#******************************************************************************
|
||||
#
|
||||
# Errors
|
||||
#
|
||||
#******************************************************************************
|
||||
class BootError(Exception):
|
||||
pass
|
||||
|
||||
class NoAckError(BootError):
|
||||
pass
|
||||
|
||||
class NoResponseError(BootError):
|
||||
pass
|
||||
|
||||
#******************************************************************************
|
||||
#
|
||||
# Main program flow
|
||||
#
|
||||
#******************************************************************************
|
||||
if __name__ == '__main__':
|
||||
|
||||
parser = argparse.ArgumentParser(description =
|
||||
'UART Wired Update Host for Apollo3')
|
||||
|
||||
parser.add_argument('port', help = 'Serial COMx Port')
|
||||
|
||||
parser.add_argument('-b', dest='baud', default=115200, type=int,
|
||||
help = 'Baud Rate (default is 115200)')
|
||||
|
||||
parser.add_argument('--raw', dest='raw', default='',
|
||||
help = 'Binary file for raw message')
|
||||
|
||||
parser.add_argument('-f', dest='binfile', default='',
|
||||
help = 'Binary file to program into the target device')
|
||||
|
||||
parser.add_argument('-i', dest = 'imagetype', default=AM_SECBOOT_WIRED_IMAGETYPE_INVALID, type=auto_int,
|
||||
choices = [
|
||||
(AM_SECBOOT_WIRED_IMAGETYPE_SBL),
|
||||
(AM_SECBOOT_WIRED_IMAGETYPE_AM3P),
|
||||
(AM_SECBOOT_WIRED_IMAGETYPE_PATCH),
|
||||
(AM_SECBOOT_WIRED_IMAGETYPE_MAIN),
|
||||
(AM_SECBOOT_WIRED_IMAGETYPE_CHILD),
|
||||
(AM_SECBOOT_WIRED_IMAGETYPE_CUSTPATCH),
|
||||
(AM_SECBOOT_WIRED_IMAGETYPE_NONSECURE),
|
||||
(AM_SECBOOT_WIRED_IMAGETYPE_INFO0),
|
||||
(AM_SECBOOT_WIRED_IMAGETYPE_INFO0_NOOTA),
|
||||
(AM_SECBOOT_WIRED_IMAGETYPE_INVALID)
|
||||
],
|
||||
help = 'ImageType ('
|
||||
+ str(AM_SECBOOT_WIRED_IMAGETYPE_SBL) + ': SBL, '
|
||||
+ str(AM_SECBOOT_WIRED_IMAGETYPE_AM3P) + ': AM3P, '
|
||||
+ str(AM_SECBOOT_WIRED_IMAGETYPE_PATCH) + ': Patch, '
|
||||
+ str(AM_SECBOOT_WIRED_IMAGETYPE_MAIN) + ': Main, '
|
||||
+ str(AM_SECBOOT_WIRED_IMAGETYPE_CHILD) + ': Child, '
|
||||
+ str(AM_SECBOOT_WIRED_IMAGETYPE_CUSTPATCH) + ': CustOTA, '
|
||||
+ str(AM_SECBOOT_WIRED_IMAGETYPE_NONSECURE) + ': NonSecure, '
|
||||
+ str(AM_SECBOOT_WIRED_IMAGETYPE_INFO0) + ': Info0 '
|
||||
+ str(AM_SECBOOT_WIRED_IMAGETYPE_INFO0_NOOTA) + ': Info0_NOOTA) '
|
||||
+ str(AM_SECBOOT_WIRED_IMAGETYPE_INVALID) + ': Invalid) '
|
||||
'- default[Invalid]')
|
||||
|
||||
parser.add_argument('-o', dest = 'otadesc', type=auto_int, default=0xFE000,
|
||||
help = 'OTA Descriptor Page address (hex) - (Default is 0xFE000 - at the end of main flash) - enter 0xFFFFFFFF to instruct SBL to skip OTA')
|
||||
|
||||
parser.add_argument('-r', dest = 'reset', default=1, type=auto_int, choices = [0,1,2],
|
||||
help = 'Should it send reset command after image download? (0 = no reset, 1 = POI, 2 = POR) (default is 1)')
|
||||
|
||||
parser.add_argument('-a', dest = 'abort', default=-1, type=int, choices = [0,1,-1],
|
||||
help = 'Should it send abort command? (0 = abort, 1 = abort and quit, -1 = no abort) (default is -1)')
|
||||
|
||||
parser.add_argument('--split', dest='split', type=auto_int, default=hex(MAX_DOWNLOAD_SIZE),
|
||||
help='Specify the max block size if the image will be downloaded in pieces')
|
||||
|
||||
args = parser.parse_args()
|
||||
|
||||
main()
|
||||
@@ -0,0 +1,17 @@
|
||||
@echo off
|
||||
|
||||
if [%1]==[] goto usage
|
||||
|
||||
jlink -device %1 -CommanderScript jlink-read-info0.txt
|
||||
diff info0.bin info0_dump.bin
|
||||
@ECHO OFF
|
||||
if ERRORLEVEL 1 (
|
||||
echo "INFO0 Invalid"
|
||||
) else (
|
||||
echo "INFO0 Valid"
|
||||
)
|
||||
pause
|
||||
goto :eof
|
||||
:usage
|
||||
@echo Usage: %0 ^<Chip Part#^>
|
||||
exit /B 1
|
||||
@@ -0,0 +1,161 @@
|
||||
#!/usr/bin/env python3
|
||||
#******************************************************************************
|
||||
#
|
||||
# This scripts creates a single Blob, which can be programmed at OTA_POINTER
|
||||
# The first 4 bytes contain address to OTA Descriptor, which immediately follows
|
||||
#
|
||||
#******************************************************************************
|
||||
|
||||
|
||||
import argparse
|
||||
import sys
|
||||
|
||||
magicnum = 0xDEADCAFE
|
||||
|
||||
#******************************************************************************
|
||||
#
|
||||
# Main function
|
||||
#
|
||||
#******************************************************************************
|
||||
def main():
|
||||
|
||||
# Read the binary file from the command line.
|
||||
with open(args.binfile, mode='rb') as binfile:
|
||||
application = binfile.read()
|
||||
|
||||
if len(args.trailerfile) > 0:
|
||||
with open(args.trailerfile, mode='rb') as binfile:
|
||||
trailer= binfile.read()
|
||||
else:
|
||||
trailer = []
|
||||
|
||||
applen = len(application)
|
||||
crc = crc32(application)
|
||||
|
||||
ota_desc = []
|
||||
|
||||
# OTA Descriptor immediately follows the OTA_POINTER
|
||||
ota_desc.extend(int_to_bytes(magicnum))
|
||||
ota_desc.extend(int_to_bytes(int(args.linkaddr, 0)))
|
||||
ota_desc.extend(int_to_bytes(applen))
|
||||
ota_desc.extend(int_to_bytes(crc))
|
||||
|
||||
trailerlen = len(trailer)
|
||||
ota_desc.extend(int_to_bytes(trailerlen))
|
||||
ota_desc.extend(int_to_bytes(int(args.options, 0)))
|
||||
ota_desc.extend(int_to_bytes(int(args.flashaddr , 0)+ 40)) # pui32SecInfoPtr
|
||||
if (args.otaimageaddr != 0):
|
||||
# Image has been flashed seprately. Just code the address in descriptor
|
||||
ota_desc.extend(int_to_bytes(int(args.otaimageaddr, 0))) # pui32ImageAddr
|
||||
else:
|
||||
# Image is written immediately following the OTA descriptor
|
||||
# Need to determine if there is a padding needed in between to ensure proper alignment
|
||||
image_addr = int(args.flashaddr , 0) + 40 + trailerlen
|
||||
if (image_addr % int(args.alignment) != 0):
|
||||
pad_size = int(args.alignment) - (image_addr % int(args.alignment))
|
||||
else:
|
||||
pad_size = 0
|
||||
image_addr = image_addr + pad_size
|
||||
ota_desc.extend(int_to_bytes(image_addr)) # pui32ImageAddr
|
||||
ota_desc_crc = crc32(ota_desc)
|
||||
# OTA_POINTER contents
|
||||
new_image = []
|
||||
new_image.extend(int_to_bytes(int(args.flashaddr , 0)+ 4)) # OTA Descriptor address
|
||||
new_image.extend(ota_desc) # OTA Descriptor
|
||||
new_image.extend(int_to_bytes(ota_desc_crc))
|
||||
|
||||
if trailerlen > 0:
|
||||
print('Adding Security Trailer')
|
||||
new_image.extend(trailer)
|
||||
if (pad_size != 0):
|
||||
print('Adding padding of {} bytes...'.format(pad_size), flush=True)
|
||||
pad_binarray = bytearray([0]*pad_size);
|
||||
new_image.extend(pad_binarray)
|
||||
if (args.otaimageaddr == 0):
|
||||
# Image
|
||||
new_image.extend(application)
|
||||
print('Saving OTA descriptor image {} bytes to {}...'.format(len(new_image), args.outfile), flush=True)
|
||||
with open(args.outfile, mode='wb') as imagefile:
|
||||
imagebytearray = bytearray(new_image)
|
||||
imagefile.write(imagebytearray)
|
||||
|
||||
print('Done.')
|
||||
|
||||
#******************************************************************************
|
||||
#
|
||||
# Turn a 32-bit number into a series of bytes for transmission.
|
||||
#
|
||||
# This command will split a 32-bit integer into an array of bytes, ordered
|
||||
# LSB-first for transmission over the UART.
|
||||
#
|
||||
#******************************************************************************
|
||||
def int_to_bytes(n):
|
||||
A = [n & 0xFF,
|
||||
(n >> 8) & 0xFF,
|
||||
(n >> 16) & 0xFF,
|
||||
(n >> 24) & 0xFF]
|
||||
|
||||
return A
|
||||
|
||||
#******************************************************************************
|
||||
#
|
||||
# Extract a word from a byte array
|
||||
#
|
||||
#******************************************************************************
|
||||
def word_from_bytes(B, n):
|
||||
return (B[n] + (B[n + 1] << 8) + (B[n + 2] << 16) + (B[n + 3] << 24))
|
||||
|
||||
#******************************************************************************
|
||||
#
|
||||
# CRC function that matches the CRC used by the Apollo bootloader.
|
||||
#
|
||||
#******************************************************************************
|
||||
poly32 = 0x1EDC6F41
|
||||
def crc32(L):
|
||||
rem = 0
|
||||
for b in L:
|
||||
rem = rem ^ (b << 24)
|
||||
for i in range(8):
|
||||
if rem & 0x80000000:
|
||||
rem = ((rem << 1) ^ poly32)
|
||||
else:
|
||||
rem = (rem << 1)
|
||||
|
||||
rem = rem & 0xFFFFFFFF
|
||||
return rem
|
||||
|
||||
#******************************************************************************
|
||||
#
|
||||
# Main program flow
|
||||
#
|
||||
#******************************************************************************
|
||||
if __name__ == '__main__':
|
||||
|
||||
parser = argparse.ArgumentParser(description =
|
||||
'Utility to generate OTA blob for multi boot test app')
|
||||
parser.add_argument('binfile',
|
||||
help = 'Binary file to program into the target device')
|
||||
|
||||
parser.add_argument('flashaddr', help = 'Flash address (hex) where blob will be flashed to')
|
||||
|
||||
parser.add_argument('linkaddr', help = 'Link address (hex) of the program file')
|
||||
|
||||
parser.add_argument('-a', dest = 'alignment', default=4,
|
||||
help = 'Desired alignment for application in image')
|
||||
|
||||
parser.add_argument('options',
|
||||
help = 'OTA options parameter')
|
||||
|
||||
parser.add_argument('-s', dest = 'trailerfile', default='',
|
||||
help = 'Binary file for (optional) security trailer')
|
||||
|
||||
parser.add_argument('-i', dest='otaimageaddr', default=0,
|
||||
help = '(optional) Flash address (hex) where the OTA image is flashed to - if not specified, the image is included in outfile immediately following the descriptor')
|
||||
|
||||
|
||||
parser.add_argument('-o', dest = 'outfile',
|
||||
help = 'output filename for the ota descriptor')
|
||||
|
||||
args = parser.parse_args()
|
||||
|
||||
main()
|
||||
@@ -0,0 +1,263 @@
|
||||
#!/usr/bin/env python3
|
||||
|
||||
import argparse
|
||||
import serial
|
||||
import sys
|
||||
|
||||
#******************************************************************************
|
||||
#
|
||||
# Main function
|
||||
#
|
||||
#******************************************************************************
|
||||
def main():
|
||||
|
||||
# Open a serial port, and load the image at the specified address.
|
||||
#
|
||||
# We will use a UART timeout value of 12 second. This should be long
|
||||
# enough that the slave will respond to us, but short enough that a human
|
||||
# operator should see errors quickly..
|
||||
# Max flashing time depends on the amount of SRAM available.
|
||||
# For very large images, the flashing happens page by page.
|
||||
# However if the image can fit in the free SRAM, it could take a long time
|
||||
# for the whole image to be flashed at the end.
|
||||
# The largest image which can be stored depends on the max SRAM.
|
||||
# Assuming worst case ~100 ms/page of flashing time, and allowing for the
|
||||
# image to be close to occupying full SRAM (256K) which is 128 pages.
|
||||
|
||||
# Read the binary file from the command line.
|
||||
with open(args.binfile, mode='rb') as binfile:
|
||||
application = binfile.read()
|
||||
|
||||
if len(args.trailerfile) > 0:
|
||||
with open(args.trailerfile, mode='rb') as binfile:
|
||||
trailer= binfile.read()
|
||||
else:
|
||||
trailer = []
|
||||
|
||||
print('Loading {} bytes over serial port {}...'.format(len(application), args.port), flush=True)
|
||||
|
||||
with serial.Serial(args.port, args.baud, timeout=12) as ser:
|
||||
load_image(application, trailer, int(args.address, 0), ser)
|
||||
|
||||
print('Done.')
|
||||
|
||||
#******************************************************************************
|
||||
#
|
||||
# Load image
|
||||
#
|
||||
# Given a serial port and a binary file, loads the target device using the
|
||||
# UART.
|
||||
#
|
||||
#******************************************************************************
|
||||
def load_image(application, trailer, address, ser):
|
||||
|
||||
# Gather the important binary metadata.
|
||||
applen = len(application)
|
||||
crc = crc32(application)
|
||||
|
||||
new_image = []
|
||||
new_image.extend(int_to_bytes(address))
|
||||
new_image.extend(int_to_bytes(applen))
|
||||
new_image.extend(int_to_bytes(crc))
|
||||
|
||||
trailerlen = len(trailer)
|
||||
if trailerlen > 0:
|
||||
print('Adding Security Trailer')
|
||||
new_image.extend(int_to_bytes(trailerlen))
|
||||
new_image.extend(trailer)
|
||||
|
||||
#print([hex(n) for n in new_image])
|
||||
|
||||
if (args.bauddetect):
|
||||
# Making sure autobaud gets set.
|
||||
ser.write([0x55])
|
||||
response = ser.read(1)
|
||||
|
||||
# Make sure we got the number of bytes we asked for.
|
||||
if len(response) == 0:
|
||||
raise NoResponseError
|
||||
|
||||
# Send a New Image command.
|
||||
response = send_bytewise_command(0x2, new_image, 4, ser)
|
||||
|
||||
if response[0] != 0x2:
|
||||
raise NoAckError
|
||||
|
||||
# Set the override pin.
|
||||
send_ackd_command(0x5, [args.ovr, args.level], ser)
|
||||
|
||||
# Loop over the bytes in the image, and send them to the target.
|
||||
resp = 0
|
||||
for x in range(0, applen, 512):
|
||||
# Split the application into chunks of 512 bytes.
|
||||
# This is the max chunk size supported by the UART bootloader
|
||||
chunk = application[x:x+512]
|
||||
|
||||
# Build a data packet with a "data command" a "length" and the actual
|
||||
# payload bytes, and send it to the target.
|
||||
resp = send_bytewise_command(0x3, int_to_bytes(len(chunk)) + list(chunk), 4, ser)
|
||||
|
||||
# Check the CRC.
|
||||
if word_from_bytes(resp, 0) == 0x3:
|
||||
|
||||
# If the CRC was good, optionally reset the target and let it run.
|
||||
if (args.reset):
|
||||
send_command(0x4, [], 0, ser)
|
||||
else:
|
||||
print('CRC was bad')
|
||||
|
||||
#******************************************************************************
|
||||
#
|
||||
# Send ACK'd command
|
||||
#
|
||||
# Sends a command, and waits for an ACK.
|
||||
#
|
||||
#******************************************************************************
|
||||
def send_ackd_command(command, params, ser):
|
||||
response = send_command(command, params, 4, ser)
|
||||
|
||||
if response[0] != 0x2:
|
||||
raise NoAckError
|
||||
|
||||
#******************************************************************************
|
||||
#
|
||||
# Send command
|
||||
#
|
||||
# Sends a command, and waits for the response.
|
||||
#
|
||||
#******************************************************************************
|
||||
def send_command(command, params, response_len, ser):
|
||||
|
||||
# Send the command first.
|
||||
ser.write(int_to_bytes(command))
|
||||
|
||||
# Next, send the parameters.
|
||||
for param in params:
|
||||
ser.write(int_to_bytes(param))
|
||||
|
||||
response = ''
|
||||
response = ser.read(response_len)
|
||||
|
||||
# Make sure we got the number of bytes we asked for.
|
||||
if len(response) != response_len:
|
||||
print('No response for command 0x{:08X}'.format(command))
|
||||
raise NoResponseError
|
||||
|
||||
return response
|
||||
|
||||
#******************************************************************************
|
||||
#
|
||||
# Send a command that uses an array of bytes as its parameters.
|
||||
#
|
||||
#******************************************************************************
|
||||
def send_bytewise_command(command, params, response_len, ser):
|
||||
# Send the command first.
|
||||
ser.write(int_to_bytes(command))
|
||||
|
||||
# Next, send the parameters.
|
||||
ser.write(params)
|
||||
|
||||
response = ''
|
||||
response = ser.read(response_len)
|
||||
|
||||
# Make sure we got the number of bytes we asked for.
|
||||
if len(response) != response_len:
|
||||
print('No response for command 0x{:08X}'.format(command))
|
||||
raise NoResponseError
|
||||
|
||||
return response
|
||||
|
||||
#******************************************************************************
|
||||
#
|
||||
# Turn a 32-bit number into a series of bytes for transmission.
|
||||
#
|
||||
# This command will split a 32-bit integer into an array of bytes, ordered
|
||||
# LSB-first for transmission over the UART.
|
||||
#
|
||||
#******************************************************************************
|
||||
def int_to_bytes(n):
|
||||
A = [n & 0xFF,
|
||||
(n >> 8) & 0xFF,
|
||||
(n >> 16) & 0xFF,
|
||||
(n >> 24) & 0xFF]
|
||||
|
||||
return A
|
||||
|
||||
#******************************************************************************
|
||||
#
|
||||
# Extract a word from a byte array
|
||||
#
|
||||
#******************************************************************************
|
||||
def word_from_bytes(B, n):
|
||||
return (B[n] + (B[n + 1] << 8) + (B[n + 2] << 16) + (B[n + 3] << 24))
|
||||
|
||||
#******************************************************************************
|
||||
#
|
||||
# CRC function that matches the CRC used by the Apollo bootloader.
|
||||
#
|
||||
#******************************************************************************
|
||||
poly32 = 0x1EDC6F41
|
||||
def crc32(L):
|
||||
rem = 0
|
||||
for b in L:
|
||||
rem = rem ^ (b << 24)
|
||||
for i in range(8):
|
||||
if rem & 0x80000000:
|
||||
rem = ((rem << 1) ^ poly32)
|
||||
else:
|
||||
rem = (rem << 1)
|
||||
|
||||
rem = rem & 0xFFFFFFFF
|
||||
return rem
|
||||
|
||||
#******************************************************************************
|
||||
#
|
||||
# Errors
|
||||
#
|
||||
#******************************************************************************
|
||||
class BootError(Exception):
|
||||
pass
|
||||
|
||||
class NoAckError(BootError):
|
||||
pass
|
||||
|
||||
class NoResponseError(BootError):
|
||||
pass
|
||||
|
||||
#******************************************************************************
|
||||
#
|
||||
# Main program flow
|
||||
#
|
||||
#******************************************************************************
|
||||
if __name__ == '__main__':
|
||||
|
||||
parser = argparse.ArgumentParser(description =
|
||||
'UART Boot Host for Apollo or Apollo2')
|
||||
parser.add_argument('binfile',
|
||||
help = 'Binary file to program into the target device')
|
||||
|
||||
parser.add_argument('address', help = 'Link address (hex)')
|
||||
|
||||
parser.add_argument('port', help = 'Serial COMx Port')
|
||||
|
||||
parser.add_argument('-b', dest='baud', default=115200, type=int,
|
||||
help = 'Baud Rate (default is 115200)')
|
||||
|
||||
parser.add_argument('-o', dest ='ovr', default = 18, type=int,
|
||||
help = 'Override pin (default is 18)')
|
||||
|
||||
parser.add_argument('-l', dest='level', default=0, type=int,
|
||||
help = 'Override pin polarity (0 or 1) Default is active low')
|
||||
|
||||
parser.add_argument('-s', dest = 'trailerfile', default='',
|
||||
help = 'Binary file for (optional) security trailer')
|
||||
|
||||
parser.add_argument('-r', dest = 'reset', default=1, type=int,
|
||||
help = 'Should it send reset command after image download? (0/1) (default is 1)')
|
||||
|
||||
parser.add_argument('-a', dest = 'bauddetect', default=1, type=int,
|
||||
help = 'Should it send a preamble for slave to detect the baudrate? (0/1) (default is 1)')
|
||||
|
||||
args = parser.parse_args()
|
||||
|
||||
main()
|
||||
@@ -0,0 +1,670 @@
|
||||
#!/usr/bin/env python3
|
||||
|
||||
# *****************************************************************************
|
||||
#
|
||||
# pinconfig.py
|
||||
#
|
||||
# @brief Script for generating a BSP pin file.
|
||||
|
||||
# *****************************************************************************
|
||||
|
||||
# *****************************************************************************
|
||||
#
|
||||
# Copyright (c) 2020, Ambiq Micro
|
||||
# All rights reserved.
|
||||
#
|
||||
# Redistribution and use in source and binary forms, with or without
|
||||
# modification, are permitted provided that the following conditions are met:
|
||||
#
|
||||
# 1. Redistributions of source code must retain the above copyright notice,
|
||||
# this list of conditions and the following disclaimer.
|
||||
#
|
||||
# 2. Redistributions in binary form must reproduce the above copyright
|
||||
# notice, this list of conditions and the following disclaimer in the
|
||||
# documentation and/or other materials provided with the distribution.
|
||||
#
|
||||
# 3. Neither the name of the copyright holder nor the names of its
|
||||
# contributors may be used to endorse or promote products derived from this
|
||||
# software without specific prior written permission.
|
||||
#
|
||||
# Third party software included in this distribution is subject to the
|
||||
# additional license terms as defined in the /docs/licenses directory.
|
||||
#
|
||||
# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
|
||||
# AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||
# IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
||||
# ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
|
||||
# LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
|
||||
# CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
|
||||
# SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
|
||||
# INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
|
||||
# CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
|
||||
# ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
|
||||
# POSSIBILITY OF SUCH DAMAGE.
|
||||
#
|
||||
# This is part of revision 2.4.2 of the AmbiqSuite Development Package.
|
||||
#
|
||||
# *****************************************************************************
|
||||
|
||||
# *****************************************************************************
|
||||
# Imported modules
|
||||
# *****************************************************************************
|
||||
import argparse
|
||||
import textwrap
|
||||
import os.path
|
||||
import rsonlite
|
||||
|
||||
|
||||
# *****************************************************************************
|
||||
# Templates
|
||||
# *****************************************************************************
|
||||
filetemplateC = '''
|
||||
//*****************************************************************************
|
||||
//
|
||||
// {filename}
|
||||
//! @file
|
||||
//!
|
||||
//! @brief BSP pin configuration definitions.
|
||||
//!
|
||||
//! @addtogroup BSP Board Support Package (BSP)
|
||||
//! @ingroup BSP
|
||||
//! @{{
|
||||
//
|
||||
//*****************************************************************************
|
||||
|
||||
//*****************************************************************************
|
||||
//
|
||||
// Copyright (c) 2020, Ambiq Micro
|
||||
// All rights reserved.
|
||||
//
|
||||
// Redistribution and use in source and binary forms, with or without
|
||||
// modification, are permitted provided that the following conditions are met:
|
||||
//
|
||||
// 1. Redistributions of source code must retain the above copyright notice,
|
||||
// this list of conditions and the following disclaimer.
|
||||
//
|
||||
// 2. Redistributions in binary form must reproduce the above copyright
|
||||
// notice, this list of conditions and the following disclaimer in the
|
||||
// documentation and/or other materials provided with the distribution.
|
||||
//
|
||||
// 3. Neither the name of the copyright holder nor the names of its
|
||||
// contributors may be used to endorse or promote products derived from this
|
||||
// software without specific prior written permission.
|
||||
//
|
||||
// Third party software included in this distribution is subject to the
|
||||
// additional license terms as defined in the /docs/licenses directory.
|
||||
//
|
||||
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
|
||||
// AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||
// IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
||||
// ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
|
||||
// LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
|
||||
// CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
|
||||
// SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
|
||||
// INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
|
||||
// CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
|
||||
// ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
|
||||
// POSSIBILITY OF SUCH DAMAGE.
|
||||
//
|
||||
// This is part of revision 2.4.2 of the AmbiqSuite Development Package.
|
||||
//
|
||||
//*****************************************************************************
|
||||
|
||||
#include "am_bsp.h"
|
||||
{pin_defs}
|
||||
//*****************************************************************************
|
||||
//
|
||||
// End Doxygen group.
|
||||
//! @}}
|
||||
//
|
||||
//*****************************************************************************
|
||||
'''.strip()
|
||||
|
||||
|
||||
filetemplateH = '''
|
||||
//*****************************************************************************
|
||||
//
|
||||
// {filename}
|
||||
//! @file
|
||||
//!
|
||||
//! @brief BSP pin configuration definitions.
|
||||
//!
|
||||
//! @addtogroup BSP Board Support Package (BSP)
|
||||
//! @addtogroup apollo3_bsp BSP for the Apollo3 EVB.
|
||||
//! @ingroup BSP
|
||||
//! @{{
|
||||
//
|
||||
//*****************************************************************************
|
||||
|
||||
//*****************************************************************************
|
||||
//
|
||||
// Copyright (c) 2020, Ambiq Micro
|
||||
// All rights reserved.
|
||||
//
|
||||
// Redistribution and use in source and binary forms, with or without
|
||||
// modification, are permitted provided that the following conditions are met:
|
||||
//
|
||||
// 1. Redistributions of source code must retain the above copyright notice,
|
||||
// this list of conditions and the following disclaimer.
|
||||
//
|
||||
// 2. Redistributions in binary form must reproduce the above copyright
|
||||
// notice, this list of conditions and the following disclaimer in the
|
||||
// documentation and/or other materials provided with the distribution.
|
||||
//
|
||||
// 3. Neither the name of the copyright holder nor the names of its
|
||||
// contributors may be used to endorse or promote products derived from this
|
||||
// software without specific prior written permission.
|
||||
//
|
||||
// Third party software included in this distribution is subject to the
|
||||
// additional license terms as defined in the /docs/licenses directory.
|
||||
//
|
||||
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
|
||||
// AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||
// IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
||||
// ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
|
||||
// LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
|
||||
// CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
|
||||
// SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
|
||||
// INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
|
||||
// CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
|
||||
// ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
|
||||
// POSSIBILITY OF SUCH DAMAGE.
|
||||
//
|
||||
// This is part of revision 2.4.2 of the AmbiqSuite Development Package.
|
||||
//
|
||||
//*****************************************************************************
|
||||
|
||||
#ifndef {headerdef}
|
||||
#define {headerdef}
|
||||
|
||||
#include <stdint.h>
|
||||
#include <stdbool.h>
|
||||
#include "am_mcu_apollo.h"
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C"
|
||||
{{
|
||||
#endif
|
||||
{pin_defs}
|
||||
|
||||
#ifdef __cplusplus
|
||||
}}
|
||||
#endif
|
||||
|
||||
#endif // {headerdef}
|
||||
|
||||
//*****************************************************************************
|
||||
//
|
||||
// End Doxygen group.
|
||||
//! @}}
|
||||
//
|
||||
//*****************************************************************************
|
||||
'''.strip()
|
||||
|
||||
|
||||
sectiontemplate = '''
|
||||
|
||||
//*****************************************************************************
|
||||
//
|
||||
// {pin_descr}
|
||||
//
|
||||
//*****************************************************************************
|
||||
'''.strip()
|
||||
|
||||
|
||||
# *****************************************************************************
|
||||
#
|
||||
# Globals
|
||||
#
|
||||
# *****************************************************************************
|
||||
|
||||
# *****************************************************************************
|
||||
#
|
||||
# Command line support.
|
||||
#
|
||||
# *****************************************************************************
|
||||
def read_arguments():
|
||||
parser = argparse.ArgumentParser()
|
||||
|
||||
parser.add_argument('input', help='input src file name')
|
||||
parser.add_argument('CorH', help='C to create C file, H to create H file',
|
||||
choices=['C','H','c','h'])
|
||||
|
||||
return parser.parse_args()
|
||||
|
||||
# *****************************************************************************
|
||||
# parse_input()
|
||||
# *****************************************************************************
|
||||
def parse_input(filename):
|
||||
'''
|
||||
Simple wrapper to pull an rsonlite list from given file.
|
||||
'''
|
||||
with open(filename) as f:
|
||||
data = f.read()
|
||||
return rsonlite.loads(data)
|
||||
|
||||
# *****************************************************************************
|
||||
# list_to_dict()
|
||||
# *****************************************************************************
|
||||
def list_to_dict(L):
|
||||
'''
|
||||
rsonlite loads data from the rson files as a very-nested list. This
|
||||
function converts that list to a set of nested dictionaries. At each level,
|
||||
the dictionary keys correspond to the "headings", and the dictionary values
|
||||
are a list of the items under that "heading". Values assigned by
|
||||
equals-sign statements are (unfortunately) also converted to (key, list)
|
||||
pairs, the same way that subheadings are.
|
||||
'''
|
||||
if len(L) == 1:
|
||||
return L[0]
|
||||
else:
|
||||
D = dict()
|
||||
for x in L:
|
||||
if x[0] in D:
|
||||
D[x[0]] = D[x[0]] + [list_to_dict(x[1])]
|
||||
else:
|
||||
D[x[0]] = [list_to_dict(x[1])]
|
||||
return D
|
||||
|
||||
# *****************************************************************************
|
||||
# get_val()
|
||||
# *****************************************************************************
|
||||
def get_val(name, D):
|
||||
'''
|
||||
get_val is just a helper to make it more obvious when you are trying to get
|
||||
at an equals-sign-assigned value from the rson file dictionary.
|
||||
'''
|
||||
if name not in D:
|
||||
return "ERROR: {} VALUE MISSING".format(name)
|
||||
else:
|
||||
return D[name][0]
|
||||
|
||||
# *****************************************************************************
|
||||
# get_version()
|
||||
# *****************************************************************************
|
||||
def get_version(filename):
|
||||
'''
|
||||
Given the filename of an 'src' file, this function will return a 'pin'
|
||||
object corresponding to the fields described in the src file.
|
||||
'''
|
||||
# Read in the contents of the src file, and use the rsonlite library to
|
||||
# parse them into a list.
|
||||
rson_data = parse_input(filename)
|
||||
|
||||
# Convert the list to a dictionary.
|
||||
rson_dict = list_to_dict(rson_data)
|
||||
|
||||
if 'pinsrc_ver' in rson_dict:
|
||||
# Convert rson list object to int
|
||||
ssrcver = rson_dict["pinsrc_ver"][0]
|
||||
if ssrcver[0:2].lower() == "0x":
|
||||
source_version = int(ssrcver, 16)
|
||||
else:
|
||||
source_version = int(ssrcver, 10)
|
||||
else:
|
||||
# If no src file version given, assume version for Apollo3
|
||||
source_version = 0x0003
|
||||
|
||||
return source_version
|
||||
|
||||
# *****************************************************************************
|
||||
# get_pinobj()
|
||||
# *****************************************************************************
|
||||
def get_pinobj(filename):
|
||||
'''
|
||||
Given the filename of an 'src' file, this function will return a 'pin'
|
||||
object corresponding to the fields described in the src file.
|
||||
'''
|
||||
|
||||
# Set the location for the supplementary files (infoblock, base addresses, etc.)
|
||||
srcdir = os.path.dirname(filename)
|
||||
|
||||
# Read in the contents of the src file, and use the rsonlite library to
|
||||
# parse them into a list.
|
||||
rson_data = parse_input(filename)
|
||||
|
||||
# Convert the list to a dictionary.
|
||||
rson_dict = list_to_dict(rson_data)
|
||||
|
||||
# Convert the dictionary to a block object, which will create field
|
||||
# objects as necessary. Return this object to the caller.
|
||||
return pinobj(rson_dict)
|
||||
|
||||
|
||||
# *****************************************************************************
|
||||
# pinfields
|
||||
# *****************************************************************************
|
||||
class pinfields:
|
||||
def __init__(self, pindict):
|
||||
|
||||
self.name = ''
|
||||
self.desc = ''
|
||||
self.pinnum = 0
|
||||
self.powersw = ''
|
||||
self.pullup = ''
|
||||
self.func_sel = ''
|
||||
self.drvstrength = 0
|
||||
self.intdir = 0
|
||||
self.GPOutcfg = ''
|
||||
self.GPinput = ''
|
||||
self.GPRdZero = ''
|
||||
self.IOMnum = ''
|
||||
self.CEnum = ''
|
||||
self.CEpol = ''
|
||||
self.bIomMSPIn = ''
|
||||
|
||||
intnotgiven = 65535
|
||||
strnotgiven = 'none_given'
|
||||
|
||||
if 'name' in pindict:
|
||||
self.name = get_val('name', pindict)
|
||||
else:
|
||||
self.name = strnotgiven
|
||||
|
||||
if 'desc' in pindict:
|
||||
self.desc = get_val('desc', pindict)
|
||||
else:
|
||||
self.desc = strnotgiven
|
||||
|
||||
if 'pinnum' in pindict:
|
||||
self.pinnum = int(get_val('pinnum', pindict))
|
||||
else:
|
||||
self.pinnum = intnotgiven
|
||||
|
||||
if 'powersw' in pindict:
|
||||
self.powersw = get_val('powersw', pindict)
|
||||
else:
|
||||
self.powersw = strnotgiven
|
||||
|
||||
if 'pullup' in pindict:
|
||||
self.pullup = get_val('pullup', pindict)
|
||||
else:
|
||||
self.pullup = strnotgiven
|
||||
|
||||
if 'func_sel' in pindict:
|
||||
self.func_sel = get_val('func_sel', pindict)
|
||||
else:
|
||||
self.func_sel = strnotgiven
|
||||
|
||||
if 'drvstrength' in pindict:
|
||||
self.drvstrength = int(get_val('drvstrength', pindict))
|
||||
else:
|
||||
self.drvstrength = intnotgiven
|
||||
|
||||
if 'intdir' in pindict:
|
||||
self.intdir = get_val('intdir', pindict)
|
||||
else:
|
||||
self.intdir = strnotgiven
|
||||
|
||||
if 'GPOutcfg' in pindict:
|
||||
self.GPOutcfg = get_val('GPOutcfg', pindict)
|
||||
else:
|
||||
self.GPOutcfg = strnotgiven
|
||||
|
||||
if 'GPinput' in pindict:
|
||||
self.GPinput = get_val('GPinput', pindict)
|
||||
else:
|
||||
self.GPinput = strnotgiven
|
||||
|
||||
if 'GPRdZero' in pindict:
|
||||
self.GPRdZero = get_val('GPRdZero', pindict)
|
||||
else:
|
||||
self.GPRdZero = strnotgiven
|
||||
|
||||
if 'IOMnum' in pindict:
|
||||
self.IOMnum = get_val('IOMnum', pindict)
|
||||
elif 'MSPInum' in pindict:
|
||||
self.IOMnum = get_val('MSPInum', pindict)
|
||||
else:
|
||||
self.IOMnum = strnotgiven
|
||||
|
||||
if 'CEnum' in pindict:
|
||||
self.CEnum = get_val('CEnum', pindict)
|
||||
else:
|
||||
self.CEnum = strnotgiven
|
||||
|
||||
if 'CEpol' in pindict:
|
||||
self.CEpol = get_val('CEpol', pindict)
|
||||
else:
|
||||
self.CEpol = strnotgiven
|
||||
|
||||
if 'bIomMSPIn' in pindict:
|
||||
self.bIomMSPIn = get_val('bIomMSPIn', pindict)
|
||||
else:
|
||||
self.bIomMSPIn = strnotgiven
|
||||
|
||||
#
|
||||
# Check for an invalid field in the src file. If so, report it.
|
||||
#
|
||||
for fld in pindict:
|
||||
if fld != 'name' and \
|
||||
fld != 'desc' and \
|
||||
fld != 'pinnum' and \
|
||||
fld != 'powersw' and \
|
||||
fld != 'pullup' and \
|
||||
fld != 'func_sel' and \
|
||||
fld != 'drvstrength' and \
|
||||
fld != 'intdir' and \
|
||||
fld != 'GPOutcfg' and \
|
||||
fld != 'GPinput' and \
|
||||
fld != 'GPRdZero' and \
|
||||
fld != 'IOMnum' and \
|
||||
fld != 'MSPInum' and \
|
||||
fld != 'CEnum' and \
|
||||
fld != 'CEpol' and \
|
||||
fld != 'bIomMSPIn':
|
||||
print("Invalid field: '%s.%s'" % (self.name, fld))
|
||||
|
||||
|
||||
# *****************************************************************************
|
||||
# pinobj
|
||||
# *****************************************************************************
|
||||
class pinobj:
|
||||
def __init__(self, pindict):
|
||||
self.name = 'name'
|
||||
self.srcver=0x0000
|
||||
self.pins = []
|
||||
|
||||
if 'pinsrc_ver' in pindict:
|
||||
# Convert rson list object to int
|
||||
ssrcver = pindict["pinsrc_ver"][0]
|
||||
if ssrcver[0:2].lower() == "0x":
|
||||
self.srcver = int(ssrcver,16)
|
||||
else:
|
||||
self.srcver = int(ssrcver,10)
|
||||
else:
|
||||
# If no src file version given, assume version for Apollo3
|
||||
self.srcver = 0x0003
|
||||
|
||||
# Run through all the pins given in the src file
|
||||
if 'pin' in pindict:
|
||||
#
|
||||
# Run through the 'pin' list.
|
||||
#
|
||||
for pin in pindict['pin']:
|
||||
self.pins.append(pinfields(pin))
|
||||
|
||||
# *****************************************************************************
|
||||
# write_Cfiles()
|
||||
# *****************************************************************************
|
||||
|
||||
def write_Cfiles(pinobj, bCreateC):
|
||||
#
|
||||
# Initializations
|
||||
#
|
||||
intnotgiven = 65535
|
||||
strnotgiven = 'none_given'
|
||||
strCfile = ''
|
||||
strHfile = ''
|
||||
|
||||
for pin in pinobj.pins:
|
||||
sectiondesc = pin.name.strip() + ' pin'
|
||||
if pin.desc == strnotgiven:
|
||||
sectiondesc += '.'
|
||||
else:
|
||||
sectiondesc += ': ' + pin.desc.strip()
|
||||
if sectiondesc[-1] != '.':
|
||||
sectiondesc += '.'
|
||||
strCfile += '\n'
|
||||
strCfile += sectiontemplate.format(pin_descr=sectiondesc)
|
||||
strCfile += '\n'
|
||||
strHfile += '\n'
|
||||
strHfile += sectiontemplate.format(pin_descr=sectiondesc)
|
||||
strHfile += '\n'
|
||||
|
||||
if pin.pinnum != intnotgiven:
|
||||
strHfile += '#define AM_BSP_GPIO_%-20s' % pin.name + '%d\n' % pin.pinnum
|
||||
strHfile += 'extern const am_hal_gpio_pincfg_t g_AM_BSP_GPIO_%s;\n' % pin.name
|
||||
#strHfile += '\n'
|
||||
|
||||
strCfile += 'const am_hal_gpio_pincfg_t g_AM_BSP_GPIO_%s =\n' % pin.name
|
||||
strCfile += '{\n'
|
||||
strCfile += '%-25s' % ' .uFuncSel' + '= %s,\n' % pin.func_sel
|
||||
|
||||
if pin.powersw != strnotgiven:
|
||||
if (pin.powersw.lower() == "vdd") or \
|
||||
(pin.powersw.lower() == "vss") or \
|
||||
(pin.powersw.lower() == "none"):
|
||||
strCfile += '%-25s' % ' .ePowerSw' + '= AM_HAL_GPIO_PIN_POWERSW_%s,\n' % pin.powersw.upper()
|
||||
else:
|
||||
strCfile += '%-25s' % ' .ePowerSw' + '= %s,\n' % pin.powersw
|
||||
|
||||
if pin.pullup != strnotgiven:
|
||||
if (pin.pullup.lower() == "none") or \
|
||||
(pin.pullup.lower() == "weak") or \
|
||||
(pin.pullup.lower() == "pulldown") or \
|
||||
(pin.pullup.lower() == "1_5k") or \
|
||||
(pin.pullup.lower() == "6k") or \
|
||||
(pin.pullup.lower() == "12k") or \
|
||||
(pin.pullup.lower() == "24k"):
|
||||
strCfile += '%-25s' % ' .ePullup' + '= AM_HAL_GPIO_PIN_PULLUP_%s,\n' % pin.pullup.upper()
|
||||
elif (pin.pullup == "1_5") or \
|
||||
(pin.pullup == "6") or \
|
||||
(pin.pullup == "12") or \
|
||||
(pin.pullup == "24"):
|
||||
strCfile += '%-25s' % ' .ePullup' + '= AM_HAL_GPIO_PIN_PULLUP_%sK,\n' % pin.pullup
|
||||
else:
|
||||
strCfile += '%-25s' % ' .ePullup' + '= %s,\n' % pin.pullup
|
||||
|
||||
if pin.drvstrength != intnotgiven:
|
||||
if (pin.drvstrength != 2) and (pin.drvstrength != 4) and \
|
||||
(pin.drvstrength != 8) and (pin.drvstrength != 12):
|
||||
pin.drvstrength = 2
|
||||
strCfile += '%-25s' % ' .eDriveStrength' + '= AM_HAL_GPIO_PIN_DRIVESTRENGTH_%dMA,\n' % pin.drvstrength
|
||||
|
||||
if pin.GPOutcfg != strnotgiven:
|
||||
if (pin.GPOutcfg.lower() == "disable") or \
|
||||
(pin.GPOutcfg.lower() == "pushpull") or \
|
||||
(pin.GPOutcfg.lower() == "opendrain") or \
|
||||
(pin.GPOutcfg.lower() == "tristate"):
|
||||
strCfile += '%-25s' % ' .eGPOutcfg' + '= AM_HAL_GPIO_PIN_OUTCFG_%s,\n' % pin.GPOutcfg.upper()
|
||||
else:
|
||||
strCfile += '%-25s' % ' .eGPOutcfg' + '= %s,\n' % pin.GPOutcfg
|
||||
|
||||
if pin.GPinput != strnotgiven:
|
||||
if (pin.GPinput.lower() == "true"):
|
||||
strCfile += '%-25s' % ' .eGPInput' + '= AM_HAL_GPIO_PIN_INPUT_ENABLE,\n'
|
||||
elif (pin.GPinput.lower() == "false"):
|
||||
strCfile += '%-25s' % ' .eGPInput' + '= AM_HAL_GPIO_PIN_INPUT_NONE,\n'
|
||||
else:
|
||||
strCfile += '%-25s' % ' .eGPInput' + '= %s,\n' % pin.GPinput
|
||||
|
||||
if pin.GPRdZero != strnotgiven:
|
||||
if (pin.GPRdZero.lower() == "true") or \
|
||||
(pin.GPRdZero.lower() == "zero"):
|
||||
strCfile += '%-25s' % ' .eGPRdZero' + '= AM_HAL_GPIO_PIN_RDZERO_ZERO,\n'
|
||||
elif (pin.GPRdZero.lower() == "false") or \
|
||||
(pin.GPRdZero.lower() == "readpin"):
|
||||
strCfile += '%-25s' % ' .eGPRdZero' + '= AM_HAL_GPIO_PIN_RDZERO_READPIN,\n'
|
||||
else:
|
||||
strCfile += '%-25s' % ' .eGPRdZero' + '= %s,\n' % pin.GPRdZero
|
||||
|
||||
if pin.intdir != strnotgiven:
|
||||
if (pin.intdir.lower() == "none") or \
|
||||
(pin.intdir.lower() == "lo2hi") or \
|
||||
(pin.intdir.lower() == "hi2lo") or \
|
||||
(pin.intdir.lower() == "either"):
|
||||
strCfile += '%-25s' % ' .eIntDir' + '= AM_HAL_GPIO_PIN_INTDIR_%s,\n' % pin.intdir.upper()
|
||||
else:
|
||||
strCfile += '%-25s' % ' .eIntDir' + '= %s,\n' % pin.intdir
|
||||
|
||||
if (pin.bIomMSPIn != strnotgiven):
|
||||
if pinobj.srcver >= 0x0003:
|
||||
if ((pin.bIomMSPIn[0:1].lower() != "m") and (pin.bIomMSPIn != "0")):
|
||||
bIom = 1
|
||||
else:
|
||||
bIom = 0
|
||||
strCfile += '%-25s' % ' .bIomMSPIn' + '= %d,\n' % bIom
|
||||
|
||||
if pin.IOMnum != strnotgiven:
|
||||
strCfile += '%-25s' % ' .uIOMnum' + '= %s,\n' % str(pin.IOMnum)
|
||||
|
||||
if pin.CEnum != strnotgiven:
|
||||
strCfile += '%-25s' % ' .uNCE' + '= %s,\n' % str(pin.CEnum)
|
||||
|
||||
# Create the define
|
||||
strtmp = '#define AM_BSP_%s_CHNL' % (pin.name)
|
||||
strHfile += '%-40s' % strtmp + '%s\n' % str((pin.CEnum))
|
||||
|
||||
if pin.CEpol != strnotgiven:
|
||||
if (pin.CEpol.lower() == "low") or \
|
||||
(pin.CEpol.lower() == "high"):
|
||||
strCfile += '%-25s' % ' .eCEpol' + '= AM_HAL_GPIO_PIN_CEPOL_ACTIVE%s,\n' % pin.CEpol.upper()
|
||||
elif (pin.CEpol.lower() == "activelow") or \
|
||||
(pin.CEpol.lower() == "activehigh"):
|
||||
strCfile += '%-25s' % ' .eCEpol' + '= AM_HAL_GPIO_PIN_CEPOL_%s,\n' % pin.CEpol.upper()
|
||||
else:
|
||||
strCfile += '%-25s' % ' .eCEpol' + '= %s,\n' % pin.CEpol
|
||||
|
||||
|
||||
# Eliminate the last comma from the last structure member
|
||||
strCfile = strCfile[:-2]
|
||||
|
||||
# Terminate the structure
|
||||
strCfile += '\n};\n'
|
||||
|
||||
if bCreateC:
|
||||
#
|
||||
# Develop and print the C file
|
||||
#
|
||||
S = filetemplateC.format(filename='am_bsp_pins.c', pin_defs=strCfile);
|
||||
print(S)
|
||||
else:
|
||||
#
|
||||
# Develop and print the H file
|
||||
#
|
||||
S = filetemplateH.format(filename='am_bsp_pins.h',
|
||||
pin_defs=strHfile,
|
||||
headerdef='AM_BSP_PINS_H')
|
||||
print(S)
|
||||
|
||||
|
||||
# *****************************************************************************
|
||||
#
|
||||
# main
|
||||
#
|
||||
# *****************************************************************************
|
||||
if __name__ == '__main__':
|
||||
|
||||
#
|
||||
# Get arguments.
|
||||
# First arg is a string for the input .src file.
|
||||
# Second arg must be a C or H.
|
||||
#
|
||||
args = read_arguments()
|
||||
if args.CorH.upper() == 'C':
|
||||
bCreateC = True
|
||||
else:
|
||||
bCreateC = False
|
||||
|
||||
version = get_version(args.input)
|
||||
|
||||
# Redirect the script based on the version number.
|
||||
|
||||
if version & 0xFF == 0x03:
|
||||
pinobj = get_pinobj(args.input)
|
||||
|
||||
#
|
||||
# pinobj.pins is a list of the pins
|
||||
#
|
||||
write_Cfiles(pinobj, bCreateC)
|
||||
@@ -0,0 +1,294 @@
|
||||
'''
|
||||
rsonlite -- an extremely lightweight version of rson.
|
||||
|
||||
Copyright (c) 2012, Patrick Maupin
|
||||
|
||||
License :: MIT
|
||||
|
||||
http://pypi.python.org/pypi/rsonlite
|
||||
http://code.google.com/p/rson/
|
||||
|
||||
rsonlite makes it easy to build a file parser for
|
||||
declarative hierarchical data structures using indentation.
|
||||
(Spaces only, tabs not considered indentation.)
|
||||
|
||||
The only special characters are '#', '=', and indentation:
|
||||
|
||||
- Indentation denotes a key/value relationship. The
|
||||
value is indented from the key.
|
||||
|
||||
- = Denotes the start of a free-format string. These
|
||||
strings can contain '=' and '#' characters, and
|
||||
even be multi-line, but every line in the string
|
||||
must be indented past the initial equal sign.
|
||||
|
||||
Note that, for multi-line strings, indentation is
|
||||
preserved but normalized such that at least one
|
||||
line starts in the left column. This allows for
|
||||
restructuredText or Python code to exist inside
|
||||
multi-line strings.
|
||||
|
||||
- # Denotes the start of a line comment, when not
|
||||
inside a free-format string.
|
||||
|
||||
The only Python objects resulting from parsing a file
|
||||
with rsonlite are:
|
||||
|
||||
- strings:
|
||||
free-format strings (described above) can
|
||||
contain any character, but the whitespace
|
||||
before/after the string may be stripped.
|
||||
|
||||
Regular strings must fit on a single line and
|
||||
cannot contain '=' or '#' characters.
|
||||
|
||||
Regular strings may be used as keys in key/value
|
||||
pairs, but free-format strings may not.
|
||||
|
||||
- tuple:
|
||||
A key/value pair is a two-element tuple. The key is always
|
||||
a string. The value is always a list.
|
||||
|
||||
- list:
|
||||
The top level is a list, and the value element of every
|
||||
key/value pair tuple is also a list. Lists can contain
|
||||
strings and key/value pair tuples.
|
||||
'''
|
||||
|
||||
import re
|
||||
|
||||
version = __version__ = '0.1.0'
|
||||
|
||||
# Our attempt at rationalizing differences between Python 2 and Python 3.
|
||||
|
||||
try:
|
||||
basestring
|
||||
except NameError:
|
||||
basestring = str
|
||||
class unicode: pass
|
||||
|
||||
# Use OrderedDict if it's available
|
||||
|
||||
try:
|
||||
from collections import OrderedDict as stddict
|
||||
except ImportError:
|
||||
stddict = dict
|
||||
|
||||
# Splits the entire file into probable tokens.
|
||||
|
||||
splitter = re.compile('(\n *|=[^\n]*|#[^\n]*|[^\n#=]+)').findall
|
||||
|
||||
class RsonToken(str):
|
||||
''' A string that may be annotated with location information
|
||||
'''
|
||||
def __new__(cls, s, line, col):
|
||||
self = str.__new__(cls, s)
|
||||
self.line = line
|
||||
self.col = col
|
||||
return self
|
||||
def __add__(self, other):
|
||||
return RsonToken(str(self) + other, self.line, self.col)
|
||||
|
||||
|
||||
def gettoks(source):
|
||||
''' Convert string into (probable) tokens
|
||||
(some tokens may be recombined later, e.g. if they
|
||||
contain # or = but were already inside a string)
|
||||
'''
|
||||
|
||||
# Use "regular" strings, whatever that means for the given Python
|
||||
if isinstance(source, unicode):
|
||||
source = source.encode('utf-8', 'replace')
|
||||
elif not isinstance(source, basestring):
|
||||
source = source.decode('utf-8', 'replace')
|
||||
|
||||
# Convert MS-DOS or Mac line endings to the one true way, and
|
||||
# prefix the source with a linefeed to simplify the tokenization.
|
||||
source = '\n' + source.replace('\r\n', '\n').replace('\r', '\n')
|
||||
|
||||
line = 0
|
||||
for tok in splitter(source):
|
||||
if tok.startswith('\n'):
|
||||
line += 1
|
||||
col = len(tok)
|
||||
else:
|
||||
yield RsonToken(tok, line, col)
|
||||
col += len(tok)
|
||||
|
||||
def multiline(lineinfo, dedent):
|
||||
''' Returns one string for each line,
|
||||
properly dedented.
|
||||
'''
|
||||
linenum = lineinfo[0].line
|
||||
for tok in lineinfo:
|
||||
while linenum < tok.line:
|
||||
yield ''
|
||||
linenum += 1
|
||||
yield (tok.col - dedent) * ' ' + tok.rstrip()
|
||||
linenum += 1
|
||||
|
||||
def getfreeformat(toklist, firsttok, firstcol):
|
||||
''' Returns a free-formatted string.
|
||||
'''
|
||||
curline = firsttok.line
|
||||
firstpart = firsttok[1:].strip() # Get past = sign
|
||||
lineinfo = []
|
||||
while toklist and toklist[-1].col > firstcol:
|
||||
tok = toklist.pop()
|
||||
if tok.line == curline:
|
||||
lineinfo[-1] += tok
|
||||
else:
|
||||
lineinfo.append(tok)
|
||||
curline = tok.line
|
||||
if lineinfo:
|
||||
dedent = min(tok.col for tok in lineinfo)
|
||||
if firstpart:
|
||||
lineinfo.insert(0, RsonToken(firstpart, firsttok.line, dedent))
|
||||
firstpart = '\n'.join(multiline(lineinfo, dedent))
|
||||
return RsonToken(firstpart, firsttok.line, firsttok.col)
|
||||
|
||||
def loads(source):
|
||||
''' load a string into an rsonlite datastructure.
|
||||
If the source is not a string instance, then
|
||||
loads will attempt to convert it into a string
|
||||
instance, by encoding to UTF-8 on Python 2,
|
||||
or decoding from UTF-8 on Python 3.
|
||||
'''
|
||||
toklist = list(gettoks(source))
|
||||
toklist.reverse()
|
||||
result = [None]
|
||||
stack = []
|
||||
curcol = -1
|
||||
curlist = result
|
||||
while toklist:
|
||||
tok = toklist.pop()
|
||||
if tok.startswith('#'):
|
||||
continue
|
||||
col = tok.col
|
||||
if col > curcol:
|
||||
stack.append((curcol, curlist))
|
||||
oldlist = curlist
|
||||
curcol, curlist = col, []
|
||||
oldlist[-1] = oldlist[-1], curlist
|
||||
while col < curcol:
|
||||
curcol, curlist = stack.pop()
|
||||
if col != curcol:
|
||||
err = IndentationError('unindent does not match any outer indentation level')
|
||||
err.filename = '<rsonlite>'
|
||||
err.lineno = tok.line
|
||||
raise err
|
||||
if tok.startswith('='):
|
||||
curlist.append(getfreeformat(toklist, tok, col))
|
||||
else:
|
||||
curlist.append(RsonToken(tok.rstrip(), tok.line, tok.col))
|
||||
if toklist and toklist[-1].line == tok.line:
|
||||
tok = toklist.pop()
|
||||
if tok.startswith('='):
|
||||
curlist[-1] = curlist[-1], [getfreeformat(toklist, tok, col)]
|
||||
else:
|
||||
assert tok.startswith('#') # else problem in regex...
|
||||
result, = result
|
||||
return [] if result is None else result[1]
|
||||
|
||||
def dumps(data, indent=' ', initial_indent=''):
|
||||
''' Dump a string loaded with loads back out.
|
||||
'''
|
||||
def getstring(data, indent2):
|
||||
if '\n' in data:
|
||||
data = ('\n'+indent2).join([''] + data.split('\n'))
|
||||
return data
|
||||
|
||||
def recurse(data, indent2):
|
||||
assert isinstance(data, list), repr(data)
|
||||
for data in data:
|
||||
if isinstance(data, tuple):
|
||||
key, value = data
|
||||
if len(value) == 1 and isinstance(value[0], basestring):
|
||||
append('%s%s = %s' % (indent2, key, getstring(value[0], indent2+indent)))
|
||||
else:
|
||||
append('%s%s' % (indent2, key))
|
||||
recurse(value, indent2 + indent)
|
||||
else:
|
||||
assert isinstance(data, basestring)
|
||||
if '\n' in data or '=' in data or '#' in data:
|
||||
append(indent2 + '=')
|
||||
append(getstring(data, indent2 + ' '))
|
||||
else:
|
||||
append('%s%s' % (indent2, data))
|
||||
result = []
|
||||
append = result.append
|
||||
recurse(data, initial_indent)
|
||||
append('')
|
||||
return '\n'.join(result)
|
||||
|
||||
def pretty(data, indent=' '):
|
||||
''' Pretty-print a string loaded by loads into
|
||||
something that makes it easy to see the actual
|
||||
structure of the data. The return value of
|
||||
this should be parseable by eval()
|
||||
'''
|
||||
def recurse(data, indent2):
|
||||
assert isinstance(data, list)
|
||||
for data in data:
|
||||
assert isinstance(data, (tuple, basestring))
|
||||
if isinstance(data, tuple) and (
|
||||
len(data[1]) != 1 or not isinstance(data[1][0], basestring)):
|
||||
append('%s(%s, [' % (indent2, repr(data[0])))
|
||||
recurse(data[1], indent2 + indent)
|
||||
append('%s])' % (indent2))
|
||||
else:
|
||||
append('%s%s,' % (indent2, repr(data)))
|
||||
result = []
|
||||
append = result.append
|
||||
append('[')
|
||||
recurse(data, indent)
|
||||
append(']')
|
||||
append('')
|
||||
return '\n'.join(result)
|
||||
|
||||
##########################################################################
|
||||
# These higher-level functions might suffice for simple data, and also
|
||||
# provide a template for designing similar functions.
|
||||
|
||||
def stringparse(s, special=dict(true=True, false=False, null=None)):
|
||||
''' This gives an example of handling the JSON special identifiers
|
||||
true, false and null, and also of handling simple arrays.
|
||||
'''
|
||||
if s in special:
|
||||
return special[s]
|
||||
if s.startswith('[') and s.endswith(']'):
|
||||
t = s[1:-1]
|
||||
for ch in '"\'[]{}\n':
|
||||
if ch in t:
|
||||
return s
|
||||
return [x.strip() for x in t.split(',')]
|
||||
return s
|
||||
|
||||
def simpleparse(source, stringparse=stringparse, stddict=stddict):
|
||||
''' Return the simplest structure that uses dicts instead
|
||||
of tuples, and doesn't lose any source information.
|
||||
Use ordered dicts if they are available.
|
||||
'''
|
||||
def recurse(mylist):
|
||||
if len(mylist) == 1 and isinstance(mylist[0], basestring):
|
||||
return stringparse(mylist[0])
|
||||
keys = [x[0] for x in mylist if isinstance(x, tuple)]
|
||||
if not keys:
|
||||
return mylist # simple list
|
||||
if len(set(keys)) == len(mylist):
|
||||
return stddict((x, recurse(y)) for (x, y) in mylist)
|
||||
# Complicated. Make a list that might have multiple dicts
|
||||
result = []
|
||||
curdict = None
|
||||
for item in mylist:
|
||||
if not isinstance(item, tuple):
|
||||
result.append(stringparse(item))
|
||||
curdict = None
|
||||
continue
|
||||
key, value = item
|
||||
if curdict is None or key in curdict:
|
||||
curdict = stddict()
|
||||
result.append(curdict)
|
||||
curdict[key] = recurse(value)
|
||||
return result
|
||||
return recurse(source if isinstance(source, list) else loads(source))
|
||||
Binary file not shown.
@@ -0,0 +1,35 @@
|
||||
0000000_META_hci_patches_v8.emp (can be programmed into IRAM or OTP)
|
||||
Container ID 77
|
||||
Build number 3089
|
||||
User Build 0
|
||||
|
||||
eight_connections.emp
|
||||
Format Version 1
|
||||
Container ID 20
|
||||
Build number 3089
|
||||
User Build 2
|
||||
|
||||
data_length_extension.emp
|
||||
Format Version 1
|
||||
Container ID 21
|
||||
Build number 3089
|
||||
User Build 2
|
||||
|
||||
sleep_clk_src_apollo.emp
|
||||
Format Version 1
|
||||
Container ID 22
|
||||
Build number 3089
|
||||
User Build 2
|
||||
|
||||
disable_pull-up_em_gpio10.emp
|
||||
Format Version 1
|
||||
Container ID 23
|
||||
Build number 3089
|
||||
User Build 2
|
||||
|
||||
disable_pull-up_em_gpio11.emp
|
||||
Format Version 1
|
||||
Container ID 24
|
||||
Build number 3089
|
||||
User Build 2
|
||||
|
||||
@@ -0,0 +1,34 @@
|
||||
This directory holds the *.emp files generated by the EM Micro tools (e.g. EM9304 Configuration Editor) or EM Micro developers (code patches).
|
||||
|
||||
All *.emp files contained in this directory will result in the generation of a patch or patches to be
|
||||
applied to the EM9304.
|
||||
|
||||
The script emp2include.py has the following usage:
|
||||
|
||||
$ ./emp2include.py --help
|
||||
usage: emp2include.py [-h] [-o MEMORY]
|
||||
|
||||
Convert multiple EM9304 *.emp files to the em9304_patches.* files.
|
||||
|
||||
optional arguments:
|
||||
-h, --help show this help message and exit
|
||||
-o MEMORY Destination memory (IRAM or OTP)
|
||||
|
||||
Patches can be applied temporarily to IRAM and then permanently applied to OTP (one-time programable) memory
|
||||
as needed. The default is IRAM.
|
||||
|
||||
The files em9304_patches.h and em9304_patches.c will be generated in the following directory:
|
||||
|
||||
/third_party/exactle/sw/hci/ambiq/em9304
|
||||
|
||||
Patches are uniquely identified by the following meta-data embedded in *.emp files:
|
||||
* Format Version - Container format version (increments as container is updated)
|
||||
* Patch ID - Unique identifier for the container/patch (assigned by patch creator)
|
||||
* Build number - EM9304 ROM minor revision supported by patch
|
||||
* User Build - User defined number (assigned by patch creator)
|
||||
=> 0, 1: Reserved by EM
|
||||
=> 2, 3: Reserved by Ambiq Micro
|
||||
=> 4+ : Available for customer
|
||||
|
||||
|
||||
Note: 0001642_PROD_boot_overhead.emp is built into 0000000_META_hci_patches_v7.emp, there's only a single emp from EM in the future.
|
||||
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
@@ -0,0 +1,455 @@
|
||||
#!/usr/bin/env python3
|
||||
|
||||
import argparse
|
||||
import configparser
|
||||
import os
|
||||
import sys
|
||||
import platform
|
||||
|
||||
#******************************************************************************
|
||||
#
|
||||
# Template for the output files
|
||||
#
|
||||
#******************************************************************************
|
||||
hfile1 = '''
|
||||
//*****************************************************************************
|
||||
//
|
||||
//! @file {name}.h
|
||||
//!
|
||||
//! @brief This is a generated file.
|
||||
//
|
||||
//*****************************************************************************
|
||||
|
||||
#include <stdint.h>
|
||||
#include <stdbool.h>
|
||||
|
||||
#ifndef {macroname}_H
|
||||
#define {macroname}_H
|
||||
|
||||
//*****************************************************************************
|
||||
//
|
||||
// Length of the binary array in bytes.
|
||||
//
|
||||
//*****************************************************************************
|
||||
#define {lengthmacro:35} {length}
|
||||
|
||||
// EM patch destination memory:
|
||||
// 1 means EM patch will be programmed into OTP if emp file
|
||||
// was not programmed before.
|
||||
// 0 means EM patch will be programmed into IRAM each time when
|
||||
// EM9304 is cold boot.
|
||||
|
||||
#define DEST_MEMORY_IRAM 0
|
||||
#define DEST_MEMORY_OTP 1
|
||||
#define {patch_dest_memory_macro:35} {dest_memory}
|
||||
|
||||
//*****************************************************************************
|
||||
//
|
||||
// EM9304 Container Info type
|
||||
//
|
||||
//*****************************************************************************
|
||||
typedef struct
|
||||
{{
|
||||
uint16_t buildNumber; // Firmware Build Number
|
||||
uint16_t userBuildNumber; // User defined Build Number (determines patch precedence)
|
||||
uint8_t containerVersion; // Container Version
|
||||
uint8_t containerType; // Container Type
|
||||
uint8_t containerID; // Container ID
|
||||
bool applyPatch; // Flag to apply this patch.
|
||||
uint8_t startingPatch; // Starting patch index.
|
||||
uint8_t endingPatch; // Ending patch index + 1.
|
||||
}} em9304_container_info_t;
|
||||
|
||||
//*****************************************************************************
|
||||
//
|
||||
// Extracted binary array.
|
||||
//
|
||||
//*****************************************************************************
|
||||
'''.strip()
|
||||
|
||||
hfile2 = '''
|
||||
|
||||
extern em9304_container_info_t g_p{varname}[{length}];
|
||||
extern const uint8_t g_p{varname}HCICmd[{numpatches}][68];
|
||||
|
||||
#endif // {macroname}_H
|
||||
'''.strip()
|
||||
|
||||
hfile3 = '''
|
||||
//
|
||||
// Note: A NULL patch was generated. This means that there were no *.emp files
|
||||
// processed during the generation of this file.
|
||||
//
|
||||
extern em9304_container_info_t g_p{varname}[1];
|
||||
extern const uint8_t g_p{varname}HCICmd[1][68];
|
||||
|
||||
#endif // {macroname}_H
|
||||
'''.strip()
|
||||
|
||||
cfile1 = '''
|
||||
//*****************************************************************************
|
||||
//
|
||||
//! @file {name}.c
|
||||
//!
|
||||
//! @brief This is a generated file.
|
||||
//
|
||||
//*****************************************************************************
|
||||
|
||||
#include <stdint.h>
|
||||
#include "{name}.h"
|
||||
|
||||
//*****************************************************************************
|
||||
//
|
||||
// Extracted binary array
|
||||
//
|
||||
//*****************************************************************************
|
||||
'''.strip()
|
||||
|
||||
cfile2 = '''
|
||||
em9304_container_info_t g_p{varname}[{length}] =
|
||||
{{
|
||||
// Build UserBuild Version Type ID bApply Start End
|
||||
'''.strip()
|
||||
|
||||
cfile2_null = '''
|
||||
//
|
||||
// This is a NULL patch. It indicates that there were no *.emp files processed
|
||||
// during the generation of this file.
|
||||
//
|
||||
em9304_container_info_t g_p{varname}[1] =
|
||||
{{
|
||||
{{ 0xFFFF, 0xFFFF, 0xFF, 0xFF, 0xFF, false, 0x00, 0x00 }}
|
||||
'''.strip()
|
||||
|
||||
cfile3 = '''
|
||||
}};
|
||||
const uint8_t g_p{varname}HCICmd[{numpatches}][68] =
|
||||
{{
|
||||
'''.strip()
|
||||
|
||||
cfile3_null = '''
|
||||
}};
|
||||
const uint8_t g_pEm9304PatchesHCICmd[1][68] =
|
||||
{{
|
||||
{{ 0x00
|
||||
}}
|
||||
'''.strip()
|
||||
|
||||
|
||||
|
||||
#******************************************************************************
|
||||
#
|
||||
# CRC32 lookup table.
|
||||
#
|
||||
#******************************************************************************
|
||||
crc32Table = [
|
||||
0x00000000, 0x77073096, 0xee0e612c, 0x990951ba, 0x076dc419, 0x706af48f,
|
||||
0xe963a535, 0x9e6495a3, 0x0edb8832, 0x79dcb8a4, 0xe0d5e91e, 0x97d2d988,
|
||||
0x09b64c2b, 0x7eb17cbd, 0xe7b82d07, 0x90bf1d91, 0x1db71064, 0x6ab020f2,
|
||||
0xf3b97148, 0x84be41de, 0x1adad47d, 0x6ddde4eb, 0xf4d4b551, 0x83d385c7,
|
||||
0x136c9856, 0x646ba8c0, 0xfd62f97a, 0x8a65c9ec, 0x14015c4f, 0x63066cd9,
|
||||
0xfa0f3d63, 0x8d080df5, 0x3b6e20c8, 0x4c69105e, 0xd56041e4, 0xa2677172,
|
||||
0x3c03e4d1, 0x4b04d447, 0xd20d85fd, 0xa50ab56b, 0x35b5a8fa, 0x42b2986c,
|
||||
0xdbbbc9d6, 0xacbcf940, 0x32d86ce3, 0x45df5c75, 0xdcd60dcf, 0xabd13d59,
|
||||
0x26d930ac, 0x51de003a, 0xc8d75180, 0xbfd06116, 0x21b4f4b5, 0x56b3c423,
|
||||
0xcfba9599, 0xb8bda50f, 0x2802b89e, 0x5f058808, 0xc60cd9b2, 0xb10be924,
|
||||
0x2f6f7c87, 0x58684c11, 0xc1611dab, 0xb6662d3d, 0x76dc4190, 0x01db7106,
|
||||
0x98d220bc, 0xefd5102a, 0x71b18589, 0x06b6b51f, 0x9fbfe4a5, 0xe8b8d433,
|
||||
0x7807c9a2, 0x0f00f934, 0x9609a88e, 0xe10e9818, 0x7f6a0dbb, 0x086d3d2d,
|
||||
0x91646c97, 0xe6635c01, 0x6b6b51f4, 0x1c6c6162, 0x856530d8, 0xf262004e,
|
||||
0x6c0695ed, 0x1b01a57b, 0x8208f4c1, 0xf50fc457, 0x65b0d9c6, 0x12b7e950,
|
||||
0x8bbeb8ea, 0xfcb9887c, 0x62dd1ddf, 0x15da2d49, 0x8cd37cf3, 0xfbd44c65,
|
||||
0x4db26158, 0x3ab551ce, 0xa3bc0074, 0xd4bb30e2, 0x4adfa541, 0x3dd895d7,
|
||||
0xa4d1c46d, 0xd3d6f4fb, 0x4369e96a, 0x346ed9fc, 0xad678846, 0xda60b8d0,
|
||||
0x44042d73, 0x33031de5, 0xaa0a4c5f, 0xdd0d7cc9, 0x5005713c, 0x270241aa,
|
||||
0xbe0b1010, 0xc90c2086, 0x5768b525, 0x206f85b3, 0xb966d409, 0xce61e49f,
|
||||
0x5edef90e, 0x29d9c998, 0xb0d09822, 0xc7d7a8b4, 0x59b33d17, 0x2eb40d81,
|
||||
0xb7bd5c3b, 0xc0ba6cad, 0xedb88320, 0x9abfb3b6, 0x03b6e20c, 0x74b1d29a,
|
||||
0xead54739, 0x9dd277af, 0x04db2615, 0x73dc1683, 0xe3630b12, 0x94643b84,
|
||||
0x0d6d6a3e, 0x7a6a5aa8, 0xe40ecf0b, 0x9309ff9d, 0x0a00ae27, 0x7d079eb1,
|
||||
0xf00f9344, 0x8708a3d2, 0x1e01f268, 0x6906c2fe, 0xf762575d, 0x806567cb,
|
||||
0x196c3671, 0x6e6b06e7, 0xfed41b76, 0x89d32be0, 0x10da7a5a, 0x67dd4acc,
|
||||
0xf9b9df6f, 0x8ebeeff9, 0x17b7be43, 0x60b08ed5, 0xd6d6a3e8, 0xa1d1937e,
|
||||
0x38d8c2c4, 0x4fdff252, 0xd1bb67f1, 0xa6bc5767, 0x3fb506dd, 0x48b2364b,
|
||||
0xd80d2bda, 0xaf0a1b4c, 0x36034af6, 0x41047a60, 0xdf60efc3, 0xa867df55,
|
||||
0x316e8eef, 0x4669be79, 0xcb61b38c, 0xbc66831a, 0x256fd2a0, 0x5268e236,
|
||||
0xcc0c7795, 0xbb0b4703, 0x220216b9, 0x5505262f, 0xc5ba3bbe, 0xb2bd0b28,
|
||||
0x2bb45a92, 0x5cb36a04, 0xc2d7ffa7, 0xb5d0cf31, 0x2cd99e8b, 0x5bdeae1d,
|
||||
0x9b64c2b0, 0xec63f226, 0x756aa39c, 0x026d930a, 0x9c0906a9, 0xeb0e363f,
|
||||
0x72076785, 0x05005713, 0x95bf4a82, 0xe2b87a14, 0x7bb12bae, 0x0cb61b38,
|
||||
0x92d28e9b, 0xe5d5be0d, 0x7cdcefb7, 0x0bdbdf21, 0x86d3d2d4, 0xf1d4e242,
|
||||
0x68ddb3f8, 0x1fda836e, 0x81be16cd, 0xf6b9265b, 0x6fb077e1, 0x18b74777,
|
||||
0x88085ae6, 0xff0f6a70, 0x66063bca, 0x11010b5c, 0x8f659eff, 0xf862ae69,
|
||||
0x616bffd3, 0x166ccf45, 0xa00ae278, 0xd70dd2ee, 0x4e048354, 0x3903b3c2,
|
||||
0xa7672661, 0xd06016f7, 0x4969474d, 0x3e6e77db, 0xaed16a4a, 0xd9d65adc,
|
||||
0x40df0b66, 0x37d83bf0, 0xa9bcae53, 0xdebb9ec5, 0x47b2cf7f, 0x30b5ffe9,
|
||||
0xbdbdf21c, 0xcabac28a, 0x53b39330, 0x24b4a3a6, 0xbad03605, 0xcdd70693,
|
||||
0x54de5729, 0x23d967bf, 0xb3667a2e, 0xc4614ab8, 0x5d681b02, 0x2a6f2b94,
|
||||
0xb40bbe37, 0xc30c8ea1, 0x5a05df1b, 0x2d02ef8d ]
|
||||
|
||||
def crc32( previousCrc, L ):
|
||||
crc = previousCrc
|
||||
for b in L:
|
||||
crc = crc32Table[( crc ^ b) & 0xFF ] ^ ( crc >> 8 )
|
||||
return (~crc & 0xFFFFFFFF)
|
||||
|
||||
#******************************************************************************
|
||||
#
|
||||
# Read in the binary file and output a C array.
|
||||
#
|
||||
#******************************************************************************
|
||||
def process(memory):
|
||||
print('Find *.emp files')
|
||||
# Change to the target directory with *.emp files.
|
||||
asps = []
|
||||
for subdir, dirs, files in os.walk('./'):
|
||||
for file in files:
|
||||
if file.endswith('.emp'):
|
||||
if subdir.endswith('./'):
|
||||
print(file)
|
||||
asps.append(file)
|
||||
|
||||
output = 'em9304_patches'
|
||||
print(output)
|
||||
|
||||
# S will be the string to accumulate the patch records in a C-friendly format
|
||||
S = ''
|
||||
|
||||
# C will be the string to accumulate the patch HCI commands in a C-friendly format
|
||||
C = ''
|
||||
|
||||
patchIndex = 0
|
||||
patchCount = 0
|
||||
|
||||
# For each file in the list
|
||||
for file in asps:
|
||||
with open(file, mode = 'rb') as f:
|
||||
binarray = f.read()
|
||||
|
||||
# Set the starting index
|
||||
cmdIndex = 0
|
||||
|
||||
#print(len(binarray))
|
||||
while ((cmdIndex < len(binarray)) & ((len(binarray) - cmdIndex) > 20)):
|
||||
#print(cmdIndex)
|
||||
# Check for the start of a new container.
|
||||
if(binarray[cmdIndex:cmdIndex+4] == b'39me'):
|
||||
#print("Found container header")
|
||||
|
||||
# Increment the patch count.
|
||||
patchCount += 1
|
||||
|
||||
# Add a record start
|
||||
S += ' { '
|
||||
|
||||
# Add the decimal representation of the patch Build Number Version
|
||||
S += '{0:4d}'.format(binarray[cmdIndex+12] + (binarray[cmdIndex+13] << 8))
|
||||
S += ', '
|
||||
|
||||
# Add the decimal representation of the patch User Build Number
|
||||
S += ' {0:4d}'.format(binarray[cmdIndex+14] + (binarray[cmdIndex+15] << 8))
|
||||
S += ', '
|
||||
|
||||
# Add the decimal representation of the patch Format Version
|
||||
S += ' {0:2d}'.format(binarray[cmdIndex+8])
|
||||
S += ', '
|
||||
|
||||
# Add the decimal representation of the patch Container Type
|
||||
S += ' {0:2d}'.format(binarray[cmdIndex+9])
|
||||
S += ', '
|
||||
|
||||
# Determine whether the patch should override user and must go into OTP.
|
||||
if ( (binarray[cmdIndex+9] == 0x09) or (binarray[cmdIndex+9] == 0x0A) ):
|
||||
bOTPOverride = True
|
||||
else:
|
||||
bOTPOverride = False
|
||||
|
||||
# Add the decimal representation of the patch Container ID
|
||||
S += ' {0:2d}'.format(binarray[cmdIndex+10])
|
||||
S += ', '
|
||||
|
||||
# Initialize the path application flag to false
|
||||
S += 'false, '
|
||||
|
||||
# Set the starting patch index
|
||||
S += ' {0:3d}, '.format(patchIndex)
|
||||
|
||||
cmdSize = binarray[cmdIndex+4] + (binarray[cmdIndex+5] << 8) + (binarray[cmdIndex+6] << 16) + (binarray[cmdIndex+7] << 24)
|
||||
#print(cmdSize)
|
||||
|
||||
firstCmd = True
|
||||
seqNum = 1
|
||||
|
||||
while (cmdSize > 0):
|
||||
# Add a record start
|
||||
C += ' { '
|
||||
|
||||
# First record is EM_WritePatchStart HCI command
|
||||
if (firstCmd):
|
||||
# Determine the binary patch data length
|
||||
if (cmdSize <= 59):
|
||||
cmdLength = cmdSize
|
||||
else:
|
||||
cmdLength = 59
|
||||
# Add the HCI Command Header (Note: Set destination to IRAM1 until testing is complete)
|
||||
C += '0x27, 0xFC,\t\t// HCI Vendor Specific Command EM_WritePatchStart\n '
|
||||
C += '0x{:02X},\t\t\t// HCI Parameter Length\n '.format(cmdLength + 5)
|
||||
if ( (memory == 'IRAM') and (not bOTPOverride) ):
|
||||
C += '0x00,\t\t\t// Destination Memory (0 = IRAM1; 1 = OTP)\n '
|
||||
elif (memory == 'OTP'):
|
||||
C += '0x01,\t\t\t// Destination Memory (0 = IRAM1; 1 = OTP)\n '
|
||||
else:
|
||||
print('ERROR in destination memory indication')
|
||||
return
|
||||
# Create the binary data to run the CRC across
|
||||
crcarray = binarray[cmdIndex:(cmdIndex+cmdLength)]
|
||||
# Clear the firstCmd flag
|
||||
firstCmd = False
|
||||
#Remaining records are EM_WritePatchContinue commands
|
||||
else:
|
||||
# Determine the binary patch data length
|
||||
if (cmdSize <= 58):
|
||||
cmdLength = cmdSize
|
||||
else:
|
||||
cmdLength = 58
|
||||
|
||||
# Add the HCI Command Header (Note: Set destination to IRAM1 until testing is complete
|
||||
C += '0x28, 0xFC,\t\t// HCI Vendor Specific Command EM_WritePatchContinue\n '
|
||||
C += '0x{:02X},\t\t\t// HCI Parameter Length\n '.format(cmdLength + 6)
|
||||
|
||||
# Add the Sequence Number
|
||||
C += '0x{:02X}, '.format(seqNum & 0xFF)
|
||||
C += '0x{:02X},\t\t\t// Sequence Number\n '.format((seqNum >> 8) & 0xFF)
|
||||
|
||||
# Create the binary data to run the CRC across
|
||||
crcarray = binarray[cmdIndex:(cmdIndex+cmdLength)]
|
||||
|
||||
# Increment the Sequence Number
|
||||
seqNum = seqNum + 1
|
||||
|
||||
# Add the CRC32 to the HCI command
|
||||
packetCRC = crc32(0xFFFFFFFF,crcarray)
|
||||
for i in range(0,4):
|
||||
C += '0x{:02X}, '.format(packetCRC & 0xFF)
|
||||
packetCRC = packetCRC >> 8
|
||||
C += '\t// CRC32'
|
||||
# Start a newline
|
||||
C += '\n '
|
||||
|
||||
# index
|
||||
i = 0
|
||||
# Loop over binarray
|
||||
for n in range(cmdIndex,(cmdIndex+cmdLength)):
|
||||
# Add the hex representation of each byte to S
|
||||
C += '0x{:02X}'.format(binarray[n])
|
||||
|
||||
# Print in comma-separated lines, 8 bytes long each.
|
||||
if i % 8 == 7:
|
||||
C += ',\n '
|
||||
else:
|
||||
C += ', '
|
||||
i += 1
|
||||
|
||||
# The end of the previous loop will leave an extra comma and some amount of
|
||||
# whitespace after the last byte value. This line will remove that.
|
||||
C = C.rsplit(',', 1)[0]
|
||||
C += '\n },\n'
|
||||
|
||||
# Increment the patch index
|
||||
patchIndex += 1
|
||||
#print("End of While Loop")
|
||||
#print(patchIndex)
|
||||
|
||||
# Adjust the command size
|
||||
cmdSize -= cmdLength
|
||||
#print(cmdSize)
|
||||
|
||||
# Adjust the command index
|
||||
cmdIndex += cmdLength
|
||||
#print(cmdIndex)
|
||||
|
||||
cmdIndex = (cmdIndex + 3) & 0xFFFFFFFC
|
||||
#print(cmdIndex)
|
||||
# Set the ending patch index
|
||||
S += ' {0:3d}'.format(patchIndex) + ' },\n'
|
||||
else:
|
||||
# skipping with extra bytes inserted by emp patch
|
||||
# tool
|
||||
cmdIndex += 1
|
||||
# The end of the previous loop will leave an extra comma and some amount of
|
||||
# whitespace after the last byte value. This line will remove that.
|
||||
C = C.rsplit(',', 1)[0]
|
||||
C += '\n};\n\n'
|
||||
|
||||
# The end of the previous loop will leave an extra comma and some amount of
|
||||
# whitespace after the last byte value. This line will remove that.
|
||||
S = S.rsplit(',', 1)[0]
|
||||
|
||||
if (memory == 'OTP'):
|
||||
memory_var = 1;
|
||||
else:
|
||||
memory_var = 0;
|
||||
|
||||
if (patchIndex > 0):
|
||||
# Define a set of names to be used in the output files.
|
||||
formatmap = {'length' : patchCount,
|
||||
'name' : output,
|
||||
'numpatches' : patchIndex,
|
||||
'macroname' : output.upper(),
|
||||
'lengthmacro' : output.upper() + '_NUM_PATCHES',
|
||||
'varname' : output.title().replace('_', ''),
|
||||
'patch_dest_memory_macro' : output.upper() + '_DEST_MEMORY',
|
||||
'dest_memory': memory_var,
|
||||
}
|
||||
else:
|
||||
# Define a set of names to be used in the output files.
|
||||
formatmap = {'length' : 1,
|
||||
'name' : output,
|
||||
'numpatches' : patchIndex,
|
||||
'macroname' : output.upper(),
|
||||
'lengthmacro' : output.upper() + '_NUM_PATCHES',
|
||||
'varname' : output.title().replace('_', ''),
|
||||
'patch_dest_memory_macro' : output.upper() + '_DEST_MEMORY',
|
||||
'dest_memory': memory_var,
|
||||
}
|
||||
dir = os.path.join(os.getcwd(),'../../ambiq_ble/em9304')
|
||||
os.chdir(dir)
|
||||
with open(output + '.c', mode = 'w') as out:
|
||||
# Print the global fileheader.
|
||||
print(cfile1.format(**formatmap), file=out)
|
||||
if (patchIndex > 0):
|
||||
print(cfile2.format(**formatmap), file=out)
|
||||
print(S, file=out)
|
||||
print(cfile3.format(**formatmap), file=out)
|
||||
print(C, file=out)
|
||||
else:
|
||||
print(cfile2_null.format(**formatmap), file=out)
|
||||
print(S, file=out)
|
||||
print(cfile3_null.format(**formatmap), file=out)
|
||||
print(C, file=out)
|
||||
|
||||
|
||||
with open(output + '.h', mode = 'w') as out:
|
||||
print(hfile1.format(**formatmap), file=out)
|
||||
if (patchIndex > 0):
|
||||
print(hfile2.format(**formatmap), file=out)
|
||||
else:
|
||||
print(hfile3.format(**formatmap), file=out)
|
||||
|
||||
return
|
||||
|
||||
#******************************************************************************
|
||||
#
|
||||
# Main program flow
|
||||
#
|
||||
#******************************************************************************
|
||||
if __name__ == '__main__':
|
||||
print('Parse Args')
|
||||
parser = argparse.ArgumentParser(description =
|
||||
'Convert multiple EM9304 *.emp files to the em9304_patches.* files.')
|
||||
parser.add_argument('-o', dest = 'memory', default = 'IRAM',
|
||||
help = 'Destination memory (IRAM or OTP)')
|
||||
|
||||
args = parser.parse_args()
|
||||
print('Call function')
|
||||
process(args.memory)
|
||||
Binary file not shown.
@@ -0,0 +1,98 @@
|
||||
#!/usr/bin/env python3
|
||||
|
||||
import argparse
|
||||
import configparser
|
||||
import os
|
||||
import sys
|
||||
import platform
|
||||
import binascii
|
||||
import struct
|
||||
|
||||
#******************************************************************************
|
||||
#
|
||||
# CRC32 lookup table.
|
||||
#
|
||||
#******************************************************************************
|
||||
crc32Table = [
|
||||
0x00000000, 0x77073096, 0xee0e612c, 0x990951ba, 0x076dc419, 0x706af48f,
|
||||
0xe963a535, 0x9e6495a3, 0x0edb8832, 0x79dcb8a4, 0xe0d5e91e, 0x97d2d988,
|
||||
0x09b64c2b, 0x7eb17cbd, 0xe7b82d07, 0x90bf1d91, 0x1db71064, 0x6ab020f2,
|
||||
0xf3b97148, 0x84be41de, 0x1adad47d, 0x6ddde4eb, 0xf4d4b551, 0x83d385c7,
|
||||
0x136c9856, 0x646ba8c0, 0xfd62f97a, 0x8a65c9ec, 0x14015c4f, 0x63066cd9,
|
||||
0xfa0f3d63, 0x8d080df5, 0x3b6e20c8, 0x4c69105e, 0xd56041e4, 0xa2677172,
|
||||
0x3c03e4d1, 0x4b04d447, 0xd20d85fd, 0xa50ab56b, 0x35b5a8fa, 0x42b2986c,
|
||||
0xdbbbc9d6, 0xacbcf940, 0x32d86ce3, 0x45df5c75, 0xdcd60dcf, 0xabd13d59,
|
||||
0x26d930ac, 0x51de003a, 0xc8d75180, 0xbfd06116, 0x21b4f4b5, 0x56b3c423,
|
||||
0xcfba9599, 0xb8bda50f, 0x2802b89e, 0x5f058808, 0xc60cd9b2, 0xb10be924,
|
||||
0x2f6f7c87, 0x58684c11, 0xc1611dab, 0xb6662d3d, 0x76dc4190, 0x01db7106,
|
||||
0x98d220bc, 0xefd5102a, 0x71b18589, 0x06b6b51f, 0x9fbfe4a5, 0xe8b8d433,
|
||||
0x7807c9a2, 0x0f00f934, 0x9609a88e, 0xe10e9818, 0x7f6a0dbb, 0x086d3d2d,
|
||||
0x91646c97, 0xe6635c01, 0x6b6b51f4, 0x1c6c6162, 0x856530d8, 0xf262004e,
|
||||
0x6c0695ed, 0x1b01a57b, 0x8208f4c1, 0xf50fc457, 0x65b0d9c6, 0x12b7e950,
|
||||
0x8bbeb8ea, 0xfcb9887c, 0x62dd1ddf, 0x15da2d49, 0x8cd37cf3, 0xfbd44c65,
|
||||
0x4db26158, 0x3ab551ce, 0xa3bc0074, 0xd4bb30e2, 0x4adfa541, 0x3dd895d7,
|
||||
0xa4d1c46d, 0xd3d6f4fb, 0x4369e96a, 0x346ed9fc, 0xad678846, 0xda60b8d0,
|
||||
0x44042d73, 0x33031de5, 0xaa0a4c5f, 0xdd0d7cc9, 0x5005713c, 0x270241aa,
|
||||
0xbe0b1010, 0xc90c2086, 0x5768b525, 0x206f85b3, 0xb966d409, 0xce61e49f,
|
||||
0x5edef90e, 0x29d9c998, 0xb0d09822, 0xc7d7a8b4, 0x59b33d17, 0x2eb40d81,
|
||||
0xb7bd5c3b, 0xc0ba6cad, 0xedb88320, 0x9abfb3b6, 0x03b6e20c, 0x74b1d29a,
|
||||
0xead54739, 0x9dd277af, 0x04db2615, 0x73dc1683, 0xe3630b12, 0x94643b84,
|
||||
0x0d6d6a3e, 0x7a6a5aa8, 0xe40ecf0b, 0x9309ff9d, 0x0a00ae27, 0x7d079eb1,
|
||||
0xf00f9344, 0x8708a3d2, 0x1e01f268, 0x6906c2fe, 0xf762575d, 0x806567cb,
|
||||
0x196c3671, 0x6e6b06e7, 0xfed41b76, 0x89d32be0, 0x10da7a5a, 0x67dd4acc,
|
||||
0xf9b9df6f, 0x8ebeeff9, 0x17b7be43, 0x60b08ed5, 0xd6d6a3e8, 0xa1d1937e,
|
||||
0x38d8c2c4, 0x4fdff252, 0xd1bb67f1, 0xa6bc5767, 0x3fb506dd, 0x48b2364b,
|
||||
0xd80d2bda, 0xaf0a1b4c, 0x36034af6, 0x41047a60, 0xdf60efc3, 0xa867df55,
|
||||
0x316e8eef, 0x4669be79, 0xcb61b38c, 0xbc66831a, 0x256fd2a0, 0x5268e236,
|
||||
0xcc0c7795, 0xbb0b4703, 0x220216b9, 0x5505262f, 0xc5ba3bbe, 0xb2bd0b28,
|
||||
0x2bb45a92, 0x5cb36a04, 0xc2d7ffa7, 0xb5d0cf31, 0x2cd99e8b, 0x5bdeae1d,
|
||||
0x9b64c2b0, 0xec63f226, 0x756aa39c, 0x026d930a, 0x9c0906a9, 0xeb0e363f,
|
||||
0x72076785, 0x05005713, 0x95bf4a82, 0xe2b87a14, 0x7bb12bae, 0x0cb61b38,
|
||||
0x92d28e9b, 0xe5d5be0d, 0x7cdcefb7, 0x0bdbdf21, 0x86d3d2d4, 0xf1d4e242,
|
||||
0x68ddb3f8, 0x1fda836e, 0x81be16cd, 0xf6b9265b, 0x6fb077e1, 0x18b74777,
|
||||
0x88085ae6, 0xff0f6a70, 0x66063bca, 0x11010b5c, 0x8f659eff, 0xf862ae69,
|
||||
0x616bffd3, 0x166ccf45, 0xa00ae278, 0xd70dd2ee, 0x4e048354, 0x3903b3c2,
|
||||
0xa7672661, 0xd06016f7, 0x4969474d, 0x3e6e77db, 0xaed16a4a, 0xd9d65adc,
|
||||
0x40df0b66, 0x37d83bf0, 0xa9bcae53, 0xdebb9ec5, 0x47b2cf7f, 0x30b5ffe9,
|
||||
0xbdbdf21c, 0xcabac28a, 0x53b39330, 0x24b4a3a6, 0xbad03605, 0xcdd70693,
|
||||
0x54de5729, 0x23d967bf, 0xb3667a2e, 0xc4614ab8, 0x5d681b02, 0x2a6f2b94,
|
||||
0xb40bbe37, 0xc30c8ea1, 0x5a05df1b, 0x2d02ef8d ]
|
||||
|
||||
def crc32( previousCrc, L ):
|
||||
crc = previousCrc
|
||||
for b in L:
|
||||
crc = crc32Table[( crc ^ b) & 0xFF ] ^ ( crc >> 8 )
|
||||
return (~crc & 0xFFFFFFFF)
|
||||
|
||||
#******************************************************************************
|
||||
#
|
||||
# Read in the source *.emp file, update the CRC and write it to destination
|
||||
# *.emp file. This only works for *.emp files with single containers.
|
||||
#
|
||||
#******************************************************************************
|
||||
def process(source, destination):
|
||||
sourceData = open(source, "rb").read()
|
||||
destData = bytearray(sourceData)
|
||||
print(binascii.b2a_hex(sourceData))
|
||||
size = struct.unpack("<I", sourceData[4:4+4])[0]
|
||||
destData[16:16+4] = struct.pack("<I", 0)
|
||||
packetCRC = crc32(0xFFFFFFFF,destData[0:size])
|
||||
destData[16:16+4] = struct.pack("<I", packetCRC)
|
||||
print(binascii.b2a_hex(destData))
|
||||
open(destination, "wb").write(destData)
|
||||
return
|
||||
|
||||
#******************************************************************************
|
||||
#
|
||||
# Main program flow
|
||||
#
|
||||
#******************************************************************************
|
||||
if __name__ == '__main__':
|
||||
parser = argparse.ArgumentParser(description =
|
||||
'Updates CRC32 for EM9304 *.emp files.')
|
||||
parser.add_argument('-i', dest = 'sourcefile', help = 'Source *.emp file')
|
||||
|
||||
parser.add_argument('-o', dest = 'destfile', help = 'Destination *.emp file')
|
||||
|
||||
args = parser.parse_args()
|
||||
process(args.sourcefile,args.destfile)
|
||||
@@ -0,0 +1 @@
|
||||
from .linker_config import generate_files
|
||||
@@ -0,0 +1,181 @@
|
||||
from string import Template
|
||||
import re
|
||||
|
||||
|
||||
def fix_startup_file(config, filename):
|
||||
|
||||
# Get the stack size from the config file. Note that the startup file
|
||||
# measures in words, not bytes.
|
||||
stack_size = config['STACK']['size'] // 4
|
||||
|
||||
# Read in every line of the given file
|
||||
input_lines = None
|
||||
with open(filename) as f:
|
||||
input_lines = [line for line in f]
|
||||
|
||||
# Perform a search-and-replace with the new stack size.
|
||||
def fix_line(line):
|
||||
return re.sub(r'(g_pui32Stack\[)([x0-9a-fA-F]*)',
|
||||
r'\g<1>' + str(stack_size),
|
||||
line)
|
||||
|
||||
output_lines = map(fix_line, input_lines)
|
||||
output_text = ''.join(output_lines)
|
||||
|
||||
# Write the new file back to the input
|
||||
with open(filename, 'w') as f:
|
||||
f.write(output_text)
|
||||
|
||||
|
||||
def generate_link_script(config):
|
||||
D = dict()
|
||||
D['ro_base'] = format_hex(config['ROMEM']['start'])
|
||||
D['ro_size'] = config['ROMEM']['size']
|
||||
|
||||
D['rw_base'] = format_hex(config['RWMEM']['start'])
|
||||
D['rw_size'] = config['RWMEM']['size']
|
||||
|
||||
D['stack_base'] = format_hex(config['STACK']['start'])
|
||||
D['stack_size'] = config['STACK']['size']
|
||||
|
||||
D['tcm_base'] = format_hex(config['TCM']['start'])
|
||||
D['tcm_size'] = config['TCM']['size']
|
||||
|
||||
D['section_definitions'] = format_section_definitions(config)
|
||||
D['additional_sections'] = format_sections(config)
|
||||
|
||||
return link_script_template.substitute(**D)
|
||||
|
||||
|
||||
def format_section_definitions(config):
|
||||
|
||||
def format_section_definition(section):
|
||||
mapping = {
|
||||
'name': section,
|
||||
'permissions': config[section]['perm'],
|
||||
'base': format_hex(config[section]['start']),
|
||||
'length': format_hex(config[section]['size']),
|
||||
}
|
||||
|
||||
return section_definition_template.substitute(**mapping)
|
||||
|
||||
extra_sections = get_extra_sections(config)
|
||||
return ''.join(map(format_section_definition, extra_sections))
|
||||
|
||||
|
||||
def format_sections(config):
|
||||
|
||||
def format_section(section):
|
||||
mapping = {
|
||||
'name': section,
|
||||
}
|
||||
|
||||
return section_template.substitute(**mapping)
|
||||
|
||||
extra_sections = get_extra_sections(config)
|
||||
return ''.join(map(format_section, extra_sections))
|
||||
|
||||
|
||||
def get_extra_sections(config):
|
||||
def section_not_required(x):
|
||||
return x not in ['ROMEM', 'RWMEM', 'STACK', 'TCM']
|
||||
|
||||
return list(filter(section_not_required, config))
|
||||
|
||||
|
||||
def format_hex(n):
|
||||
return '0x{:08X}'.format(n)
|
||||
|
||||
|
||||
link_script_template = Template('''\
|
||||
/******************************************************************************
|
||||
*
|
||||
* linker_script.ld - Linker script for applications using startup_gnu.c
|
||||
*
|
||||
*****************************************************************************/
|
||||
ENTRY(Reset_Handler)
|
||||
|
||||
MEMORY
|
||||
{
|
||||
ROMEM (rx) : ORIGIN = ${ro_base}, LENGTH = ${ro_size}
|
||||
RWMEM (rwx) : ORIGIN = ${rw_base}, LENGTH = ${rw_size}
|
||||
TCM (rwx) : ORIGIN = ${tcm_base}, LENGTH = ${tcm_size}
|
||||
STACKMEM (rwx) : ORIGIN = ${stack_base}, LENGTH = ${stack_size}
|
||||
}
|
||||
|
||||
SECTIONS
|
||||
{
|
||||
.text :
|
||||
{
|
||||
. = ALIGN(4);
|
||||
KEEP(*(.isr_vector))
|
||||
KEEP(*(.patch))
|
||||
*(.text)
|
||||
*(.text*)
|
||||
*(.rodata)
|
||||
*(.rodata*)
|
||||
. = ALIGN(4);
|
||||
_etext = .;
|
||||
} > ROMEM
|
||||
|
||||
.data :
|
||||
{
|
||||
. = ALIGN(4);
|
||||
_sdata = .;
|
||||
*(.data)
|
||||
*(.data*)
|
||||
. = ALIGN(4);
|
||||
_edata = .;
|
||||
} > RWMEM AT>ROMEM
|
||||
|
||||
/* used by startup to initialize data */
|
||||
_init_data = LOADADDR(.data);
|
||||
|
||||
.tcm :
|
||||
{
|
||||
. = ALIGN(4);
|
||||
_stcm = .;
|
||||
*(.tcm)
|
||||
*(.tcm*)
|
||||
. = ALIGN(4);
|
||||
_etcm = .;
|
||||
} > TCM AT>ROMEM
|
||||
|
||||
/* used by startup to initialize tcm */
|
||||
_init_tcm = LOADADDR(.tcm);
|
||||
|
||||
/* User stack section initialized by startup code. */
|
||||
.stack (NOLOAD):
|
||||
{
|
||||
. = ALIGN(8);
|
||||
*(.stack)
|
||||
*(.stack*)
|
||||
. = ALIGN(8);
|
||||
} > STACKMEM
|
||||
|
||||
.bss :
|
||||
{
|
||||
. = ALIGN(4);
|
||||
_sbss = .;
|
||||
*(.bss)
|
||||
*(.bss*)
|
||||
*(COMMON)
|
||||
. = ALIGN(4);
|
||||
_ebss = .;
|
||||
} > RWMEM
|
||||
|
||||
.ARM.attributes 0 : { *(.ARM.attributes) }
|
||||
}\
|
||||
''')
|
||||
|
||||
section_definition_template = Template('''\
|
||||
${name} (${permissions}) : ORIGIN = ${base}, LENGTH = ${length}
|
||||
''')
|
||||
|
||||
section_template = Template('''\
|
||||
${name} :
|
||||
{
|
||||
*(${name})
|
||||
} > ${name}
|
||||
|
||||
''')
|
||||
@@ -0,0 +1,168 @@
|
||||
from string import Template
|
||||
import re
|
||||
|
||||
required_sections = ['ROMEM', 'RWMEM', 'STACK']
|
||||
|
||||
|
||||
def fix_startup_file(config, filename):
|
||||
|
||||
# Get the stack size from the config file. Note that the startup file
|
||||
# measures in words, not bytes.
|
||||
stack_size = config['STACK']['size'] // 4
|
||||
|
||||
# Read in every line of the given file
|
||||
input_lines = None
|
||||
with open(filename) as f:
|
||||
input_lines = [line for line in f]
|
||||
|
||||
# Perform a search-and-replace with the new stack size.
|
||||
def fix_line(line):
|
||||
return re.sub(r'(pui32Stack\[)([x0-9a-fA-F]*)',
|
||||
r'\g<1>' + str(stack_size),
|
||||
line)
|
||||
|
||||
output_lines = map(fix_line, input_lines)
|
||||
output_text = ''.join(output_lines)
|
||||
|
||||
# Write the new file back to the input
|
||||
with open(filename, 'w') as f:
|
||||
f.write(output_text)
|
||||
|
||||
|
||||
def generate_link_script(config):
|
||||
robase = config['ROMEM']['start']
|
||||
roend = robase + config['ROMEM']['size']
|
||||
rwbase = config['RWMEM']['start']
|
||||
rwend = rwbase + config['RWMEM']['size']
|
||||
tcmbase = config['TCM']['start']
|
||||
tcmend = tcmbase + config['TCM']['size']
|
||||
stackbase = config['STACK']['start']
|
||||
stackend = stackbase + config['STACK']['size']
|
||||
|
||||
D = dict()
|
||||
D['robase'] = format_hex(robase)
|
||||
D['roend'] = format_hex(roend)
|
||||
D['rwbase'] = format_hex(rwbase)
|
||||
D['rwend'] = format_hex(rwend)
|
||||
D['tcmbase'] = format_hex(tcmbase)
|
||||
D['tcmend'] = format_hex(tcmend)
|
||||
|
||||
D['stackbase'] = format_hex(stackbase)
|
||||
D['stackend'] = format_hex(stackend)
|
||||
|
||||
D['stack_size'] = config['STACK']['size']
|
||||
|
||||
#D['section_defs'] = format_sections(section_definition, config)
|
||||
#D['section_blocks'] = format_sections(section_block, config)
|
||||
#D['section_placements'] = format_sections(section_placement, config)
|
||||
|
||||
return link_script_template.substitute(**D)
|
||||
|
||||
|
||||
def format_sections(template, config):
|
||||
|
||||
def fill_section_template(section):
|
||||
mapping = {
|
||||
'section_name': section,
|
||||
'block_name': section + '_BLOCK',
|
||||
'mem_name': section + '_MEM',
|
||||
'align': 4,
|
||||
'start': format_hex(config[section]['start']),
|
||||
'size': format_hex(config[section]['size']),
|
||||
'end': format_hex(config[section]['start'] +
|
||||
config[section]['size']),
|
||||
|
||||
'permissions': convert_permissions(config[section]['perm']),
|
||||
}
|
||||
|
||||
return template.substitute(**mapping)
|
||||
|
||||
def is_extra_section(section):
|
||||
return section not in required_sections
|
||||
|
||||
sections = filter(is_extra_section, config)
|
||||
|
||||
return ''.join(map(fill_section_template, sections))
|
||||
|
||||
|
||||
def convert_permissions(perm_string):
|
||||
if 'r' in perm_string and 'w' in perm_string and 'x' in perm_string:
|
||||
return 'readwrite'
|
||||
else:
|
||||
return 'readonly'
|
||||
|
||||
|
||||
def format_hex(n):
|
||||
return '0x{:08X}'.format(n)
|
||||
|
||||
|
||||
link_script_template = Template('''\
|
||||
//*****************************************************************************
|
||||
//
|
||||
// linker_script.icf
|
||||
//
|
||||
// IAR linker Configuration File
|
||||
//
|
||||
//*****************************************************************************
|
||||
|
||||
//
|
||||
// Define a memory section that covers the entire 4 GB addressable space of the
|
||||
// processor. (32-bit can address up to 4GB)
|
||||
//
|
||||
define memory mem with size = 4G;
|
||||
|
||||
//
|
||||
// Define regions for the various types of internal memory.
|
||||
//
|
||||
define region ROMEM = mem:[from ${robase} to ${roend}];
|
||||
define region RWMEM = mem:[from ${rwbase} to ${rwend}];
|
||||
define region TCM = mem:[from ${tcmbase} to ${tcmend}];
|
||||
define region STACKMEM = mem:[from ${stackbase} to ${stackend}];
|
||||
|
||||
//
|
||||
// Define blocks for logical groups of data.
|
||||
//
|
||||
define block HEAP with alignment = 0x8, size = 0x00000000 { };
|
||||
define block CSTACK with alignment = 0x8, size = ${stack_size}
|
||||
{
|
||||
section .stack
|
||||
};
|
||||
|
||||
define block ROSTART with fixed order
|
||||
{
|
||||
readonly section .intvec,
|
||||
readonly section .patch
|
||||
};
|
||||
|
||||
//
|
||||
// Set section properties.
|
||||
//
|
||||
initialize by copy { readwrite };
|
||||
initialize by copy { section RWMEM };
|
||||
do not initialize { section .noinit };
|
||||
do not initialize { section .stack };
|
||||
|
||||
//
|
||||
// Place code sections in memory regions.
|
||||
//
|
||||
place at start of ROMEM { block ROSTART };
|
||||
place in ROMEM { readonly };
|
||||
place at start of STACKMEM { block CSTACK};
|
||||
place in RWMEM { block HEAP, readwrite, section .noinit };
|
||||
place in TCM { section .tcm };
|
||||
''')
|
||||
|
||||
section_definition = Template('''\
|
||||
define region ${mem_name} = mem:[from ${start} to ${end}];
|
||||
''')
|
||||
|
||||
section_block = Template('''\
|
||||
define block ${block_name} with alignment = ${align}, size = ${size}
|
||||
{
|
||||
${permissions} section ${section_name}
|
||||
};
|
||||
''')
|
||||
|
||||
section_placement = Template('''\
|
||||
place in ${mem_name} { block ${block_name} };
|
||||
''')
|
||||
@@ -0,0 +1,171 @@
|
||||
from string import Template
|
||||
import textwrap
|
||||
import re
|
||||
|
||||
|
||||
def fix_startup_file(config, filename):
|
||||
|
||||
# Get the stack size from the config file. Note that the startup file
|
||||
# measures in words, not bytes.
|
||||
stack_size = config['STACK']['size']
|
||||
|
||||
# Read in every line of the given file
|
||||
input_lines = None
|
||||
with open(filename) as f:
|
||||
input_lines = [line for line in f]
|
||||
|
||||
# Perform a search-and-replace with the new stack size.
|
||||
def fix_line(line):
|
||||
return re.sub(r'(Stack EQU )0x[0-9a-fA-F]*',
|
||||
r'\g<1>' + '0x{:08X}'.format(stack_size),
|
||||
line)
|
||||
|
||||
output_lines = map(fix_line, input_lines)
|
||||
output_text = ''.join(output_lines)
|
||||
|
||||
# Write the new file back to the input
|
||||
with open(filename, 'w') as f:
|
||||
f.write(output_text)
|
||||
|
||||
|
||||
def generate_link_script(config):
|
||||
|
||||
mapping = dict()
|
||||
mapping['ro_base'] = format_number(config['ROMEM']['start'])
|
||||
mapping['ro_size'] = format_number(config['ROMEM']['size'])
|
||||
mapping['rw_base'] = format_number(config['RWMEM']['start'])
|
||||
mapping['rw_size'] = format_number(config['RWMEM']['size'])
|
||||
mapping['stack_base'] = format_number(config['STACK']['start'])
|
||||
mapping['stack_size'] = format_number(config['STACK']['size'])
|
||||
mapping['tcm_base'] = format_number(config['TCM']['start'])
|
||||
mapping['tcm_size'] = format_number(config['TCM']['size'])
|
||||
mapping['additional_sections'] = generate_sections(config)
|
||||
|
||||
link_script = link_script_template.substitute(**mapping)
|
||||
debug_file = debug_file_template.substitute(**mapping)
|
||||
|
||||
return (link_script, debug_file)
|
||||
|
||||
|
||||
def generate_sections(config):
|
||||
# If there aren't any custom sections in the config file, we don't need to
|
||||
# add anything to the linker scripts.
|
||||
if 'custom_sections' not in config:
|
||||
return ''
|
||||
elif not config['custom_sections']:
|
||||
return ''
|
||||
|
||||
L = []
|
||||
for mem_section in config['custom_sections']:
|
||||
D = dict()
|
||||
D['name'] = mem_section['blockname']
|
||||
D['start'] = format_number(mem_section['start'])
|
||||
D['length'] = format_number(mem_section['length'])
|
||||
D['sections'] = '\n'.join(' * ({})'.format(x) for x in mem_section['sections'])
|
||||
|
||||
S = extra_section_template.substitute(**D)
|
||||
L.append(textwrap.indent(S, 4 * ' '))
|
||||
|
||||
return '\n' + '\n'.join(L)
|
||||
|
||||
|
||||
def format_number(n):
|
||||
return '0x{:08X}'.format(n)
|
||||
|
||||
|
||||
link_script_template = Template('''\
|
||||
;******************************************************************************
|
||||
;
|
||||
; Scatter file for Keil linker configuration.
|
||||
;
|
||||
;******************************************************************************
|
||||
LR_1 ${ro_base}
|
||||
{
|
||||
ROMEM ${ro_base} ${ro_size}
|
||||
{
|
||||
*.o (RESET, +First)
|
||||
* (+RO)
|
||||
}
|
||||
|
||||
RWMEM ${rw_base} ${rw_size}
|
||||
{
|
||||
* (+RW, +ZI)
|
||||
}
|
||||
|
||||
TCM ${tcm_base} ${tcm_size}
|
||||
{
|
||||
* (.tcm)
|
||||
}
|
||||
|
||||
STACKMEM ${stack_base} ${stack_size}
|
||||
{
|
||||
startup_keil.o (STACK)
|
||||
}
|
||||
}
|
||||
''')
|
||||
|
||||
extra_section_template = Template('''\
|
||||
${name} ${start} ${length}
|
||||
{
|
||||
${sections}
|
||||
}
|
||||
''')
|
||||
|
||||
debug_file_template = Template('''\
|
||||
/*----------------------------------------------------------------------------
|
||||
* Name: Dbg_RAM.ini
|
||||
* Purpose: RAM Debug Initialization File
|
||||
* Note(s):
|
||||
*----------------------------------------------------------------------------
|
||||
* This file is part of the uVision/ARM development tools.
|
||||
* This software may only be used under the terms of a valid, current,
|
||||
* end user licence from KEIL for a compatible version of KEIL software
|
||||
* development tools. Nothing else gives you the right to use this software.
|
||||
*
|
||||
* This software is supplied "AS IS" without warranties of any kind.
|
||||
*
|
||||
* Copyright (c) 2008-2013 Keil - An ARM Company. All rights reserved.
|
||||
*----------------------------------------------------------------------------*/
|
||||
|
||||
|
||||
/*----------------------------------------------------------------------------
|
||||
TraceSetup() Turn on ITM clocks, etc.
|
||||
*----------------------------------------------------------------------------*/
|
||||
FUNC void TraceSetup (void)
|
||||
{
|
||||
// turn on the ITM/TPIU clock
|
||||
//_WDWORD(0x40020250, 0x00000201); // TPIU clock enabled at 3MHz
|
||||
}
|
||||
|
||||
/*----------------------------------------------------------------------------
|
||||
Setup() configure PC & SP for RAM Debug
|
||||
*----------------------------------------------------------------------------*/
|
||||
FUNC void Setup (void) {
|
||||
SP = _RDWORD(${ro_base}+0x0); // Setup Stack Pointer
|
||||
PC = _RDWORD(${ro_base}+0x4); // Setup Program Counter
|
||||
_WDWORD(0xE000ED08, ${ro_base}+0x0); // Setup Vector Table Offset Register (done in system file)
|
||||
}
|
||||
|
||||
/*----------------------------------------------------------------------------
|
||||
OnResetExec() executed after reset via uVision's 'Reset'-button
|
||||
*----------------------------------------------------------------------------*/
|
||||
FUNC void OnResetExec (void)
|
||||
{
|
||||
}
|
||||
|
||||
LOAD %L INCREMENTAL // load the application
|
||||
Setup(); // Setup for Running
|
||||
|
||||
BS main
|
||||
g
|
||||
|
||||
/*----------------------------------------------------------------------------
|
||||
*----------------------------------------------------------------------------*/
|
||||
''')
|
||||
|
||||
extra_section_template = Template('''\
|
||||
${name} ${start} ${length}
|
||||
{
|
||||
${sections}
|
||||
}
|
||||
''')
|
||||
@@ -0,0 +1,224 @@
|
||||
# <TextAddressRange></TextAddressRange>
|
||||
# <DataAddressRange></DataAddressRange>
|
||||
import argparse
|
||||
import yaml
|
||||
from . import iar_link
|
||||
from . import gcc_link
|
||||
from . import keil_link
|
||||
|
||||
# Linker file locations.
|
||||
IAR_LD_SCRIPT = "iar/linker_script.icf"
|
||||
KEIL_LD_SCRIPT = "keil/linker_script.sct"
|
||||
KEIL_DEBUG_FILE = "keil/Dbg_RAM.ini"
|
||||
GCC_LD_SCRIPT = "gcc/linker_script.ld"
|
||||
|
||||
KEIL_STARTUP_FILE = "keil/startup_keil.s"
|
||||
IAR_STARTUP_FILE = "iar/startup_iar.c"
|
||||
GCC_STARTUP_FILE = "gcc/startup_gcc.c"
|
||||
|
||||
|
||||
def main():
|
||||
parser = argparse.ArgumentParser()
|
||||
parser.add_argument('config_file', default='default_config_apollo3.yaml')
|
||||
parser.add_argument('-i', dest='iar', action='store_true')
|
||||
parser.add_argument('-k', dest='keil', action='store_true')
|
||||
parser.add_argument('-g', dest='gcc', action='store_true')
|
||||
|
||||
args = parser.parse_args()
|
||||
|
||||
# Read the configuration file.
|
||||
config = read_configuration(args.config_file)
|
||||
|
||||
# Figure out what we want to build. If no specific toolchains were
|
||||
# specified, just build everything. Otherwise, only build what was
|
||||
# specified.
|
||||
build_all = True
|
||||
|
||||
if args.keil:
|
||||
write_keil_linker_scripts(config)
|
||||
build_all = False
|
||||
|
||||
if args.iar:
|
||||
write_iar_linker_scripts(config)
|
||||
build_all = False
|
||||
|
||||
if args.gcc:
|
||||
write_gcc_linker_scripts(config)
|
||||
build_all = False
|
||||
|
||||
if build_all:
|
||||
write_keil_linker_scripts(config)
|
||||
write_iar_linker_scripts(config)
|
||||
write_gcc_linker_scripts(config)
|
||||
|
||||
# Print the memory map
|
||||
print_memory_map(config)
|
||||
|
||||
|
||||
def generate_files(config_file, toolchains):
|
||||
config = read_configuration(config_file)
|
||||
|
||||
print_memory_map(config)
|
||||
|
||||
if 'keil' in toolchains:
|
||||
write_keil_linker_scripts(config)
|
||||
|
||||
if 'iar' in toolchains:
|
||||
write_iar_linker_scripts(config)
|
||||
|
||||
if 'gcc' in toolchains:
|
||||
write_gcc_linker_scripts(config)
|
||||
|
||||
|
||||
def read_configuration(config_file):
|
||||
"""Read a configuration YAML files and return a dictionary of memory sections"""
|
||||
|
||||
# Read the YAML configuration file as is.
|
||||
with open(config_file) as file_object:
|
||||
config_string = file_object.read()
|
||||
config = yaml.load(config_string, Loader=yaml.FullLoader)
|
||||
|
||||
memory_sections = config['MemorySections']
|
||||
|
||||
# Search through the memory sections...
|
||||
for name in memory_sections.keys():
|
||||
|
||||
# Find the start value, and convert it if necessary.
|
||||
start = memory_sections[name]['start']
|
||||
memory_sections[name]['start'] = convert_number(start)
|
||||
|
||||
# If we find a size value, use it.
|
||||
if 'size' in memory_sections[name]:
|
||||
size = memory_sections[name]['size']
|
||||
memory_sections[name]['size'] = convert_number(size)
|
||||
|
||||
# It not, try to use an "end" value.
|
||||
elif 'end' in memory_sections[name]:
|
||||
end = memory_sections[name]['end']
|
||||
memory_sections[name]['size'] = convert_number(end) - convert_number(start)
|
||||
|
||||
stack_size = config['StackOptions']['size']
|
||||
config['StackOptions']['size'] = convert_number(stack_size)
|
||||
|
||||
# Create a memory section for the stack.
|
||||
memory_sections['STACK'] = dict()
|
||||
|
||||
# Create a section for the stack. To do this, we'll either need to
|
||||
# carve space out of TCM or RWMEM.
|
||||
if config['StackOptions']['place_in_tcm']:
|
||||
if config['StackOptions']['size'] > memory_sections['TCM']['size']:
|
||||
raise LinkerConfigError("Stack ({} B) doesn't fit in TCM ({} B)".format(
|
||||
config['StackOptions']['size'],
|
||||
memory_sections['TCM']['size']))
|
||||
|
||||
memory_sections['STACK']['start'] = memory_sections['TCM']['start']
|
||||
|
||||
memory_sections['STACK']['size'] = config['StackOptions']['size']
|
||||
|
||||
memory_sections['TCM']['start'] = (memory_sections['STACK']['start'] +
|
||||
config['StackOptions']['size'])
|
||||
|
||||
memory_sections['TCM']['size'] = (memory_sections['TCM']['size'] -
|
||||
config['StackOptions']['size'])
|
||||
|
||||
else:
|
||||
if config['StackOptions']['size'] > memory_sections['RWMEM']['size']:
|
||||
raise LinkerConfigError("Stack ({} B) doesn't fit in RWMEM ({} B)".format(
|
||||
config['StackOptions']['size'],
|
||||
memory_sections['RWMEM']['size']))
|
||||
|
||||
memory_sections['STACK']['start'] = memory_sections['RWMEM']['start']
|
||||
|
||||
memory_sections['STACK']['size'] = config['StackOptions']['size']
|
||||
|
||||
memory_sections['RWMEM']['start'] = (memory_sections['STACK']['start'] +
|
||||
config['StackOptions']['size'])
|
||||
|
||||
memory_sections['RWMEM']['size'] = (memory_sections['RWMEM']['size'] -
|
||||
config['StackOptions']['size'])
|
||||
|
||||
return memory_sections
|
||||
|
||||
|
||||
def write_keil_linker_scripts(config):
|
||||
try:
|
||||
linker_file_data, debug_file_data = keil_link.generate_link_script(config)
|
||||
|
||||
with open(KEIL_LD_SCRIPT, 'w') as linker_file:
|
||||
linker_file.write(linker_file_data)
|
||||
|
||||
with open(KEIL_DEBUG_FILE, 'w') as debug_file:
|
||||
debug_file.write(debug_file_data)
|
||||
|
||||
keil_link.fix_startup_file(config, KEIL_STARTUP_FILE)
|
||||
|
||||
except FileNotFoundError:
|
||||
pass
|
||||
|
||||
|
||||
def write_iar_linker_scripts(config):
|
||||
try:
|
||||
with open(IAR_LD_SCRIPT, 'w') as linker_file:
|
||||
linker_file.write(iar_link.generate_link_script(config))
|
||||
|
||||
iar_link.fix_startup_file(config, IAR_STARTUP_FILE)
|
||||
|
||||
except FileNotFoundError:
|
||||
pass
|
||||
|
||||
|
||||
def write_gcc_linker_scripts(config):
|
||||
try:
|
||||
with open(GCC_LD_SCRIPT, 'w') as linker_file:
|
||||
linker_file.write(gcc_link.generate_link_script(config))
|
||||
|
||||
gcc_link.fix_startup_file(config, GCC_STARTUP_FILE)
|
||||
|
||||
except FileNotFoundError:
|
||||
pass
|
||||
|
||||
|
||||
def convert_number(N):
|
||||
"""Take in an integer or a numerical string ending in 'K', and convert it to an int"""
|
||||
if isinstance(N, int):
|
||||
return N
|
||||
elif isinstance(N, str):
|
||||
if N.endswith('K'):
|
||||
return int(N[:-1]) * 1024
|
||||
else:
|
||||
raise LinkerConfigError('"{}" not recognized as a number'.format(N))
|
||||
else:
|
||||
raise LinkerConfigError('"{}" not recognized as a number'.format(N))
|
||||
|
||||
|
||||
def print_memory_map(memory_sections):
|
||||
"""Show the memory map in a human readable format"""
|
||||
# Sort the section names by their starting address.
|
||||
section_names = sorted(memory_sections.keys(), key=lambda x: memory_sections[x]['start'])
|
||||
|
||||
# Search for the longest section name, and record its length.
|
||||
max_name_length = max(len(x) for x in section_names)
|
||||
|
||||
# This is a roundabout way to copy the maximum name length into a format
|
||||
# string, so we can make the output string look pretty.
|
||||
name_format = '{{:{}}}'.format(max_name_length + 1)
|
||||
|
||||
for name in section_names:
|
||||
section = memory_sections[name]
|
||||
mapping = {
|
||||
'name': name_format.format(name + ':'),
|
||||
'start': '0x{:08X}'.format(section['start']),
|
||||
'end': '0x{:08X}'.format(section['start'] + section['size']),
|
||||
'size': section['size'],
|
||||
}
|
||||
|
||||
print('{name} {start:10} - {end:10} ({size} bytes)'.format(**mapping))
|
||||
|
||||
|
||||
# Custom error for linker configuration problems.
|
||||
class LinkerConfigError(Exception):
|
||||
pass
|
||||
|
||||
|
||||
if __name__ == '__main__':
|
||||
main()
|
||||
@@ -0,0 +1,127 @@
|
||||
import string
|
||||
import datetime
|
||||
|
||||
|
||||
memory_header_string = '''\
|
||||
//*****************************************************************************
|
||||
//
|
||||
// file am_memory_map.h
|
||||
//
|
||||
// brief Memory map include file.
|
||||
//
|
||||
// This file is generated by "memory_map.py".
|
||||
//
|
||||
//*****************************************************************************
|
||||
|
||||
//*****************************************************************************
|
||||
//
|
||||
// Copyright (c) {copyrightyear}, Ambiq Micro
|
||||
// All rights reserved.
|
||||
//
|
||||
// Redistribution and use in source and binary forms, with or without
|
||||
// modification, are permitted provided that the following conditions are met:
|
||||
//
|
||||
// 1. Redistributions of source code must retain the above copyright notice,
|
||||
// this list of conditions and the following disclaimer.
|
||||
//
|
||||
// 2. Redistributions in binary form must reproduce the above copyright
|
||||
// notice, this list of conditions and the following disclaimer in the
|
||||
// documentation and/or other materials provided with the distribution.
|
||||
//
|
||||
// 3. Neither the name of the copyright holder nor the names of its
|
||||
// contributors may be used to endorse or promote products derived from this
|
||||
// software without specific prior written permission.
|
||||
//
|
||||
// Third party software included in this distribution is subject to the
|
||||
// additional license terms as defined in the /docs/licenses directory.
|
||||
//
|
||||
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
|
||||
// AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||
// IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
||||
// ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
|
||||
// LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
|
||||
// CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
|
||||
// SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
|
||||
// INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
|
||||
// CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
|
||||
// ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
|
||||
// POSSIBILITY OF SUCH DAMAGE.
|
||||
//
|
||||
// This is part of the AmbiqSuite Development Package.
|
||||
//
|
||||
//*****************************************************************************
|
||||
|
||||
#ifndef AM_MEMORY_MAP_H
|
||||
#define AM_MEMORY_MAP_H
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C"
|
||||
{
|
||||
#endif
|
||||
|
||||
//*****************************************************************************
|
||||
//
|
||||
// Memory block locations.
|
||||
//
|
||||
//*****************************************************************************
|
||||
${memory_locations}
|
||||
|
||||
//*****************************************************************************
|
||||
//
|
||||
// Memory block sizes (in bytes)
|
||||
//
|
||||
//*****************************************************************************
|
||||
${memory_sizes}
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif // AM_MEMORY_MAP_H
|
||||
'''
|
||||
|
||||
currdatetime = datetime.datetime.now()
|
||||
memory_header_template = string.Template(memory_header_string.format(copyrightyear=currdatetime.year))
|
||||
|
||||
|
||||
|
||||
memory_location_define = '#define AM_MEM_{name:36} ((void *) 0x{start:08X})'
|
||||
memory_size_define = '#define AM_MEM_{name:36} {size}'
|
||||
|
||||
|
||||
def generate(memory_sections):
|
||||
|
||||
mapping = {
|
||||
'memory_locations': '\n'.join(write_memory_locations(memory_sections)),
|
||||
'memory_sizes': '\n'.join(write_memory_sizes(memory_sections)),
|
||||
}
|
||||
|
||||
return memory_header_template.substitute(**mapping)
|
||||
|
||||
|
||||
def write_memory_locations(memory_sections):
|
||||
section_names = sorted_sections(memory_sections)
|
||||
for n in section_names:
|
||||
mapping = {
|
||||
'name': n,
|
||||
'start': memory_sections[n]['start'],
|
||||
}
|
||||
yield memory_location_define.format_map(mapping)
|
||||
|
||||
|
||||
def write_memory_sizes(memory_sections):
|
||||
section_names = sorted_sections(memory_sections)
|
||||
for n in section_names:
|
||||
mapping = {
|
||||
'name': n + '_SIZE',
|
||||
'size': memory_sections[n]['size'],
|
||||
}
|
||||
yield memory_size_define.format_map(mapping)
|
||||
|
||||
|
||||
def sorted_sections(memory_sections):
|
||||
|
||||
def start_address(section):
|
||||
return memory_sections[section]['start']
|
||||
|
||||
return sorted(memory_sections.keys(), key=start_address)
|
||||
@@ -0,0 +1,51 @@
|
||||
import argparse
|
||||
import apollo3p
|
||||
import os
|
||||
|
||||
DEFAULT_TOOLCHAINS = ['iar', 'keil', 'gcc']
|
||||
|
||||
linker_generators = {
|
||||
'apollo3p': apollo3p.generate_files,
|
||||
}
|
||||
|
||||
|
||||
def main():
|
||||
parser = argparse.ArgumentParser()
|
||||
parser.add_argument('config_file')
|
||||
parser.add_argument('-i', dest='iar', action='store_true')
|
||||
parser.add_argument('-k', dest='keil', action='store_true')
|
||||
parser.add_argument('-g', dest='gcc', action='store_true')
|
||||
parser.add_argument('-p', dest='part')
|
||||
|
||||
args = parser.parse_args()
|
||||
|
||||
toolchains = []
|
||||
|
||||
if args.iar:
|
||||
toolchains.append('iar')
|
||||
if args.keil:
|
||||
toolchains.append('keil')
|
||||
if args.gcc:
|
||||
toolchains.append('gcc')
|
||||
|
||||
if toolchains == []:
|
||||
#
|
||||
# No command line arguments were specified.
|
||||
# Determine which toolchains need a linker control file based on whether
|
||||
# a directory already exists for that toolchain.
|
||||
#
|
||||
for toolnm in DEFAULT_TOOLCHAINS:
|
||||
if os.path.isdir(toolnm):
|
||||
toolchains.append(toolnm)
|
||||
if toolchains == []:
|
||||
toolchains = DEFAULT_TOOLCHAINS
|
||||
|
||||
if args.part in linker_generators:
|
||||
print('Building linker scripts for {} and toolchains {}.'.format(args.part, toolchains))
|
||||
linker_generators[args.part](args.config_file, toolchains)
|
||||
else:
|
||||
print("Can't generate linker scripts for {}. (No generator functions found)".format(args.part))
|
||||
|
||||
|
||||
if __name__ == '__main__':
|
||||
main()
|
||||
Reference in New Issue
Block a user