[beken-72xx] Generate UF2 firmware images

This commit is contained in:
Kuba Szczodrzyński
2022-06-23 13:32:31 +02:00
parent 94e8b9f87e
commit 236e9ccda6
5 changed files with 108 additions and 17 deletions

View File

@@ -552,6 +552,12 @@ env.Replace(
SIZEPRINTCMD="$SIZETOOL -B -d $SOURCES", 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 # Build all libraries
env.BuildLibraries() env.BuildLibraries()
@@ -559,4 +565,21 @@ env.BuildLibraries()
env.Replace( env.Replace(
# linker command (encryption + packaging) # linker command (encryption + packaging)
LINK="${LINK2BIN} ${VARIANT} '' ''", 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
"",
),
],
) )

View File

@@ -32,6 +32,7 @@ def env_add_defaults(env, platform, board):
LDSCRIPT_PATH=["${LDSCRIPT_SDK}"], LDSCRIPT_PATH=["${LDSCRIPT_SDK}"],
# Board config variables # Board config variables
MCU=board.get("build.mcu").upper(), MCU=board.get("build.mcu").upper(),
MCULC=board.get("build.mcu"),
VARIANT=board.get("build.variant"), VARIANT=board.get("build.variant"),
LDSCRIPT_SDK=board.get("build.ldscript_sdk"), LDSCRIPT_SDK=board.get("build.ldscript_sdk"),
LDSCRIPT_ARDUINO=board.get("build.ldscript_arduino"), LDSCRIPT_ARDUINO=board.get("build.ldscript_arduino"),

View File

@@ -5,7 +5,7 @@ from os import stat
from os.path import basename from os.path import basename
from typing import Tuple 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.fileio import chext, chname, isnewer, writebin, writejson
from tools.util.models import Family from tools.util.models import Family
from tools.util.obj import get from tools.util.obj import get
@@ -31,9 +31,10 @@ def elf2bin_bk72xx(
app_addr = nmap["_vector_start"] app_addr = nmap["_vector_start"]
app_offs = calc_offset(app_addr) app_offs = calc_offset(app_addr)
app_size = int(rbl_size, 16) app_size = int(rbl_size, 16)
rbl_offs = app_offs
# build output name # 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") fw_bin = chext(input, "bin")
# print graph element # print graph element
print(f"| |-- {basename(output)}") print(f"| |-- {basename(output)}")
@@ -53,5 +54,42 @@ def elf2bin_bk72xx(
fw_size = stat(fw_bin).st_size fw_size = stat(fw_bin).st_size
raw = open(fw_bin, "rb") raw = open(fw_bin, "rb")
out = open(output, "wb") 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) 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()

View File

@@ -91,19 +91,19 @@ class Input:
if input[0] and input[1]: if input[0] and input[1]:
if "+" in input[0]: if "+" in input[0]:
(self.ota1_part, self.ota1_offs) = input[0].split("+") (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: else:
self.ota1_part = input[0] self.ota1_part = input[0]
self.ota1_file = input[1] self.ota1_file = input[1]
if input[2] and input[3]: if input[2] and input[3]:
if "+" in input[2]: if "+" in input[2]:
(self.ota2_part, self.ota2_offs) = input[2].split("+") (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: else:
self.ota2_part = input[2] self.ota2_part = input[2]
self.ota2_file = input[3] 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 # currently, offsets cannot differ when storing images
# (this would require to actually store it twice) # (this would require to actually store it twice)
raise ValueError(f"Offsets cannot differ ({self.ota1_file})") raise ValueError(f"Offsets cannot differ ({self.ota1_file})")

View File

@@ -8,12 +8,12 @@ sys.path.append(join(dirname(__file__), "..", ".."))
from argparse import ArgumentParser, FileType from argparse import ArgumentParser, FileType
from binascii import crc32 from binascii import crc32
from dataclasses import dataclass, field from dataclasses import dataclass, field
from enum import IntFlag from enum import Enum, IntFlag
from io import SEEK_SET, FileIO from io import SEEK_SET, FileIO
from os import stat from os import stat
from struct import Struct from struct import Struct
from time import time from time import time
from typing import Union from typing import Generator, Tuple, Union
from tools.util.bitint import BitInt from tools.util.bitint import BitInt
from tools.util.bkcrypto import BekenCrypto 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): class OTAAlgorithm(IntFlag):
NONE = 0 NONE = 0
CRYPT_XOR = 1 CRYPT_XOR = 1
@@ -125,11 +136,14 @@ class BekenBinary:
coeffs = list(map(BitInt, map(betoint, biniter(coeffs, 4)))) coeffs = list(map(BitInt, map(betoint, biniter(coeffs, 4))))
self.crypto = BekenCrypto(coeffs) 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): for block in geniter(data, 32):
crc = CRC16.CMS.calc(block) crc = CRC16.CMS.calc(block)
yield block block += inttobe16(crc)
yield inttobe16(crc) if type:
yield (type, block)
else:
yield block
def uncrc(self, data: ByteGenerator, check: bool = True) -> ByteGenerator: def uncrc(self, data: ByteGenerator, check: bool = True) -> ByteGenerator:
for block in geniter(data, 34): for block in geniter(data, 34):
@@ -149,11 +163,23 @@ class BekenBinary:
yield word yield word
addr += 4 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: if not rbl.container_size:
raise ValueError("RBL must have a total size when packaging") raise ValueError("RBL must have a total size when packaging")
crc_total = 0 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 # when to stop reading input data
data_end = size data_end = size
if rbl.has_part_table: if rbl.has_part_table:
@@ -169,7 +195,7 @@ class BekenBinary:
# iterate over encrypted 32-byte blocks # iterate over encrypted 32-byte blocks
for block in geniter(data_crypt_gen, 32): for block in geniter(data_crypt_gen, 32):
# add CRC16 and yield # add CRC16 and yield
yield from self.crc(block) yield from self.crc(block, type_binary)
crc_total += 2 crc_total += 2
rbl.update(block) rbl.update(block)
@@ -188,16 +214,19 @@ class BekenBinary:
# add last padding with normal values # add last padding with normal values
buf += b"\xff" * 16 buf += b"\xff" * 16
# yield the temporary buffer # yield the temporary buffer
yield from self.crc(buf) yield from self.crc(buf, type_binary)
crc_total += 2 * (len(buf) // 32) crc_total += 2 * (len(buf) // 32)
# pad the entire container with 0xFF, excluding RBL and its CRC16 # 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 pad_size = pad_up(rbl.data_size + crc_total, rbl.container_size_crc) - 102
for _ in range(pad_size): if type_padding:
yield b"\xff" yield (type_padding, pad_size)
else:
for _ in range(pad_size):
yield b"\xff"
# yield RBL with CRC16 # yield RBL with CRC16
yield from self.crc(rbl.serialize()) yield from self.crc(rbl.serialize(), type_rbl)
def auto_int(x): def auto_int(x):