From 294d28ecd247f861e864d0f1e5189cb68005e02f Mon Sep 17 00:00:00 2001 From: Xavier Chapron Date: Mon, 28 Aug 2023 17:36:55 +0200 Subject: [PATCH 1/2] os: Compute usable THROW LR value and allow app to access it --- src/os.c | 19 ++++++++++++++++++- 1 file changed, 18 insertions(+), 1 deletion(-) diff --git a/src/os.c b/src/os.c index fd8fc6abc..e442b030b 100644 --- a/src/os.c +++ b/src/os.c @@ -81,12 +81,29 @@ char os_secure_memcmp(const void *src1, const void* src2, size_t 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 From 854a0ab963c43070dd26cc13791b8d5174011a68 Mon Sep 17 00:00:00 2001 From: Xavier Chapron Date: Mon, 28 Aug 2023 17:40:11 +0200 Subject: [PATCH 2/2] lib_standard_app: Add a mecanism to display a debug screen upon Throw reception --- lib_standard_app/debug.c | 76 ++++++++++++++++++++++++++++++++++++++++ lib_standard_app/debug.h | 3 ++ lib_standard_app/main.c | 20 +++++++++++ 3 files changed, 99 insertions(+) create mode 100644 lib_standard_app/debug.c create mode 100644 lib_standard_app/debug.h diff --git a/lib_standard_app/debug.c b/lib_standard_app/debug.c new file mode 100644 index 000000000..60ba8d7b4 --- /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 000000000..0987417fc --- /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 c4fa902d3..cd4bf6f81 100644 --- a/lib_standard_app/main.c +++ b/lib_standard_app/main.c @@ -19,6 +19,7 @@ #include "os.h" #include "io.h" +#include "debug.h" #ifdef HAVE_SWAP #include "swap.h" @@ -62,6 +63,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 { }