microchip: mec: zephyr spi image generation

Added mchp mec zephyr image generator python script. It takes
zephyr.bin as input and produces zephyr.mchp.bin.
The default behavior is to not pad to SPI flash size.
(Enable through CONFIG_MCHP_MEC_UNSIGNED_HEADER=y and
CONFIG_MCHP_MEC_HEADER_FLASH_SIZE_256K=y)

zephyr.mchp.bin is composed of:
1. First 4KB contains TAG at offset 0 and header at offset 0x100
2. Offset 0x1000 is the start of zephyr.bin which has been padded
to a multiple of 128 bytes.
3. Boot-ROM EC Info Block (128 bytes)
4. Boot-ROM Co-Signature Block (96 bytes)
5. Boot-ROM trailer (160 bytes) contains the SHA-384 digest of 2-4.

Signed-off-by: Jay Vasanth <jay.vasanth@microchip.com>
This commit is contained in:
Jay Vasanth 2022-04-29 17:16:36 -04:00 committed by Carles Cufí
commit e74978cc03
3 changed files with 712 additions and 0 deletions

View file

@ -1,6 +1,7 @@
# Microchip MEC MCU line # Microchip MEC MCU line
# Copyright (c) 2018, Intel Corporation # Copyright (c) 2018, Intel Corporation
# Copyright (c) 2022, Microchip Technology Inc.
# SPDX-License-Identifier: Apache-2.0 # SPDX-License-Identifier: Apache-2.0
config SOC_FAMILY_MEC config SOC_FAMILY_MEC
@ -11,6 +12,210 @@ config SOC_FAMILY
string string
default "microchip_mec" default "microchip_mec"
menuconfig MCHP_MEC_UNSIGNED_HEADER
bool "Create an unsigned output binary with MCHP MEC binary header"
help
On Microchip MEC series chip, the ROM code loads firmware image from flash
to RAM using a TAG to locate a Header which specifies the location and
size of the firmware image. Enable this to invoke the mec_spi_gen tool
which generates an SPI image with TAG, Header, and firmware binary. This
tool does not produce a signed image which can be authenticated by the
Boot-ROM. Use the full Microchip SPI image generator program for
authentication and all other Boot-ROM loader features. Refer to the MCHP
EVB boards for an example.
if MCHP_MEC_UNSIGNED_HEADER
config MCHP_MEC_HEADER_CHIP
string
default "mec152x" if SOC_SERIES_MEC1501X
default "mec172x" if SOC_SERIES_MEC172X
choice MCHP_MEC_HEADER_SPI_FREQ_MHZ_CHOICE
prompt "Clock rate to use for SPI flash"
default MCHP_MEC_HEADER_SPI_FREQ_MHZ_12
help
This selects the SPI clock frequency that will be used for loading
firmware binary from flash to RAM.
config MCHP_MEC_HEADER_SPI_FREQ_MHZ_12
bool "SPI flash clock rate of 12 MHz"
config MCHP_MEC_HEADER_SPI_FREQ_MHZ_16
bool "SPI flash clock rate of 16 MHz"
config MCHP_MEC_HEADER_SPI_FREQ_MHZ_24
bool "SPI flash clock rate of 24 MHz"
config MCHP_MEC_HEADER_SPI_FREQ_MHZ_48
bool "SPI flash clock rate of 48 MHz"
endchoice
config MCHP_MEC_HEADER_SPI_FREQ_MHZ
int
default 12 if MCHP_MEC_HEADER_SPI_FREQ_MHZ_12
default 25 if MCHP_MEC_HEADER_SPI_FREQ_MHZ_16
default 24 if MCHP_MEC_HEADER_SPI_FREQ_MHZ_24
default 48 if MCHP_MEC_HEADER_SPI_FREQ_MHZ_48
choice MCHP_MEC_HEADER_SPI_READ_MODE_CHOICE
prompt "Reading mode used by the SPI flash"
default MCHP_MEC_HEADER_SPI_READ_MODE_FAST
help
This sets the reading mode that can be used by the SPI flash.
Reading modes supported are normal, fast, dual, and quad.
config MCHP_MEC_HEADER_SPI_READ_MODE_NORMAL
bool "SPI flash operates full-duplex with frequency (< 25 MHz)"
config MCHP_MEC_HEADER_SPI_READ_MODE_FAST
bool "SPI flash operates full-duplex with fast reading mode"
config MCHP_MEC_HEADER_SPI_READ_MODE_DUAL
bool "SPI flash operates with dual data reading mode"
config MCHP_MEC_HEADER_SPI_READ_MODE_QUAD
bool "SPI flash operates with quad data reading mode"
endchoice
config MCHP_MEC_HEADER_SPI_READ_MODE
string
default "slow" if MCHP_MEC_HEADER_SPI_READ_MODE_NORMAL
default "fast" if MCHP_MEC_HEADER_SPI_READ_MODE_FAST
default "dual" if MCHP_MEC_HEADER_SPI_READ_MODE_DUAL
default "quad" if MCHP_MEC_HEADER_SPI_READ_MODE_QUAD
choice MCHP_MEC_HEADER_FLASH_SIZE_CHOICE
prompt "Flash size"
default MCHP_MEC_HEADER_FLASH_SIZE_16M
help
This sets the SPI flash size.
config MCHP_MEC_HEADER_FLASH_SIZE_256K
bool "SPI flash size 256K Bytes"
help
The SPI flash size is 256K Bytes.
config MCHP_MEC_HEADER_FLASH_SIZE_512K
bool "SPI flash size 512K Bytes"
help
The SPI flash size is 512K Bytes.
config MCHP_MEC_HEADER_FLASH_SIZE_1M
bool "SPI flash size 1M Bytes"
help
The SPI flash size is 1M Bytes.
config MCHP_MEC_HEADER_FLASH_SIZE_2M
bool "SPI flash size 2M Bytes"
help
The SPI flash size is 2M Bytes.
config MCHP_MEC_HEADER_FLASH_SIZE_4M
bool "SPI flash size 4M Bytes"
help
The SPI flash size is 4M Bytes.
config MCHP_MEC_HEADER_FLASH_SIZE_8M
bool "SPI flash size 8M Bytes"
help
The SPI flash size is 8M Bytes.
config MCHP_MEC_HEADER_FLASH_SIZE_16M
bool "SPI flash size 16M Bytes"
help
The SPI flash size is 16M Bytes.
endchoice
config MCHP_MEC_HEADER_FLASH_SIZE
int
default 256 if MCHP_MEC_HEADER_FLASH_SIZE_256K
default 512 if MCHP_MEC_HEADER_FLASH_SIZE_512K
default 1024 if MCHP_MEC_HEADER_FLASH_SIZE_1M
default 2048 if MCHP_MEC_HEADER_FLASH_SIZE_2M
default 4096 if MCHP_MEC_HEADER_FLASH_SIZE_4M
default 8192 if MCHP_MEC_HEADER_FLASH_SIZE_8M
default 16384 if MCHP_MEC_HEADER_FLASH_SIZE_16M
choice MCHP_MEC_HEADER_SPI_DRVSTR_CHOICE
prompt "Flash drive strength"
default MCHP_MEC_HEADER_SPI_DRVSTR_1X
help
This sets the SPI flash size.
config MCHP_MEC_HEADER_SPI_DRVSTR_1X
bool "SPI flash drive strength multiplier 1"
help
The SPI flash size is 256K Bytes.
config MCHP_MEC_HEADER_SPI_DRVSTR_2X
bool "SPI flash drive strength multiplier 2"
help
The SPI flash size is 256K Bytes.
config MCHP_MEC_HEADER_SPI_DRVSTR_4X
bool "SPI flash drive strength multiplier 4"
help
The SPI flash size is 512K Bytes.
config MCHP_MEC_HEADER_SPI_DRVSTR_6X
bool "SPI flash drive strength multiplier 6"
help
The SPI flash size is 1M Bytes.
endchoice
config MCHP_MEC_HEADER_SPI_DRVSTR
string
default "1x" if MCHP_MEC_HEADER_SPI_DRVSTR_1X
default "2x" if MCHP_MEC_HEADER_SPI_DRVSTR_2X
default "4x" if MCHP_MEC_HEADER_SPI_DRVSTR_4X
default "6x" if MCHP_MEC_HEADER_SPI_DRVSTR_6X
choice MCHP_MEC_HEADER_SPI_SLEW_RATE_CHOICE
prompt "Slew rate of SPI pins"
default MCHP_MEC_HEADER_SPI_SLEW_RATE_SLOW
help
This sets the slew rate of the SPI pins. Default is slow
slew rate which is 1/2 the AHB clock rate. Fast slew is the
AHB clock rate.
config MCHP_MEC_HEADER_SPI_SLEW_RATE_SLOW
bool "SPI pins slew rate is 1/2 AHB frequency"
config MCHP_MEC_HEADER_SPI_SLEW_RATE_FAST
bool "SPI pins slew rate is 1x AHB frequency"
endchoice
config MCHP_MEC_HEADER_SPI_SLEW_RATE
string
default "slow" if MCHP_MEC_HEADER_SPI_SLEW_RATE_SLOW
default "fast" if MCHP_MEC_HEADER_SPI_SLEW_RATE_FAST
config MCHP_MEC_HEADER_FLASH_SPI_MODE
int "Flash SPI Mode"
range 0 7
default 0
help
This three bit value corresponds to the QMSPI controllers clock idle and
input/output data phases. Bits[0:2] are CPOL:CPHA_MOSI:CPHA_MISO. Refer
to the data sheet. Default value is 0 corresponding to SPI Mode 0
signalling.
Setting this field to 0 selects mode 0, CPOL=0, CPHA_MOSI=0, CPHA_MISO=0
Setting this filed to 7 selects mode 3, CPOL=1, CPHA_MOSI=1, CPHA_MISO=1
config MCHP_HEADER_VERBOSE_OUTPUT
bool "Debug console output"
default n
help
Enable print output from SPI generator script for debug
endif # MCHP_MEC_UNSIGNED_HEADER
# Select SoC Part No. and configuration options # Select SoC Part No. and configuration options
source "soc/arm/microchip_mec/*/Kconfig.soc" source "soc/arm/microchip_mec/*/Kconfig.soc"

