refactor(core): generate macros for rust bindgen automatically

[no changelog]
pull/3753/head
tychovrahe 4 weeks ago committed by TychoVrahe
parent c635b945e1
commit d349c44a58

@ -42,6 +42,8 @@ OPENOCD_INTERFACE ?= stlink
# OpenOCD transport default. Alternative: jtag
OPENOCD_TRANSPORT ?= hla_swd
BINDGEN_MACROS_COMMON=-I../unix,-I../trezorhal/unix,-I../../build/unix,-I../../vendor/micropython/ports/unix,-I../../../crypto,-I../../../storage,-I../../vendor/micropython,-I../../vendor/micropython/lib/uzlib,-I../lib,-I../trezorhal,-I../trezorhal/unix,-I../models,-DTREZOR_EMULATOR,-DTREZOR_BOARD="boards/board-unix.h",
ifeq ($(TREZOR_MODEL), 1)
MCU = STM32F2
LAYOUT_FILE = embed/models/model_T1B1.h
@ -50,10 +52,14 @@ else ifeq ($(TREZOR_MODEL),$(filter $(TREZOR_MODEL),T))
MCU = STM32F4
LAYOUT_FILE = embed/models/model_T2T1.h
OPENOCD_TARGET = target/stm32f4x.cfg
BINDGEN_MACROS_MODEL = -DSTM32F427,-DTREZOR_MODEL_T,-DFLASH_BIT_ACCESS=1,-DFLASH_BLOCK_WORDS=1,
MODEL_FEATURE = model_tt
else ifeq ($(TREZOR_MODEL),$(filter $(TREZOR_MODEL),R))
MCU = STM32F4
LAYOUT_FILE = embed/models/model_T2B1.h
OPENOCD_TARGET = target/stm32f4x.cfg
BINDGEN_MACROS_MODEL =-DSTM32F427,-DTREZOR_MODEL_R,-DFLASH_BIT_ACCESS=1,-DFLASH_BLOCK_WORDS=1,
MODEL_FEATURE = model_tr
else ifeq ($(TREZOR_MODEL),$(filter $(TREZOR_MODEL),T3T1))
MCU = STM32U5
OPENOCD_TARGET = target/stm32u5x.cfg
@ -137,9 +143,10 @@ emu: ## run emulator
test: ## run unit tests
cd tests ; ./run_tests.sh $(TESTOPTS)
test_rust: export BINDGEN_MACROS=$(BINDGEN_MACROS_COMMON)$(BINDGEN_MACROS_MODEL)
test_rust: ## run rs unit tests
cd embed/rust ; cargo test $(TESTOPTS) --target=$(RUST_TARGET) \
--no-default-features --features model_t$(shell echo $(TREZOR_MODEL) | tr "TR" "tr"),test \
--no-default-features --features $(MODEL_FEATURE),test \
-- --test-threads=1 --nocapture
test_emu: ## run selected device tests from python-trezor
@ -206,8 +213,9 @@ typecheck: pyright
pyright:
python ../tools/pyright_tool.py
clippy: export BINDGEN_MACROS:=$(BINDGEN_MACROS_COMMON)$(BINDGEN_MACROS_MODEL)
clippy:
cd embed/rust ; cargo clippy --all-features --target=$(RUST_TARGET)
cd embed/rust ; cargo clippy $(TESTOPTS) --all-features --target=$(RUST_TARGET)
## code generation:

