diff --git a/Makefile.standard_app b/Makefile.standard_app index 37edb57d..573e41cd 100644 --- a/Makefile.standard_app +++ b/Makefile.standard_app @@ -75,7 +75,8 @@ endif # STANDARD DEFINES # ##################################################################### DEFINES += $(DEFINES_LIB) -DEFINES += APPNAME=\"$(APPNAME)\" +# Added directly as a CFLAG because it might contain spaces +CFLAGS += -DAPPNAME=\"$(APPNAME)\" DEFINES += APPVERSION=\"$(APPVERSION)\" DEFINES += MAJOR_VERSION=$(APPVERSION_M) MINOR_VERSION=$(APPVERSION_N) PATCH_VERSION=$(APPVERSION_P) DEFINES += IO_HID_EP_LENGTH=64 @@ -91,11 +92,12 @@ ifneq ($(DISABLE_STANDARD_SNPRINTF), 1) DEFINES += HAVE_SPRINTF HAVE_SNPRINTF_FORMAT_U endif -ifneq ($(TARGET_NAME),TARGET_NANOS) +ifneq ($(DEBUG), 0) # Since the PRINTF implementation uses the USB code - ifneq ($(DEBUG), 0) + ifneq ($(TARGET_NAME),TARGET_NANOS) DISABLE_STANDARD_USB = 0 endif + DISABLE_SEPROXYHAL = 0 endif ifneq ($(DISABLE_STANDARD_USB), 1) diff --git a/lib_standard_app/debug.c b/lib_standard_app/debug.c new file mode 100644 index 00000000..60ba8d7b --- /dev/null +++ b/lib_standard_app/debug.c @@ -0,0 +1,76 @@ +/***************************************************************************** + * (c) 2020 Ledger SAS. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + *****************************************************************************/ + +#include // uint*_t +#include // memset, explicit_bzero + +#include "os.h" +#include "io.h" + +#ifdef HAVE_NBGL +#include "nbgl_use_case.h" +#endif + +#ifdef HAVE_DEBUG_THROWS +static char errordata[20]; + +WEAK void app_throw_info(unsigned int exception, unsigned int lr_val) { + snprintf(errordata, + sizeof(errordata), + "n%d, LR=0x%08X", + exception, + lr_val); +} + +static void review_choice(bool confirm) { + UNUSED(confirm); + os_sched_exit(-1); +} + +#ifdef HAVE_BAGL +UX_STEP_CB(ux_error, + bnnn_paging, + review_choice(true), + { + .title = "App error", + .text = errordata, + }); +UX_FLOW(ux_error_flow, &ux_error); +#endif + +WEAK void __attribute__((noreturn)) debug_display_throw_error(int exception) { + UNUSED(exception); + +#ifdef HAVE_BAGL + ux_flow_init(0, ux_error_flow, NULL); +#endif + +#ifdef HAVE_NBGL + nbgl_useCaseChoice(&C_round_warning_64px, + "App error", + errordata, + "Exit app", + "Exit app", + review_choice); +#endif + + // Block until the user approve and the app is quit + while (1) { + io_seproxyhal_io_heartbeat(); + } +} + +#endif diff --git a/lib_standard_app/debug.h b/lib_standard_app/debug.h new file mode 100644 index 00000000..0987417f --- /dev/null +++ b/lib_standard_app/debug.h @@ -0,0 +1,3 @@ +#pragma once + +WEAK void __attribute__((noreturn)) debug_display_throw_error(int exception); diff --git a/lib_standard_app/main.c b/lib_standard_app/main.c index c4fa902d..e2e2ea1d 100644 --- a/lib_standard_app/main.c +++ b/lib_standard_app/main.c @@ -19,9 +19,14 @@ #include "os.h" #include "io.h" +#include "debug.h" #ifdef HAVE_SWAP #include "swap.h" + +#ifdef HAVE_NBGL +#include "nbgl_use_case.h" +#endif // HAVE_NBGL #endif // HAVE_SWAP ux_state_t G_ux; @@ -62,6 +67,25 @@ static void standalone_app_main(void) { } CATCH_OTHER(e) { PRINTF("Exiting following exception: %d\n", e); + +#ifdef HAVE_DEBUG_THROWS + // Disable USB and BLE, the app have crashed and is going to be exited + // This is necessary to avoid device freeze while displaying throw error + // in a specific case: + // - the app receives an APDU + // - the app throws before replying + // - the app displays the error on screen + // - the user unplug the NanoX instead of confirming the screen + // - the NanoX goes on battery power and display the lock screen + // - the user plug the NanoX instead of entering its pin + // - the device is frozen, battery should be removed + USB_power(0); +#ifdef HAVE_BLE + BLE_power(0, NULL); +#endif + // Display crash info on screen for debug purpose + debug_display_throw_error(e); +#endif } FINALLY { } @@ -74,9 +98,6 @@ static void standalone_app_main(void) { #ifdef HAVE_SWAP static void library_app_main(libargs_t *args) { - G_called_from_swap = true; - G_swap_response_ready = false; - BEGIN_TRY { TRY { PRINTF("Inside library\n"); @@ -87,12 +108,16 @@ static void library_app_main(libargs_t *args) { // BSS data. bool success = swap_copy_transaction_parameters(args->create_transaction); if (success) { - // BSS was wiped, so init these global again + // BSS was wiped, we can now init these globals G_called_from_swap = true; G_swap_response_ready = false; common_app_init(); +#ifdef HAVE_NBGL + nbgl_useCaseSpinner("Signing"); +#endif // HAVE_NBGL + app_main(); } break; diff --git a/src/os.c b/src/os.c index e51a5131..079a09b4 100644 --- a/src/os.c +++ b/src/os.c @@ -79,12 +79,29 @@ char os_secure_memcmp(void * src1, void * src2, unsigned int length) { } #ifndef HAVE_BOLOS +#define MAIN_LINKER_SCRIPT_LOCATION 0xC0DE0000 +int main(void); + +// This function can be used to declare a callback to THROW in the application +__attribute((weak)) void app_throw_info(unsigned int exception, unsigned int lr_val) { + UNUSED(exception); + UNUSED(lr_val); +} + void os_longjmp(unsigned int exception) { -#ifdef HAVE_PRINTF unsigned int lr_val; __asm volatile("mov %0, lr" :"=r"(lr_val)); + + // Compute location before relocation (sort of anti PIC) + lr_val = lr_val - (unsigned int)main + MAIN_LINKER_SCRIPT_LOCATION; + +#ifdef HAVE_PRINTF PRINTF("exception[%d]: LR=0x%08X\n", exception, lr_val); #endif // HAVE_PRINTF + + // Send to the app the info of exception and LR for debug purpose + app_throw_info(exception, lr_val); + longjmp(try_context_get()->jmp_buf, exception); } #endif // HAVE_BOLOS