View file

@ -4,3 +4,24 @@ zephyr_include_directories_ifdef(CONFIG_SOC_SERIES_MEC172X .)
zephyr_library_sources_ifdef(CONFIG_SOC_SERIES_MEC172X zephyr_library_sources_ifdef(CONFIG_SOC_SERIES_MEC172X
soc_i2c.c soc_i2c.c
) )
if (DEFINED CONFIG_MCHP_HEADER_VERBOSE_OUTPUT)
set(MCHP_HEADER_VERBOSE_OPTION "-v")
endif()
if (DEFINED CONFIG_MCHP_MEC_UNSIGNED_HEADER)
set(MCHP_MEC_BIN_NAME ${CONFIG_KERNEL_BIN_NAME}.mchp.bin)
set_property(GLOBAL APPEND PROPERTY extra_post_build_commands
COMMAND ${PYTHON_EXECUTABLE} ${SOC_DIR}/${ARCH}/${SOC_FAMILY}/common/spigen/mec_spi_gen.py
-i ${KERNEL_BIN_NAME}
-o ${MCHP_MEC_BIN_NAME}
-c ${CONFIG_MCHP_MEC_HEADER_CHIP}
-s ${CONFIG_MCHP_MEC_HEADER_FLASH_SIZE}
-f ${CONFIG_MCHP_MEC_HEADER_SPI_FREQ_MHZ}
-r ${CONFIG_MCHP_MEC_HEADER_SPI_READ_MODE}
-m ${CONFIG_MCHP_MEC_HEADER_FLASH_SPI_MODE}
--drvstr ${CONFIG_MCHP_MEC_HEADER_SPI_DRVSTR}
--slewrate ${CONFIG_MCHP_MEC_HEADER_SPI_SLEW_RATE}
${MCHP_HEADER_VERBOSE_OPTION}
)
endif()