@ -151,6 +151,18 @@ env.Replace(
env.Replace(
TREZOR_MODEL=TREZOR_MODEL, )
ALLPATHS = [
'embed/rust',
'embed/bootloader',
'embed/bootloader/nanopb',
'embed/bootloader/protob',
'embed/lib',
'embed/models',
'embed/trezorhal',
'embed/extmod/modtrezorui',
'vendor/nanopb',
] + CPPPATH_MOD + PATH_HAL
env.Replace(
COPT=env.get('ENV').get('OPTIMIZE', '-Os'),
CCFLAGS='$COPT '
@ -163,17 +175,7 @@ env.Replace(
+ env.get('ENV')["CPU_CCFLAGS"] + CCFLAGS_MOD,
CCFLAGS_QSTR='-DNO_QSTR -DN_X64 -DN_X86 -DN_THUMB',
LINKFLAGS=f'-T embed/bootloader/memory_{LINKER_SCRIPT_SUFFIX}.ld -Wl,--gc-sections -Wl,-Map=build/bootloader/bootloader.map -Wl,--warn-common -Wl,--print-memory-usage',
CPPPATH=[
'embed/rust',
'embed/bootloader',
'embed/bootloader/nanopb',
'embed/bootloader/protob',
'embed/lib',
'embed/models',
'embed/trezorhal',
'embed/extmod/modtrezorui',
'vendor/nanopb',
] + CPPPATH_MOD + PATH_HAL,
CPPPATH=ALLPATHS,
CPPDEFINES=[
'BOOTLOADER',
'TREZOR_MODEL_'+TREZOR_MODEL,
@ -228,6 +230,8 @@ def cargo_build():
features.append("bootloader")
features.extend(FEATURES_AVAILABLE)
env.get("ENV")["BINDGEN_MACROS"] = tools.get_bindgen_defines(env.get("ALLDEFS"), ALLPATHS)
cargo_opts = [
f'--target={env.get("ENV")["RUST_TARGET"]}',
f'--target-dir=../../build/bootloader/rust',

@ -198,6 +198,19 @@ else:
MODEL_IDENTIFIER = tools.get_model_identifier(TREZOR_MODEL)
MODEL_AS_NUMBER = str(boards.get_hw_model_as_number(MODEL_IDENTIFIER))
ALLPATHS = ['embed/rust',
'embed/bootloader',
'embed/bootloader/nanopb',
'embed/bootloader/protob',
'embed/lib',
'embed/models',
'embed/trezorhal',
'embed/trezorhal/unix',
'embed/unix',
'embed/extmod/modtrezorui',
'vendor/nanopb',
] + CPPPATH_MOD,
env.Replace(
COPT=env.get('ENV').get('OPTIMIZE', '-Os'),
CCFLAGS='$COPT '
@ -208,19 +221,7 @@ env.Replace(
'-ffreestanding '
'-fstack-protector-all '
+ CCFLAGS_MOD,
CPPPATH=[
'embed/rust',
'embed/bootloader',
'embed/bootloader/nanopb',
'embed/bootloader/protob',
'embed/lib',
'embed/models',
'embed/trezorhal',
'embed/trezorhal/unix',
'embed/unix',
'embed/extmod/modtrezorui',
'vendor/nanopb',
] + CPPPATH_MOD,
CPPPATH=ALLPATHS,
CPPDEFINES=[
'BOOTLOADER',
'TREZOR_EMULATOR',
@ -290,6 +291,8 @@ def cargo_build():
features.append("ui")
features.append("bootloader")
env.get("ENV")["BINDGEN_MACROS"] = tools.get_bindgen_defines(env.get("ALLDEFS"), ALLPATHS)
cargo_opts = [
f'--target={RUST_TARGET}',
'--target-dir=../../build/bootloader_emu/rust',

@ -452,6 +452,17 @@ if TREZOR_MODEL in ('1',):
else:
LD_VARIANT = ''
ALLPATHS = [
'.',
'embed/rust',
'embed/firmware',
'embed/lib',
'embed/models',
'embed/trezorhal',
'embed/extmod/modtrezorui',
'vendor/micropython',
] + CPPPATH_MOD + PATH_HAL
env.Replace(
COPT=env.get('ENV').get('OPTIMIZE', '-Os'),
CCFLAGS='$COPT '
@ -464,16 +475,7 @@ env.Replace(
+ env.get('ENV')["CPU_CCFLAGS"] + CCFLAGS_MOD,
CCFLAGS_QSTR='-DNO_QSTR -DN_X64 -DN_X86 -DN_THUMB',
LINKFLAGS='-T embed/firmware/memory_${TREZOR_MODEL}%s.ld -Wl,--gc-sections -Wl,--print-memory-usage -Wl,-Map=build/firmware/firmware.map -Wl,--warn-common' % LD_VARIANT,
CPPPATH=[
'.',
'embed/rust',
'embed/firmware',
'embed/lib',
'embed/models',
'embed/trezorhal',
'embed/extmod/modtrezorui',
'vendor/micropython',
] + CPPPATH_MOD + PATH_HAL,
CPPPATH=ALLPATHS,
CPPDEFINES=[
'FIRMWARE',
'TREZOR_MODEL_'+TREZOR_MODEL,
@ -711,6 +713,35 @@ if FROZEN:
env.Depends(source_mpyc, qstr_generated)
#
# Program objects
#
source_files = SOURCE_MOD + SOURCE_FIRMWARE + SOURCE_MICROPYTHON + SOURCE_MICROPYTHON_SPEED + SOURCE_HAL
obj_program = []
obj_program.extend(env.Object(source=SOURCE_MOD))
if FEATURE_FLAGS["SECP256K1_ZKP"]:
obj_program.extend(env.Object(source=SOURCE_MOD_SECP256K1_ZKP, CCFLAGS='$CCFLAGS -Wno-unused-function'))
source_files.extend(SOURCE_MOD_SECP256K1_ZKP)
obj_program.extend(env.Object(source=SOURCE_FIRMWARE))
obj_program.extend(env.Object(source=SOURCE_MICROPYTHON))
obj_program.extend(env.Object(source=SOURCE_MICROPYTHON_SPEED, COPT='-O3'))
obj_program.extend(env.Object(source=SOURCE_HAL))
if FROZEN:
obj_program.extend(env.Object(source=source_mpyc))
env.Replace(
ALLSOURCES=source_files,
ALLDEFS=tools.get_defs_for_cmake(env['CPPDEFINES'] + env['CPPDEFINES_IMPLICIT'] + [f"PRODUCTION={int(PRODUCTION)}", f"BOOTLOADER_QA={int(BOOTLOADER_QA)}", f"PYOPT={PYOPT}", f"BITCOIN_ONLY={BITCOIN_ONLY}"]))
cmake_gen = env.Command(
target='CMakeLists.txt',
source='',
action='$MAKECMAKELISTS --sources $ALLSOURCES --dirs $CPPPATH --defs $ALLDEFS',
)
#
# Rust library
#
@ -749,6 +780,8 @@ def cargo_build():
features.extend(FEATURES_AVAILABLE)
env.get("ENV")["BINDGEN_MACROS"] = tools.get_bindgen_defines(env.get("ALLDEFS"), ALLPATHS)
cargo_opts = [
f'--target={env.get("ENV")["RUST_TARGET"]}',
f'--target-dir=../../build/firmware/rust',
@ -772,34 +805,6 @@ env.Depends(rust, TRANSLATION_DATA)
env.Append(LINKFLAGS=f' -L{RUST_LIBDIR}')
env.Append(LINKFLAGS=f' -l{RUST_LIB}')
#
# Program objects
#
source_files = SOURCE_MOD + SOURCE_FIRMWARE + SOURCE_MICROPYTHON + SOURCE_MICROPYTHON_SPEED + SOURCE_HAL
obj_program = []
obj_program.extend(env.Object(source=SOURCE_MOD))
if FEATURE_FLAGS["SECP256K1_ZKP"]:
obj_program.extend(env.Object(source=SOURCE_MOD_SECP256K1_ZKP, CCFLAGS='$CCFLAGS -Wno-unused-function'))
source_files.extend(SOURCE_MOD_SECP256K1_ZKP)
obj_program.extend(env.Object(source=SOURCE_FIRMWARE))
obj_program.extend(env.Object(source=SOURCE_MICROPYTHON))
obj_program.extend(env.Object(source=SOURCE_MICROPYTHON_SPEED, COPT='-O3'))
obj_program.extend(env.Object(source=SOURCE_HAL))
if FROZEN:
obj_program.extend(env.Object(source=source_mpyc))
env.Replace(
ALLSOURCES=source_files,
ALLDEFS=tools.get_defs_for_cmake(env['CPPDEFINES'] + env['CPPDEFINES_IMPLICIT'] + [f"PRODUCTION={int(PRODUCTION)}", f"BOOTLOADER_QA={int(BOOTLOADER_QA)}", f"PYOPT={PYOPT}", f"BITCOIN_ONLY={BITCOIN_ONLY}"]))
cmake_gen = env.Command(
target='CMakeLists.txt',
source='',
action='$MAKECMAKELISTS --sources $ALLSOURCES --dirs $CPPPATH --defs $ALLDEFS',
)
MODEL_IDENTIFIER = tools.get_model_identifier(TREZOR_MODEL)
BOOTLOADER_SUFFIX = MODEL_IDENTIFIER

@ -532,6 +532,19 @@ elif TREZOR_MODEL in ('1',):
else:
raise ValueError('Unknown Trezor model')
ALLPATHS=['.',
'embed/rust',
'embed/lib',
'embed/models',
'embed/unix',
'embed/trezorhal',
'embed/trezorhal/unix',
'embed/extmod/modtrezorui',
'vendor/micropython',
'vendor/micropython/ports/unix',
'vendor/micropython/lib/mp-readline',
] + CPPPATH_MOD
env.Replace(
CCFLAGS='$COPT '
'-g3 '
@ -539,19 +552,7 @@ env.Replace(
'-fdata-sections -ffunction-sections -fPIE ' + CCFLAGS_MOD,
CCFLAGS_QSTR='-DNO_QSTR -DN_X64 -DN_X86 -DN_THUMB',
LIBS=['m'],
CPPPATH=[
'.',
'embed/rust',
'embed/lib',
'embed/models',
'embed/unix',
'embed/trezorhal',
'embed/trezorhal/unix',
'embed/extmod/modtrezorui',
'vendor/micropython',
'vendor/micropython/ports/unix',
'vendor/micropython/lib/mp-readline',
] + CPPPATH_MOD,
CPPPATH=ALLPATHS,
CPPDEFINES=[
CPU_MODEL,
'TREZOR_EMULATOR',
@ -798,6 +799,34 @@ if FROZEN:
env.Depends(source_mpyc, qstr_generated)
#
# Program objects
#
obj_program = []
source_files = SOURCE_MOD + SOURCE_MICROPYTHON + SOURCE_UNIX
obj_program.extend(env.Object(source=SOURCE_MOD))
if FEATURE_FLAGS["SECP256K1_ZKP"]:
obj_program.extend(env.Object(source=SOURCE_MOD_SECP256K1_ZKP, CCFLAGS='$CCFLAGS -Wno-unused-function'))
source_files.extend(SOURCE_MOD_SECP256K1_ZKP)
obj_program.extend(env.Object(source=SOURCE_MICROPYTHON))
obj_program.extend(env.Object(source=SOURCE_UNIX))
if FROZEN:
obj_program.extend(env.Object(source=source_mpyc))
env.Replace(
ALLSOURCES=source_files,
ALLDEFS=tools.get_defs_for_cmake(env['CPPDEFINES']))
cmake_gen = env.Command(
target='CMakeLists.txt',
source='',
action='$MAKECMAKELISTS --sources $ALLSOURCES --dirs $CPPPATH --defs $ALLDEFS',
)
#
# Rust library
#
@ -842,7 +871,7 @@ def cargo_build():
if TREZOR_MODEL in ('R', '1'):
features.append('button')
env.get('ENV')['TREZOR_MODEL'] = TREZOR_MODEL
env.get("ENV")["BINDGEN_MACROS"] = tools.get_bindgen_defines(env.get("ALLDEFS"), ALLPATHS)
return f'cd embed/rust; cargo build --profile {RUST_PROFILE} --target-dir=../../build/unix/rust --no-default-features --features "{" ".join(features)}" --target {TARGET}'
@ -857,33 +886,6 @@ env.Depends(rust, TRANSLATION_DATA)
env.Append(LINKFLAGS=f'-L{RUST_LIBDIR}')
env.Append(LINKFLAGS=f'-l{RUST_LIB}')
#
# Program objects
#
obj_program = []
source_files = SOURCE_MOD + SOURCE_MICROPYTHON + SOURCE_UNIX
obj_program.extend(env.Object(source=SOURCE_MOD))
if FEATURE_FLAGS["SECP256K1_ZKP"]:
obj_program.extend(env.Object(source=SOURCE_MOD_SECP256K1_ZKP, CCFLAGS='$CCFLAGS -Wno-unused-function'))
source_files.extend(SOURCE_MOD_SECP256K1_ZKP)
obj_program.extend(env.Object(source=SOURCE_MICROPYTHON))
obj_program.extend(env.Object(source=SOURCE_UNIX))
if FROZEN:
obj_program.extend(env.Object(source=source_mpyc))
env.Replace(
ALLSOURCES=source_files,
ALLDEFS=tools.get_defs_for_cmake(env['CPPDEFINES']))
cmake_gen = env.Command(
target='CMakeLists.txt',
source='',
action='$MAKECMAKELISTS --sources $ALLSOURCES --dirs $CPPPATH --defs $ALLDEFS',
)
env.Depends(obj_program, qstr_generated)
program = env.Command(

@ -14,20 +14,6 @@ fn main() {
link_core_objects();
}
fn mcu_type() -> String {
match env::var("MCU_TYPE") {
Ok(mcu) => mcu,
Err(_) => String::from("STM32F427xx"),
}
}
fn model() -> String {
match env::var("TREZOR_MODEL") {
Ok(model) => model,
Err(_) => String::from("T"),
}
}
// fn block_words() -> String {
// match env::var("FLASH_BLOCK_WORDS") {
// Ok(model) => model,
@ -35,19 +21,6 @@ fn model() -> String {
// }
// }
fn board() -> String {
if !is_firmware() {
return String::from("boards/board-unix.h");
}
match env::var("TREZOR_BOARD") {
Ok(board) => {
format!("boards/{}", board)
}
Err(_) => String::from("boards/trezor_t.h"),
}
}
/// Generates Rust module that exports QSTR constants used in firmware.
#[cfg(feature = "micropython")]
fn generate_qstr_bindings() {
@ -96,35 +69,19 @@ fn generate_qstr_bindings() {
fn prepare_bindings() -> bindgen::Builder {
let mut bindings = bindgen::Builder::default();
// Common include paths and defines
bindings = bindings.clang_args([
"-I../../../crypto",
"-I../../../storage",
"-I../../vendor/micropython",
"-I../../vendor/micropython/lib/uzlib",
"-I../lib",
"-I../trezorhal",
"-I../models",
format!("-D{}", mcu_type()).as_str(),
format!("-DTREZOR_MODEL_{}", model()).as_str(),
format!("-DTREZOR_BOARD=\"{}\"", board()).as_str(),
]);
let mut clang_args: Vec<&str> = Vec::new();
let includes = env::var("BINDGEN_MACROS").unwrap();
let args = includes.split(',');
for arg in args {
clang_args.push(arg);
}
// Pass in correct include paths and defines.
if is_firmware() {
let mut clang_args: Vec<&str> = Vec::new();
let includes = env::var("RUST_INCLUDES").unwrap();
let args = includes.split(';');
for arg in args {
clang_args.push(arg);
}
clang_args.push("-nostdinc");
clang_args.push("-I../firmware");
clang_args.push("-I../../build/firmware");
clang_args.push("-DUSE_HAL_DRIVER");
bindings = bindings.clang_args(&clang_args);
// Append gcc-arm-none-eabi's include paths.
let cc_output = Command::new("arm-none-eabi-gcc")
@ -147,17 +104,11 @@ fn prepare_bindings() -> bindgen::Builder {
bindings = bindings.clang_args(include_args);
} else {
bindings = bindings.clang_args(&[
"-I../unix",
"-I../trezorhal/unix",
"-I../../build/unix",
"-I../../vendor/micropython/ports/unix",
"-DTREZOR_EMULATOR",
"-DFLASH_BIT_ACCESS=1",
"-DFLASH_BLOCK_WORDS=1",
]);
clang_args.push("-I../../build/unix");
}
bindings = bindings.clang_args(&clang_args);
bindings
// Customize the standard types.
.use_core()

@ -68,7 +68,4 @@ def configure(
]
features_available.append("usb")
env.get("ENV")["TREZOR_BOARD"] = board
env.get("ENV")["MCU_TYPE"] = mcu
return features_available

@ -90,8 +90,6 @@ def configure(
features_available.append("framebuffer")
features_available.append("framebuffer32bit")
env.get("ENV")["TREZOR_BOARD"] = board
env.get("ENV")["MCU_TYPE"] = mcu
env.get("ENV")["LINKER_SCRIPT"] = linker_script
defs = env.get("CPPDEFINES_IMPLICIT")

@ -69,17 +69,5 @@ def stm32f4_common_files(env, defines, sources, paths):
"embed/trezorhal/stm32f4/util.s",
]
env.get("ENV")["RUST_INCLUDES"] = (
"-I../trezorhal/stm32f4;"
"-I../../vendor/micropython/lib/stm32lib/STM32F4xx_HAL_Driver/Inc;"
"-I../../vendor/micropython/lib/stm32lib/CMSIS/STM32F4xx/Include;"
"-I../../vendor/micropython/lib/cmsis/inc;"
"-DSTM32_HAL_H=<stm32f4xx.h>;"
"-DSTM32F4;"
"-DFLASH_BLOCK_WORDS=1;"
"-DFLASH_BIT_ACCESS=1;"
"-DCONFIDENTIAL;"
)
env.get("ENV")["SUFFIX"] = "stm32f4"
env.get("ENV")["LINKER_SCRIPT"] = "stm32f4"

@ -82,15 +82,4 @@ def stm32u5_common_files(env, defines, sources, paths):
"embed/trezorhal/stm32u5/util.s",
]
env.get("ENV")["RUST_INCLUDES"] = (
"-I../trezorhal/stm32u5;"
"-I../../vendor/stm32u5xx_hal_driver/Inc;"
"-I../../vendor/cmsis_device_u5/Include;"
"-I../../vendor/cmsis_5/CMSIS/Core/Include;"
"-DSTM32_HAL_H=<stm32u5xx.h>;"
"-DSTM32U5;"
"-DFLASH_BLOCK_WORDS=4;"
"-DCONFIDENTIAL;"
)
env.get("ENV")["SUFFIX"] = "stm32u5"

@ -51,7 +51,4 @@ def configure(
]
features_available.append("usb")
env.get("ENV")["TREZOR_BOARD"] = board
env.get("ENV")["MCU_TYPE"] = mcu
return features_available

@ -73,7 +73,4 @@ def configure(
sources += ["vendor/trezor-crypto/hash_to_curve.c"]
features_available.append("optiga")
env.get("ENV")["TREZOR_BOARD"] = board
env.get("ENV")["MCU_TYPE"] = mcu
return features_available

@ -61,7 +61,4 @@ def configure(
]
features_available.append("usb")
env.get("ENV")["TREZOR_BOARD"] = board
env.get("ENV")["MCU_TYPE"] = mcu
return features_available

@ -57,7 +57,4 @@ def configure(
]
features_available.append("usb")
env.get("ENV")["TREZOR_BOARD"] = board
env.get("ENV")["MCU_TYPE"] = mcu
return features_available

@ -57,7 +57,4 @@ def configure(
]
features_available.append("usb")
env.get("ENV")["TREZOR_BOARD"] = board
env.get("ENV")["MCU_TYPE"] = mcu
return features_available

@ -92,7 +92,4 @@ def configure(
]
features_available.append("dma2d")
env.get("ENV")["TREZOR_BOARD"] = board
env.get("ENV")["MCU_TYPE"] = mcu
return features_available

@ -112,8 +112,4 @@ def configure(
defs = env.get("CPPDEFINES_IMPLICIT")
defs += ["__ARM_FEATURE_CMSE=3"]
rust_defs = env.get("ENV")["RUST_INCLUDES"]
rust_defs += "-DFRAMEBUFFER;"
env.get("ENV")["RUST_INCLUDES"] = rust_defs
return features_available

@ -105,15 +105,9 @@ def configure(
sources += ["vendor/trezor-crypto/hash_to_curve.c"]
features_available.append("optiga")
env.get("ENV")["TREZOR_BOARD"] = board
env.get("ENV")["MCU_TYPE"] = mcu
env.get("ENV")["LINKER_SCRIPT"] = linker_script
defs = env.get("CPPDEFINES_IMPLICIT")
defs += ["__ARM_FEATURE_CMSE=3"]
rust_defs = env.get("ENV")["RUST_INCLUDES"]
rust_defs += "-DFRAMEBUFFER;"
env.get("ENV")["RUST_INCLUDES"] = rust_defs
return features_available

@ -148,6 +148,20 @@ def _compress(data: bytes) -> bytes:
return z.compress(data) + z.flush()
def get_bindgen_defines(
defines: list[str | tuple[str, str]], paths: list[str]
) -> tuple(str, str):
rest_defs = []
for d in defines:
rest_defs.append(
f"-D{d}".replace('"<', "<").replace('>"', ">").replace('\\"', '"')
)
for d in paths:
rest_defs.append(f"-I../../{d}")
return ",".join(rest_defs)
def embed_binary(obj_program, env, section, target_, file):
_in = f"embedded_{section}.bin.deflated"

Loading…
Cancel
Save