[beken-72xx] Generate UF2 firmware images
This commit is contained in:
@@ -552,6 +552,12 @@ env.Replace(
|
||||
SIZEPRINTCMD="$SIZETOOL -B -d $SOURCES",
|
||||
)
|
||||
|
||||
# Calculate RBL header offset
|
||||
app_offs = int(env["FLASH_APP_OFFSET"], 16)
|
||||
app_size = int(board.get("build.bkrbl_size_app"), 16)
|
||||
rbl_offs = int(app_size // 32 * 34) - 102
|
||||
env.Replace(FLASH_RBL_OFFSET=f"0x{app_offs + rbl_offs:06X}")
|
||||
|
||||
# Build all libraries
|
||||
env.BuildLibraries()
|
||||
|
||||
@@ -559,4 +565,21 @@ env.BuildLibraries()
|
||||
env.Replace(
|
||||
# linker command (encryption + packaging)
|
||||
LINK="${LINK2BIN} ${VARIANT} '' ''",
|
||||
# UF2OTA input list
|
||||
UF2OTA=[
|
||||
# app binary image (enc+crc), OTA1 (uploader) only
|
||||
(
|
||||
"app",
|
||||
"${BUILD_DIR}/${MCULC}_app_${FLASH_APP_OFFSET}.crc",
|
||||
"",
|
||||
"",
|
||||
),
|
||||
# app RBL header (crc), OTA1 (uploader) only
|
||||
(
|
||||
f"app+{rbl_offs}",
|
||||
"${BUILD_DIR}/${MCULC}_app_${FLASH_RBL_OFFSET}.rblh",
|
||||
"", # not used for OTA2
|
||||
"",
|
||||
),
|
||||
],
|
||||
)
|
||||
|
||||
@@ -32,6 +32,7 @@ def env_add_defaults(env, platform, board):
|
||||
LDSCRIPT_PATH=["${LDSCRIPT_SDK}"],
|
||||
# Board config variables
|
||||
MCU=board.get("build.mcu").upper(),
|
||||
MCULC=board.get("build.mcu"),
|
||||
VARIANT=board.get("build.variant"),
|
||||
LDSCRIPT_SDK=board.get("build.ldscript_sdk"),
|
||||
LDSCRIPT_ARDUINO=board.get("build.ldscript_arduino"),
|
||||
|
||||
@@ -5,7 +5,7 @@ from os import stat
|
||||
from os.path import basename
|
||||
from typing import Tuple
|
||||
|
||||
from tools.util.bkutil import RBL, BekenBinary
|
||||
from tools.util.bkutil import RBL, BekenBinary, DataType
|
||||
from tools.util.fileio import chext, chname, isnewer, writebin, writejson
|
||||
from tools.util.models import Family
|
||||
from tools.util.obj import get
|
||||
@@ -31,9 +31,10 @@ def elf2bin_bk72xx(
|
||||
app_addr = nmap["_vector_start"]
|
||||
app_offs = calc_offset(app_addr)
|
||||
app_size = int(rbl_size, 16)
|
||||
rbl_offs = app_offs
|
||||
|
||||
# build output name
|
||||
output = chname(input, f"{mcu}_app_0x{app_offs:06X}.bin")
|
||||
output = chname(input, f"{mcu}_app_0x{app_offs:06X}.rbl")
|
||||
fw_bin = chext(input, "bin")
|
||||
# print graph element
|
||||
print(f"| |-- {basename(output)}")
|
||||
@@ -53,5 +54,42 @@ def elf2bin_bk72xx(
|
||||
fw_size = stat(fw_bin).st_size
|
||||
raw = open(fw_bin, "rb")
|
||||
out = open(output, "wb")
|
||||
for data in bk.package(raw, app_addr, fw_size, rbl):
|
||||
|
||||
# open encrypted+CRC binary output
|
||||
out_crc = chname(input, f"{mcu}_app_0x{app_offs:06X}.crc")
|
||||
print(f"| |-- {basename(out_crc)}")
|
||||
crc = open(out_crc, "wb")
|
||||
|
||||
# get partial (type, bytes) data generator
|
||||
package_gen = bk.package(raw, app_addr, fw_size, rbl, partial=True)
|
||||
|
||||
# write all BINARY blocks
|
||||
for data_type, data in package_gen:
|
||||
if data_type != DataType.BINARY:
|
||||
break
|
||||
out.write(data)
|
||||
crc.write(data)
|
||||
rbl_offs += len(data)
|
||||
|
||||
# skip PADDING_SIZE bytes for RBL header, write it to main output
|
||||
if data_type == DataType.PADDING_SIZE:
|
||||
out.write(b"\xff" * data)
|
||||
rbl_offs += data
|
||||
|
||||
# open RBL header output
|
||||
out_rblh = chname(input, f"{mcu}_app_0x{rbl_offs:06X}.rblh")
|
||||
print(f"| |-- {basename(out_rblh)}")
|
||||
rblh = open(out_rblh, "wb")
|
||||
|
||||
# write all RBL blocks
|
||||
for data_type, data in package_gen:
|
||||
if data_type != DataType.RBL:
|
||||
break
|
||||
out.write(data)
|
||||
rblh.write(data)
|
||||
|
||||
# close all files
|
||||
raw.close()
|
||||
out.close()
|
||||
crc.close()
|
||||
rblh.close()
|
||||
|
||||
@@ -91,19 +91,19 @@ class Input:
|
||||
if input[0] and input[1]:
|
||||
if "+" in input[0]:
|
||||
(self.ota1_part, self.ota1_offs) = input[0].split("+")
|
||||
self.ota1_offs = int(self.ota1_offs, 16)
|
||||
self.ota1_offs = int(self.ota1_offs, 0)
|
||||
else:
|
||||
self.ota1_part = input[0]
|
||||
self.ota1_file = input[1]
|
||||
if input[2] and input[3]:
|
||||
if "+" in input[2]:
|
||||
(self.ota2_part, self.ota2_offs) = input[2].split("+")
|
||||
self.ota2_offs = int(self.ota2_offs, 16)
|
||||
self.ota2_offs = int(self.ota2_offs, 0)
|
||||
else:
|
||||
self.ota2_part = input[2]
|
||||
self.ota2_file = input[3]
|
||||
|
||||
if self.ota1_offs != self.ota2_offs:
|
||||
if self.ota1_file and self.ota2_file and self.ota1_offs != self.ota2_offs:
|
||||
# currently, offsets cannot differ when storing images
|
||||
# (this would require to actually store it twice)
|
||||
raise ValueError(f"Offsets cannot differ ({self.ota1_file})")
|
||||
|
||||
@@ -8,12 +8,12 @@ sys.path.append(join(dirname(__file__), "..", ".."))
|
||||
from argparse import ArgumentParser, FileType
|
||||
from binascii import crc32
|
||||
from dataclasses import dataclass, field
|
||||
from enum import IntFlag
|
||||
from enum import Enum, IntFlag
|
||||
from io import SEEK_SET, FileIO
|
||||
from os import stat
|
||||
from struct import Struct
|
||||
from time import time
|
||||
from typing import Union
|
||||
from typing import Generator, Tuple, Union
|
||||
|
||||
from tools.util.bitint import BitInt
|
||||
from tools.util.bkcrypto import BekenCrypto
|
||||
@@ -34,6 +34,17 @@ from tools.util.intbin import (
|
||||
)
|
||||
|
||||
|
||||
class DataType(Enum):
|
||||
BINARY = "BINARY"
|
||||
PADDING_SIZE = "PADDING_SIZE"
|
||||
RBL = "RBL"
|
||||
|
||||
|
||||
DataTuple = Tuple[DataType, Union[bytes, int]]
|
||||
DataUnion = Union[bytes, DataTuple]
|
||||
DataGenerator = Generator[DataUnion, None, None]
|
||||
|
||||
|
||||
class OTAAlgorithm(IntFlag):
|
||||
NONE = 0
|
||||
CRYPT_XOR = 1
|
||||
@@ -125,11 +136,14 @@ class BekenBinary:
|
||||
coeffs = list(map(BitInt, map(betoint, biniter(coeffs, 4))))
|
||||
self.crypto = BekenCrypto(coeffs)
|
||||
|
||||
def crc(self, data: ByteGenerator) -> ByteGenerator:
|
||||
def crc(self, data: ByteGenerator, type: DataType = None) -> DataGenerator:
|
||||
for block in geniter(data, 32):
|
||||
crc = CRC16.CMS.calc(block)
|
||||
yield block
|
||||
yield inttobe16(crc)
|
||||
block += inttobe16(crc)
|
||||
if type:
|
||||
yield (type, block)
|
||||
else:
|
||||
yield block
|
||||
|
||||
def uncrc(self, data: ByteGenerator, check: bool = True) -> ByteGenerator:
|
||||
for block in geniter(data, 34):
|
||||
@@ -149,11 +163,23 @@ class BekenBinary:
|
||||
yield word
|
||||
addr += 4
|
||||
|
||||
def package(self, f: FileIO, addr: int, size: int, rbl: RBL) -> ByteGenerator:
|
||||
def package(
|
||||
self,
|
||||
f: FileIO,
|
||||
addr: int,
|
||||
size: int,
|
||||
rbl: RBL,
|
||||
partial: bool = False,
|
||||
) -> DataGenerator:
|
||||
if not rbl.container_size:
|
||||
raise ValueError("RBL must have a total size when packaging")
|
||||
crc_total = 0
|
||||
|
||||
# yield all data as (type, bytes) tuples, if partial mode enabled
|
||||
type_binary = DataType.BINARY if partial else None
|
||||
type_padding = DataType.PADDING_SIZE if partial else None
|
||||
type_rbl = DataType.RBL if partial else None
|
||||
|
||||
# when to stop reading input data
|
||||
data_end = size
|
||||
if rbl.has_part_table:
|
||||
@@ -169,7 +195,7 @@ class BekenBinary:
|
||||
# iterate over encrypted 32-byte blocks
|
||||
for block in geniter(data_crypt_gen, 32):
|
||||
# add CRC16 and yield
|
||||
yield from self.crc(block)
|
||||
yield from self.crc(block, type_binary)
|
||||
crc_total += 2
|
||||
rbl.update(block)
|
||||
|
||||
@@ -188,16 +214,19 @@ class BekenBinary:
|
||||
# add last padding with normal values
|
||||
buf += b"\xff" * 16
|
||||
# yield the temporary buffer
|
||||
yield from self.crc(buf)
|
||||
yield from self.crc(buf, type_binary)
|
||||
crc_total += 2 * (len(buf) // 32)
|
||||
|
||||
# pad the entire container with 0xFF, excluding RBL and its CRC16
|
||||
pad_size = pad_up(rbl.data_size + crc_total, rbl.container_size_crc) - 102
|
||||
for _ in range(pad_size):
|
||||
yield b"\xff"
|
||||
if type_padding:
|
||||
yield (type_padding, pad_size)
|
||||
else:
|
||||
for _ in range(pad_size):
|
||||
yield b"\xff"
|
||||
|
||||
# yield RBL with CRC16
|
||||
yield from self.crc(rbl.serialize())
|
||||
yield from self.crc(rbl.serialize(), type_rbl)
|
||||
|
||||
|
||||
def auto_int(x):
|
||||
|
||||
Reference in New Issue
Block a user