View file

@ -0,0 +1,486 @@
#!/usr/bin/env python3
# Copyright (c) 2022 Microchip Technology Inc.
# SPDX-License-Identifier: Apache-2.0
import sys
import argparse
import hashlib
verbose_mode = False
# Header parameters
HDR_SIZE = 0x140
HDR_VER_MEC172X = 0x03
HDR_VER_MEC152X = 0x02
HDR_SPI_CLK_12MHZ = 0x3
HDR_SPI_CLK_16MHZ = 0x2
HDR_SPI_CLK_24MHZ = 0x1
HDR_SPI_CLK_48MHZ = 0
HDR_SPI_DRV_STR_1X = 0
HDR_SPI_DRV_STR_2X = 0x4
HDR_SPI_DRV_STR_4X = 0x8
HDR_SPI_DRV_STR_6X = 0xc
HDR_SPI_SLEW_SLOW = 0
HDR_SPI_SLEW_FAST = 0x10
HDR_SPI_CPOL_LO = 0
HDR_SPI_CPOL_HI = 0x20
HDR_SPI_CHPHA_MOSI_EDGE_2 = 0
HDR_SPI_CHPHA_MOSI_EDGE_1 = 0x40
HDR_SPI_CHPHA_MISO_EDGE_1 = 0
HDR_SPI_CHPHA_MISO_EDGE_2 = 0x80
# User defined constants HDR_SPI_RD_ (0, 1, 2, 3) as per boot rom spec.
# 1st digit - number of I/O pins used to transmit the opcode
# 2nd digit - number of I/O pins used to transmit the SPI address
# 3rd digit - number of pins used to read data from flash
# 4th digit (if present) - dummy clocks between address and data phase
HDR_SPI_RD_111 = 0
HDR_SPI_RD_1118 = 1
HDR_SPI_RD_1128 = 2
HDR_SPI_RD_1148 = 3
# Payload parameters
PLD_LOAD_ADDR = 0xc0000
PLD_LOAD_ADDR_MEC172X = 0xc0000
PLD_LOAD_ADDR_MEC152X = 0xe0000
PLD_ENTRY_ADDR = 0
PLD_GRANULARITY = 128
PLD_PAD_SIZE = 128
PLD_PAD_BYTE = b'\xff'
MCHP_CHAR_P = 0x50
MCHP_CHAR_H = 0x48
MCHP_CHAR_C = 0x43
MCHP_CHAR_M = 0x4D
EC_INFO_BLOCK_SIZE = 128
ENCR_KEY_HDR_SIZE = 128
COSIG_SIZE = 96
TRAILER_SIZE = 160
TRAILER_PAD_BYTE = b'\xff'
TAG_SPI_LOC = 0
HDR_SPI_LOC = 0x100
PLD_SPI_LOC = 0x1000
CRC_TABLE = [0x00, 0x07, 0x0e, 0x09, 0x1c, 0x1b, 0x12, 0x15,
0x38, 0x3f, 0x36, 0x31, 0x24, 0x23, 0x2a, 0x2d]
CHIP_DICT = {
'mec152x': { 'sram_base': 0xe0000, 'sram_size': 0x40000, 'header_ver': 2 },
'mec172x': { 'sram_base': 0xc0000, 'sram_size': 0x68000, 'header_ver': 3 },
}
CHIP_DEFAULT = 'mec172x'
SPI_READ_MODE_DEFAULT = 'fast'
SPI_FREQ_MHZ_DEFAULT = 12
SPI_MODE_DEFAULT = 0
SPI_MODE_MIN = 0
SPI_MODE_MAX = 7
SPI_DRIVE_STRENGTH_MULT_DEFAULT = "1x"
SPI_SLEW_RATE_DEFAULT = "slow"
def print_bytes(title, b):
"""Print bytes or bytearray as hex values"""
print("{0} = {{ ".format(title), end='')
count = 1
for v in b:
print("0x{0:02x}, ".format(v), end='')
if (count % 8) == 0:
print("")
count = count + 1
print("}")
def crc8(crc, data):
"""Update CRC8 value.
CRC8-ITU calculation
"""
for v in data:
crc = ((crc << 4) & 0xff) ^ (CRC_TABLE[(crc >> 4) ^ (v >> 4)])
crc = ((crc << 4) & 0xff) ^ (CRC_TABLE[(crc >> 4) ^ (v & 0xf)])
return crc ^ 0x55
def build_tag(hdr_spi_loc):
"""Build MEC172x Boot-ROM TAG
MEC172x Boot-ROM TAG is 4 bytes
bits[23:0] = bits[31:8] of the Header SPI address
Header location must be a mutliple of 256 bytes
bits[31:24] = CRC8-ITU of bits[23:0]
return immutable bytes type
"""
tag = bytearray([(hdr_spi_loc >> 8) & 0xff,
(hdr_spi_loc >> 16) & 0xff,
(hdr_spi_loc >> 24) & 0xff])
tag.append(crc8(0, tag))
return bytes(tag)
def build_header(chip, spi_config, hdr_spi_loc, pld_spi_loc, pld_entry_addr, pld_len):
"""Build MEC152x/MEC172x Boot-ROM SPI image header
Args:
chip: mec152x or mec172x
spi_config: spi configuration
hdr_spi_loc: Header location in SPI Image
pld_spi_loc: Payload(FW binary) location in SPI Image
pld_entry_addr: Payload load address in MEC172x SPI SRAM
Payload entry point address: index 0 instructs Boot-ROM to assume
ARM vector table at beginning of payload and reset handler
address is at offset 4 of payload.
pld_len: Payload length, must be multiple of PLD_GRANULARITY
return: immutable bytes type for built header
"""
hdr = bytearray(HDR_SIZE)
hdr[0] = MCHP_CHAR_P
hdr[1] = MCHP_CHAR_H
hdr[2] = MCHP_CHAR_C
hdr[3] = MCHP_CHAR_M
hdr[4] = CHIP_DICT[chip]['header_ver'] & 0xff
if spi_config['spi_freq_mhz'] == 48:
hdr[5] = HDR_SPI_CLK_48MHZ
elif spi_config['spi_freq_mhz'] == 24:
hdr[5] = HDR_SPI_CLK_24MHZ
elif spi_config['spi_freq_mhz'] == 16:
hdr[5] = HDR_SPI_CLK_16MHZ
else:
hdr[5] = HDR_SPI_CLK_12MHZ
if spi_config['spi_mode'] & 0x01:
hdr[5] |= HDR_SPI_CPOL_HI
if spi_config['spi_mode'] & 0x02:
hdr[5] |= HDR_SPI_CHPHA_MOSI_EDGE_1
if spi_config['spi_mode'] & 0x04:
hdr[5] |= HDR_SPI_CHPHA_MISO_EDGE_2
# translate 1x, 2x, 4x, 6x to 0, 1, 2, 3
if spi_config['spi_drive_str'] == "6x":
hdr[5] |= HDR_SPI_DRV_STR_6X
elif spi_config['spi_drive_str'] == "4x":
hdr[5] |= HDR_SPI_DRV_STR_4X
elif spi_config['spi_drive_str'] == "2x":
hdr[5] |= HDR_SPI_DRV_STR_2X
else:
hdr[5] |= HDR_SPI_DRV_STR_1X
# translate "slow", "fast" to 0, 1
if spi_config['spi_slew_rate'] == "fast":
hdr[5] |= HDR_SPI_SLEW_FAST
# MEC172x b[0]=0 do not allow 96MHz SPI clock
hdr[6] = 0 # not using authentication or encryption
if spi_config['spi_read_mode'] == 'quad':
hdr[7] = HDR_SPI_RD_1148
elif spi_config['spi_read_mode'] == 'dual':
hdr[7] = HDR_SPI_RD_1128
elif spi_config['spi_read_mode'] == 'normal':
hdr[7] = HDR_SPI_RD_111
else:
hdr[7] = HDR_SPI_RD_1118
# payload load address in SRAM
pld_load_addr = CHIP_DICT[chip]['sram_base']
hdr[8] = pld_load_addr & 0xff
hdr[9] = (pld_load_addr >> 8) & 0xff
hdr[0xA] = (pld_load_addr >> 16) & 0xff
hdr[0xB] = (pld_load_addr >> 24) & 0xff
# payload entry point address in SRAM
hdr[0xC] = pld_entry_addr & 0xff
hdr[0xD] = (pld_entry_addr >> 8) & 0xff
hdr[0xE] = (pld_entry_addr >> 16) & 0xff
hdr[0xF] = (pld_entry_addr >> 24) & 0xff
# payload size (16-bit) in granularity units
pld_units = pld_len // PLD_GRANULARITY
hdr[0x10] = pld_units & 0xff
hdr[0x11] = (pld_units >> 8) & 0xff
# hdr[0x12:0x13] = 0 reserved
# Unsigned offset from start of Header to start of FW Binary
# FW binary(payload) must always be located after header
pld_offset = pld_spi_loc - hdr_spi_loc
hdr[0x14] = pld_offset & 0xff
hdr[0x15] = (pld_offset >> 8) & 0xff
hdr[0x16] = (pld_offset >> 16) & 0xff
hdr[0x17] = (pld_offset >> 24) & 0xff
# hdr[0x18] = 0 not using authentication
# hdr[0x19] = 0 not adjusting SPI flash device drive strength
# hdr[0x1A through 0x1F] = 0 reserved
# hdr[0x20 through 0x27] = 0 not adjust SPI flash device drive strength
# hdr[0x28 through 0x47] = 0 reserved
# hdr[0x48 through 0x4F] = 0 reserved
# hdr[0x50 through 0x7F] = ECDSA P-384 Public key x-component
# hdr[0x80 through 0xAF] = ECDSA P-384 Public key y-component
# hdr[0xB0 through 0xDF] = SHA-384 digest of hdr[0 through 0xAF] Always required
# hdr[0xE0 through 0x10F] = ECDSA signature R-component of hdr[0 through 0xDF]
# hdr[0x110 through 0x13F] = ECDSA signature S-component of hdr[0 through 0xDF]
h = hashlib.sha384()
h.update(hdr[0:0xB0])
hdr_digest = h.digest()
if verbose_mode:
print_bytes("hdr_sha384_digest", hdr_digest)
hdr[0xB0:0xE0] = hdr_digest
return bytes(hdr)
def parse_args():
parser = argparse.ArgumentParser()
# Use a lambda to handle base 10 or base 16 (hex) input
parser.add_argument("-c",
type=str,
dest="chip",
choices = ["mec152x", "mec172x"],
default="mec172x",
help="Chip name: mec172x(default) or mec152x")
parser.add_argument("-i",
type=str,
dest="infilename",
default="zephyr.bin",
help="Input firmware binary file path/name (default: %(default)s)")
parser.add_argument("-o",
type=str,
dest="outfilename",
default="zephyr.mchp.bin",
help="Output SPI image file path/name (default: %(default)s)")
parser.add_argument("-s",
type=int,
dest="spi_size_kb",
default=256,
help="SPI image size in kilobytes (default: %(default)s)")
parser.add_argument("-e",
type=int,
dest="entry_point",
default=0,
help="FW entry point address Lookup in image (default: %(default)s)")
parser.add_argument("-f",
type=int,
dest="spi_freq_mhz",
choices = [12, 16, 24, 48],
default=12,
help="SPI frequency: 12, 16, 24, or 48 MHz")
parser.add_argument("-r",
type=str,
dest="spi_read_mode",
choices = ["normal", "fast", "dual", "quad"],
default="fast",
help="SPI read mode: normal, fast, dual or quad")
parser.add_argument("-m",
type=int,
dest="spi_mode",
choices = [0, 1, 2, 3, 4, 5, 6, 7],
default=0,
help="SPI signalling mode 3-bit field: 0-7")
parser.add_argument("--drvstr",
type=str,
dest="spi_drive_strength",
choices = ["1x", "2x", "4x", "6x"],
default="1x",
help="SPI pin driver strength multiplier encoded")
parser.add_argument("--slewrate",
type=str,
dest="spi_slew_rate",
choices = ["slow", "fast"],
default="slow",
help="SPI pins slew rate")
parser.add_argument("--fill",
dest="fill",
action='store_true',
help="Fill with 0xFF to flash size")
parser.add_argument("-v",
dest="verbose",
action='store_true',
help="Enable messages to console")
ret_args = parser.parse_args()
return ret_args
def main():
"""MEC SPI Gen"""
args = parse_args()
verbose_mode = args.verbose
if verbose_mode:
print("Command line arguments/defaults")
print(" chip = {0}".format(args.chip))
print(" infilename = {0}".format(args.infilename))
print(" outfilename = {0}".format(args.outfilename))
print(" SPI size (kilobytes) = {0}".format(args.spi_size_kb))
print(" Entry point address = {0}".format(args.entry_point))
print(" SPI frequency MHz = {0}".format(args.spi_freq_mhz))
print(" SPI Read Mode = {0}".format(args.spi_read_mode))
print(" SPI Signalling Mode = {0}".format(args.spi_mode))
print(" SPI drive strength = {0}".format(args.spi_drive_strength))
print(" SPI slew rate fast = {0}".format(args.spi_slew_rate))
print(" Verbose = {0}".format(args.verbose))
if args.infilename is None:
print("ERROR: Specify input binary file name with -i")
sys.exit(-1)
if args.outfilename is None:
print("ERROR: Specify output binary file name with -o")
sys.exit(-1)
chip = args.chip
spi_read_mode = args.spi_read_mode
spi_freq_mhz = args.spi_freq_mhz
spi_mode = args.spi_mode
spi_drive_str_mult = args.spi_drive_strength
spi_slew = args.spi_slew_rate
spi_size = args.spi_size_kb * 1024
indata = None
with open(args.infilename, "rb") as fin:
indata = fin.read()
indata_len = len(indata)
if verbose_mode:
print("Read input FW binary: length = {0}".format(indata_len))
# if necessary pad input data to PLD_GRANULARITY required by Boot-ROM loader
pad_len = 0
if (indata_len % PLD_GRANULARITY) != 0:
pad_len = PLD_GRANULARITY - (indata_len % PLD_GRANULARITY)
# NOTE: MCHP Production SPI Image Gen. pads with 0
padding = PLD_PAD_BYTE * pad_len
indata = indata + padding
indata_len += pad_len
if verbose_mode:
print("Padded FW binary: length = {0}".format(indata_len))
# Do we have enough space for 4KB block containing TAG and Header, padded FW binary,
# EC Info Block, Co-Sig Block, and Trailer?
mec_add_info_size = PLD_SPI_LOC + EC_INFO_BLOCK_SIZE + COSIG_SIZE + TRAILER_SIZE
if indata_len > (spi_size - mec_add_info_size):
print("ERROR: FW binary exceeds flash size! indata_len = {0} spi_size = {1}".format(indata_len, spi_size))
sys.exit(-1)
entry_point = args.entry_point
if args.entry_point == 0:
# Look up entry point in image
# Assumes Cortex-M4 vector table
# at beginning of image and second
# word in table is address of reset handler
entry_point = int.from_bytes(indata[4:8], byteorder="little")
tag = build_tag(HDR_SPI_LOC)
if verbose_mode:
print_bytes("TAG", tag)
print("Build Header at {0}: Load Address = 0x{1:0x} Entry Point Address = 0x{2:0x}".format(
HDR_SPI_LOC, PLD_LOAD_ADDR, entry_point))
spi_config_info = {
"spi_freq_mhz": spi_freq_mhz,
"spi_mode": spi_mode,
"spi_read_mode": spi_read_mode,
"spi_drive_str": spi_drive_str_mult,
"spi_slew_rate": spi_slew,
}
header = build_header(chip, spi_config_info, HDR_SPI_LOC, PLD_SPI_LOC, entry_point, indata_len)
if verbose_mode:
print_bytes("HEADER", header)
print("")
# appended to end of padded payload
ec_info_block = bytearray(EC_INFO_BLOCK_SIZE)
ec_info_loc = PLD_SPI_LOC + len(indata)
# appended to end of (padded payload + ec_info_block)
cosig = bytearray(b'\xff' * COSIG_SIZE)
cosig_loc = ec_info_loc + EC_INFO_BLOCK_SIZE
# appended to end of (padded payload + ec_info_block + cosig)
# trailer[0:0x30] = SHA384(indata || ec_info_block || cosig)
# trailer[0x30:] = 0xFF
trailer = bytearray(b'\xff' * TRAILER_SIZE)
trailer_loc = cosig_loc + COSIG_SIZE
h = hashlib.sha384()
h.update(indata)
h.update(ec_info_block)
h.update(cosig)
image_digest = h.digest()
trailer[0:len(image_digest)] = image_digest
if verbose_mode:
print("SHA-384 digest (paddedFW || ec_info_block || cosig)")
print_bytes("digest", image_digest)
spi_bufs = []
spi_bufs.append(("TAG", TAG_SPI_LOC, tag))
spi_bufs.append(("HEADER", HDR_SPI_LOC, header))
spi_bufs.append(("PAYLOAD", PLD_SPI_LOC, indata))
spi_bufs.append(("EC_INFO", ec_info_loc, ec_info_block))
spi_bufs.append(("COSIG", cosig_loc, cosig))
spi_bufs.append(("TRAILER", trailer_loc, trailer))
spi_bufs.sort(key=lambda x: x[1])
if verbose_mode:
i = 0
for sb in spi_bufs:
print("buf[{0}]: {1} location=0x{2:0x} length=0x{3:0x}".format(i, sb[0], sb[1], len(sb[2])))
print("")
fill = bytes(b'\xff' * 256)
if verbose_mode:
print("len(fill) = {0}".format(len(fill)))
loc = 0
with open(args.outfilename, "wb") as fout:
for sb in spi_bufs:
if verbose_mode:
print("sb: {0} location=0x{1:0x} len=0x{2:0x}".format(sb[0], sb[1], len(sb[2])))
if loc < sb[1]:
fill_len = sb[1] - loc
if verbose_mode:
print("loc = 0x{0:0x}: Fill with 0xFF len=0x{1:0x}".format(loc, fill_len))
nfill = fill_len // 256
rem = fill_len % 256
for _ in range(nfill):
fout.write(fill)
if rem > 0:
fout.write(fill[0:rem])
loc = loc + fill_len
if verbose_mode:
print("loc = 0x{0:0x}: write {1} len=0x{2:0x}".format(loc, sb[0], len(sb[2])))
fout.write(sb[2])
loc = loc + len(sb[2])
if args.fill and (loc < spi_size):
fill_len = spi_size - loc
nfill = fill_len // 256
rem = fill_len % 256
for _ in range(nfill):
fout.write(fill)
if rem > 0:
fout.write(fill[0:rem])
loc = loc + fill_len
if verbose_mode:
print("Final loc = 0x{0:0x}".format(loc))
if verbose_mode:
print("MEC SPI Gen done")
if __name__ == '__main__':
main()