mirror of
https://github.com/openshwprojects/OpenBK7231T_App.git
synced 2026-08-18 11:06:31 +00:00
add Tuya coeff-key OpenBK7252 build to release (#2152)
* add Tuya BK7252U back * Update .releaserc.yaml * rbl * Probe BK7252 Tuya OTA readback CRC * Fix BK7252 Tuya OTA partition table * Restore BK7252 Tuya OTA artefact * Probe BK7252 OTA flash readback CRC * patch RT bootloader * remove releaser * use standard partitions * Update Makefile * Create bk7252_partition_2M.json
This commit is contained in:
2
.github/workflows/workflow.yaml
vendored
2
.github/workflows/workflow.yaml
vendored
@ -317,9 +317,11 @@ jobs:
|
||||
name: ${{ env.APP_NAME }}_${{ needs.refs.outputs.version }}_${{ matrix.platform }}${{ matrix.variant != 'default' && '_' || '' }}${{ matrix.variant != 'default' && matrix.variant || '' }}
|
||||
path: |
|
||||
output/${{ needs.refs.outputs.version }}${{ matrix.variant != 'default' && '_' || '' }}${{ matrix.variant != 'default' && matrix.variant || '' }}/${{ matrix.platform }}_UA_${{ needs.refs.outputs.version }}${{ matrix.variant != 'default' && '_' || '' }}${{ matrix.variant != 'default' && matrix.variant || '' }}.bin
|
||||
output/${{ needs.refs.outputs.version }}${{ matrix.variant != 'default' && '_' || '' }}${{ matrix.variant != 'default' && matrix.variant || '' }}/${{ matrix.platform }}_Tuya_UA_${{ needs.refs.outputs.version }}${{ matrix.variant != 'default' && '_' || '' }}${{ matrix.variant != 'default' && matrix.variant || '' }}.bin
|
||||
output/${{ needs.refs.outputs.version }}${{ matrix.variant != 'default' && '_' || '' }}${{ matrix.variant != 'default' && matrix.variant || '' }}/${{ matrix.platform }}_UG_${{ needs.refs.outputs.version }}${{ matrix.variant != 'default' && '_' || '' }}${{ matrix.variant != 'default' && matrix.variant || '' }}.bin
|
||||
output/${{ needs.refs.outputs.version }}${{ matrix.variant != 'default' && '_' || '' }}${{ matrix.variant != 'default' && matrix.variant || '' }}/${{ matrix.platform }}_UG_${{ needs.refs.outputs.version }}${{ matrix.variant != 'default' && '_' || '' }}${{ matrix.variant != 'default' && matrix.variant || '' }}.img
|
||||
output/${{ needs.refs.outputs.version }}${{ matrix.variant != 'default' && '_' || '' }}${{ matrix.variant != 'default' && matrix.variant || '' }}/${{ matrix.platform }}_QIO_${{ needs.refs.outputs.version }}${{ matrix.variant != 'default' && '_' || '' }}${{ matrix.variant != 'default' && matrix.variant || '' }}.bin
|
||||
output/${{ needs.refs.outputs.version }}${{ matrix.variant != 'default' && '_' || '' }}${{ matrix.variant != 'default' && matrix.variant || '' }}/${{ matrix.platform }}_Tuya_QIO_${{ needs.refs.outputs.version }}${{ matrix.variant != 'default' && '_' || '' }}${{ matrix.variant != 'default' && matrix.variant || '' }}.bin
|
||||
output/${{ needs.refs.outputs.version }}${{ matrix.variant != 'default' && '_' || '' }}${{ matrix.variant != 'default' && matrix.variant || '' }}/OpenBK7231M_QIO_${{ needs.refs.outputs.version }}.bin
|
||||
output/${{ needs.refs.outputs.version }}${{ matrix.variant != 'default' && '_' || '' }}${{ matrix.variant != 'default' && matrix.variant || '' }}/OpenBK7231M_ALT_QIO_${{ needs.refs.outputs.version }}${{ matrix.variant != 'default' && '_' || '' }}${{ matrix.variant != 'default' && matrix.variant || '' }}.bin
|
||||
output/${{ needs.refs.outputs.version }}${{ matrix.variant != 'default' && '_' || '' }}${{ matrix.variant != 'default' && matrix.variant || '' }}/${{ matrix.platform }}_${{ needs.refs.outputs.version }}${{ matrix.variant != 'default' && '_' || '' }}${{ matrix.variant != 'default' && matrix.variant || '' }}.rbl
|
||||
|
||||
18
Makefile
18
Makefile
@ -726,7 +726,23 @@ OpenBK7231U: prebuild_OpenBK7231U
|
||||
|
||||
.PHONY: OpenBK7252
|
||||
OpenBK7252: prebuild_OpenBK7252
|
||||
cd sdk/beken_freertos_sdk && ARM_GCC_TOOLCHAIN=$(PWD)/sdk/beken_freertos_sdk/toolchain/arm-none-eabi/bin/ OBK_VARIANT=$(OBK_VARIANT) sh build.sh bk7251 $(APP_VERSION)
|
||||
cd sdk/beken_freertos_sdk && { \
|
||||
boot=./tools/beken_packager/bootloader_bk7251_uart2_v1.0.15_enc.bin; \
|
||||
raw=./tools/beken_packager/bootloader_bk7251_uart2_v1.0.15.bin; \
|
||||
patched=./tools/beken_packager/bootloader_bk7251_uart2_v1.0.15_tuya_ota_patch.bin; \
|
||||
patched_enc=./tools/beken_packager/bootloader_bk7251_uart2_v1.0.15_tuya_ota_patch_enc.bin; \
|
||||
bak=$$boot.bk7252-tuya-patch; \
|
||||
cp "$$boot" "$$bak" || exit $$?; \
|
||||
status=0; \
|
||||
python ../../platforms/BK723x/patch_bk7252_tuya_bootloader.py "$$raw" "$$patched" "$(PWD)/sdk/beken_freertos_sdk/toolchain/arm-none-eabi/bin" ../../platforms/BK723x/bk7252_tuya_ota_write_wrap.c && \
|
||||
./tools/crc_binary/encrypt_n "$$patched" 510fb093 a3cbeadc 5993a17e c7adeb03 0 && \
|
||||
mv -f "$$patched_enc" "$$boot" && \
|
||||
./tools/rt_partition_tool/rt_partition_tool_cli-x64 "$$boot" ../../platforms/BK723x/bk7252_partition_2M.json && \
|
||||
ARM_GCC_TOOLCHAIN=$(PWD)/sdk/beken_freertos_sdk/toolchain/arm-none-eabi/bin/ OBK_VARIANT=$(OBK_VARIANT) sh build.sh bk7251 $(APP_VERSION) || status=$$?; \
|
||||
rm -f "$$patched" "$$patched_enc"; \
|
||||
mv -f "$$bak" "$$boot"; \
|
||||
exit $$status; \
|
||||
}
|
||||
mkdir -p output/$(APP_VERSION)
|
||||
cp sdk/beken_freertos_sdk/out/bk7251.bin output/$(APP_VERSION)/OpenBK7252_${APP_VERSION}.bin
|
||||
cp sdk/beken_freertos_sdk/out/bk7251_QIO.bin output/$(APP_VERSION)/OpenBK7252_QIO_${APP_VERSION}.bin
|
||||
|
||||
22
platforms/BK723x/bk7252_partition_2M.json
Normal file
22
platforms/BK723x/bk7252_partition_2M.json
Normal file
@ -0,0 +1,22 @@
|
||||
{
|
||||
"part_table": [
|
||||
{
|
||||
"name": "download",
|
||||
"flash_name": "beken_onchip",
|
||||
"offset": "0x00132000",
|
||||
"len": "696K"
|
||||
},
|
||||
{
|
||||
"name": "app",
|
||||
"flash_name": "beken_onchip_crc",
|
||||
"offset": "0x00010000",
|
||||
"len": "1088K"
|
||||
},
|
||||
{
|
||||
"name": "bootloader",
|
||||
"flash_name": "beken_onchip_crc",
|
||||
"offset": "0x00000000",
|
||||
"len": "64K"
|
||||
}
|
||||
]
|
||||
}
|
||||
131
platforms/BK723x/bk7252_tuya_ota_write_wrap.c
Normal file
131
platforms/BK723x/bk7252_tuya_ota_write_wrap.c
Normal file
@ -0,0 +1,131 @@
|
||||
#include <stdint.h>
|
||||
|
||||
#define COEF0 0x510FB093u
|
||||
#define COEF1 0xA3CBEADCu
|
||||
#define COEF2 0x5993A17Eu
|
||||
#define COEF3 0xC7ADEB03u
|
||||
|
||||
typedef int (*fal_partition_write_fn)(void *part, uint32_t offset, const uint8_t *buf, uint32_t size);
|
||||
|
||||
static uint32_t rol32(uint32_t v, unsigned int bits)
|
||||
{
|
||||
return (v << bits) | (v >> (32u - bits));
|
||||
}
|
||||
|
||||
static uint32_t pn15(uint32_t v, uint32_t disabled)
|
||||
{
|
||||
uint32_t part1;
|
||||
uint32_t x;
|
||||
uint32_t part2;
|
||||
|
||||
if (disabled)
|
||||
return 0;
|
||||
|
||||
v &= 0xffffu;
|
||||
part1 = ((v << 9) + (v >> 7)) & 0xffffu;
|
||||
x = v >> 5;
|
||||
part2 = ((x << 12) + ((x & 0xfu) << 8) + ((x << 4) & 0xffu) + (x & 0xfu)) & 0x6371u;
|
||||
return part1 ^ part2;
|
||||
}
|
||||
|
||||
static uint32_t pn16(uint32_t v, uint32_t disabled)
|
||||
{
|
||||
uint32_t part1;
|
||||
uint32_t seed;
|
||||
uint32_t part2;
|
||||
|
||||
if (disabled)
|
||||
return 0;
|
||||
|
||||
v &= 0x1ffffu;
|
||||
part1 = (((v & 0x3ffu) << 7) + ((v >> 10) & 0x7fu)) & 0x1ffffu;
|
||||
seed = (((v >> 1) & 1u) << 3) + (((v >> 5) & 1u) << 2) + (((v >> 9) & 1u) << 1) + ((v >> 13) & 1u);
|
||||
part2 = ((((v >> 4) & 1u) << 16) + (seed << 12) + (seed << 8) + (seed << 4) + seed) & 0x13659u;
|
||||
return part1 ^ part2;
|
||||
}
|
||||
|
||||
static uint32_t pn32(uint32_t v, uint32_t disabled)
|
||||
{
|
||||
uint32_t seed;
|
||||
uint32_t part2;
|
||||
|
||||
if (disabled)
|
||||
return 0;
|
||||
|
||||
seed = (v >> 2) & 0xfu;
|
||||
part2 = (seed << 28) + (seed << 24) + (seed << 20) + (seed << 16) + (seed << 12) + (seed << 8) + (seed << 4) + seed;
|
||||
return rol32(v, 17) ^ (part2 & 0xE519A4F1u);
|
||||
}
|
||||
|
||||
static uint32_t enc_word(uint32_t addr, uint32_t data)
|
||||
{
|
||||
uint32_t all_disabled;
|
||||
uint32_t high_a;
|
||||
uint32_t high_b;
|
||||
uint32_t low_b;
|
||||
uint32_t pn15_input;
|
||||
uint32_t pn16_input;
|
||||
uint32_t pn32_input;
|
||||
uint32_t word_mode;
|
||||
uint32_t rotate_mode;
|
||||
uint32_t mask;
|
||||
|
||||
all_disabled = (((COEF3 & 0xff000000u) == 0xff000000u) || ((COEF3 & 0xff000000u) == 0));
|
||||
word_mode = (COEF3 >> 5) & 3u;
|
||||
rotate_mode = (COEF3 >> 11) & 3u;
|
||||
|
||||
high_a = (((addr >> 24) << 8) + ((addr >> 16) & 0xffu)) & 0xffffu;
|
||||
high_b = (((addr >> 16) << 8) + ((addr >> 24) & 0xffu)) & 0xffffu;
|
||||
low_b = ((addr << 8) + ((addr >> 8) & 0xffu)) & 0xffffu;
|
||||
|
||||
if (word_mode == 0)
|
||||
pn15_input = high_a ^ (addr & 0xffffu);
|
||||
else if (word_mode == 1)
|
||||
pn15_input = high_a ^ low_b;
|
||||
else if (word_mode == 2)
|
||||
pn15_input = high_b ^ (addr & 0xffffu);
|
||||
else
|
||||
pn15_input = high_b ^ low_b;
|
||||
|
||||
pn16_input = (addr >> ((COEF3 >> 8) & 3u)) & 0x1ffffu;
|
||||
if (rotate_mode == 0)
|
||||
pn32_input = addr;
|
||||
else if (rotate_mode == 1)
|
||||
pn32_input = rol32(addr, 24);
|
||||
else if (rotate_mode == 2)
|
||||
pn32_input = rol32(addr, 16);
|
||||
else
|
||||
pn32_input = rol32(addr, 8);
|
||||
|
||||
mask = (pn15(((COEF1 >> 16) ^ pn15_input) & 0xffffu, all_disabled || (COEF3 & 1u)) & 0xffffu) << 16;
|
||||
mask |= pn16(((((COEF1 >> 8) & 0xffu) << 9) + (((COEF3 >> 4) & 1u) << 8) + (COEF1 & 0xffu)) ^ pn16_input,
|
||||
all_disabled || (COEF3 & 2u)) & 0xffffu;
|
||||
mask ^= pn32(COEF0 ^ pn32_input, all_disabled || (COEF3 & 4u));
|
||||
if (!(all_disabled || (COEF3 & 8u)))
|
||||
mask ^= COEF2;
|
||||
|
||||
return data ^ mask;
|
||||
}
|
||||
|
||||
int tuya_fal_partition_write(void *part, uint32_t offset, uint8_t *buf, uint32_t size)
|
||||
{
|
||||
uint32_t padded_size;
|
||||
uint32_t addr;
|
||||
uint32_t i;
|
||||
|
||||
padded_size = (size + 31u) & ~31u;
|
||||
for (i = size; i < padded_size; i++)
|
||||
buf[i] = 0xffu;
|
||||
|
||||
addr = *(const uint32_t *)((const uint8_t *)part + 0x34u) + offset;
|
||||
for (i = 0; i < padded_size; i += 4) {
|
||||
uint32_t word = (uint32_t)buf[i] | ((uint32_t)buf[i + 1] << 8) | ((uint32_t)buf[i + 2] << 16) | ((uint32_t)buf[i + 3] << 24);
|
||||
word = enc_word(addr + i, word);
|
||||
buf[i] = (uint8_t)word;
|
||||
buf[i + 1] = (uint8_t)(word >> 8);
|
||||
buf[i + 2] = (uint8_t)(word >> 16);
|
||||
buf[i + 3] = (uint8_t)(word >> 24);
|
||||
}
|
||||
|
||||
return ((fal_partition_write_fn)0x7779u)(part, offset, buf, padded_size);
|
||||
}
|
||||
119
platforms/BK723x/patch_bk7252_tuya_bootloader.py
Normal file
119
platforms/BK723x/patch_bk7252_tuya_bootloader.py
Normal file
@ -0,0 +1,119 @@
|
||||
#!/usr/bin/env python3
|
||||
import argparse
|
||||
import hashlib
|
||||
import pathlib
|
||||
import subprocess
|
||||
import tempfile
|
||||
|
||||
|
||||
RAW_BOOTLOADER_SHA256 = "6342d53961e743dfe73c852b31c7083f08f740fc27444cb75ebcb22d4b1031f8"
|
||||
WRAPPER_OFFSET = 0xD300
|
||||
ORIGINAL_WRITE = 0x7778
|
||||
CALL_SITES = (0x6774, 0x6816)
|
||||
|
||||
|
||||
def thumb_bl(site, target):
|
||||
offset = target - (site + 4)
|
||||
if offset & 1:
|
||||
raise ValueError("unaligned Thumb BL target")
|
||||
if not (-(1 << 22) <= offset < (1 << 22)):
|
||||
raise ValueError("Thumb BL target out of range")
|
||||
|
||||
imm = offset >> 1
|
||||
hi = 0xF000 | ((imm >> 11) & 0x7FF)
|
||||
lo = 0xF800 | (imm & 0x7FF)
|
||||
return hi.to_bytes(2, "little") + lo.to_bytes(2, "little")
|
||||
|
||||
|
||||
def tool_path(toolchain, name):
|
||||
path = toolchain / name
|
||||
if path.exists():
|
||||
return path
|
||||
|
||||
exe_path = toolchain / (name + ".exe")
|
||||
if exe_path.exists():
|
||||
return exe_path
|
||||
|
||||
return path
|
||||
|
||||
|
||||
def build_wrapper(toolchain, source):
|
||||
gcc = tool_path(toolchain, "arm-none-eabi-gcc")
|
||||
nm = tool_path(toolchain, "arm-none-eabi-nm")
|
||||
objcopy = tool_path(toolchain, "arm-none-eabi-objcopy")
|
||||
|
||||
with tempfile.TemporaryDirectory(prefix="bk7252_tuya_bl_") as tmp:
|
||||
tmp_path = pathlib.Path(tmp)
|
||||
obj = tmp_path / "wrap.o"
|
||||
elf = tmp_path / "wrap.elf"
|
||||
binary = tmp_path / "wrap.bin"
|
||||
|
||||
subprocess.run([
|
||||
str(gcc), "-c", str(source), "-o", str(obj),
|
||||
"-Os", "-mthumb", "-mcpu=arm9tdmi",
|
||||
"-ffreestanding", "-fno-builtin", "-fno-pic",
|
||||
"-fno-unwind-tables", "-fno-asynchronous-unwind-tables",
|
||||
], check=True)
|
||||
subprocess.run([
|
||||
str(gcc), "-nostdlib", "-Wl,-Ttext=0x%08x" % WRAPPER_OFFSET,
|
||||
"-Wl,-e,tuya_fal_partition_write",
|
||||
"-o", str(elf), str(obj),
|
||||
], check=True)
|
||||
nm_output = subprocess.check_output([str(nm), "-n", str(elf)], text=True)
|
||||
for line in nm_output.splitlines():
|
||||
parts = line.split()
|
||||
if len(parts) >= 3 and parts[2] == "tuya_fal_partition_write":
|
||||
entry = int(parts[0], 16)
|
||||
if entry != WRAPPER_OFFSET:
|
||||
raise RuntimeError("wrapper entry at 0x%04x, expected 0x%04x" % (entry, WRAPPER_OFFSET))
|
||||
break
|
||||
else:
|
||||
raise RuntimeError("wrapper entry symbol not found")
|
||||
|
||||
subprocess.run([
|
||||
str(objcopy), "-O", "binary", "-j", ".text", str(elf), str(binary),
|
||||
], check=True)
|
||||
|
||||
return binary.read_bytes()
|
||||
|
||||
|
||||
def patch_bootloader(raw_path, output_path, wrapper):
|
||||
raw = bytearray(raw_path.read_bytes())
|
||||
raw_sha = hashlib.sha256(raw).hexdigest()
|
||||
if raw_sha != RAW_BOOTLOADER_SHA256:
|
||||
raise RuntimeError("unexpected BK7252 bootloader SHA256: %s" % raw_sha)
|
||||
|
||||
for site in CALL_SITES:
|
||||
expected = thumb_bl(site, ORIGINAL_WRITE)
|
||||
found = bytes(raw[site:site + 4])
|
||||
if found != expected:
|
||||
raise RuntimeError("unexpected call at 0x%04x: got %s expected %s" % (site, found.hex(), expected.hex()))
|
||||
raw[site:site + 4] = thumb_bl(site, WRAPPER_OFFSET)
|
||||
|
||||
wrapper_end = WRAPPER_OFFSET + len(wrapper)
|
||||
if len(raw) > WRAPPER_OFFSET:
|
||||
raise RuntimeError("wrapper offset overlaps bootloader body")
|
||||
if wrapper_end > 0x10000:
|
||||
raise RuntimeError("patched bootloader exceeds 64K logical boot partition")
|
||||
|
||||
raw.extend(b"\xff" * (WRAPPER_OFFSET - len(raw)))
|
||||
raw[WRAPPER_OFFSET:wrapper_end] = wrapper
|
||||
output_path.write_bytes(raw)
|
||||
|
||||
print("Patched BK7252 Tuya bootloader: wrapper %d bytes at 0x%04x" % (len(wrapper), WRAPPER_OFFSET))
|
||||
|
||||
|
||||
def main():
|
||||
parser = argparse.ArgumentParser(description="Patch the BK7252 RT bootloader to coeff-encrypt app writes for Tuya OTA.")
|
||||
parser.add_argument("raw_bootloader", type=pathlib.Path)
|
||||
parser.add_argument("output_bootloader", type=pathlib.Path)
|
||||
parser.add_argument("toolchain_bin", type=pathlib.Path)
|
||||
parser.add_argument("wrapper_source", type=pathlib.Path)
|
||||
args = parser.parse_args()
|
||||
|
||||
wrapper = build_wrapper(args.toolchain_bin, args.wrapper_source)
|
||||
patch_bootloader(args.raw_bootloader, args.output_bootloader, wrapper)
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
main()
|
||||
Reference in New Issue
Block a user