From 7cdb0cf244d725a1078f23b897f1ee86b0ebe0f4 Mon Sep 17 00:00:00 2001 From: Roman Zeyde Date: Wed, 9 Apr 2025 14:54:16 +0300 Subject: [PATCH] feat(vendor): update MicroPython to allow excluding line numbers from bytecode Setting `MICROPY_ENABLE_SOURCE_LINE=0` helps reducing the debug firmware size by ~2%: ``` $ TREZOR_MODEL=T3T1 MICROPY_ENABLE_SOURCE_LINE=0 PYOPT=0 make -C core build_firmware FLASH: 1,629,456 B 1664 KB 95.63% ``` Before this PR: ``` FLASH: 1,662,224 B 1664 KB 97.55% ``` [no changelog] --- core/Makefile | 9 +- core/SConscript.firmware | 2 + core/SConscript.unix | 2 + core/embed/projects/firmware/mpconfigport.h | 2 + core/embed/projects/unix/mpconfigport.h | 2 + .../upymod/mpycross_include/mpconfigport.h | 172 ++++++++++++++++++ 6 files changed, 188 insertions(+), 1 deletion(-) create mode 100644 core/embed/upymod/mpycross_include/mpconfigport.h diff --git a/core/Makefile b/core/Makefile index 08e4b8b6f9..cb8d81bc58 100644 --- a/core/Makefile +++ b/core/Makefile @@ -129,6 +129,7 @@ SCONS_VARS = \ DISABLE_TROPIC="$(DISABLE_TROPIC)" \ HW_REVISION="$(HW_REVISION)" \ LOG_STACK_USAGE="$(LOG_STACK_USAGE)" \ + MICROPY_ENABLE_SOURCE_LINE="$(MICROPY_ENABLE_SOURCE_LINE)" \ PRODUCTION="$(PRODUCTION)" \ PYOPT="$(PYOPT)" \ QUIET_MODE="$(QUIET_MODE)" \ @@ -302,21 +303,27 @@ build_reflash: ## build reflash firmware + reflash image build_kernel: ## build kernel image $(SCONS) $(KERNEL_BUILD_DIR)/kernel.bin +build_firmware: MICROPY_ENABLE_SOURCE_LINE ?= 0 build_firmware: templates build_cross build_kernel ## build firmware with frozen modules $(SCONS) $(FIRMWARE_BUILD_DIR)/firmware.bin +build_unix: MICROPY_ENABLE_SOURCE_LINE ?= 1 build_unix: templates ## build unix port $(SCONS) PYOPT=0 $(UNIX_BUILD_DIR)/trezor-emu-core $(UNIX_PORT_OPTS) +build_unix_frozen: MICROPY_ENABLE_SOURCE_LINE ?= 1 build_unix_frozen: templates build_cross ## build unix port with frozen modules $(SCONS) $(UNIX_BUILD_DIR)/trezor-emu-core $(UNIX_PORT_OPTS) TREZOR_EMULATOR_FROZEN=1 +build_unix_debug: MICROPY_ENABLE_SOURCE_LINE ?= 1 build_unix_debug: templates ## build unix port $(SCONS) --max-drift=1 $(UNIX_BUILD_DIR)/trezor-emu-core $(UNIX_PORT_OPTS) \ TREZOR_EMULATOR_ASAN=1 TREZOR_EMULATOR_DEBUGGABLE=1 build_cross: ## build mpy-cross port - $(MAKE) -C vendor/micropython/mpy-cross $(CROSS_PORT_OPTS) + INC=-I$(CURDIR)/embed/upymod/mpycross_include/ \ + $(MAKE) -C vendor/micropython/mpy-cross $(CROSS_PORT_OPTS) \ + CFLAGS_EXTRA=-DMICROPY_ENABLE_SOURCE_LINE=$(MICROPY_ENABLE_SOURCE_LINE) ## clean commands: diff --git a/core/SConscript.firmware b/core/SConscript.firmware index 9118826234..bf3348f399 100644 --- a/core/SConscript.firmware +++ b/core/SConscript.firmware @@ -20,6 +20,7 @@ SCM_REVISION = ARGUMENTS.get('SCM_REVISION', None) THP = ARGUMENTS.get('THP', '0') == '1' # Trezor-Host Protocol BENCHMARK = ARGUMENTS.get('BENCHMARK', '0') == '1' LOG_STACK_USAGE = ARGUMENTS.get('LOG_STACK_USAGE', '0') == '1' +MICROPY_ENABLE_SOURCE_LINE = ARGUMENTS.get('MICROPY_ENABLE_SOURCE_LINE', '0') DISABLE_ANIMATION = ARGUMENTS.get('TREZOR_DISABLE_ANIMATION', '0') == '1' BLOCK_ON_VCP = ARGUMENTS.get('BLOCK_ON_VCP', '0') == '1' UI_DEBUG_OVERLAY = ARGUMENTS.get('UI_DEBUG_OVERLAY', '0') == '1' @@ -87,6 +88,7 @@ CPPDEFINES_MOD += [ ('USE_CARDANO', '1' if EVERYTHING else '0'), ('USE_NEM', '1' if (EVERYTHING and TREZOR_MODEL == "T2T1") else '0'), ('USE_EOS', '1' if (EVERYTHING and TREZOR_MODEL == "T2T1") else '0'), + ('MICROPY_ENABLE_SOURCE_LINE', MICROPY_ENABLE_SOURCE_LINE), ('DISABLE_ANIMATION', '1' if DISABLE_ANIMATION else '0'), ('LOG_STACK_USAGE', '1' if LOG_STACK_USAGE else '0'), ('BLOCK_ON_VCP', '1' if BLOCK_ON_VCP else '0') diff --git a/core/SConscript.unix b/core/SConscript.unix index 58491b9c4b..97aa986a4c 100644 --- a/core/SConscript.unix +++ b/core/SConscript.unix @@ -16,6 +16,7 @@ BENCHMARK = ARGUMENTS.get('BENCHMARK', '0') == '1' PYOPT = ARGUMENTS.get('PYOPT', '1') FROZEN = ARGUMENTS.get('TREZOR_EMULATOR_FROZEN', 0) RASPI = os.getenv('TREZOR_EMULATOR_RASPI') == '1' +MICROPY_ENABLE_SOURCE_LINE = ARGUMENTS.get('MICROPY_ENABLE_SOURCE_LINE', '1') if BENCHMARK and PYOPT != '0': print("BENCHMARK=1 works only with PYOPT=0.") @@ -83,6 +84,7 @@ CPPDEFINES_MOD += [ ('USE_CARDANO', '1' if EVERYTHING else '0'), ('USE_NEM', '1' if (EVERYTHING and TREZOR_MODEL == "T2T1") else '0'), ('USE_EOS', '1' if (EVERYTHING and TREZOR_MODEL == "T2T1") else '0'), + ('MICROPY_ENABLE_SOURCE_LINE', MICROPY_ENABLE_SOURCE_LINE), ] SOURCE_MOD += [ 'embed/upymod/trezorobj.c', diff --git a/core/embed/projects/firmware/mpconfigport.h b/core/embed/projects/firmware/mpconfigport.h index 5c69a1bc6b..1fd2bd21c8 100644 --- a/core/embed/projects/firmware/mpconfigport.h +++ b/core/embed/projects/firmware/mpconfigport.h @@ -75,7 +75,9 @@ #define MICROPY_REPL_EMACS_KEYS (1) #define MICROPY_REPL_AUTO_INDENT (1) #define MICROPY_LONGINT_IMPL (MICROPY_LONGINT_IMPL_MPZ) +#ifndef MICROPY_ENABLE_SOURCE_LINE #define MICROPY_ENABLE_SOURCE_LINE (1) +#endif #define MICROPY_FLOAT_IMPL (MICROPY_FLOAT_IMPL_FLOAT) #define MICROPY_STREAMS_NON_BLOCK (1) #define MICROPY_MODULE_WEAK_LINKS (1) diff --git a/core/embed/projects/unix/mpconfigport.h b/core/embed/projects/unix/mpconfigport.h index a409abad36..7c32cbe7dc 100644 --- a/core/embed/projects/unix/mpconfigport.h +++ b/core/embed/projects/unix/mpconfigport.h @@ -82,7 +82,9 @@ #define MICROPY_REPL_EMACS_KEYS (1) #define MICROPY_REPL_AUTO_INDENT (1) #define MICROPY_LONGINT_IMPL (MICROPY_LONGINT_IMPL_MPZ) +#ifndef MICROPY_ENABLE_SOURCE_LINE #define MICROPY_ENABLE_SOURCE_LINE (1) +#endif #define MICROPY_FLOAT_IMPL (MICROPY_FLOAT_IMPL_FLOAT) #define MICROPY_STREAMS_NON_BLOCK (1) #define MICROPY_MODULE_WEAK_LINKS (1) diff --git a/core/embed/upymod/mpycross_include/mpconfigport.h b/core/embed/upymod/mpycross_include/mpconfigport.h new file mode 100644 index 0000000000..54255a45c1 --- /dev/null +++ b/core/embed/upymod/mpycross_include/mpconfigport.h @@ -0,0 +1,172 @@ +/* + * This file is part of the MicroPython project, http://micropython.org/ + * + * The MIT License (MIT) + * + * Copyright (c) 2013-2015 Damien P. George + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ + +// options to control how MicroPython is built + +#define MICROPY_ALLOC_PATH_MAX (PATH_MAX) +#define MICROPY_PERSISTENT_CODE_LOAD (0) +#define MICROPY_PERSISTENT_CODE_SAVE (1) + +#ifndef MICROPY_PERSISTENT_CODE_SAVE_FILE +#if defined(__i386__) || defined(__x86_64__) || defined(_WIN32) || \ + defined(__unix__) || defined(__APPLE__) +#define MICROPY_PERSISTENT_CODE_SAVE_FILE (1) +#else +#define MICROPY_PERSISTENT_CODE_SAVE_FILE (0) +#endif +#endif + +#define MICROPY_EMIT_X64 (1) +#define MICROPY_EMIT_X86 (1) +#define MICROPY_EMIT_THUMB (1) +#define MICROPY_EMIT_INLINE_THUMB (1) +#define MICROPY_EMIT_ARM (1) +#define MICROPY_EMIT_XTENSA (1) +#define MICROPY_EMIT_INLINE_XTENSA (1) +#define MICROPY_EMIT_XTENSAWIN (1) + +#define MICROPY_DYNAMIC_COMPILER (1) +#define MICROPY_COMP_CONST_FOLDING (1) +#define MICROPY_COMP_MODULE_CONST (1) +#define MICROPY_COMP_CONST (1) +#define MICROPY_COMP_DOUBLE_TUPLE_ASSIGN (1) +#define MICROPY_COMP_TRIPLE_TUPLE_ASSIGN (1) +#define MICROPY_COMP_RETURN_IF_EXPR (1) + +#define MICROPY_READER_POSIX (1) +#define MICROPY_ENABLE_RUNTIME (0) +#define MICROPY_ENABLE_GC (1) +#ifndef __EMSCRIPTEN__ +#define MICROPY_STACK_CHECK (1) +#endif +#define MICROPY_HELPER_LEXER_UNIX (1) +#define MICROPY_LONGINT_IMPL (MICROPY_LONGINT_IMPL_MPZ) +#ifndef MICROPY_ENABLE_SOURCE_LINE +#define MICROPY_ENABLE_SOURCE_LINE (1) +#endif +#define MICROPY_ENABLE_DOC_STRING (0) +#define MICROPY_ERROR_REPORTING (MICROPY_ERROR_REPORTING_DETAILED) +#define MICROPY_WARNINGS (1) + +#define MICROPY_FLOAT_IMPL (MICROPY_FLOAT_IMPL_DOUBLE) +#define MICROPY_CPYTHON_COMPAT (1) +#define MICROPY_USE_INTERNAL_PRINTF (0) + +#define MICROPY_PY_FSTRINGS (1) +#define MICROPY_PY_BUILTINS_STR_UNICODE (1) + +#if !(defined(MICROPY_GCREGS_SETJMP) || defined(__x86_64__) || \ + defined(__i386__) || defined(__thumb2__) || defined(__thumb__) || \ + defined(__arm__)) +// Fall back to setjmp() implementation for discovery of GC pointers in +// registers. +#define MICROPY_GCREGS_SETJMP (1) +#endif + +#define MICROPY_PY___FILE__ (0) +#define MICROPY_PY_ARRAY (0) +#define MICROPY_PY_ATTRTUPLE (0) +#define MICROPY_PY_COLLECTIONS (0) +#define MICROPY_PY_MATH (0) +#define MICROPY_PY_CMATH (0) +#define MICROPY_PY_GC (0) +#define MICROPY_PY_IO (0) +#define MICROPY_PY_SYS (0) + +// type definitions for the specific machine + +#ifdef __LP64__ +typedef long mp_int_t; // must be pointer size +typedef unsigned long mp_uint_t; // must be pointer size +#elif defined(__MINGW32__) && defined(_WIN64) +#include +typedef __int64 mp_int_t; +typedef unsigned __int64 mp_uint_t; +#elif defined(_MSC_VER) && defined(_WIN64) +typedef __int64 mp_int_t; +typedef unsigned __int64 mp_uint_t; +#else +// These are definitions for machines where sizeof(int) == sizeof(void*), +// regardless for actual size. +typedef int mp_int_t; // must be pointer size +typedef unsigned int mp_uint_t; // must be pointer size +#endif + +// Cannot include , as it may lead to symbol name clashes +#if _FILE_OFFSET_BITS == 64 && !defined(__LP64__) +typedef long long mp_off_t; +#else +typedef long mp_off_t; +#endif + +#define MP_PLAT_PRINT_STRN(str, len) (void)0 + +// We need to provide a declaration/definition of alloca() +#ifdef __FreeBSD__ +#include +#elif defined(_WIN32) +#include +#else +#include +#endif + +#include + +// MSVC specifics - see windows/mpconfigport.h for explanation +#ifdef _MSC_VER + +#define MP_ENDIANNESS_LITTLE (1) +#define NORETURN __declspec(noreturn) +#define MP_NOINLINE __declspec(noinline) +#define MP_LIKELY(x) (x) +#define MP_UNLIKELY(x) (x) +#define MICROPY_PORT_CONSTANTS \ + { MP_ROM_QSTR(MP_QSTR_dummy), MP_ROM_PTR(NULL) } +#ifdef _WIN64 +#define MP_SSIZE_MAX _I64_MAX +#else +#define MP_SSIZE_MAX _I32_MAX +#endif +#define MICROPY_MAKE_POINTER_CALLABLE(p) \ + ((void *)(p)) // Avoid compiler warning about different const qualifiers +#define restrict +#define inline __inline +#define alignof(t) __alignof(t) +#undef MICROPY_ALLOC_PATH_MAX +#define MICROPY_ALLOC_PATH_MAX 260 +#define PATH_MAX MICROPY_ALLOC_PATH_MAX +#define S_ISREG(m) (((m) & S_IFMT) == S_IFREG) +#define S_ISDIR(m) (((m) & S_IFMT) == S_IFDIR) +#ifdef _WIN64 +#define SSIZE_MAX _I64_MAX +typedef __int64 ssize_t; +#else +#define SSIZE_MAX _I32_MAX +typedef int ssize_t; +#endif +typedef mp_off_t off_t; + +#endif