mirror of
https://github.com/RT-Thread/rt-thread.git
synced 2025-02-26 00:17:23 +08:00
Move the combine.sh to under cv18xx_aarch64, so we can run this script the same as scons and no need to change cwd. Rename the folder boot to prebuild just becuase all the files under boot are prebuild binaries. Move the prebuilt fip.bin to under prebuild/milkv-duo256m because it's only for 256. Update combine.sh accordingly and output fip.bin to the output folder where we create fip.bin/boot.sd as other bsp. Signed-off-by: Chen Wang <unicorn_wang@outlook.com>
804 lines
25 KiB
Python
Executable File
804 lines
25 KiB
Python
Executable File
#!/usr/bin/env python3
|
|
# SPDX-License-Identifier: BSD-3-Clause
|
|
# PYTHON_ARGCOMPLETE_OK
|
|
|
|
import sys
|
|
import logging
|
|
import os
|
|
import os.path
|
|
import argparse
|
|
from collections import OrderedDict
|
|
import binascii
|
|
from struct import pack, unpack
|
|
import lzma
|
|
import pprint
|
|
|
|
|
|
PYTHON_MIN_VERSION = (3, 5, 2) # Ubuntu 16.04 LTS contains Python v3.5.2 by default
|
|
|
|
|
|
if sys.version_info < PYTHON_MIN_VERSION:
|
|
print("Python >= %r is required" % (PYTHON_MIN_VERSION,))
|
|
sys.exit(-1)
|
|
|
|
|
|
try:
|
|
import coloredlogs
|
|
except ImportError:
|
|
coloredlogs = None
|
|
|
|
try:
|
|
import argcomplete
|
|
except ImportError:
|
|
argcomplete = None
|
|
|
|
|
|
LOADER_2ND_MAGIC_ORIG = b"BL33"
|
|
LOADER_2ND_MAGIC_LZMA = b"B3MA"
|
|
LOADER_2ND_MAGIC_LZ4 = b"B3Z4"
|
|
|
|
LOADER_2ND_MAGIC_LIST = [
|
|
LOADER_2ND_MAGIC_ORIG,
|
|
LOADER_2ND_MAGIC_LZMA,
|
|
LOADER_2ND_MAGIC_LZ4,
|
|
]
|
|
|
|
IMAGE_ALIGN = 512
|
|
PARAM1_SIZE = 0x1000
|
|
PARAM1_SIZE_WO_SIG = 0x800
|
|
PARAM2_SIZE = 0x1000
|
|
|
|
|
|
def round_up(divident, divisor):
|
|
return ((divident + divisor - 1) // divisor) * divisor
|
|
|
|
|
|
def lzma_compress(body):
|
|
z = lzma.LZMACompressor(lzma.FORMAT_ALONE, preset=lzma.PRESET_EXTREME)
|
|
compressed = z.compress(body)
|
|
compressed += z.flush()
|
|
|
|
return compressed
|
|
|
|
|
|
def lz4_compress(body):
|
|
try:
|
|
import lz4.frame
|
|
except ImportError:
|
|
logging.error("lz4 is not installed. Run 'pip install lz4'.")
|
|
raise
|
|
|
|
compressed = lz4.frame.compress(body)
|
|
return compressed
|
|
|
|
|
|
class Entry:
|
|
__slots__ = "name", "type", "addr", "_content", "entry_size"
|
|
|
|
def __init__(self):
|
|
self.addr = None
|
|
self._content = None
|
|
|
|
@property
|
|
def end(self):
|
|
return self.addr + self.entry_size
|
|
|
|
@property
|
|
def content(self):
|
|
return self._content
|
|
|
|
@content.setter
|
|
def content(self, value):
|
|
if type(value) == int:
|
|
value = value.to_bytes(self.entry_size, "little")
|
|
|
|
if self.entry_size is not None:
|
|
if len(value) > self.entry_size:
|
|
raise ValueError("%s (%d bytes) must <= %#r" % (self.name, len(value), self.entry_size))
|
|
value = value + b"\0" * (self.entry_size - len(value))
|
|
|
|
self._content = value
|
|
|
|
@classmethod
|
|
def make(cls, name, entry_size, _type, init=None):
|
|
entry = Entry()
|
|
entry.name = name
|
|
entry.type = _type
|
|
entry.entry_size = entry_size
|
|
|
|
if type(init) in (bytes, bytearray):
|
|
entry.content = bytes(init)
|
|
elif entry_size is not None:
|
|
entry.content = b"\0" * entry.entry_size
|
|
else:
|
|
entry.content = b""
|
|
|
|
return (name, entry)
|
|
|
|
def toint(self):
|
|
if self.type != int:
|
|
raise TypeError("%s is not int type" % self.name)
|
|
|
|
return int.from_bytes(self.content, "little")
|
|
|
|
def tostr(self):
|
|
v = self.content
|
|
if self.type == int:
|
|
v = "%#08x" % self.toint()
|
|
elif type(self.content) in [bytes, bytearray]:
|
|
v = v.hex()
|
|
if len(v) > 32:
|
|
v = v[:32] + "..."
|
|
|
|
return v
|
|
|
|
def __str__(self):
|
|
v = self.tostr()
|
|
return "<%s=%s (%dbytes)>" % (self.name, v, self.entry_size)
|
|
|
|
def __repr__(self):
|
|
v = self.tostr()
|
|
return "<%s: a=%#x s=%#x c=%s %r>" % (self.name, self.addr, self.entry_size, v, self.type)
|
|
|
|
|
|
class FIP:
|
|
param1 = OrderedDict(
|
|
[
|
|
Entry.make("MAGIC1", 8, int, b"CVBL01\n\0"),
|
|
Entry.make("MAGIC2", 4, int),
|
|
Entry.make("PARAM_CKSUM", 4, int),
|
|
Entry.make("NAND_INFO", 128, int),
|
|
Entry.make("NOR_INFO", 36, int),
|
|
Entry.make("FIP_FLAGS", 8, int),
|
|
Entry.make("CHIP_CONF_SIZE", 4, int),
|
|
Entry.make("BLCP_IMG_CKSUM", 4, int),
|
|
Entry.make("BLCP_IMG_SIZE", 4, int),
|
|
Entry.make("BLCP_IMG_RUNADDR", 4, int),
|
|
Entry.make("BLCP_PARAM_LOADADDR", 4, int),
|
|
Entry.make("BLCP_PARAM_SIZE", 4, int),
|
|
Entry.make("BL2_IMG_CKSUM", 4, int),
|
|
Entry.make("BL2_IMG_SIZE", 4, int),
|
|
Entry.make("BLD_IMG_SIZE", 4, int),
|
|
Entry.make("PARAM2_LOADADDR", 4, int),
|
|
Entry.make("RESERVED1", 4, int),
|
|
Entry.make("CHIP_CONF", 760, bytes),
|
|
Entry.make("BL_EK", 32, bytes),
|
|
Entry.make("ROOT_PK", 512, bytes),
|
|
Entry.make("BL_PK", 512, bytes),
|
|
Entry.make("BL_PK_SIG", 512, bytes),
|
|
Entry.make("CHIP_CONF_SIG", 512, bytes),
|
|
Entry.make("BL2_IMG_SIG", 512, bytes),
|
|
Entry.make("BLCP_IMG_SIG", 512, bytes),
|
|
]
|
|
)
|
|
|
|
body1 = OrderedDict(
|
|
[
|
|
Entry.make("BLCP", None, bytes),
|
|
Entry.make("BL2", None, bytes),
|
|
]
|
|
)
|
|
|
|
param2 = OrderedDict(
|
|
[
|
|
Entry.make("MAGIC1", 8, int, b"CVLD02\n\0"),
|
|
Entry.make("PARAM2_CKSUM", 4, int),
|
|
Entry.make("RESERVED1", 4, bytes),
|
|
# DDR param
|
|
Entry.make("DDR_PARAM_CKSUM", 4, int),
|
|
Entry.make("DDR_PARAM_LOADADDR", 4, int),
|
|
Entry.make("DDR_PARAM_SIZE", 4, int),
|
|
Entry.make("DDR_PARAM_RESERVED", 4, int),
|
|
# BLCP_2ND
|
|
Entry.make("BLCP_2ND_CKSUM", 4, int),
|
|
Entry.make("BLCP_2ND_LOADADDR", 4, int),
|
|
Entry.make("BLCP_2ND_SIZE", 4, int),
|
|
Entry.make("BLCP_2ND_RUNADDR", 4, int),
|
|
# ATF-BL31 or OpenSBI
|
|
Entry.make("MONITOR_CKSUM", 4, int),
|
|
Entry.make("MONITOR_LOADADDR", 4, int),
|
|
Entry.make("MONITOR_SIZE", 4, int),
|
|
Entry.make("MONITOR_RUNADDR", 4, int),
|
|
# u-boot
|
|
Entry.make("LOADER_2ND_RESERVED0", 4, int),
|
|
Entry.make("LOADER_2ND_LOADADDR", 4, int),
|
|
Entry.make("LOADER_2ND_RESERVED1", 4, int),
|
|
Entry.make("LOADER_2ND_RESERVED2", 4, int),
|
|
# Reserved
|
|
Entry.make("RESERVED_LAST", 4096 - 16 * 5, bytes),
|
|
]
|
|
)
|
|
|
|
body2 = OrderedDict(
|
|
[
|
|
Entry.make("DDR_PARAM", None, bytes),
|
|
Entry.make("BLCP_2ND", None, bytes),
|
|
Entry.make("MONITOR", None, bytes),
|
|
Entry.make("LOADER_2ND", None, bytes),
|
|
]
|
|
)
|
|
|
|
ldr_2nd_hdr = OrderedDict(
|
|
[
|
|
Entry.make("JUMP0", 4, int),
|
|
Entry.make("MAGIC", 4, int),
|
|
Entry.make("CKSUM", 4, int),
|
|
Entry.make("SIZE", 4, int),
|
|
Entry.make("RUNADDR", 8, int),
|
|
Entry.make("RESERVED1", 4, int),
|
|
Entry.make("RESERVED2", 4, int),
|
|
]
|
|
)
|
|
|
|
FIP_FLAGS_SCS_MASK = 0x000c
|
|
FIP_FLAGS_ENCRYPTED_MASK = 0x0030
|
|
|
|
def _param_size(self, param):
|
|
return max((e.end for e in param.values()))
|
|
|
|
def _gen_param(self):
|
|
addr = 0
|
|
for entry in self.param1.values():
|
|
entry.addr = addr
|
|
addr += entry.entry_size
|
|
|
|
assert PARAM1_SIZE_WO_SIG == self.param1["BL_PK_SIG"].addr
|
|
|
|
addr = 0
|
|
for entry in self.param2.values():
|
|
entry.addr = addr
|
|
addr += entry.entry_size
|
|
|
|
assert PARAM2_SIZE == self.param2["RESERVED_LAST"].addr + self.param2["RESERVED_LAST"].entry_size
|
|
|
|
addr = 0
|
|
for entry in self.ldr_2nd_hdr.values():
|
|
entry.addr = addr
|
|
addr += entry.entry_size
|
|
|
|
def __init__(self):
|
|
self.compress_algo = None
|
|
self._gen_param()
|
|
|
|
def image_crc(self, image):
|
|
crc = binascii.crc_hqx(image, 0)
|
|
crc = pack("<H", crc) + b"\xFE\xCA"
|
|
return crc
|
|
|
|
def pad(self, data, block_size):
|
|
if type(data) not in [bytearray, bytes]:
|
|
raise TypeError("Need bytearray or bytes")
|
|
|
|
r = len(data) % block_size
|
|
if r:
|
|
data += b"\0" * (block_size - r)
|
|
|
|
return data
|
|
|
|
def _pprint_attr(self, name):
|
|
v = getattr(self, name)
|
|
|
|
if type(v) == OrderedDict:
|
|
v = list(v.values())
|
|
logging.info("print(%s):\n" % name + pprint.pformat(v, 4, 140))
|
|
|
|
def print_fip_params(self):
|
|
self._pprint_attr("param1")
|
|
self._pprint_attr("param2")
|
|
self._pprint_attr("ldr_2nd_hdr")
|
|
|
|
def read_fip(self, path):
|
|
logging.debug("read_fip:")
|
|
|
|
with open(path, "rb") as fp:
|
|
fip_bin = fp.read()
|
|
|
|
fip_bin = bytearray(fip_bin)
|
|
|
|
e = self.param1["MAGIC1"]
|
|
if fip_bin[e.addr : e.end] != e.content:
|
|
raise ValueError("Unknown magic %r" % fip_bin[e.addr : e.end])
|
|
|
|
# Read param1 from fip.bin
|
|
for e in self.param1.values():
|
|
e.content = fip_bin[e.addr : e.end]
|
|
|
|
self.read_end = PARAM1_SIZE
|
|
|
|
# Read BLCP
|
|
e = self.param1["BLCP_IMG_SIZE"]
|
|
blcp_img_size = unpack("<I", fip_bin[e.addr : e.end])[0]
|
|
if blcp_img_size:
|
|
start = self.read_end
|
|
self.read_end = start + blcp_img_size
|
|
self.body1["BLCP"].content = fip_bin[start : self.read_end]
|
|
|
|
# Read FSBL as BL2
|
|
e = self.param1["BL2_IMG_SIZE"]
|
|
bl2_img_size = unpack("<I", fip_bin[e.addr : e.end])[0]
|
|
if bl2_img_size:
|
|
start = self.read_end
|
|
self.read_end = start + bl2_img_size
|
|
self.body1["BL2"].content = fip_bin[start : self.read_end]
|
|
|
|
logging.info("read_fip end=%#x", self.read_end)
|
|
self.rest_fip = fip_bin[self.read_end :]
|
|
|
|
self.read_fip2(fip_bin)
|
|
|
|
def read_fip2(self, fip_bin):
|
|
param2_loadaddr = self.param1["PARAM2_LOADADDR"].toint()
|
|
param2_bin = fip_bin[param2_loadaddr : param2_loadaddr + PARAM2_SIZE]
|
|
|
|
for e in self.param2.values():
|
|
e.content = param2_bin[e.addr : e.end]
|
|
|
|
self.read_end = param2_loadaddr + PARAM2_SIZE
|
|
|
|
# Read DDR_PARAM, BLCP_2ND, and MONITOR
|
|
for name in ["DDR_PARAM", "BLCP_2ND", "MONITOR"]:
|
|
size = self.param2[name + "_SIZE"].toint()
|
|
loadaddr = self.param2[name + "_LOADADDR"].toint()
|
|
self.body2[name].content = fip_bin[loadaddr : loadaddr + size]
|
|
self.read_end = loadaddr + size
|
|
|
|
# Read LOADER_2ND
|
|
loader_2nd_loadaddr = self.param2["LOADER_2ND_LOADADDR"].toint()
|
|
if loader_2nd_loadaddr:
|
|
self.read_loader_2nd(fip_bin)
|
|
|
|
logging.info("read_fip2 end=%#x", self.read_end)
|
|
self.rest_fip = fip_bin[self.read_end :]
|
|
|
|
def read_loader_2nd(self, fip_bin):
|
|
loader_2nd_loadaddr = self.param2["LOADER_2ND_LOADADDR"].toint()
|
|
|
|
self._parse_ldr_2nd_hdr(fip_bin[loader_2nd_loadaddr:])
|
|
|
|
if self.ldr_2nd_hdr["MAGIC"].content not in LOADER_2ND_MAGIC_LIST:
|
|
raise ValueError("%r" % self.ldr_2nd_hdr["MAGIC"].content)
|
|
|
|
ldr_2nd_size = self.ldr_2nd_hdr["SIZE"].toint()
|
|
|
|
self.body2["LOADER_2ND"].content = fip_bin[loader_2nd_loadaddr : loader_2nd_loadaddr + ldr_2nd_size]
|
|
|
|
self.read_end = loader_2nd_loadaddr + ldr_2nd_size
|
|
self.rest_fip = fip_bin[self.read_end :]
|
|
|
|
def add_chip_conf(self, args):
|
|
logging.debug("add_chip_conf:")
|
|
|
|
with open(args.CHIP_CONF, "rb") as fp:
|
|
image = fp.read()
|
|
|
|
if image.startswith(b"APLB"):
|
|
image = image[8:] # strip old BLP header
|
|
|
|
self.param1["CHIP_CONF"].content = image
|
|
|
|
def add_blcp(self, args):
|
|
logging.debug("add_blcp:")
|
|
|
|
with open(args.BLCP, "rb") as fp:
|
|
image = fp.read()
|
|
|
|
image = self.pad(image, IMAGE_ALIGN)
|
|
|
|
self.param1["BLCP_IMG_RUNADDR"].content = args.BLCP_IMG_RUNADDR
|
|
self.body1["BLCP"].content = image
|
|
|
|
def add_bl2(self, args):
|
|
logging.debug("add_bl2:")
|
|
|
|
with open(args.BL2, "rb") as fp:
|
|
image = fp.read()
|
|
|
|
bl2_fill = 0
|
|
if args.BL2_FILL:
|
|
bl2_fill = args.BL2_FILL
|
|
|
|
image += b"\xA9" * (bl2_fill - len(image))
|
|
image = self.pad(image, IMAGE_ALIGN)
|
|
|
|
self.body1["BL2"].content = image
|
|
|
|
def add_nor_info(self, args):
|
|
logging.debug("add_nor_info:")
|
|
self.param1["NOR_INFO"].content = args.NOR_INFO
|
|
|
|
def add_nand_info(self, args):
|
|
logging.debug("add_nand_info:")
|
|
self.param1["NAND_INFO"].content = args.NAND_INFO
|
|
|
|
def update_param1_cksum(self, image):
|
|
image = bytearray(image)
|
|
crc = self.image_crc(image[self.param1["NAND_INFO"].addr : PARAM1_SIZE_WO_SIG])
|
|
|
|
param_cksum = self.param1["PARAM_CKSUM"]
|
|
param_cksum.content = crc
|
|
image[param_cksum.addr : param_cksum.end] = crc
|
|
return image
|
|
|
|
def make_fip1(self):
|
|
logging.debug("make_fip1:")
|
|
|
|
chip_conf = self.param1["CHIP_CONF"].content
|
|
self.param1["CHIP_CONF_SIZE"].content = len(chip_conf)
|
|
|
|
blcp = self.body1["BLCP"].content
|
|
self.param1["BLCP_IMG_CKSUM"].content = self.image_crc(blcp)
|
|
self.param1["BLCP_IMG_SIZE"].content = len(blcp)
|
|
|
|
bl2 = self.body1["BL2"].content
|
|
self.param1["BL2_IMG_CKSUM"].content = self.image_crc(bl2)
|
|
self.param1["BL2_IMG_SIZE"].content = len(bl2)
|
|
|
|
# Pack body1
|
|
body1_bin = b""
|
|
for entry in self.body1.values():
|
|
if len(entry.content) % IMAGE_ALIGN:
|
|
raise ValueError("%s (%d) is not align to %d" % (entry.name, len(entry.content), IMAGE_ALIGN))
|
|
|
|
logging.info("add %s (%#x)", entry.name, len(entry.content))
|
|
body1_bin += entry.content
|
|
|
|
logging.debug("len(body1_bin) is %d", len(body1_bin))
|
|
|
|
# Param1 cksum
|
|
param1_bin = b"".join((entry.content for entry in self.param1.values()))
|
|
param1_bin = self.update_param1_cksum(param1_bin)
|
|
|
|
if len(param1_bin) != PARAM1_SIZE:
|
|
raise ValueError("param1_bin is %d bytes" % len(param1_bin))
|
|
|
|
fip1_bin = param1_bin + body1_bin
|
|
logging.debug("len(fip1_bin) is %d", len(fip1_bin))
|
|
|
|
return fip1_bin
|
|
|
|
def add_ddr_param(self, args):
|
|
with open(args.DDR_PARAM, "rb") as fp:
|
|
ddr_param = fp.read()
|
|
|
|
logging.debug("ddr_param=%#x bytes", len(ddr_param))
|
|
self.body2["DDR_PARAM"].content = ddr_param
|
|
|
|
def add_blcp_2nd(self, args):
|
|
with open(args.BLCP_2ND, "rb") as fp:
|
|
blcp_2nd = fp.read()
|
|
|
|
logging.debug("blcp_2nd=%#x bytes", len(blcp_2nd))
|
|
self.body2["BLCP_2ND"].content = blcp_2nd
|
|
|
|
def add_monitor(self, args):
|
|
with open(args.MONITOR, "rb") as fp:
|
|
monitor = fp.read()
|
|
|
|
logging.debug("monitor=%#x bytes", len(monitor))
|
|
self.body2["MONITOR"].content = monitor
|
|
|
|
def add_loader_2nd(self, args):
|
|
with open(args.LOADER_2ND, "rb") as fp:
|
|
loader_2nd = fp.read()
|
|
|
|
logging.debug("loader_2nd=%#x bytes", len(loader_2nd))
|
|
|
|
e = self.ldr_2nd_hdr["MAGIC"]
|
|
magic = loader_2nd[e.addr : e.end]
|
|
if magic != LOADER_2ND_MAGIC_ORIG:
|
|
raise ValueError("loader_2nd's magic should be %r, but %r" % (LOADER_2ND_MAGIC_ORIG, magic))
|
|
|
|
self.compress_algo = args.compress
|
|
self.body2["LOADER_2ND"].content = loader_2nd
|
|
|
|
def pack_ddr_param(self, fip_bin):
|
|
if not len(self.body2["DDR_PARAM"].content):
|
|
return
|
|
|
|
fip_bin = self.pad(fip_bin, IMAGE_ALIGN)
|
|
|
|
# Pack DDR_PARAM to body2
|
|
ddr_param = self.pad(self.body2["DDR_PARAM"].content, IMAGE_ALIGN)
|
|
|
|
self.param2["DDR_PARAM_CKSUM"].content = self.image_crc(ddr_param)
|
|
self.param2["DDR_PARAM_SIZE"].content = len(ddr_param)
|
|
self.param2["DDR_PARAM_LOADADDR"].content = len(fip_bin)
|
|
|
|
return fip_bin + ddr_param
|
|
|
|
def pack_blcp_2nd(self, fip_bin, blcp_2nd_runaddr):
|
|
logging.debug("pack_blcp_2nd:")
|
|
if not len(self.body2["BLCP_2ND"].content):
|
|
return
|
|
|
|
runaddr = int(blcp_2nd_runaddr)
|
|
|
|
fip_bin = self.pad(fip_bin, IMAGE_ALIGN)
|
|
|
|
# Pack MONITOR to body2
|
|
body = self.pad(self.body2["BLCP_2ND"].content, IMAGE_ALIGN)
|
|
|
|
self.param2["BLCP_2ND_CKSUM"].content = self.image_crc(body)
|
|
self.param2["BLCP_2ND_SIZE"].content = len(body)
|
|
self.param2["BLCP_2ND_LOADADDR"].content = len(fip_bin)
|
|
self.param2["BLCP_2ND_RUNADDR"].content = runaddr
|
|
|
|
return fip_bin + body
|
|
|
|
def pack_monitor(self, fip_bin, monitor_runaddr):
|
|
logging.debug("pack_monitor:")
|
|
if not len(self.body2["MONITOR"].content):
|
|
return
|
|
|
|
monitor_runaddr = int(monitor_runaddr)
|
|
|
|
fip_bin = self.pad(fip_bin, IMAGE_ALIGN)
|
|
|
|
# Pack MONITOR to body2
|
|
monitor = self.pad(self.body2["MONITOR"].content, IMAGE_ALIGN)
|
|
|
|
self.param2["MONITOR_CKSUM"].content = self.image_crc(monitor)
|
|
self.param2["MONITOR_SIZE"].content = len(monitor)
|
|
self.param2["MONITOR_LOADADDR"].content = len(fip_bin)
|
|
self.param2["MONITOR_RUNADDR"].content = monitor_runaddr
|
|
|
|
return fip_bin + monitor
|
|
|
|
def _parse_ldr_2nd_hdr(self, image):
|
|
for e in self.ldr_2nd_hdr.values():
|
|
e.content = image[e.addr : e.end]
|
|
|
|
def _update_ldr_2nd_hdr(self):
|
|
image = self.body2["LOADER_2ND"].content
|
|
hdr_size = self._param_size(self.ldr_2nd_hdr)
|
|
hdr, body = image[:hdr_size], image[hdr_size:]
|
|
|
|
# Update SIZE
|
|
self.ldr_2nd_hdr["SIZE"].content = len(image)
|
|
|
|
# Update CKSUM
|
|
hdr = bytearray(b"".join((e.content for e in self.ldr_2nd_hdr.values())))
|
|
# CKSUM is calculated after "CKSUM" field
|
|
hdr_cksum = self.ldr_2nd_hdr["CKSUM"]
|
|
crc = self.image_crc((hdr + body)[hdr_cksum.end :])
|
|
hdr_cksum.content = crc
|
|
hdr = bytearray(b"".join((e.content for e in self.ldr_2nd_hdr.values())))
|
|
|
|
self.body2["LOADER_2ND"].content = hdr + body
|
|
|
|
def _compress_ldr_2nd(self):
|
|
image = self.body2["LOADER_2ND"].content
|
|
hdr_size = self._param_size(self.ldr_2nd_hdr)
|
|
hdr, body = image[:hdr_size], image[hdr_size:]
|
|
|
|
magic = self.ldr_2nd_hdr["MAGIC"].content
|
|
if magic == LOADER_2ND_MAGIC_ORIG:
|
|
# if image is uncompressed, compress it.
|
|
if self.compress_algo is None:
|
|
pass
|
|
elif self.compress_algo == "lzma":
|
|
self.ldr_2nd_hdr["MAGIC"].content = LOADER_2ND_MAGIC_LZMA
|
|
body = lzma_compress(body)
|
|
logging.info("lzma loader_2nd=%#x bytes wo header", len(body))
|
|
elif self.compress_algo == "lz4":
|
|
self.ldr_2nd_hdr["MAGIC"].content = LOADER_2ND_MAGIC_LZ4
|
|
body = lz4_compress(body)
|
|
logging.info("lz4 loader_2nd=%#x bytes wo header", len(body))
|
|
else:
|
|
raise NotImplementedError("'%r' is not supported." % self.compress_algo)
|
|
elif magic in LOADER_2ND_MAGIC_LIST:
|
|
logging.info("loader_2nd is already compressed")
|
|
else:
|
|
raise ValueError("unknown loader_2nd magic (%r)", magic)
|
|
|
|
self.body2["LOADER_2ND"].content = self.pad(hdr + body, IMAGE_ALIGN)
|
|
|
|
def pack_loader_2nd(self, fip_bin):
|
|
logging.debug("pack_loader_2nd:")
|
|
if not len(self.body2["LOADER_2ND"].content):
|
|
return
|
|
|
|
fip_bin = self.pad(fip_bin, IMAGE_ALIGN)
|
|
self.param2["LOADER_2ND_LOADADDR"].content = len(fip_bin)
|
|
|
|
self._parse_ldr_2nd_hdr(self.body2["LOADER_2ND"].content)
|
|
self._compress_ldr_2nd()
|
|
self._update_ldr_2nd_hdr()
|
|
|
|
# Append LOADER_2ND to body2
|
|
return fip_bin + self.body2["LOADER_2ND"].content
|
|
|
|
def insert_param1(self, fip_bin, name, value):
|
|
fip_bin = bytearray(fip_bin)
|
|
e = self.param1[name]
|
|
e.content = value
|
|
fip_bin[e.addr : e.end] = value
|
|
return self.update_param1_cksum(fip_bin)
|
|
|
|
def append_fip2(self, fip1_bin, args):
|
|
logging.debug("make_fip2:")
|
|
fip_bin = bytearray(fip1_bin)
|
|
|
|
# Update PARAM2_LOADADDR
|
|
param2_loadaddr = len(fip1_bin)
|
|
fip_bin = self.insert_param1(fip_bin, "PARAM2_LOADADDR", pack("<I", param2_loadaddr))
|
|
|
|
# Add an empty PARAM2
|
|
fip_bin += b"\0" * PARAM2_SIZE
|
|
|
|
# Pack body
|
|
fip_bin = self.pack_ddr_param(fip_bin)
|
|
|
|
if len(self.body2["BLCP_2ND"].content):
|
|
runaddr = self.param2["BLCP_2ND_RUNADDR"].toint()
|
|
if not runaddr:
|
|
runaddr = int(args.BLCP_2ND_RUNADDR)
|
|
fip_bin = self.pack_blcp_2nd(fip_bin, runaddr)
|
|
|
|
if len(self.body2["MONITOR"].content):
|
|
runaddr = self.param2["MONITOR_RUNADDR"].toint()
|
|
if not runaddr:
|
|
runaddr = int(args.MONITOR_RUNADDR)
|
|
fip_bin = self.pack_monitor(fip_bin, runaddr)
|
|
|
|
if len(self.body2["LOADER_2ND"].content):
|
|
fip_bin = self.pack_loader_2nd(fip_bin)
|
|
|
|
# Pack param2_bin
|
|
param2_bin = b"".join((entry.content for entry in self.param2.values()))
|
|
self.param2["PARAM2_CKSUM"].content = self.image_crc(param2_bin[self.param2["PARAM2_CKSUM"].end :])
|
|
param2_bin = b"".join((entry.content for entry in self.param2.values())) # update cksum
|
|
|
|
logging.debug("len(param2_bin) is %d", len(param2_bin))
|
|
assert len(param2_bin) == PARAM2_SIZE
|
|
|
|
fip_bin[param2_loadaddr : param2_loadaddr + PARAM2_SIZE] = param2_bin
|
|
|
|
return fip_bin
|
|
|
|
def make(self, args=None):
|
|
fip_bin = self.make_fip1()
|
|
if len(self.body2["DDR_PARAM"].content):
|
|
fip_bin = self.append_fip2(fip_bin, args)
|
|
|
|
logging.info("generated fip_bin is %d bytes", len(fip_bin))
|
|
|
|
if getattr(self, "rest_fip", None):
|
|
logging.error("the rest of fip is not used: %#x bytes ", len(self.rest_fip))
|
|
|
|
return fip_bin
|
|
|
|
|
|
METHODS = {
|
|
"NOR_INFO": FIP.add_nor_info,
|
|
"NAND_INFO": FIP.add_nand_info,
|
|
"CHIP_CONF": FIP.add_chip_conf,
|
|
"BLCP": FIP.add_blcp,
|
|
"BL2": FIP.add_bl2,
|
|
"DDR_PARAM": FIP.add_ddr_param,
|
|
"BLCP_2ND": FIP.add_blcp_2nd,
|
|
"MONITOR": FIP.add_monitor,
|
|
"LOADER_2ND": FIP.add_loader_2nd,
|
|
}
|
|
|
|
|
|
def generate_fip(args):
|
|
logging.debug("generate_fip:")
|
|
fip = FIP()
|
|
|
|
if args.OLD_FIP:
|
|
fip.read_fip(args.OLD_FIP)
|
|
|
|
for m, f in METHODS.items():
|
|
if getattr(args, m):
|
|
f(fip, args)
|
|
|
|
fip_bin = fip.make(args)
|
|
fip.print_fip_params()
|
|
|
|
if args.output:
|
|
with open(args.output, "wb") as fp:
|
|
fp.write(fip_bin)
|
|
|
|
|
|
def parse_args():
|
|
parser = argparse.ArgumentParser(description="FIP tools")
|
|
|
|
parser.add_argument(
|
|
"-v",
|
|
"--verbose",
|
|
help="Increase output verbosity",
|
|
action="store_const",
|
|
const=logging.DEBUG,
|
|
default=logging.INFO,
|
|
)
|
|
|
|
subparsers = parser.add_subparsers(dest="subcmd", help="Sub-command help")
|
|
pr_gen = subparsers.add_parser("genfip", help="Generate keys")
|
|
|
|
for name in list(METHODS):
|
|
if name in ["NOR_INFO", "NAND_INFO"]:
|
|
pr_gen.add_argument("--" + name, type=bytes.fromhex)
|
|
else:
|
|
pr_gen.add_argument("--" + name, dest=name, type=str, help="Add %s into FIP" % name)
|
|
|
|
def auto_int(x):
|
|
return int(x, 0)
|
|
|
|
pr_gen.add_argument("--BLCP_IMG_RUNADDR", type=auto_int)
|
|
pr_gen.add_argument("--BLCP_PARAM_LOADADDR", type=auto_int)
|
|
|
|
pr_gen.add_argument("--BLCP_2ND_RUNADDR", type=auto_int)
|
|
|
|
pr_gen.add_argument("--MONITOR_RUNADDR", type=auto_int)
|
|
|
|
pr_gen.add_argument("--compress", choices=["lzma", "lz4", ""])
|
|
|
|
pr_gen.add_argument("--OLD_FIP", type=str)
|
|
pr_gen.add_argument("--BLOCK_SIZE", type=auto_int)
|
|
pr_gen.add_argument("--BL2_FILL", type=auto_int)
|
|
|
|
pr_gen.add_argument("output", type=str, help="Output filename")
|
|
|
|
pr_gen.set_defaults(func=generate_fip)
|
|
|
|
if argcomplete:
|
|
argcomplete.autocomplete(parser)
|
|
|
|
args = parser.parse_args()
|
|
init_logging(stdout_level=args.verbose)
|
|
logging.info("PROG: %s", parser.prog)
|
|
|
|
if not args.subcmd:
|
|
parser.print_help()
|
|
raise SystemExit(1)
|
|
|
|
for a, v in sorted(vars(args).items()):
|
|
logging.debug(" %s=%r", a, v)
|
|
|
|
return args
|
|
|
|
|
|
def main():
|
|
args = parse_args()
|
|
args.func(args)
|
|
|
|
|
|
def init_logging(log_file=None, file_level="DEBUG", stdout_level="WARNING"):
|
|
root_logger = logging.getLogger()
|
|
root_logger.setLevel(logging.NOTSET)
|
|
|
|
fmt = "%(asctime)s %(levelname)8s:%(name)s:%(message)s"
|
|
|
|
if log_file is not None:
|
|
file_handler = logging.FileHandler(log_file, encoding="utf-8")
|
|
file_handler.setFormatter(logging.Formatter(fmt))
|
|
file_handler.setLevel(file_level)
|
|
root_logger.addHandler(file_handler)
|
|
|
|
if coloredlogs:
|
|
os.environ["COLOREDLOGS_DATE_FORMAT"] = "%H:%M:%S"
|
|
|
|
field_styles = {
|
|
"asctime": {"color": "green"},
|
|
"hostname": {"color": "magenta"},
|
|
"levelname": {"color": "black", "bold": True},
|
|
"name": {"color": "blue"},
|
|
"programname": {"color": "cyan"},
|
|
}
|
|
|
|
level_styles = coloredlogs.DEFAULT_LEVEL_STYLES
|
|
level_styles["debug"]["color"] = "cyan"
|
|
|
|
coloredlogs.install(
|
|
level=stdout_level,
|
|
fmt=fmt,
|
|
field_styles=field_styles,
|
|
level_styles=level_styles,
|
|
milliseconds=True,
|
|
)
|
|
|
|
|
|
if __name__ == "__main__":
|
|
main()
|