From d56f695502a11240d8a047ccb5e19514c7bed7e5 Mon Sep 17 00:00:00 2001 From: Robert Lukotka Date: Wed, 25 May 2022 11:01:17 +0200 Subject: [PATCH 01/17] Move app icon copying from to app/Makefile Thus app icon copies norrectly in non-dockerized build, or build via make shell. --- app/Makefile | 16 ++++++++++++++++ deps/ledger-zxlib/dockerized_build.mk | 2 -- 2 files changed, 16 insertions(+), 2 deletions(-) diff --git a/app/Makefile b/app/Makefile index 7b59c0e2..a72e9d62 100755 --- a/app/Makefile +++ b/app/Makefile @@ -178,6 +178,22 @@ GLYPH_SRC_DIR = glyphs INCLUDES_PATH += $(MY_DIR)/glyphs include $(BOLOS_SDK)/Makefile.glyphs +.PHONY: copy_app_icon +copy_app_icon: + $(info Replacing app icon) + cp $(ICONNAME) glyphs/icon_app.gif + +.PHONY: delete_app_icon +delete_app_icon: + $(info Deleting app icon) + rm -rf glyphs/icon_app.gif + +#before generating glyph files we need to copy app icon +$(GLYPH_DESTH): copy_app_icon + +#deleting app icon is a part of clean +clean: delete_app_icon + APP_SOURCE_PATH += $(MY_DIR)/src APP_SOURCE_PATH += $(MY_DIR)/../deps/ledger-zxlib/include APP_SOURCE_PATH += $(MY_DIR)/../deps/ledger-zxlib/src diff --git a/deps/ledger-zxlib/dockerized_build.mk b/deps/ledger-zxlib/dockerized_build.mk index 2b8f0c29..d6e45ff3 100644 --- a/deps/ledger-zxlib/dockerized_build.mk +++ b/deps/ledger-zxlib/dockerized_build.mk @@ -133,8 +133,6 @@ pull_build_container: .PHONY: build build: pull_build_container - $(info Replacing app icon) - @cp $(LEDGER_SRC)/$(NANO_ICON_GIF) $(LEDGER_SRC)/glyphs/icon_app.gif $(info calling make inside docker) $(call run_docker, , make -j `nproc`) From 3a546eefa3010fdeb51ded7869abaf3f0fd6a336 Mon Sep 17 00:00:00 2001 From: Robert Lukotka Date: Fri, 22 Jul 2022 16:28:05 +0200 Subject: [PATCH 02/17] Merkle trees to remove tx metadata from ledger app --- app/Makefile | 2 +- .../2022-05-16-071046-61-1/index.html | 97 + .../2022-05-16-071046-61-1/report-05ba52.html | 1431 ++ .../2022-05-16-071046-61-1/report-8e376d.html | 1877 ++ .../2022-05-16-071046-61-1/scanview.css | 62 + .../2022-05-16-071046-61-1/sorttable.js | 492 + .../2022-05-16-071232-98-1/index.html | 94 + .../2022-05-16-071232-98-1/report-660403.html | 1880 ++ .../2022-05-16-071232-98-1/scanview.css | 62 + .../2022-05-16-071232-98-1/sorttable.js | 492 + app/src/common/app_main.c | 19 +- app/src/parser.h | 4 +- app/src/parser_impl.c | 2 +- app/src/tx_metadata.c | 1074 +- app/src/tx_metadata.h | 18 +- deps/ledger-zxlib/dockerized_build.mk | 7 + docs/APDUSPEC.md | 81 +- js/src/common.js | 3 + js/src/helperV2.js | 49 + js/src/index.js | 66 +- js/src/txMerkleTree.js | 16956 ++++++++++++++++ ...testvectors.cpp => testvectors.cpp.ignore} | 0 tests/tx_metadata.cpp | 66 +- ..._output.cpp => expected_output.cpp.ignore} | 0 ...cted_output.h => expected_output.h.ignore} | 0 .../{testcases.cpp => testcases.cpp.ignore} | 0 tests_speculos/speculos-transaction.js | 25 +- tests_speculos/test-basic-app-version.js | 8 +- .../test-basic-sign-basic-invalid.js | 11 +- tests_speculos/test-menu/nanos.03.png | Bin 405 -> 417 bytes tests_speculos/test-menu/nanos.14.png | Bin 405 -> 417 bytes tests_speculos/test-menu/nanos.36.png | Bin 405 -> 417 bytes tests_speculos/test-menu/nanos.52.png | Bin 405 -> 417 bytes tests_speculos/test-menu/nanos.58.png | Bin 405 -> 417 bytes tests_speculos/test-menu/nanox.03.png | Bin 350 -> 370 bytes tests_speculos/test-menu/nanox.16.png | Bin 350 -> 370 bytes tests_speculos/test-menu/nanox.39.png | Bin 350 -> 370 bytes tests_speculos/test-menu/nanox.55.png | Bin 350 -> 370 bytes tests_speculos/test-menu/nanox.61.png | Bin 350 -> 370 bytes .../test-slot-transaction-interaction.js | 12 +- .../test-transaction-expert-mode.js | 5 +- tests_speculos/test-transactions.js | 19 +- .../nanos.07.png | Bin 485 -> 535 bytes .../nanos.08.png | Bin 643 -> 656 bytes .../nanos.09.png | Bin 670 -> 683 bytes .../nanos.10.png | Bin 672 -> 681 bytes .../nanos.11.png | Bin 605 -> 621 bytes .../nanos.19.png | Bin 334 -> 361 bytes .../nanox.08.png | Bin 508 -> 602 bytes .../nanox.09.png | Bin 912 -> 976 bytes .../nanox.10.png | Bin 945 -> 1013 bytes .../nanox.11.png | Bin 613 -> 669 bytes .../nanox.17.png | Bin 364 -> 412 bytes .../nanos.07.png | Bin 485 -> 535 bytes .../nanos.08.png | Bin 643 -> 656 bytes .../nanos.09.png | Bin 670 -> 683 bytes .../nanos.10.png | Bin 672 -> 681 bytes .../nanos.11.png | Bin 605 -> 621 bytes .../nanox.08.png | Bin 508 -> 602 bytes .../nanox.09.png | Bin 912 -> 976 bytes .../nanox.10.png | Bin 945 -> 1013 bytes .../nanox.11.png | Bin 613 -> 669 bytes .../nanos.07.png | Bin 485 -> 535 bytes .../nanos.08.png | Bin 643 -> 656 bytes .../nanos.09.png | Bin 670 -> 683 bytes .../nanos.10.png | Bin 672 -> 681 bytes .../nanos.11.png | Bin 605 -> 621 bytes .../nanos.19.png | Bin 665 -> 657 bytes .../nanos.20.png | Bin 646 -> 652 bytes .../nanos.21.png | Bin 637 -> 647 bytes .../nanos.22.png | Bin 664 -> 671 bytes .../nanos.23.png | Bin 402 -> 409 bytes .../nanox.08.png | Bin 508 -> 602 bytes .../nanox.09.png | Bin 912 -> 976 bytes .../nanox.10.png | Bin 945 -> 1013 bytes .../nanox.11.png | Bin 613 -> 669 bytes .../nanox.17.png | Bin 909 -> 949 bytes .../nanox.18.png | Bin 914 -> 940 bytes .../nanox.19.png | Bin 730 -> 755 bytes .../nanos.07.png | Bin 485 -> 535 bytes .../nanos.08.png | Bin 643 -> 656 bytes .../nanos.09.png | Bin 670 -> 683 bytes .../nanos.10.png | Bin 672 -> 681 bytes .../nanos.11.png | Bin 605 -> 621 bytes .../nanos.19.png | Bin 665 -> 657 bytes .../nanos.20.png | Bin 646 -> 652 bytes .../nanos.21.png | Bin 637 -> 647 bytes .../nanos.22.png | Bin 664 -> 671 bytes .../nanos.23.png | Bin 402 -> 409 bytes .../nanos.24.png | Bin 674 -> 665 bytes .../nanos.25.png | Bin 652 -> 652 bytes .../nanos.26.png | Bin 641 -> 654 bytes .../nanos.27.png | Bin 674 -> 676 bytes .../nanos.28.png | Bin 406 -> 412 bytes .../nanos.29.png | Bin 667 -> 665 bytes .../nanos.30.png | Bin 643 -> 651 bytes .../nanos.31.png | Bin 639 -> 649 bytes .../nanos.32.png | Bin 675 -> 671 bytes .../nanos.33.png | Bin 411 -> 412 bytes .../nanox.08.png | Bin 508 -> 602 bytes .../nanox.09.png | Bin 912 -> 976 bytes .../nanox.10.png | Bin 945 -> 1013 bytes .../nanox.11.png | Bin 613 -> 669 bytes .../nanox.17.png | Bin 909 -> 949 bytes .../nanox.18.png | Bin 914 -> 940 bytes .../nanox.19.png | Bin 730 -> 755 bytes .../nanox.20.png | Bin 924 -> 960 bytes .../nanox.21.png | Bin 913 -> 944 bytes .../nanox.22.png | Bin 740 -> 766 bytes .../nanox.23.png | Bin 919 -> 945 bytes .../nanox.24.png | Bin 920 -> 945 bytes .../nanox.25.png | Bin 732 -> 756 bytes .../nanos.06.png | Bin 665 -> 657 bytes .../nanos.07.png | Bin 646 -> 652 bytes .../nanos.08.png | Bin 637 -> 647 bytes .../nanos.09.png | Bin 664 -> 671 bytes .../nanos.10.png | Bin 402 -> 409 bytes .../nanox.07.png | Bin 909 -> 949 bytes .../nanox.08.png | Bin 914 -> 940 bytes .../nanox.09.png | Bin 730 -> 755 bytes .../nanos.06.png | Bin 665 -> 657 bytes .../nanos.07.png | Bin 646 -> 652 bytes .../nanos.08.png | Bin 637 -> 647 bytes .../nanos.09.png | Bin 664 -> 671 bytes .../nanos.10.png | Bin 402 -> 409 bytes .../nanos.11.png | Bin 674 -> 665 bytes .../nanos.12.png | Bin 652 -> 652 bytes .../nanos.13.png | Bin 641 -> 654 bytes .../nanos.14.png | Bin 674 -> 676 bytes .../nanos.15.png | Bin 406 -> 412 bytes .../nanos.16.png | Bin 667 -> 665 bytes .../nanos.17.png | Bin 643 -> 651 bytes .../nanos.18.png | Bin 639 -> 649 bytes .../nanos.19.png | Bin 675 -> 671 bytes .../nanos.20.png | Bin 411 -> 412 bytes .../nanox.07.png | Bin 909 -> 949 bytes .../nanox.08.png | Bin 914 -> 940 bytes .../nanox.09.png | Bin 730 -> 755 bytes .../nanox.10.png | Bin 924 -> 960 bytes .../nanox.11.png | Bin 913 -> 944 bytes .../nanox.12.png | Bin 740 -> 766 bytes .../nanox.13.png | Bin 919 -> 945 bytes .../nanox.14.png | Bin 920 -> 945 bytes .../nanox.15.png | Bin 732 -> 756 bytes .../nanos.02.png | Bin 435 -> 456 bytes .../nanox.03.png | Bin 473 -> 525 bytes .../nanos.02.png | Bin 435 -> 456 bytes .../nanox.03.png | Bin 473 -> 525 bytes .../nanos.02.png | Bin 449 -> 467 bytes .../nanox.03.png | Bin 525 -> 542 bytes .../nanos.02.png | Bin 449 -> 467 bytes .../nanox.03.png | Bin 525 -> 542 bytes .../nanos.02.png | Bin 449 -> 442 bytes .../nanox.03.png | Bin 520 -> 512 bytes .../nanos.02.png | Bin 444 -> 432 bytes .../nanox.03.png | Bin 510 -> 493 bytes .../nanos.02.png | Bin 445 -> 369 bytes .../nanox.03.png | Bin 488 -> 436 bytes .../nanos.02.png | Bin 457 -> 455 bytes .../nanox.03.png | Bin 530 -> 524 bytes .../nanos.02.png | Bin 431 -> 436 bytes .../nanox.03.png | Bin 497 -> 509 bytes .../nanos.02.png | Bin 460 -> 466 bytes .../nanox.03.png | Bin 526 -> 535 bytes .../nanos.02.png | Bin 359 -> 475 bytes .../nanox.03.png | Bin 420 -> 530 bytes .../nanos.02.png | Bin 519 -> 454 bytes .../nanox.03.png | Bin 600 -> 529 bytes .../nanos.02.png | Bin 514 -> 453 bytes .../nanox.03.png | Bin 592 -> 523 bytes .../nanos.02.png | Bin 451 -> 478 bytes .../nanox.03.png | Bin 536 -> 539 bytes .../nanos.02.png | Bin 509 -> 454 bytes .../nanox.03.png | Bin 639 -> 529 bytes .../nanos.02.png | Bin 519 -> 453 bytes .../nanox.03.png | Bin 612 -> 523 bytes .../nanos.02.png | Bin 440 -> 441 bytes .../nanox.03.png | Bin 529 -> 516 bytes .../nanos.04.png | Bin 309 -> 463 bytes .../nanos.05.png | Bin 457 -> 309 bytes .../nanox.05.png | Bin 354 -> 506 bytes .../nanox.06.png | Bin 478 -> 354 bytes transaction_metadata/index.js | 228 + transaction_metadata/manifest.mainnet.json | 1468 ++ transaction_metadata/manifest.testnet.json | 1469 ++ transaction_metadata/package.json | 11 + transaction_metadata/txMerkleTree.js | 16956 ++++++++++++++++ 187 files changed, 43969 insertions(+), 1077 deletions(-) create mode 100644 app/output-scan-build/2022-05-16-071046-61-1/index.html create mode 100644 app/output-scan-build/2022-05-16-071046-61-1/report-05ba52.html create mode 100644 app/output-scan-build/2022-05-16-071046-61-1/report-8e376d.html create mode 100644 app/output-scan-build/2022-05-16-071046-61-1/scanview.css create mode 100644 app/output-scan-build/2022-05-16-071046-61-1/sorttable.js create mode 100644 app/output-scan-build/2022-05-16-071232-98-1/index.html create mode 100644 app/output-scan-build/2022-05-16-071232-98-1/report-660403.html create mode 100644 app/output-scan-build/2022-05-16-071232-98-1/scanview.css create mode 100644 app/output-scan-build/2022-05-16-071232-98-1/sorttable.js create mode 100644 js/src/helperV2.js create mode 100644 js/src/txMerkleTree.js rename tests/{testvectors.cpp => testvectors.cpp.ignore} (100%) rename tests/utils/{expected_output.cpp => expected_output.cpp.ignore} (100%) rename tests/utils/{expected_output.h => expected_output.h.ignore} (100%) rename tests/utils/{testcases.cpp => testcases.cpp.ignore} (100%) create mode 100644 transaction_metadata/index.js create mode 100644 transaction_metadata/manifest.mainnet.json create mode 100644 transaction_metadata/manifest.testnet.json create mode 100644 transaction_metadata/package.json create mode 100644 transaction_metadata/txMerkleTree.js diff --git a/app/Makefile b/app/Makefile index 7b59c0e2..2608efbf 100755 --- a/app/Makefile +++ b/app/Makefile @@ -48,7 +48,7 @@ endif APPVERSION_M=0 APPVERSION_N=10 -APPVERSION_P=0 +APPVERSION_P=4 $(info COIN = [$(COIN)]) ifeq ($(COIN),FLOW) diff --git a/app/output-scan-build/2022-05-16-071046-61-1/index.html b/app/output-scan-build/2022-05-16-071046-61-1/index.html new file mode 100644 index 00000000..9eeca55a --- /dev/null +++ b/app/output-scan-build/2022-05-16-071046-61-1/index.html @@ -0,0 +1,97 @@ + + +app - scan-build results + + + + + + +

app - scan-build results

+ + + + + + + +
User:unknown@c095cbd396f2
Working Directory:/app
Command Line:make default
Clang Version:Ubuntu clang version 12.0.0-3ubuntu1~20.04.5 +
Date:Mon May 16 07:10:46 2022
+

Bug Summary

+ + + + +
Bug TypeQuantityDisplay?
All Bugs2
Dead store
Dead assignment2
+

Reports

+ + + + + + + + + + + + + + + + + + + + +
Bug GroupBug Type ▾FileFunction/MethodLinePath Length
Dead storeDead assignmentlib_bagl/src/bagl.cbagl_draw_with_context7901View Report
Dead storeDead assignmentsrc/os_io_seproxyhal.cio_seproxyhal_display_icon7611View Report
+ + diff --git a/app/output-scan-build/2022-05-16-071046-61-1/report-05ba52.html b/app/output-scan-build/2022-05-16-071046-61-1/report-05ba52.html new file mode 100644 index 00000000..027fd03f --- /dev/null +++ b/app/output-scan-build/2022-05-16-071046-61-1/report-05ba52.html @@ -0,0 +1,1431 @@ + + + +/opt/nanox-secure-sdk/lib_bagl/src/bagl.c + + + + + + + + + + + + + + + + + + + + + + + + + + +

Bug Summary

+ + + + +
File:lib_bagl/src/bagl.c
Warning:line 790, column 11
Value stored to 'pos' is never read
+ +

Annotated Source Code

+

Press '?' + to see keyboard shortcuts

+ + +
clang -cc1 -cc1 -triple thumbv6m-none-unknown-eabi -analyze -disable-free -disable-llvm-verifier -discard-value-names -main-file-name bagl.c -analyzer-store=region -analyzer-opt-analyze-nested-blocks -analyzer-checker=core -analyzer-checker=apiModeling -analyzer-checker=unix -analyzer-checker=deadcode -analyzer-checker=security.insecureAPI.UncheckedReturn -analyzer-checker=security.insecureAPI.getpw -analyzer-checker=security.insecureAPI.gets -analyzer-checker=security.insecureAPI.mktemp -analyzer-checker=security.insecureAPI.mkstemp -analyzer-checker=security.insecureAPI.vfork -analyzer-checker=nullability.NullPassedToNonnull -analyzer-checker=nullability.NullReturnedFromNonnull -analyzer-output plist -w -setup-static-analyzer -mrelocation-model ropi-rwpi -fropi -frwpi -fhalf-no-semantic-interposition -fno-jump-tables -mframe-pointer=none -fmath-errno -fno-rounding-math -fno-verbose-asm -mconstructor-aliases -nostdsysteminc -target-cpu cortex-m0plus -target-feature +soft-float -target-feature +soft-float-abi -target-feature -crc -target-feature -sha2 -target-feature -aes -target-feature -dsp -target-feature -ras -target-feature -sb -target-feature -i8mm -target-feature -lob -target-feature -cdecp0 -target-feature -cdecp1 -target-feature -cdecp2 -target-feature -cdecp3 -target-feature -cdecp4 -target-feature -cdecp5 -target-feature -cdecp6 -target-feature -cdecp7 -target-feature -hwdiv-arm -target-feature -hwdiv -target-feature -vfp2 -target-feature -vfp2sp -target-feature -vfp3 -target-feature -vfp3d16 -target-feature -vfp3d16sp -target-feature -vfp3sp -target-feature -fp16 -target-feature -vfp4 -target-feature -vfp4d16 -target-feature -vfp4d16sp -target-feature -vfp4sp -target-feature -fp-armv8 -target-feature -fp-armv8d16 -target-feature -fp-armv8d16sp -target-feature -fp-armv8sp -target-feature -fullfp16 -target-feature -fp64 -target-feature -d32 -target-feature -neon -target-feature -crypto -target-feature -dotprod -target-feature -fp16fml -target-feature -bf16 -target-feature -mve -target-feature -mve.fp -target-feature -fpregs -target-feature +strict-align -target-abi aapcs -msoft-float -mfloat-abi soft -fallow-half-arguments-and-returns -fno-split-dwarf-inlining -debugger-tuning=gdb -ffunction-sections -fdata-sections -resource-dir /usr/lib/llvm-12/lib/clang/12.0.0 -D gcc -D __IO=volatile -D NDEBUG -D HAVE_SE_SCREEN -D HAVE_SE_BUTTON -D HAVE_MCU_SERIAL_STORAGE -D HAVE_FONTS -D HAVE_BATTERY -D HAVE_NES_CRYPT -D HAVE_ST_EDES_PLUS -D HAVE_ST_AES -D NATIVE_LITTLE_ENDIAN -D HAVE_CRC -D HAVE_HASH -D HAVE_RIPEMD160 -D HAVE_SHA224 -D HAVE_SHA256 -D HAVE_SHA3 -D HAVE_SHA384 -D HAVE_SHA512 -D HAVE_SHA512_WITH_BLOCK_ALT_METHOD -D HAVE_SHA512_WITH_BLOCK_ALT_METHOD_M0 -D HAVE_BLAKE2 -D HAVE_HMAC -D HAVE_PBKDF2 -D HAVE_DES -D HAVE_AES -D HAVE_MATH -D HAVE_RNG -D HAVE_RNG_RFC6979 -D HAVE_RNG_SP800_90A -D HAVE_ECC -D HAVE_ECC_WEIERSTRASS -D HAVE_ECC_TWISTED_EDWARDS -D HAVE_ECC_MONTGOMERY -D HAVE_SECP256K1_CURVE -D HAVE_SECP256R1_CURVE -D HAVE_SECP384R1_CURVE -D HAVE_SECP521R1_CURVE -D HAVE_FR256V1_CURVE -D HAVE_STARK256_CURVE -D HAVE_BRAINPOOL_P256R1_CURVE -D HAVE_BRAINPOOL_P256T1_CURVE -D HAVE_BRAINPOOL_P320R1_CURVE -D HAVE_BRAINPOOL_P320T1_CURVE -D HAVE_BRAINPOOL_P384R1_CURVE -D HAVE_BRAINPOOL_P384T1_CURVE -D HAVE_BRAINPOOL_P512R1_CURVE -D HAVE_BRAINPOOL_P512T1_CURVE -D HAVE_BLS12_381_G1_CURVE -D HAVE_CV25519_CURVE -D HAVE_CV448_CURVE -D HAVE_ED25519_CURVE -D HAVE_ED448_CURVE -D HAVE_ECDH -D HAVE_ECDSA -D HAVE_EDDSA -D HAVE_ECSCHNORR -D HAVE_X25519 -D HAVE_X448 -D APP_CONSUMER -D UNUSED(x)=(void)x -D PRINTF(...)= -D APPVERSION="0.9.13" -D OS_IO_SEPROXYHAL -D HAVE_BAGL -D HAVE_SPRINTF -D HAVE_IO_USB -D HAVE_L4_USBLIB -D IO_USB_MAX_ENDPOINTS=7 -D IO_HID_EP_LENGTH=64 -D HAVE_USB_APDU -D LEDGER_MAJOR_VERSION=0 -D LEDGER_MINOR_VERSION=9 -D LEDGER_PATCH_VERSION=13 -D USB_SEGMENT_SIZE=64 -D HAVE_BOLOS_APP_STACK_CANARY -D HAVE_WEBUSB -D WEBUSB_URL_SIZE_B=0 -D WEBUSB_URL= -D HAVE_BLE -D HAVE_BLE_APDU -D BLE_COMMAND_TIMEOUT_MS=2000 -D IO_SEPROXYHAL_BUFFER_SIZE_B=300 -D HAVE_GLO096 -D HAVE_BAGL -D BAGL_WIDTH=128 -D BAGL_HEIGHT=64 -D HAVE_BAGL_ELLIPSIS -D HAVE_BAGL_FONT_OPEN_SANS_REGULAR_11PX -D HAVE_BAGL_FONT_OPEN_SANS_EXTRABOLD_11PX -D HAVE_BAGL_FONT_OPEN_SANS_LIGHT_16PX -D HAVE_UX_FLOW -D LEDGER_SPECIFIC -I .//glyphs -I /opt/nanox-secure-sdk/lib_cxng/include -I /opt/nanox-secure-sdk/lib_blewbxx/ -I /opt/nanox-secure-sdk/lib_blewbxx/core/template/ -I /opt/nanox-secure-sdk/lib_blewbxx/core/template/ -I /opt/nanox-secure-sdk/lib_blewbxx/core/template/ -I /opt/nanox-secure-sdk/lib_blewbxx/core/ -I /opt/nanox-secure-sdk/lib_blewbxx/core/ -I /opt/nanox-secure-sdk/lib_blewbxx/core/ -I /opt/nanox-secure-sdk/lib_blewbxx/core/auto/ -I /opt/nanox-secure-sdk/lib_blewbxx/core/auto/ -I /opt/nanox-secure-sdk/lib_blewbxx/core/auto/ -I /opt/nanox-secure-sdk/lib_blewbxx/core/auto/ -I /opt/nanox-secure-sdk/lib_blewbxx/core/auto/ -I /opt/nanox-secure-sdk/lib_blewbxx/core/auto/ -I /opt/nanox-secure-sdk/lib_blewbxx/core/ -I /opt/nanox-secure-sdk/lib_blewbxx/core/ -I /opt/nanox-secure-sdk/lib_blewbxx/ -I /opt/nanox-secure-sdk/lib_blewbxx_impl/include/ -I /opt/nanox-secure-sdk/lib_blewbxx_impl/ -I /opt/nanox-secure-sdk/lib_stusb/ -I /opt/nanox-secure-sdk/lib_stusb/STM32_USB_Device_Library/Class/CCID/inc/ -I /opt/nanox-secure-sdk/lib_stusb/STM32_USB_Device_Library/Class/CCID/inc/ -I /opt/nanox-secure-sdk/lib_stusb/STM32_USB_Device_Library/Class/CCID/inc/ -I /opt/nanox-secure-sdk/lib_stusb/STM32_USB_Device_Library/Class/CCID/inc/ -I /opt/nanox-secure-sdk/lib_stusb/STM32_USB_Device_Library/Class/HID/Inc/ -I /opt/nanox-secure-sdk/lib_stusb/STM32_USB_Device_Library/Core/Inc/ -I /opt/nanox-secure-sdk/lib_stusb/STM32_USB_Device_Library/Core/Inc/ -I /opt/nanox-secure-sdk/lib_stusb/STM32_USB_Device_Library/Core/Inc/ -I /opt/nanox-secure-sdk/lib_stusb/STM32_USB_Device_Library/Core/Inc/ -I /opt/nanox-secure-sdk/lib_stusb/STM32_USB_Device_Library/Core/Inc/ -I /opt/nanox-secure-sdk/lib_stusb_impl/ -I /opt/nanox-secure-sdk/lib_stusb_impl/ -I /opt/nanox-secure-sdk/lib_stusb_impl/ -I /opt/nanox-secure-sdk/lib_ux/include/ -I /opt/nanox-secure-sdk/lib_ux/include/ -I /opt/nanox-secure-sdk/lib_ux/include/ -I /opt/nanox-secure-sdk/lib_ux/include/ -I /opt/nanox-secure-sdk/lib_ux/src/ -I include -I /opt/nanox-secure-sdk/include -I /opt/nanox-secure-sdk/include/arm -I .//src/ -I .//src/json/ -I .//src/ -I .//src/ -I .//src/ -I .//src/ -I .//src/ -I .//src/ -I .//src/ -I .//src/ -I .//src/ -I .//src/ -I .//src/ -I .//src/common/ -I .//src/common/ -I .//src/common/ -I .//../deps/ledger-zxlib/include/ -I .//../deps/ledger-zxlib/include/ -I .//../deps/ledger-zxlib/include/ -I .//../deps/ledger-zxlib/include/ -I .//../deps/ledger-zxlib/include/ -I .//../deps/ledger-zxlib/include/ -I .//../deps/ledger-zxlib/include/ -I .//../deps/ledger-zxlib/include/ -I .//../deps/ledger-zxlib/include/ -I .//../deps/ledger-zxlib/include/ -I .//../deps/ledger-zxlib/include/ -I .//../deps/ledger-zxlib/include/ -I .//../deps/ledger-zxlib/include/ -I .//../deps/ledger-zxlib/include/ -I .//../deps/ledger-zxlib/include/ -I .//../deps/ledger-zxlib/include/ -I .//../deps/ledger-zxlib/include/ -I .//../deps/ledger-zxlib/include/ -I .//../deps/ledger-zxlib/include/ -I .//../deps/ledger-zxlib/include/ -I .//../deps/ledger-zxlib/include/ -I .//../deps/ledger-zxlib/include/ -I .//../deps/ledger-zxlib/app/common/ -I .//../deps/ledger-zxlib/app/common/ -I .//../deps/jsmn/src/ -isysroot /opt/gcc-arm-none-eabi-10.3-2021.10/bin/../arm-none-eabi -internal-isystem /usr/lib/llvm-12/lib/clang/12.0.0/include -internal-isystem /opt/gcc-arm-none-eabi-10.3-2021.10/bin/../arm-none-eabi/include -Os -Wno-main -Wno-unknown-pragmas -std=gnu99 -fdebug-compilation-dir /app -ferror-limit 19 -fshort-enums -fno-signed-char -fgnuc-version=4.2.1 -vectorize-loops -vectorize-slp -analyzer-checker security -analyzer-checker unix -analyzer-checker valist -analyzer-opt-analyze-headers -analyzer-output=html -faddrsig -o /app/output-scan-build/2022-05-16-071046-61-1 -x c /opt/nanox-secure-sdk/lib_bagl/src/bagl.c +
+ + + +
+ + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
1
2/*******************************************************************************
3* Ledger Nano S - Secure firmware
4* (c) 2022 Ledger
5*
6* Licensed under the Apache License, Version 2.0 (the "License");
7* you may not use this file except in compliance with the License.
8* You may obtain a copy of the License at
9*
10* http://www.apache.org/licenses/LICENSE-2.0
11*
12* Unless required by applicable law or agreed to in writing, software
13* distributed under the License is distributed on an "AS IS" BASIS,
14* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
15* See the License for the specific language governing permissions and
16* limitations under the License.
17********************************************************************************/
18
19#ifdef HAVE_BAGL1
20
21#include "bagl.h"
22#include <string.h>
23#include <stdio.h>
24
25#include "os.h"
26
27/**
28 Coordinate system for BAGL:
29 ===========================
30
31 0 X axis
32 0 +----->
33 |
34Y axis | #####
35 v #######
36 ## ##
37 #######
38 #####
39*/
40
41
42// --------------------------------------------------------------------------------------
43// Checks
44// --------------------------------------------------------------------------------------
45
46/*
47#ifndef BAGL_COMPONENT_MAXCOUNT
48#error BAGL_COMPONENT_MAXCOUNT not set
49#endif // !BAGL_COMPONENT_MAXCOUNT
50*/
51
52#ifndef BAGL_WIDTH128
53#error BAGL_WIDTH128 not set
54#endif // !BAGL_WIDTH
55
56#ifndef BAGL_HEIGHT64
57#error BAGL_HEIGHT64 not set
58#endif // !BAGL_HEIGHT
59
60// --------------------------------------------------------------------------------------
61// Definitions
62// --------------------------------------------------------------------------------------
63
64#define ICON_WIDTH0 0
65#ifndef MIN
66#define MIN(x,y)((x) < (y) ? (x) : (y)) ((x)<(y)?(x):(y))
67#endif
68#ifndef MAX
69#define MAX(x,y)((x) > (y) ? (x) : (y)) ((x)>(y)?(x):(y))
70#endif
71#ifndef U2BE
72#define U2BE(buf, off)((((buf)[off]&0xFF)<<8) | ((buf)[off+1]&0xFF) ) ((((buf)[off]&0xFF)<<8) | ((buf)[off+1]&0xFF) )
73#endif
74#ifndef U4BE
75#define U4BE(buf, off)((((((buf)[off]&0xFF)<<8) | ((buf)[off+1]&0xFF)
)<<16) | (((((buf)[off+2]&0xFF)<<8) | ((buf)
[off+2 +1]&0xFF) )&0xFFFF))
((U2BE(buf, off)((((buf)[off]&0xFF)<<8) | ((buf)[off+1]&0xFF) )<<16) | (U2BE(buf, off+2)((((buf)[off+2]&0xFF)<<8) | ((buf)[off+2 +1]&0xFF
) )
&0xFFFF))
76#endif
77
78// --------------------------------------------------------------------------------------
79// Variables
80// --------------------------------------------------------------------------------------
81
82#ifdef HAVE_BAGL_GLYPH_ARRAY
83const bagl_glyph_array_entry_t* G_glyph_array;
84unsigned int G_glyph_count;
85#endif // HAVE_BAGL_GLYPH_ARRAY
86
87// --------------------------------------------------------------------------------------
88// API
89// --------------------------------------------------------------------------------------
90
91// --------------------------------------------------------------------------------------
92void bagl_draw_bg(unsigned int color) {
93 bagl_component_t c;
94 memset(&c, 0, sizeof(c));
95 c.type = BAGL_RECTANGLE;
96 c.userid = BAGL_NONE;
97 c.fgcolor = color;
98 c.x = 0;
99 c.y = 0;
100 c.width = BAGL_WIDTH128;
101 c.height = BAGL_HEIGHT64;
102 c.fill = BAGL_FILL1;
103 // draw the rect
104 bagl_draw_with_context(&c, NULL((void*)0), 0, 0);
105}
106
107#ifdef HAVE_BAGL_GLYPH_ARRAY
108// --------------------------------------------------------------------------------------
109// internal helper, get the glyph entry from the glyph id (sparse glyph array support)
110const bagl_glyph_array_entry_t* bagl_get_glyph(unsigned int icon_id, const bagl_glyph_array_entry_t* glyph_array, unsigned int glyph_count) {
111 unsigned int i=glyph_count;
112
113 while(i--) {
114 // font id match this entry (non linear)
115 if (glyph_array[i].icon_id == icon_id) {
116 return &glyph_array[i];
117 }
118 }
119
120 // id not found
121 return NULL((void*)0);
122}
123#endif // HAVE_BAGL_GLYPH_ARRAY
124
125// --------------------------------------------------------------------------------------
126// internal helper, get the font entry from the font id (sparse font array support)
127const bagl_font_t* bagl_get_font(unsigned int font_id) {
128 unsigned int i=C_bagl_fonts_count;
129 font_id &= BAGL_FONT_ID_MASK0x0FFF;
130
131 while(i--) {
132 // font id match this entry (non indexed array)
133 if (PIC_FONT(C_bagl_fonts[i])((bagl_font_t const *)pic((void *)C_bagl_fonts[i]))->font_id == font_id) {
134 return PIC_FONT(C_bagl_fonts[i])((bagl_font_t const *)pic((void *)C_bagl_fonts[i]));
135 }
136 }
137
138 // id not found
139 return NULL((void*)0);
140}
141
142// --------------------------------------------------------------------------------------
143// return the width of a text (first line only) for alignment processing
144unsigned short bagl_compute_line_width(unsigned short font_id, unsigned short width, const void * text, unsigned char text_length, unsigned char text_encoding) {
145 unsigned short xx;
146 const bagl_font_t *font = bagl_get_font(font_id);
147 if (font == NULL((void*)0)) {
148 return 0;
149 }
150
151 // initialize first index
152 xx = 0;
153
154 //printf("display text: %s\n", text);
155
156 // depending on encoding
157 while (text_length--) {
158 unsigned int ch = 0;
159 // TODO support other encoding than ascii ISO8859 Latin
160 switch(text_encoding) {
161 default:
162 case BAGL_ENCODING_LATIN10:
163 ch = *((unsigned char*)text);
164 text = (void*)(((unsigned char*)text)+1);
165 break;
166 }
167
168 unsigned char ch_width = 0;
169 if (ch < font->first_char || ch > font->last_char) {
170 // only proceed the first line width, not the whole paragraph
171 if (ch == '\n' || ch == '\r') {
172 return xx;
173 }
174
175 // else use the low bits as an extra spacing value
176 if (ch >= 0xC0) {
177 ch_width = ch&0x3F;
178 }
179 else if (ch >= 0x80) {
180 // open the glyph font
181 const bagl_font_t *font_symbols = bagl_get_font((ch&0x20)?BAGL_FONT_SYMBOLS_1:BAGL_FONT_SYMBOLS_0);
182 if (font_symbols != NULL((void*)0)) {
183 // extract the size of the symbols' font character
184 ch_width = PIC_CHAR(font_symbols->characters)((const bagl_font_character_t *)pic((void *)font_symbols->
characters))
[ch & 0x1F].char_width;
185 }
186 }
187 }
188 else {
189 // compute the index in the bitmap array
190 ch -= font->first_char;
191 ch_width = PIC_CHAR(font->characters)((const bagl_font_character_t *)pic((void *)font->characters
))
[ch].char_width;
192 }
193
194 // retrieve the char bitmap
195
196 // go to next line if needed, kerning is not used here
197 if (width > 0 && xx + ch_width > width) {
198 return xx;
199 }
200
201 // prepare for next char
202 xx += ch_width;
203 }
204 return xx;
205}
206
207// --------------------------------------------------------------------------------------
208// draw char until a char fit before reaching width
209// TODO support hyphenation ??
210int bagl_draw_string(unsigned short font_id, unsigned int fgcolor, unsigned int bgcolor, int x, int y, unsigned int width, unsigned int height, const void* text, unsigned int text_length, unsigned char text_encoding) {
211 int xx;
212 unsigned int colors[16];
213 colors[0] = bgcolor;
214 colors[1] = fgcolor;
215 unsigned int ch = 0;
216
217 const bagl_font_t *font = bagl_get_font(font_id);
218 if (font == NULL((void*)0)) {
219 return 0;
220 }
221
222
223#ifdef BAGL_MULTICHROME
224 if (font->bpp > 1) {
225 // fgcolor = 0x7e7ecc
226 // bgcolor = 0xeca529
227 // $1 = {0xeca529, 0xc6985f, 0xa28b95, 0x7e7ecc}
228
229 unsigned int color_count = 1<<(font->bpp);
230 memset(colors, 0, sizeof(colors));
231 colors[0] = bgcolor;
232 colors[color_count-1] = fgcolor;
233
234 // compute for all base colors
235 int off;
236 for (off = 0; off < 3; off++) {
237
238 int cfg = (fgcolor>>(off*8))&0xFF;
239 int cbg = (bgcolor>>(off*8))&0xFF;
240
241 int crange = MAX(cfg,cbg)((cfg) > (cbg) ? (cfg) : (cbg))-MIN(cfg,cbg)((cfg) < (cbg) ? (cfg) : (cbg))+1;
242 int cinc = crange/(color_count-1UL);
243
244 if (cfg > cbg) {
245 unsigned int i;
246 for (i=1; i < color_count-1UL; i++) {
247 colors[i] |= MIN(0xFF, cbg+i*cinc)((0xFF) < (cbg+i*cinc) ? (0xFF) : (cbg+i*cinc))<<(off*8);
248 }
249 }
250 else {
251 unsigned int i;
252
253 for (i=1; i < color_count-1UL; i++) {
254 colors[i] |= MIN(0xFF, cfg+(color_count-1UL-i)*cinc)((0xFF) < (cfg+(color_count-1UL-i)*cinc) ? (0xFF) : (cfg+(
color_count-1UL-i)*cinc))
<<(off*8);
255 }
256 }
257 }
258 }
259#endif // BAGL_MULTICHROME // for the blue
260
261 // always comparing this way, very optimized etc
262 width += x;
263 height += y;
264
265 // initialize first index
266 xx = x;
267
268 //printf("display text: %s\n", text);
269
270
271 // depending on encoding
272 while (text_length--) {
273 // TODO support other encoding than ascii ISO8859 Latin
274 switch(text_encoding) {
275 default:
276 case BAGL_ENCODING_LATIN10:
277 // avoid 2 new line on \r and \n for windows familiar users
278 if (ch == '\r') {
279 ch = *((unsigned char*)text);
280 if (ch == '\n') {
281 text = (void*)(((unsigned int)text)+1);
282 continue;
283 }
284 }
285 else {
286 ch = *((unsigned char*)text);
287 }
288 text = (void*)(((unsigned int)text)+1);
289 break;
290 }
291
292 unsigned char ch_height = font->char_height;
293 unsigned char ch_kerning = 0;
294 unsigned char ch_width = 0;
295 const unsigned char * ch_bitmap = NULL((void*)0);
296 int ch_y = y;
297
298 if (ch < font->first_char || ch > font->last_char) {
299 //printf("invalid char");
300 // can't proceed
301 if (ch == '\n' || ch == '\r') {
302 y += ch_height; // no interleave
303
304 // IGNORED for first line
305 if (y + ch_height > (int)height) {
306 // we're writing half height of the last line ... probably better to put some dashes
307 return (y<<16)|(xx&0xFFFF);
308 }
309
310 // newline starts back at first x offset
311 xx = x;
312 continue;
313 }
314
315 if (ch >= 0xC0) {
316 ch_width = ch & 0x3F;
317 }
318 else if (ch >= 0x80) {
319 // open the glyph font
320 const bagl_font_t *font_symbols = bagl_get_font((ch&0x20)?BAGL_FONT_SYMBOLS_1:BAGL_FONT_SYMBOLS_0);
321 if (font_symbols != NULL((void*)0)) {
322 ch_bitmap = &PIC_BMP(font_symbols->bitmap)((unsigned char const *)pic((void *)font_symbols->bitmap))[PIC_CHAR(font_symbols->characters)((const bagl_font_character_t *)pic((void *)font_symbols->
characters))
[ch & 0x1F].bitmap_offset];
323 ch_width = PIC_CHAR(font_symbols->characters)((const bagl_font_character_t *)pic((void *)font_symbols->
characters))
[ch & 0x1F].char_width;
324 ch_height = font_symbols->char_height;
325 // align baselines
326 ch_y = y + font->baseline_height - font_symbols->baseline_height;
327 }
328 }
329 }
330 else {
331 ch -= font->first_char;
332 ch_bitmap = &PIC_BMP(font->bitmap)((unsigned char const *)pic((void *)font->bitmap))[PIC_CHAR(font->characters)((const bagl_font_character_t *)pic((void *)font->characters
))
[ch].bitmap_offset];
333 ch_width = PIC_CHAR(font->characters)((const bagl_font_character_t *)pic((void *)font->characters
))
[ch].char_width;
334 ch_kerning = font->char_kerning;
335 }
336
337 // retrieve the char bitmap
338
339 // go to next line if needed
340 if (xx + ch_width > (int)width) {
341 y += ch_height; // no interleave
342
343 // IGNORED for first line
344 if (y + ch_height > (int)height) {
345 // we're writing half height of the last line ... probably better to put some dashes
346 return (y<<16)|(xx&0xFFFF);
347 }
348
349 // newline starts back at first x offset
350 xx = x;
351 ch_y = y;
352 }
353
354 /* IGNORED for first line
355 if (y + ch_height > height) {
356 // we're writing half height of the last line ... probably better to put some dashes
357 return;
358 }
359 */
360
361 // chars are storred LSB to MSB in each char, packed chars. horizontal scan
362 if (ch_bitmap) {
363 bagl_hal_draw_bitmap_within_rect(xx, ch_y, ch_width, ch_height, (1<<font->bpp), colors, font->bpp, ch_bitmap, font->bpp*ch_width*ch_height); // note, last parameter is computable could be avoided
364 }
365 else {
366 bagl_hal_draw_rect(bgcolor, xx, ch_y, ch_width, ch_height);
367 }
368 // prepare for next char
369 xx += ch_width + ch_kerning;
370 }
371
372 // return newest position, for upcoming printf
373 return (y<<16)|(xx&0xFFFF);
374}
375
376// --------------------------------------------------------------------------------------
377
378// draw round or circle. unaliased.
379// if radiusint is !=0 then draw a circle of color outline, and colorint inside
380void bagl_draw_circle_helper(unsigned int color, int x_center, int y_center, unsigned int radius, unsigned char octants, unsigned int radiusint, unsigned int colorint) {
381
382/*
383 128 ***** 32
384 * *
385 64 * * 16
386 * *
387 * *
388 4 * * 1
389 * *
390 8 ***** 2
391*/
392
393 int last_x;
394 int x = radius;
395 int y = 0;
396 int decisionOver2 = 1 - x; // Decision criterion divided by 2 evaluated at x=r, y=0
397 int dradius = radius-radiusint;
398 last_x = x;
399 unsigned int drawint = (radiusint > 0 && dradius > 0 /*&& xint <= yint*/);
400
401 while( y <= x )
402 {
403 if (octants & 1) { //
404 if (drawint) {
405 bagl_hal_draw_rect(colorint, x_center, y+y_center, x-(dradius-1), 1);
406 bagl_hal_draw_rect(color, x_center+x-(dradius-1), y+y_center, dradius, 1);
407 }
408 else {
409 bagl_hal_draw_rect(color, x_center, y+y_center-1, x, 1);
410 }
411 }
412 if (octants & 2) { //
413 if (drawint) {
414 if (last_x != x) {
415 bagl_hal_draw_rect(colorint, x_center, x+y_center, y-(dradius-1), 1);
416 }
417 bagl_hal_draw_rect(color, x_center+y-(dradius-1), x+y_center, dradius, 1);
418 }
419 else {
420 bagl_hal_draw_rect(color, x_center, x+y_center-1, y, 1);
421 }
422 }
423 if (octants & 4) { //
424 if (drawint) {
425 bagl_hal_draw_rect(colorint, x_center-x, y+y_center, x-(dradius-1), 1);
426 bagl_hal_draw_rect(color, x_center-x-(dradius-1), y+y_center, dradius, 1);
427 }
428 else {
429 bagl_hal_draw_rect(color, x_center-x, y+y_center-1, x, 1);
430 }
431 }
432 if (octants & 8) { //
433 if (drawint) {
434 if (last_x != x) {
435 bagl_hal_draw_rect(colorint, x_center-y, x+y_center, y-(dradius-1), 1);
436 }
437 bagl_hal_draw_rect(color, x_center-y-(dradius-1), x+y_center, dradius, 1);
438 }
439 else {
440 bagl_hal_draw_rect(color, x_center-y, x+y_center-1, y, 1);
441 }
442 }
443 if (octants & 16) { //
444 if (drawint) {
445 bagl_hal_draw_rect(colorint, x_center, y_center-y, x-(dradius-1), 1);
446 bagl_hal_draw_rect(color, x_center+x-(dradius-1), y_center-y, dradius, 1);
447 }
448 else {
449 bagl_hal_draw_rect(color, x_center, y_center-y, x, 1);
450 }
451 }
452 if (octants & 32) { //
453 if (drawint) {
454 if (last_x != x) {
455 bagl_hal_draw_rect(colorint, x_center, y_center-x, y-(dradius-1), 1);
456 }
457 bagl_hal_draw_rect(color, x_center+y-(dradius-1), y_center-x, dradius, 1);
458 }
459 else {
460 bagl_hal_draw_rect(color, x_center, y_center-x, y, 1);
461 }
462 }
463 if (octants & 64) { //
464 if (drawint) {
465 bagl_hal_draw_rect(colorint, x_center-x, y_center-y, x-(dradius-1), 1);
466 bagl_hal_draw_rect(color, x_center-x-(dradius-1), y_center-y, dradius, 1);
467 }
468 else {
469 bagl_hal_draw_rect(color, x_center-x, y_center-y, x, 1);
470 }
471 }
472 if (octants & 128) { //
473 if (drawint) {
474 if (last_x != x) {
475 bagl_hal_draw_rect(colorint, x_center-y, y_center-x, y-(dradius-1), 1);
476 }
477 bagl_hal_draw_rect(color, x_center-y-(dradius-1), y_center-x, dradius, 1);
478 }
479 else {
480 bagl_hal_draw_rect(color, x_center-y, y_center-x, y, 1);
481 }
482 }
483
484 last_x = x;
485 y++;
486 if (decisionOver2<=0)
487 {
488 decisionOver2 += 2 * y + 1; // Change in decision criterion for y -> y+1
489 }
490 else
491 {
492 x--;
493 decisionOver2 += 2 * (y - x) + 1; // Change for y -> y+1, x -> x-1
494 }
495 }
496}
497
498// --------------------------------------------------------------------------------------
499
500#ifdef HAVE_BAGL_GLYPH_ARRAY
501void bagl_set_glyph_array(const bagl_glyph_array_entry_t* array, unsigned int count) {
502 G_glyph_array = array;
503 G_glyph_count = count;
504}
505#endif // HAVE_BAGL_GLYPH_ARRAY
506
507// --------------------------------------------------------------------------------------
508
509void bagl_draw_with_context(const bagl_component_t* component, const void* context, unsigned short context_length, unsigned char context_encoding) {
510 //unsigned char comp_idx;
511 int halignment=0;
512 int valignment=0;
513#ifdef HAVE_BAGL_GLYPH_ARRAY
514 int x,y;
515#endif // HAVE_BAGL_GLYPH_ARRAY
516 int baseline=0;
517 unsigned int height_to_draw=0;
518 int strwidth = 0;
519 unsigned int ellipsis_1_len = 0;
520#ifdef HAVE_BAGL_ELLIPSIS1
521 const char* ellipsis_2_start = NULL((void*)0);
522#endif // HAVE_BAGL_ELLIPSIS
523
524#ifdef HAVE_BAGL_GLYPH_ARRAY
525 const bagl_glyph_array_entry_t* glyph=NULL((void*)0);
526#endif // HAVE_BAGL_GLYPH_ARRAY
527
528 // DESIGN NOTE: always consider drawing onto a bg color filled image. (done upon undraw)
529
530 /*
531 // check if userid already exist, if yes, reuse entry
532 for (comp_idx=0; comp_idx < BAGL_COMPONENT_MAXCOUNT; comp_idx++) {
533 if (bagl_components[comp_idx].userid == component->userid) {
534 goto idx_ok;
535 }
536 }
537
538 // find the first empty entry
539 for (comp_idx=0; comp_idx < BAGL_COMPONENT_MAXCOUNT; comp_idx++) {
540 if (bagl_components[comp_idx].userid == BAGL_NONE) {
541 goto idx_ok;
542 }
543 }
544 // no more space :(
545 //BAGL_THROW(NO_SPACE);
546 return;
547
548
549idx_ok:
550 */
551
552 // strip the flags to match kinds
553 unsigned int type = component->type&~(BAGL_TYPE_FLAGS_MASK0x80);
554
555 // compute alignment if text provided and requiring special alignment
556 if (type != BAGL_ICON) {
557 const bagl_font_t* font = bagl_get_font(component->font_id);
558 if (font) {
559 baseline = font->baseline_height;
560 height_to_draw = component->height;
561
562 if (context && context_length) {
563 // compute with some margin to fit other characters and check if ellipsis algorithm is required
564 strwidth = bagl_compute_line_width(component->font_id, component->width+100, context, context_length, context_encoding);
565 ellipsis_1_len = context_length;
566
567#ifdef HAVE_BAGL_ELLIPSIS1
568 // ellipsis mode (ensure something is to be splitted!)
569 if (strwidth > component->width && context_length>4) {
570 unsigned int robin = 0; // remove char by char either on the left or right side
571 unsigned int dots_len = bagl_compute_line_width(component->font_id, 100 /*probably larger than ... whatever the font*/, "...", 3, context_encoding);
572 ellipsis_1_len = context_length/2;
573 ellipsis_2_start = ((char*)context) + context_length/2;
574 // split line in 2 halves, strip a char from end of left part, and from start of right part, reassemble with ... , repeat until it fits.
575 // NOTE: algorithm is wrong if special blank chars are inserted, they should be removed first
576 while (strwidth > component->width && ellipsis_1_len && (context_length - ((unsigned int)ellipsis_2_start-(unsigned int)context) )) {
577 unsigned int left_part = bagl_compute_line_width(component->font_id, component->width, context, ellipsis_1_len, context_encoding);
578 unsigned int right_part = bagl_compute_line_width(component->font_id, component->width, ellipsis_2_start, (context_length - ((unsigned int)ellipsis_2_start-(unsigned int)context) ), context_encoding);
579 // update to check and to compute alignement if needed
580 strwidth = left_part + dots_len + right_part;
581 // only start to split if the middle char if odd context_length removal is not sufficient
582 if (strwidth > component->width) {
583 // either remove a left char, OR remove a right char
584 switch(robin) {
585 case 0:
586 // remove a left char
587 ellipsis_1_len--;
588 break;
589 case 1:
590 // remove a right char
591 ellipsis_2_start++;
592 break;
593 }
594 robin = (robin+1)%2;
595 }
596 }
597 // we've computed split positions
598 }
599#endif // HAVE_BAGL_ELLIPSIS
600
601 switch (component->font_id & BAGL_FONT_ALIGNMENT_HORIZONTAL_MASK0xC000 ) {
602 default:
603 case BAGL_FONT_ALIGNMENT_LEFT0x0000:
604 halignment = 0;
605 break;
606 case BAGL_FONT_ALIGNMENT_RIGHT0x4000:
607 halignment = MAX(0,component->width - strwidth)((0) > (component->width - strwidth) ? (0) : (component
->width - strwidth))
;
608 break;
609 case BAGL_FONT_ALIGNMENT_CENTER0x8000:
610 // x xalign strwidth width
611 // ' ' ' '
612 // ^
613 // xalign = x+ (width/2) - (strwidth/2) => align -x
614 halignment = MAX(0,component->width/2 - strwidth/2)((0) > (component->width/2 - strwidth/2) ? (0) : (component
->width/2 - strwidth/2))
;
615 break;
616 }
617
618 switch (component->font_id & BAGL_FONT_ALIGNMENT_VERTICAL_MASK0x3000 ) {
619 default:
620 case BAGL_FONT_ALIGNMENT_TOP0x0000:
621 valignment = 0;
622 break;
623 case BAGL_FONT_ALIGNMENT_BOTTOM0x1000:
624 valignment = component->height - baseline;
625 break;
626 case BAGL_FONT_ALIGNMENT_MIDDLE0x2000:
627 // y yalign charheight height
628 // ' ' v ' '
629 // baseline
630 // yalign = y+ (height/2) - (baseline/2) => align - y
631 valignment = component->height/2 - baseline/2 - 1;
632 break;
633 }
634 }
635 }
636 }
637
638 unsigned int radius = component->radius;
639 radius = MIN(radius, MIN(component->width/2, component->height/2))((radius) < (((component->width/2) < (component->
height/2) ? (component->width/2) : (component->height/2
))) ? (radius) : (((component->width/2) < (component->
height/2) ? (component->width/2) : (component->height/2
))))
;
640
641 // Check the type only, ignore the touchable flag
642 switch (type) {
643 /*
644 button (B)
645 < |Icon|Space|Textstring| >
646 I.w W.w T.w
647 I.x = B.x+B.w/2-(I.w+W.w+T.w)/2
648 W.x = I.x+I.w
649 T.x = W.x+W.w = I.x+I.w+W.w = B.x+B.w/2-(I.w+W.w+T.w)/2+I.w+W.w = B.x+B.w/2-T.w/2+(I.w+W.w)/2
650 */
651
652 // Following types are supposed to draw a rectangle or write text or both
653 case BAGL_BUTTON:
654 case BAGL_LABEL:
655 case BAGL_RECTANGLE:
656 case BAGL_LINE:
657 case BAGL_LABELINE:
658 if((type == BAGL_LINE) && (component->radius == 0)) {
659 bagl_hal_draw_rect(component->fgcolor,
660 component->x, component->y,
661 component->width, component->height);
662 break;
663 }
664
665 if ((type == BAGL_LABEL) || (type == BAGL_LABELINE)) {
666 /*if (component->fill == BAGL_FILL)*/ {
667 bagl_hal_draw_rect(component->bgcolor,
668 component->x, component->y-(type==BAGL_LABELINE?(baseline):0),
669 component->width, (type==BAGL_LABELINE? height_to_draw : component->height));
670 }
671 }
672 else {
673 // Draw the rounded or not, filled or not rectangle
674 if (component->fill != BAGL_FILL1) {
675 // inner
676 // centered top to bottom
677 bagl_hal_draw_rect(component->bgcolor,
678 component->x+radius, component->y,
679 component->width-2*radius, component->height);
680 // left to center rect
681 bagl_hal_draw_rect(component->bgcolor,
682 component->x, component->y+radius,
683 radius, component->height-2*radius);
684 // center rect to right
685 bagl_hal_draw_rect(component->bgcolor,
686 component->x+component->width-radius-1, component->y+radius,
687 radius, component->height-2*radius);
688
689 // outline
690 // 4 rectangles (with last pixel of each corner not set)
691 bagl_hal_draw_rect(component->fgcolor,
692 component->x+radius, component->y,
693 component->width-2*radius, component->stroke); // top
694 bagl_hal_draw_rect(component->fgcolor,
695 component->x+radius, component->y+component->height-1,
696 component->width-2*radius, component->stroke); // bottom
697 bagl_hal_draw_rect(component->fgcolor,
698 component->x, component->y+radius,
699 component->stroke, component->height-2*radius); // left
700 bagl_hal_draw_rect(component->fgcolor,
701 component->x+component->width-1, component->y+radius,
702 component->stroke, component->height-2*radius); // right
703 }
704 else {
705 // centered top to bottom
706 bagl_hal_draw_rect(component->fgcolor,
707 component->x+radius, component->y,
708 component->width-2*radius, component->height);
709 // left to center rect
710 bagl_hal_draw_rect(component->fgcolor,
711 component->x, component->y+radius,
712 radius, component->height-2*radius);
713
714 // center rect to right
715 bagl_hal_draw_rect(component->fgcolor,
716 component->x+component->width-radius, component->y+radius,
717 radius, component->height-2*radius);
718 }
719
720 // draw corners
721 if (radius > 1) {
722 unsigned int radiusint = 0;
723 // carve round when not filling
724 if ((component->fill != BAGL_FILL1) && (component->stroke < radius)) {
725 radiusint = radius-component->stroke;
726 }
727 bagl_draw_circle_helper(component->fgcolor,
728 component->x+radius,
729 component->y+radius,
730 radius, BAGL_FILL_CIRCLE_PI2_PI(64 | 128), radiusint,
731 component->bgcolor);
732 bagl_draw_circle_helper(component->fgcolor,
733 component->x+component->width-radius-component->stroke,
734 component->y+radius,
735 radius, BAGL_FILL_CIRCLE_0_PI2(16 | 32), radiusint,
736 component->bgcolor);
737 bagl_draw_circle_helper(component->fgcolor,
738 component->x+radius,
739 component->y+component->height-radius-component->stroke,
740 radius, BAGL_FILL_CIRCLE_PI_3PI2(4 | 8), radiusint,
741 component->bgcolor);
742 bagl_draw_circle_helper(component->fgcolor,
743 component->x+component->width-radius-component->stroke,
744 component->y+component->height-radius-component->stroke,
745 radius, BAGL_FILL_CIRCLE_3PI2_2PI(1 | 2), radiusint,
746 component->bgcolor);
747 }
748 }
749
750 if (type == BAGL_LINE) {
751 // No text for this type
752 break;
753 }
754
755 // Text display
756 if (context && context_length) {
757 unsigned int pos = 0;
758 unsigned int fgcolor = component->fgcolor;
759 unsigned int bgcolor = component->bgcolor;
760
761 // Invert colors of text when rectangle/button is filled
762 if ( ((type == BAGL_BUTTON) || (type == BAGL_RECTANGLE))
763 && (component->fill == BAGL_FILL1)) {
764 fgcolor = component->bgcolor;
765 bgcolor = component->fgcolor;
766 }
767
768 pos = bagl_draw_string(component->font_id,
769 fgcolor, bgcolor,
770 component->x + halignment,
771 component->y + ((type==BAGL_LABELINE)?-(baseline):valignment),
772 component->width - halignment,
773 component->height - ((type==BAGL_LABELINE)?0:valignment),
774 context,
775 ellipsis_1_len,
776 context_encoding);
777#ifdef HAVE_BAGL_ELLIPSIS1
778 if (ellipsis_2_start) {
779 // draw ellipsis
780 pos = bagl_draw_string(component->font_id,
781 fgcolor, bgcolor,
782 (pos & 0xFFFF),
783 component->y + ((type==BAGL_LABELINE)?-(baseline):valignment),
784 component->width - halignment,
785 component->height - (type==BAGL_LABELINE?0:valignment),
786 "...",
787 3,
788 context_encoding);
789 // draw the right part
790 pos = bagl_draw_string(component->font_id,
Value stored to 'pos' is never read
791 fgcolor, bgcolor,
792 (pos & 0xFFFF),
793 component->y + ((type==BAGL_LABELINE)?-(baseline):valignment),
794 component->width - halignment,
795 component->height - ((type==BAGL_LABELINE)?0:valignment),
796 ellipsis_2_start,
797 (context_length - ((unsigned int)ellipsis_2_start-(unsigned int)context) ),
798 context_encoding);
799 }
800#endif // HAVE_BAGL_ELLIPSIS
801 }
802 break;
803
804#ifdef HAVE_BAGL_GLYPH_ARRAY
805 case BAGL_ICON:
806 // icon data follows are in the context
807 if (component->icon_id != 0) {
808
809 // select the default or custom glyph array
810 if (context_encoding && G_glyph_array && G_glyph_count > 0) {
811 glyph = bagl_get_glyph(component->icon_id, G_glyph_array, G_glyph_count);
812 }
813 else {
814 glyph = bagl_get_glyph(component->icon_id, C_glyph_array, C_glyph_count);
815 }
816
817 // 404 glyph not found
818 if (glyph == NULL((void*)0)) {
819 break;
820 }
821
822 // color accounted as bytes in the context length
823 if (context_length) {
824 if ((1<<glyph->bits_per_pixel)*4 != context_length) {
825 // invalid color count
826 break;
827 }
828 context_length /= 4;
829 }
830 // use default colors
831 if (!context_length || !context) {
832 context_length = 1<<(glyph->bits_per_pixel);
833 context = glyph->default_colors;
834 }
835
836 // center glyph in rect
837 // draw the glyph from the bitmap using the context for colors
838 bagl_hal_draw_bitmap_within_rect(component->x + (component->width / 2 - glyph->width / 2),
839 component->y + (component->height / 2 - glyph->height / 2),
840 glyph->width,
841 glyph->height,
842 context_length,
843 (unsigned int*)context, // Endianness remarkably ignored !
844 glyph->bits_per_pixel,
845 glyph->bitmap,
846 glyph->bits_per_pixel*(glyph->width*glyph->height));
847 }
848 else {
849 // context: <bitperpixel> [color_count*4 bytes (LE encoding)] <icon bitmap (raw scan, LE)>
850
851 unsigned int colors[4];
852 unsigned int bpp = ((unsigned char*)context)[0];
853 // no space to display that
854 if (bpp > 2) {
855 break;
856 }
857 unsigned int i=1<<bpp;
858 while(i--) {
859 colors[i] = U4BE((unsigned char*)context, 1+i*4)(((((((unsigned char*)context)[1+i*4]&0xFF)<<8) | (
((unsigned char*)context)[1+i*4 +1]&0xFF) )<<16) | (
(((((unsigned char*)context)[1+i*4 +2]&0xFF)<<8) | (
((unsigned char*)context)[1+i*4 +2 +1]&0xFF) )&0xFFFF
))
;
860 }
861
862 // draw the glyph from the bitmap using the context for colors
863 bagl_hal_draw_bitmap_within_rect(component->x, component->y,
864 component->width, component->height,
865 1<<bpp, colors, bpp,
866 ((unsigned char*)context)+1+(1<<bpp)*4,
867 bpp*(component->width*component->height));
868 }
869 break;
870#endif // HAVE_BAGL_GLYPH_ARRAY
871
872 case BAGL_CIRCLE:
873 // draw the circle (all 8 octants)
874 bagl_draw_circle_helper(component->fgcolor,
875 component->x+component->radius, component->y+component->radius,
876 component->radius, 0xFF,
877 ((component->fill != BAGL_FILL1 && component->stroke < component->radius)?component->radius-component->stroke:0),
878 component->bgcolor);
879 break;
880
881 default:
882 break;
883 }
884}
885
886// --------------------------------------------------------------------------------------
887void bagl_draw_glyph(const bagl_component_t* component, const bagl_icon_details_t* icon_details) {
888 // no space to display that
889 if (icon_details->bpp > 2) {
890 return;
891 }
892
893 /*
894 // take into account the remaining bits not byte aligned
895 unsigned int w = ((component->width*component->height*icon_details->bpp)/8);
896 if (w%8) {
897 w++;
898 }
899 */
900
901 // draw the glyph from the bitmap using the context for colors
902 bagl_hal_draw_bitmap_within_rect(component->x,
903 component->y,
904 icon_details->width,
905 icon_details->height,
906 1<<(icon_details->bpp),
907 (unsigned int*)PIC((unsigned int)icon_details->colors)pic((void *)(unsigned int)icon_details->colors),
908 icon_details->bpp,
909 (unsigned char*)PIC((unsigned int)icon_details->bitmap)pic((void *)(unsigned int)icon_details->bitmap),
910 icon_details->bpp*(icon_details->width*icon_details->height));
911}
912
913
914// --------------------------------------------------------------------------------------
915
916void bagl_animate(bagl_animated_t* anim, unsigned int timestamp_ms, unsigned int interval_ms) {
917 // nothing to be animated right now (or no horizontal scrolling speed defined)
918 if ((anim->next_ms != 0 && anim->next_ms > timestamp_ms) || anim->c.width == 0 || anim->c.icon_id == 0 || (anim->current_x & 0xF0000000)==0x40000000) {
919 return;
920 }
921
922 // when starting the animation, perform a pause on the left of the string
923 if (anim->next_ms == 0) {
924 anim->next_ms = timestamp_ms + (anim->c.stroke&0x7F)*100;
925 anim->current_x = 0x0;
926 anim->current_char_idx = 0;
927 }
928
929 unsigned int a,b;
930 unsigned int valignment=0;
931 unsigned int baseline=0;
932 //unsigned int char_height=0;
933 unsigned int totalwidth = 0;
934 unsigned int remwidth = 0;
935 unsigned int charwidth=0;
936 unsigned int type = anim->c.type&~(BAGL_TYPE_FLAGS_MASK0x80);
937
938 // compute alignment if text provided and requiring special alignment
939 if (anim->text && anim->text_length && (type == BAGL_LABELINE || type == BAGL_LABEL)) {
940 const bagl_font_t* font = bagl_get_font(anim->c.font_id);
941 // invalid font, nothing to animate :(
942 if (font == NULL((void*)0)) {
943 return;
944 }
945 unsigned int maxcharwidth = bagl_compute_line_width(anim->c.font_id, 0, "W", 1, anim->text_encoding)+1;
946 baseline = font->baseline_height;
947 //char_height = font->char_height;
948
949 totalwidth = bagl_compute_line_width(anim->c.font_id, 0, anim->text, anim->text_length, anim->text_encoding);
950
951 // nothing to be animated here, text is already fully drawn in its text box
952 if (totalwidth <= anim->c.width) {
953 return;
954 }
955 if (anim->current_char_idx > anim->text_length) {
956 anim->current_char_idx = 0;
957 }
958
959 remwidth = bagl_compute_line_width(anim->c.font_id, 0, anim->text+anim->current_char_idx, anim->text_length-anim->current_char_idx, anim->text_encoding);
960 charwidth = bagl_compute_line_width(anim->c.font_id, 0, anim->text+anim->current_char_idx, 1, anim->text_encoding);
961
962 switch (anim->c.font_id & BAGL_FONT_ALIGNMENT_VERTICAL_MASK0x3000 ) {
963 default:
964 case BAGL_FONT_ALIGNMENT_TOP0x0000:
965 valignment = 0;
966 break;
967 case BAGL_FONT_ALIGNMENT_BOTTOM0x1000:
968 valignment = anim->c.height - baseline;
969 break;
970 case BAGL_FONT_ALIGNMENT_MIDDLE0x2000:
971 // y yalign charheight height
972 // ' ' v ' '
973 // baseline
974 // yalign = y+ (height/2) - (baseline/2) => align - y
975 valignment = anim->c.height/2 - baseline/2 - 1;
976 break;
977 }
978
979 // consider the current char of the string has been displayed on the screen (or at least a part of it)
980 // viewport | < width > |
981 // totalwidth | a text that does not fit the viewport |
982 // rem width |xt that does not fit the viewport | s
983 //
984 unsigned int current_char_displayed_width = (anim->current_x & ~(0xF0000000)) - (totalwidth - remwidth);
985
986 // draw a bg rectangle on the area before painting the animated value, to clearup glitches on both sides
987
988 a = anim->c.y + (type==BAGL_LABELINE?-(baseline):valignment);
989 b = anim->c.height- (type==BAGL_LABELINE?0/*-char_height*/:valignment);
990 bagl_draw_string(anim->c.font_id,
991 anim->c.fgcolor,
992 anim->c.bgcolor,
993 anim->c.x - current_char_displayed_width,
994 a,
995 anim->c.width + current_char_displayed_width + charwidth /*- 2*component->stroke*/,
996 b,
997 anim->text+anim->current_char_idx, anim->text_length-anim->current_char_idx, anim->text_encoding);
998
999 // crop the viewport
1000 bagl_hal_draw_rect(anim->c.bgcolor,
1001 anim->c.x-maxcharwidth,
1002 a,
1003 maxcharwidth,
1004 b);
1005 bagl_hal_draw_rect(anim->c.bgcolor,
1006 anim->c.x+anim->c.width,
1007 a,
1008 maxcharwidth,
1009 b);
1010
1011 // report on screen
1012 screen_update();
1013 unsigned int step_ms=interval_ms;
1014 unsigned int step_x=anim->c.icon_id * step_ms/1000;
1015 while(step_x == 0) {
1016 step_ms += interval_ms;
1017 step_x = anim->c.icon_id * step_ms / 1000;
1018 }
1019
1020 switch (anim->current_x & 0xF0000000) {
1021 // left to right
1022 case 0:
1023 anim->next_ms += step_ms;
1024 if (current_char_displayed_width >= charwidth) {
1025 anim->current_char_idx++;
1026 // if text fits, then stop scrolling and wait a bit
1027 if (remwidth - current_char_displayed_width <= anim->c.width) {
1028 anim->current_x = (totalwidth-remwidth+current_char_displayed_width) | 0x10000000;
1029 break;
1030 }
1031 }
1032 anim->current_x += step_x;
1033 break;
1034
1035 // pause after finished left to right
1036 case 0x10000000:
1037 anim->next_ms += (anim->c.stroke&0x7F)*100;
1038 anim->current_x = (totalwidth-remwidth+current_char_displayed_width) | 0x20000000;
1039 break;
1040
1041 // right to left
1042 case 0x20000000:
1043 anim->next_ms += step_ms;
1044 if (current_char_displayed_width >= charwidth) {
1045 // we're displaying from the start
1046 if (remwidth >= totalwidth) {
1047 anim->current_x = 0x30000000;
1048 anim->current_char_idx = 0;
1049 break;
1050 }
1051 anim->current_char_idx--;
1052 }
1053 anim->current_x = ((anim->current_x & ~(0xF0000000)) - step_x) | 0x20000000;
1054 break;
1055
1056 // pause after finished right to left
1057 case 0x30000000:
1058 anim->next_ms += (anim->c.stroke&0x7F)*100;
1059 anim->current_x = 0;
1060 // not going for another scroll anim
1061 if (anim->c.stroke & 0x80) {
1062 anim->current_x = 0x40000000;
1063 }
1064 break;
1065 case 0x40000000:
1066 // stalled, nothing to do
1067 break;
1068 }
1069 }
1070}
1071
1072// --------------------------------------------------------------------------------------
1073
1074void bagl_draw(const bagl_component_t* component) {
1075 // component without text
1076 bagl_draw_with_context(component, NULL((void*)0), 0, 0);
1077}
1078
1079#endif // HAVE_BAGL
diff --git a/app/output-scan-build/2022-05-16-071046-61-1/report-8e376d.html b/app/output-scan-build/2022-05-16-071046-61-1/report-8e376d.html new file mode 100644 index 00000000..bdbad4f1 --- /dev/null +++ b/app/output-scan-build/2022-05-16-071046-61-1/report-8e376d.html @@ -0,0 +1,1877 @@ + + + +/opt/nanox-secure-sdk/src/os_io_seproxyhal.c + + + + + + + + + + + + + + + + + + + + + + + + + + +

Bug Summary

+ + + + +
File:src/os_io_seproxyhal.c
Warning:line 761, column 5
Value stored to 'icon_component' is never read
+ +

Annotated Source Code

+

Press '?' + to see keyboard shortcuts

+ + +
clang -cc1 -cc1 -triple thumbv6m-none-unknown-eabi -analyze -disable-free -disable-llvm-verifier -discard-value-names -main-file-name os_io_seproxyhal.c -analyzer-store=region -analyzer-opt-analyze-nested-blocks -analyzer-checker=core -analyzer-checker=apiModeling -analyzer-checker=unix -analyzer-checker=deadcode -analyzer-checker=security.insecureAPI.UncheckedReturn -analyzer-checker=security.insecureAPI.getpw -analyzer-checker=security.insecureAPI.gets -analyzer-checker=security.insecureAPI.mktemp -analyzer-checker=security.insecureAPI.mkstemp -analyzer-checker=security.insecureAPI.vfork -analyzer-checker=nullability.NullPassedToNonnull -analyzer-checker=nullability.NullReturnedFromNonnull -analyzer-output plist -w -setup-static-analyzer -mrelocation-model ropi-rwpi -fropi -frwpi -fhalf-no-semantic-interposition -fno-jump-tables -mframe-pointer=none -fmath-errno -fno-rounding-math -fno-verbose-asm -mconstructor-aliases -nostdsysteminc -target-cpu cortex-m0plus -target-feature +soft-float -target-feature +soft-float-abi -target-feature -crc -target-feature -sha2 -target-feature -aes -target-feature -dsp -target-feature -ras -target-feature -sb -target-feature -i8mm -target-feature -lob -target-feature -cdecp0 -target-feature -cdecp1 -target-feature -cdecp2 -target-feature -cdecp3 -target-feature -cdecp4 -target-feature -cdecp5 -target-feature -cdecp6 -target-feature -cdecp7 -target-feature -hwdiv-arm -target-feature -hwdiv -target-feature -vfp2 -target-feature -vfp2sp -target-feature -vfp3 -target-feature -vfp3d16 -target-feature -vfp3d16sp -target-feature -vfp3sp -target-feature -fp16 -target-feature -vfp4 -target-feature -vfp4d16 -target-feature -vfp4d16sp -target-feature -vfp4sp -target-feature -fp-armv8 -target-feature -fp-armv8d16 -target-feature -fp-armv8d16sp -target-feature -fp-armv8sp -target-feature -fullfp16 -target-feature -fp64 -target-feature -d32 -target-feature -neon -target-feature -crypto -target-feature -dotprod -target-feature -fp16fml -target-feature -bf16 -target-feature -mve -target-feature -mve.fp -target-feature -fpregs -target-feature +strict-align -target-abi aapcs -msoft-float -mfloat-abi soft -fallow-half-arguments-and-returns -fno-split-dwarf-inlining -debugger-tuning=gdb -ffunction-sections -fdata-sections -resource-dir /usr/lib/llvm-12/lib/clang/12.0.0 -D gcc -D __IO=volatile -D NDEBUG -D HAVE_SE_SCREEN -D HAVE_SE_BUTTON -D HAVE_MCU_SERIAL_STORAGE -D HAVE_FONTS -D HAVE_BATTERY -D HAVE_NES_CRYPT -D HAVE_ST_EDES_PLUS -D HAVE_ST_AES -D NATIVE_LITTLE_ENDIAN -D HAVE_CRC -D HAVE_HASH -D HAVE_RIPEMD160 -D HAVE_SHA224 -D HAVE_SHA256 -D HAVE_SHA3 -D HAVE_SHA384 -D HAVE_SHA512 -D HAVE_SHA512_WITH_BLOCK_ALT_METHOD -D HAVE_SHA512_WITH_BLOCK_ALT_METHOD_M0 -D HAVE_BLAKE2 -D HAVE_HMAC -D HAVE_PBKDF2 -D HAVE_DES -D HAVE_AES -D HAVE_MATH -D HAVE_RNG -D HAVE_RNG_RFC6979 -D HAVE_RNG_SP800_90A -D HAVE_ECC -D HAVE_ECC_WEIERSTRASS -D HAVE_ECC_TWISTED_EDWARDS -D HAVE_ECC_MONTGOMERY -D HAVE_SECP256K1_CURVE -D HAVE_SECP256R1_CURVE -D HAVE_SECP384R1_CURVE -D HAVE_SECP521R1_CURVE -D HAVE_FR256V1_CURVE -D HAVE_STARK256_CURVE -D HAVE_BRAINPOOL_P256R1_CURVE -D HAVE_BRAINPOOL_P256T1_CURVE -D HAVE_BRAINPOOL_P320R1_CURVE -D HAVE_BRAINPOOL_P320T1_CURVE -D HAVE_BRAINPOOL_P384R1_CURVE -D HAVE_BRAINPOOL_P384T1_CURVE -D HAVE_BRAINPOOL_P512R1_CURVE -D HAVE_BRAINPOOL_P512T1_CURVE -D HAVE_BLS12_381_G1_CURVE -D HAVE_CV25519_CURVE -D HAVE_CV448_CURVE -D HAVE_ED25519_CURVE -D HAVE_ED448_CURVE -D HAVE_ECDH -D HAVE_ECDSA -D HAVE_EDDSA -D HAVE_ECSCHNORR -D HAVE_X25519 -D HAVE_X448 -D APP_CONSUMER -D UNUSED(x)=(void)x -D PRINTF(...)= -D APPVERSION="0.9.13" -D OS_IO_SEPROXYHAL -D HAVE_BAGL -D HAVE_SPRINTF -D HAVE_IO_USB -D HAVE_L4_USBLIB -D IO_USB_MAX_ENDPOINTS=7 -D IO_HID_EP_LENGTH=64 -D HAVE_USB_APDU -D LEDGER_MAJOR_VERSION=0 -D LEDGER_MINOR_VERSION=9 -D LEDGER_PATCH_VERSION=13 -D USB_SEGMENT_SIZE=64 -D HAVE_BOLOS_APP_STACK_CANARY -D HAVE_WEBUSB -D WEBUSB_URL_SIZE_B=0 -D WEBUSB_URL= -D HAVE_BLE -D HAVE_BLE_APDU -D BLE_COMMAND_TIMEOUT_MS=2000 -D IO_SEPROXYHAL_BUFFER_SIZE_B=300 -D HAVE_GLO096 -D HAVE_BAGL -D BAGL_WIDTH=128 -D BAGL_HEIGHT=64 -D HAVE_BAGL_ELLIPSIS -D HAVE_BAGL_FONT_OPEN_SANS_REGULAR_11PX -D HAVE_BAGL_FONT_OPEN_SANS_EXTRABOLD_11PX -D HAVE_BAGL_FONT_OPEN_SANS_LIGHT_16PX -D HAVE_UX_FLOW -D LEDGER_SPECIFIC -I .//glyphs -I /opt/nanox-secure-sdk/lib_cxng/include -I /opt/nanox-secure-sdk/lib_blewbxx/ -I /opt/nanox-secure-sdk/lib_blewbxx/core/template/ -I /opt/nanox-secure-sdk/lib_blewbxx/core/template/ -I /opt/nanox-secure-sdk/lib_blewbxx/core/template/ -I /opt/nanox-secure-sdk/lib_blewbxx/core/ -I /opt/nanox-secure-sdk/lib_blewbxx/core/ -I /opt/nanox-secure-sdk/lib_blewbxx/core/ -I /opt/nanox-secure-sdk/lib_blewbxx/core/auto/ -I /opt/nanox-secure-sdk/lib_blewbxx/core/auto/ -I /opt/nanox-secure-sdk/lib_blewbxx/core/auto/ -I /opt/nanox-secure-sdk/lib_blewbxx/core/auto/ -I /opt/nanox-secure-sdk/lib_blewbxx/core/auto/ -I /opt/nanox-secure-sdk/lib_blewbxx/core/auto/ -I /opt/nanox-secure-sdk/lib_blewbxx/core/ -I /opt/nanox-secure-sdk/lib_blewbxx/core/ -I /opt/nanox-secure-sdk/lib_blewbxx/ -I /opt/nanox-secure-sdk/lib_blewbxx_impl/include/ -I /opt/nanox-secure-sdk/lib_blewbxx_impl/ -I /opt/nanox-secure-sdk/lib_stusb/ -I /opt/nanox-secure-sdk/lib_stusb/STM32_USB_Device_Library/Class/CCID/inc/ -I /opt/nanox-secure-sdk/lib_stusb/STM32_USB_Device_Library/Class/CCID/inc/ -I /opt/nanox-secure-sdk/lib_stusb/STM32_USB_Device_Library/Class/CCID/inc/ -I /opt/nanox-secure-sdk/lib_stusb/STM32_USB_Device_Library/Class/CCID/inc/ -I /opt/nanox-secure-sdk/lib_stusb/STM32_USB_Device_Library/Class/HID/Inc/ -I /opt/nanox-secure-sdk/lib_stusb/STM32_USB_Device_Library/Core/Inc/ -I /opt/nanox-secure-sdk/lib_stusb/STM32_USB_Device_Library/Core/Inc/ -I /opt/nanox-secure-sdk/lib_stusb/STM32_USB_Device_Library/Core/Inc/ -I /opt/nanox-secure-sdk/lib_stusb/STM32_USB_Device_Library/Core/Inc/ -I /opt/nanox-secure-sdk/lib_stusb/STM32_USB_Device_Library/Core/Inc/ -I /opt/nanox-secure-sdk/lib_stusb_impl/ -I /opt/nanox-secure-sdk/lib_stusb_impl/ -I /opt/nanox-secure-sdk/lib_stusb_impl/ -I /opt/nanox-secure-sdk/lib_ux/include/ -I /opt/nanox-secure-sdk/lib_ux/include/ -I /opt/nanox-secure-sdk/lib_ux/include/ -I /opt/nanox-secure-sdk/lib_ux/include/ -I /opt/nanox-secure-sdk/lib_ux/src/ -I include -I /opt/nanox-secure-sdk/include -I /opt/nanox-secure-sdk/include/arm -I .//src/ -I .//src/json/ -I .//src/ -I .//src/ -I .//src/ -I .//src/ -I .//src/ -I .//src/ -I .//src/ -I .//src/ -I .//src/ -I .//src/ -I .//src/ -I .//src/common/ -I .//src/common/ -I .//src/common/ -I .//../deps/ledger-zxlib/include/ -I .//../deps/ledger-zxlib/include/ -I .//../deps/ledger-zxlib/include/ -I .//../deps/ledger-zxlib/include/ -I .//../deps/ledger-zxlib/include/ -I .//../deps/ledger-zxlib/include/ -I .//../deps/ledger-zxlib/include/ -I .//../deps/ledger-zxlib/include/ -I .//../deps/ledger-zxlib/include/ -I .//../deps/ledger-zxlib/include/ -I .//../deps/ledger-zxlib/include/ -I .//../deps/ledger-zxlib/include/ -I .//../deps/ledger-zxlib/include/ -I .//../deps/ledger-zxlib/include/ -I .//../deps/ledger-zxlib/include/ -I .//../deps/ledger-zxlib/include/ -I .//../deps/ledger-zxlib/include/ -I .//../deps/ledger-zxlib/include/ -I .//../deps/ledger-zxlib/include/ -I .//../deps/ledger-zxlib/include/ -I .//../deps/ledger-zxlib/include/ -I .//../deps/ledger-zxlib/include/ -I .//../deps/ledger-zxlib/app/common/ -I .//../deps/ledger-zxlib/app/common/ -I .//../deps/jsmn/src/ -isysroot /opt/gcc-arm-none-eabi-10.3-2021.10/bin/../arm-none-eabi -internal-isystem /usr/lib/llvm-12/lib/clang/12.0.0/include -internal-isystem /opt/gcc-arm-none-eabi-10.3-2021.10/bin/../arm-none-eabi/include -Os -Wno-main -Wno-unknown-pragmas -std=gnu99 -fdebug-compilation-dir /app -ferror-limit 19 -fshort-enums -fno-signed-char -fgnuc-version=4.2.1 -vectorize-loops -vectorize-slp -analyzer-checker security -analyzer-checker unix -analyzer-checker valist -analyzer-opt-analyze-headers -analyzer-output=html -faddrsig -o /app/output-scan-build/2022-05-16-071046-61-1 -x c /opt/nanox-secure-sdk/src/os_io_seproxyhal.c +
+ + + +
+ + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
1
2/*******************************************************************************
3* Ledger Nano S - Secure firmware
4* (c) 2022 Ledger
5*
6* Licensed under the Apache License, Version 2.0 (the "License");
7* you may not use this file except in compliance with the License.
8* You may obtain a copy of the License at
9*
10* http://www.apache.org/licenses/LICENSE-2.0
11*
12* Unless required by applicable law or agreed to in writing, software
13* distributed under the License is distributed on an "AS IS" BASIS,
14* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
15* See the License for the specific language governing permissions and
16* limitations under the License.
17********************************************************************************/
18
19#include "bolos_target.h"
20
21#ifdef TARGET_NANOX
22#ifndef HAVE_SEPROXYHAL_MCU
23# define HAVE_SEPROXYHAL_MCU
24#endif // HAVE_SEPROXYHAL_MCU
25#ifndef HAVE_MCU_PROTECT
26#define HAVE_MCU_PROTECT
27#endif // HAVE_MCU_PROTECT
28#endif // TARGET_NANOX
29
30#include "errors.h"
31#include "exceptions.h"
32#include "os_apdu.h"
33#include "os_apilevel.h"
34
35#if defined(DEBUG_OS_STACK_CONSUMPTION)
36# include "os_debug.h"
37#endif // DEBUG_OS_STACK_CONSUMPTION
38
39#include "os_id.h"
40#include "os_io.h"
41#include "os_io_usb.h"
42#include "os_pic.h"
43#include "os_pin.h"
44#include "os_registry.h"
45#include "os_seed.h"
46#include "os_utils.h"
47#include <string.h>
48
49#ifdef OS_IO_SEPROXYHAL1
50
51#include "os_io_seproxyhal.h"
52
53#ifdef HAVE_BLE1
54#include "ledger_ble.h"
55#endif // HAVE_BLE
56
57#include "ux.h"
58#include "checks.h"
59
60#ifdef HAVE_IO_U2F
61#include "u2f_processing.h"
62#include "u2f_transport.h"
63#endif
64
65#ifndef VERSION"dummy"
66#define VERSION"dummy" "dummy"
67#endif // VERSION
68
69#ifdef DEBUG
70#define LOG printf
71#else
72#define LOG(...)
73#endif
74
75#ifdef HAVE_IO_USB1
76#ifdef HAVE_L4_USBLIB1
77#include "usbd_def.h"
78#include "usbd_core.h"
79extern USBD_HandleTypeDef USBD_Device;
80#endif
81#endif
82
83#if !defined(HAVE_BOLOS_NO_DEFAULT_APDU)
84# define DEFAULT_APDU_CLA0xB0 0xB0
85# define DEFAULT_APDU_INS_GET_VERSION0x01 0x01
86
87# if defined(HAVE_SEED_COOKIE)
88# define DEFAULT_APDU_INS_GET_SEED_COOKIE 0x02
89# endif
90
91# if defined(DEBUG_OS_STACK_CONSUMPTION)
92# define DEFAULT_APDU_INS_STACK_CONSUMPTION 0x57
93# endif // DEBUG_OS_STACK_CONSUMPTION
94
95# define DEFAULT_APDU_INS_APP_EXIT0xA7 0xA7
96#endif // !HAVE_BOLOS_NO_DEFAULT_APDU
97
98void io_seproxyhal_handle_ble_event(void);
99
100unsigned int os_io_seph_recv_and_process(unsigned int dont_process_ux_events);
101
102#ifndef HAVE_BOLOS
103io_seph_app_t G_io_app;
104#endif // ! HAVE_BOLOS
105
106 // usb endpoint buffer
107unsigned char G_io_usb_ep_buffer[MAX(USB_SEGMENT_SIZE, BLE_SEGMENT_SIZE)((64) > (64) ? (64) : (64))];
108
109ux_seph_os_and_app_t G_ux_os;
110
111#ifndef IO_RAPDU_TRANSMIT_TIMEOUT_MS2000UL
112#define IO_RAPDU_TRANSMIT_TIMEOUT_MS2000UL 2000UL
113#endif // IO_RAPDU_TRANSMIT_TIMEOUT_MS
114
115static const unsigned char seph_io_general_status[]= {
116 SEPROXYHAL_TAG_GENERAL_STATUS0x60,
117 0,
118 2,
119 SEPROXYHAL_TAG_GENERAL_STATUS_LAST_COMMAND0x0000>>8,
120 SEPROXYHAL_TAG_GENERAL_STATUS_LAST_COMMAND0x0000,
121};
122void io_seproxyhal_general_status(void) {
123 // send the general status
124 io_seproxyhal_spi_sendio_seph_send(seph_io_general_status, sizeof(seph_io_general_status));
125}
126
127static const unsigned char seph_io_request_status[]= {
128 SEPROXYHAL_TAG_REQUEST_STATUS0x52,
129 0,
130 0,
131};
132void io_seproxyhal_request_mcu_status(void) {
133 // send the general status
134 io_seproxyhal_spi_sendio_seph_send(seph_io_request_status, sizeof(seph_io_request_status));
135}
136
137#ifdef HAVE_IO_USB1
138#ifdef HAVE_L4_USBLIB1
139
140void io_seproxyhal_handle_usb_event(void) {
141 switch(G_io_seproxyhal_spi_buffer[3]) {
142 case SEPROXYHAL_TAG_USB_EVENT_RESET0x01:
143 USBD_LL_SetSpeed(&USBD_Device, USBD_SPEED_FULL);
144 USBD_LL_Reset(&USBD_Device);
145 // ongoing APDU detected, throw a reset, even if not the media. to avoid potential troubles.
146 if (G_io_app.apdu_media != IO_APDU_MEDIA_NONE) {
147 THROW(EXCEPTION_IO_RESET)os_longjmp(0x5);
148 }
149 memset(G_io_app.usb_ep_xfer_len, 0, sizeof(G_io_app.usb_ep_xfer_len));
150 memset(G_io_app.usb_ep_timeouts, 0, sizeof(G_io_app.usb_ep_timeouts));
151 break;
152 case SEPROXYHAL_TAG_USB_EVENT_SOF0x02:
153 USBD_LL_SOF(&USBD_Device);
154 break;
155 case SEPROXYHAL_TAG_USB_EVENT_SUSPENDED0x04:
156 USBD_LL_Suspend(&USBD_Device);
157 break;
158 case SEPROXYHAL_TAG_USB_EVENT_RESUMED0x08:
159 USBD_LL_Resume(&USBD_Device);
160 break;
161 }
162}
163
164uint16_t io_seproxyhal_get_ep_rx_size(uint8_t epnum) {
165 if ((epnum & 0x7F) < IO_USB_MAX_ENDPOINTS7) {
166 return G_io_app.usb_ep_xfer_len[epnum&0x7F];
167 }
168 return 0;
169}
170
171void io_seproxyhal_handle_usb_ep_xfer_event(void) {
172 uint8_t epnum;
173
174 epnum = G_io_seproxyhal_spi_buffer[3] & 0x7F;
175
176 switch(G_io_seproxyhal_spi_buffer[4]) {
177 /* This event is received when a new SETUP token had been received on a control endpoint */
178 case SEPROXYHAL_TAG_USB_EP_XFER_SETUP0x01:
179 // assume length of setup packet, and that it is on endpoint 0
180 USBD_LL_SetupStage(&USBD_Device, &G_io_seproxyhal_spi_buffer[6]);
181 break;
182
183 /* This event is received after the prepare data packet has been flushed to the usb host */
184 case SEPROXYHAL_TAG_USB_EP_XFER_IN0x02:
185 if (epnum < IO_USB_MAX_ENDPOINTS7) {
186 // discard ep timeout as we received the sent packet confirmation
187 G_io_app.usb_ep_timeouts[epnum].timeout = 0;
188 // propagate sending ack of the data
189 USBD_LL_DataInStage(&USBD_Device, epnum, &G_io_seproxyhal_spi_buffer[6]);
190 }
191 break;
192
193 /* This event is received when a new DATA token is received on an endpoint */
194 case SEPROXYHAL_TAG_USB_EP_XFER_OUT0x04:
195 if (epnum < IO_USB_MAX_ENDPOINTS7) {
196 // saved just in case it is needed ...
197#if IO_SEPROXYHAL_BUFFER_SIZE_B300 - 6 >= 256
198 G_io_app.usb_ep_xfer_len[epnum] = G_io_seproxyhal_spi_buffer[5];
199#else
200 G_io_app.usb_ep_xfer_len[epnum] = MIN(G_io_seproxyhal_spi_buffer[5], IO_SEPROXYHAL_BUFFER_SIZE_B - 6)((G_io_seproxyhal_spi_buffer[5]) < (300 - 6) ? (G_io_seproxyhal_spi_buffer
[5]) : (300 - 6))
;
201#endif
202 // prepare reception
203 USBD_LL_DataOutStage(&USBD_Device, epnum, &G_io_seproxyhal_spi_buffer[6]);
204 }
205 break;
206 }
207}
208
209#else
210//no usb lib: X86 for example
211
212void io_seproxyhal_handle_usb_event(void) {
213}
214void io_seproxyhal_handle_usb_ep_xfer_event(void) {
215}
216
217#endif // HAVE_L4_USBLIB
218
219// TODO, refactor this using the USB DataIn event like for the U2F tunnel
220// TODO add a blocking parameter, for HID KBD sending, or use a USB busy flag per channel to know if
221// the transfer has been processed or not. and move on to the next transfer on the same endpoint
222void io_usb_send_ep(unsigned int ep, unsigned char* buffer, unsigned short length, unsigned int timeout) {
223
224 // don't spoil the timeout :)
225 if (timeout) {
226 timeout++;
227 }
228
229 // won't send if overflowing seproxyhal buffer format
230 if (length > 255) {
231 return;
232 }
233
234 G_io_seproxyhal_spi_buffer[0] = SEPROXYHAL_TAG_USB_EP_PREPARE0x50;
235 G_io_seproxyhal_spi_buffer[1] = (3+length)>>8;
236 G_io_seproxyhal_spi_buffer[2] = (3+length);
237 G_io_seproxyhal_spi_buffer[3] = ep|0x80;
238 G_io_seproxyhal_spi_buffer[4] = SEPROXYHAL_TAG_USB_EP_PREPARE_DIR_IN0x20;
239 G_io_seproxyhal_spi_buffer[5] = length;
240 io_seproxyhal_spi_sendio_seph_send(G_io_seproxyhal_spi_buffer, 6);
241 io_seproxyhal_spi_sendio_seph_send(buffer, length);
242 // setup timeout of the endpoint
243 G_io_app.usb_ep_timeouts[ep&0x7F].timeout = IO_RAPDU_TRANSMIT_TIMEOUT_MS2000UL;
244}
245
246void io_usb_send_apdu_data(unsigned char* buffer, unsigned short length) {
247 // wait for 20 events before hanging up and timeout (~2 seconds of timeout)
248 io_usb_send_ep(0x82, buffer, length, 20);
249}
250
251#ifdef HAVE_WEBUSB1
252void io_usb_send_apdu_data_ep0x83(unsigned char* buffer, unsigned short length) {
253 // wait for 20 events before hanging up and timeout (~2 seconds of timeout)
254 io_usb_send_ep(0x83, buffer, length, 20);
255}
256#endif // HAVE_WEBUSB
257
258#endif // HAVE_IO_USB
259
260void io_seproxyhal_handle_capdu_event(void) {
261 if (G_io_app.apdu_state == APDU_IDLE) {
262 size_t max = MIN(sizeof(G_io_apdu_buffer)-3, sizeof(G_io_seproxyhal_spi_buffer)-3)((sizeof(G_io_apdu_buffer)-3) < (sizeof(G_io_seproxyhal_spi_buffer
)-3) ? (sizeof(G_io_apdu_buffer)-3) : (sizeof(G_io_seproxyhal_spi_buffer
)-3))
;
263 size_t size = U2BE(G_io_seproxyhal_spi_buffer, 1);
264
265 G_io_app.apdu_media = IO_APDU_MEDIA_RAW; // for application code
266 G_io_app.apdu_state = APDU_RAW; // for next call to io_exchange
267 G_io_app.apdu_length = MIN(size, max)((size) < (max) ? (size) : (max));
268 // copy apdu to apdu buffer
269 memcpy(G_io_apdu_buffer, G_io_seproxyhal_spi_buffer+3, G_io_app.apdu_length);
270 }
271}
272
273unsigned int io_seproxyhal_handle_event(void) {
274#if defined(HAVE_IO_USB1) || defined(HAVE_BLE1)
275 unsigned int rx_len = U2BE(G_io_seproxyhal_spi_buffer, 1);
276#endif
277
278 switch(G_io_seproxyhal_spi_buffer[0]) {
279 #ifdef HAVE_IO_USB1
280 case SEPROXYHAL_TAG_USB_EVENT0x0F:
281 if (rx_len != 1) {
282 return 0;
283 }
284 io_seproxyhal_handle_usb_event();
285 return 1;
286
287 case SEPROXYHAL_TAG_USB_EP_XFER_EVENT0x10:
288 if (rx_len < 3) {
289 // error !
290 return 0;
291 }
292 io_seproxyhal_handle_usb_ep_xfer_event();
293 return 1;
294 #endif // HAVE_IO_USB
295
296 #ifdef HAVE_BLE1
297 case SEPROXYHAL_TAG_BLE_RECV_EVENT0x18:
298 LEDGER_BLE_receive();
299 return 1;
300 #endif // HAVE_BLE
301
302 case SEPROXYHAL_TAG_UX_EVENT0x1A:
303 switch (G_io_seproxyhal_spi_buffer[3]) {
304
305#ifdef HAVE_BLE1
306 case SEPROXYHAL_TAG_UX_CMD_BLE_DISABLE_ADV0x00:
307 LEDGER_BLE_enable_advertising(0);
308 return 1;
309 break;
310
311 case SEPROXYHAL_TAG_UX_CMD_BLE_ENABLE_ADV0x01:
312 LEDGER_BLE_enable_advertising(1);
313 return 1;
314 break;
315
316 case SEPROXYHAL_TAG_UX_CMD_BLE_RESET_PAIRINGS0x02:
317 LEDGER_BLE_reset_pairings();
318 return 1;
319 break;
320#endif // HAVE_BLE
321
322#ifndef HAVE_BOLOS
323 case SEPROXYHAL_TAG_UX_CMD_REDISPLAY0x03:
324 ux_stack_redisplay();
325 return 1;
326 break;
327#endif // HAVE_BOLOS
328
329 default:
330 return io_event(CHANNEL_SPI2);
331 break;
332 }
333 break;
334
335 case SEPROXYHAL_TAG_CAPDU_EVENT0x16:
336 io_seproxyhal_handle_capdu_event();
337 return 1;
338
339 // ask the user if not processed here
340 case SEPROXYHAL_TAG_TICKER_EVENT0x0E:
341 // process ticker events to timeout the IO transfers, and forward to the user io_event function too
342 G_io_app.ms += 100; // value is by default, don't change the ticker configuration
343#ifdef HAVE_IO_USB1
344 {
345 unsigned int i = IO_USB_MAX_ENDPOINTS7;
346 while(i--) {
347 if (G_io_app.usb_ep_timeouts[i].timeout) {
348 G_io_app.usb_ep_timeouts[i].timeout-=MIN(G_io_app.usb_ep_timeouts[i].timeout, 100)((G_io_app.usb_ep_timeouts[i].timeout) < (100) ? (G_io_app
.usb_ep_timeouts[i].timeout) : (100))
;
349 if (!G_io_app.usb_ep_timeouts[i].timeout) {
350 // timeout !
351 G_io_app.apdu_state = APDU_IDLE;
352 THROW(EXCEPTION_IO_RESET)os_longjmp(0x5);
353 }
354 }
355 }
356 }
357#endif // HAVE_IO_USB
358#ifdef HAVE_BLE_APDU1
359 {
360 if (G_io_app.ble_xfer_timeout) {
361 G_io_app.ble_xfer_timeout -= MIN(G_io_app.ble_xfer_timeout, 100)((G_io_app.ble_xfer_timeout) < (100) ? (G_io_app.ble_xfer_timeout
) : (100))
;
362 if (!G_io_app.ble_xfer_timeout) {
363 G_io_app.apdu_state = APDU_IDLE;
364 THROW(EXCEPTION_IO_RESET)os_longjmp(0x5);
365 }
366 }
367 }
368#endif // HAVE_BLE_APDU
369 __attribute__((fallthrough));
370 // no break is intentional
371 default:
372 return io_event(CHANNEL_SPI2);
373 }
374 // defaultly return as not processed
375 return 0;
376}
377
378//#define DEBUG_APDU
379#ifdef DEBUG_APDU
380volatile unsigned int debug_apdus_offset;
381const char debug_apdus[] = {
382 5, 0xE0, 0x40, 0x00, 0x00, 0x00,
383 //9, 0xe0, 0x22, 0x00, 0x00, 0x04, 0x31, 0x32, 0x33, 0x34,
384};
385#endif // DEBUG_APDU
386
387#ifdef HAVE_BOLOS_APP_STACK_CANARY1
388#define APP_STACK_CANARY_MAGIC0xDEAD0031 0xDEAD0031
389extern unsigned int app_stack_canary;
390#endif // HAVE_BOLOS_APP_STACK_CANARY
391
392#if (!defined(HAVE_BOLOS) && defined(HAVE_MCU_PROTECT))
393static const unsigned char seph_io_mcu_protect[]= {
394 SEPROXYHAL_TAG_MCU0x31,
395 0,
396 1,
397 SEPROXYHAL_TAG_MCU_TYPE_PROTECT0x02,
398};
399#endif // (!defined(HAVE_BOLOS) && defined(HAVE_MCU_PROTECT))
400
401void io_seproxyhal_init(void) {
402#ifndef HAVE_BOLOS
403 // Enforce OS compatibility
404 check_api_level(CX_COMPAT_APILEVEL12);
405
406#ifdef HAVE_MCU_PROTECT
407 // engage RDP2 on MCU
408 io_seproxyhal_spi_sendio_seph_send(seph_io_mcu_protect, sizeof(seph_io_mcu_protect));
409#endif // HAVE_MCU_PROTECT
410#endif // HAVE_BOLOS
411
412#ifdef HAVE_BOLOS_APP_STACK_CANARY1
413 app_stack_canary = APP_STACK_CANARY_MAGIC0xDEAD0031;
414#endif // HAVE_BOLOS_APP_STACK_CANARY
415
416 // wipe the io structure before it's used
417#ifdef HAVE_BLE1
418 unsigned int plane = G_io_app.plane_mode;
419#endif // HAVE_BLE
420 memset(&G_io_app, 0, sizeof(G_io_app));
421#ifdef HAVE_BLE1
422 G_io_app.plane_mode = plane;
423#endif // HAVE_BLE
424
425 G_io_app.apdu_state = APDU_IDLE;
426 G_io_app.apdu_length = 0;
427 G_io_app.apdu_media = IO_APDU_MEDIA_NONE;
428
429 G_io_app.ms = 0;
430
431 #ifdef DEBUG_APDU
432 debug_apdus_offset = 0;
433 #endif // DEBUG_APDU
434
435 #ifdef HAVE_USB_APDU1
436 io_usb_hid_init();
437 #endif // HAVE_USB_APDU
438
439 io_seproxyhal_init_ux();
440 io_seproxyhal_init_button();
441
442#if !defined(HAVE_BOLOS) && defined(HAVE_PENDING_REVIEW_SCREEN)
443 check_audited_app();
444#endif // !defined(HAVE_BOLOS) && defined(HAVE_PENDING_REVIEW_SCREEN)
445}
446
447void io_seproxyhal_init_ux(void) {
448#ifdef TARGET_BLUE
449 // initialize the touch part
450 G_ux_os.last_touched_not_released_component = NULL((void*)0);
451#endif // TARGET_BLUE
452}
453
454void io_seproxyhal_init_button(void) {
455 // no button push so far
456 G_ux_os.button_mask = 0;
457 G_ux_os.button_same_mask_counter = 0;
458}
459
460#ifdef HAVE_BAGL1
461
462#ifdef TARGET_BLUE
463unsigned int io_seproxyhal_touch_out(const bagl_element_t* element, bagl_element_callback_t before_display) {
464 const bagl_element_t* el;
465 if (element->out != NULL((void*)0)) {
466 el = (const bagl_element_t*)PIC(((bagl_element_callback_t)PIC(element->out))(element))pic((void *)((bagl_element_callback_t)pic((void *)element->
out))(element))
;
467 // backward compatible with samples and such
468 if (! el) {
469 return 0;
470 }
471 if ((unsigned int)el != 1) {
472 element = el;
473 }
474 }
475
476 // out function might have triggered a draw of its own during a display callback
477 if (before_display) {
478 el = before_display(element);
479 if (!el) {
480 return 0;
481 }
482 if ((unsigned int)el != 1) {
483 element = el;
484 }
485 }
486
487 io_seproxyhal_display(element);
488 return 1;
489}
490
491unsigned int io_seproxyhal_touch_over(const bagl_element_t* element, bagl_element_callback_t before_display) {
492 bagl_element_t e;
493 const bagl_element_t* el;
494 if (element->over != NULL((void*)0)) {
495 el = (const bagl_element_t*)PIC(((bagl_element_callback_t)PIC(element->over))(element))pic((void *)((bagl_element_callback_t)pic((void *)element->
over))(element))
;
496 // backward compatible with samples and such
497 if (!el) {
498 return 0;
499 }
500 if ((unsigned int)el != 1) {
501 element = el;
502 }
503 }
504
505 // over function might have triggered a draw of its own during a display callback
506 if (before_display) {
507 el = before_display(element);
508 element = &e;
509 if (!el) {
510 return 0;
511 }
512 // problem for default screen_before_before_display where we return the given element, it have could been modified. but we don't know here
513 if ((unsigned int)el != 1) {
514 element = el;
515 }
516 }
517
518 // swap colors
519 memcpy(&e, (void*)element, sizeof(bagl_element_t));
520 e.component.fgcolor = element->overfgcolor;
521 e.component.bgcolor = element->overbgcolor;
522
523 io_seproxyhal_display(&e);
524 return 1;
525}
526
527unsigned int io_seproxyhal_touch_tap(const bagl_element_t* element, bagl_element_callback_t before_display) {
528 const bagl_element_t* el;
529 if (element->tap != NULL((void*)0)) {
530 el = (const bagl_element_t*)PIC(((bagl_element_callback_t)PIC(element->tap))(element))pic((void *)((bagl_element_callback_t)pic((void *)element->
tap))(element))
;
531 // backward compatible with samples and such
532 if (!el) {
533 return 0;
534 }
535 if ((unsigned int)el != 1) {
536 element = el;
537 }
538 }
539
540 // tap function might have triggered a draw of its own during a display callback
541 if (before_display) {
542 el = before_display(element);
543 if (!el) {
544 return 0;
545 }
546 if ((unsigned int)el != 1) {
547 element = el;
548 }
549 }
550 io_seproxyhal_display(element);
551 return 1;
552}
553
554void io_seproxyhal_touch(const bagl_element_t* elements, unsigned short element_count, unsigned short x, unsigned short y, unsigned char event_kind) {
555 io_seproxyhal_touch_element_callback(elements, element_count, x, y, event_kind, NULL((void*)0));
556}
557
558// browse all elements and until an element has changed state, continue browsing
559// return if processed or not
560void io_seproxyhal_touch_element_callback(const bagl_element_t* elements, unsigned short element_count, unsigned short x, unsigned short y, unsigned char event_kind, bagl_element_callback_t before_display) {
561 unsigned char comp_idx;
562 unsigned char last_touched_not_released_component_was_in_current_array = 0;
563
564 // find the first empty entry
565 for (comp_idx=0; comp_idx < element_count; comp_idx++) {
566 // process all components matching the x/y/w/h (no break) => fishy for the released out of zone
567 // continue processing only if a status has not been sent
568 if (io_seproxyhal_spi_is_status_sentio_seph_is_status_sent()) {
569 // continue instead of return to process all elemnts and therefore discard last touched element
570 break;
571 }
572
573 // only perform out callback when element was in the current array, else, leave it be
574 if (&elements[comp_idx] == G_ux_os.last_touched_not_released_component) {
575 last_touched_not_released_component_was_in_current_array = 1;
576 }
577
578 // the first component drawn with a
579 if ((elements[comp_idx].component.type & BAGL_FLAG_TOUCHABLE)
580 && elements[comp_idx].component.x-elements[comp_idx].touch_area_brim <= x && x<elements[comp_idx].component.x+elements[comp_idx].component.width+elements[comp_idx].touch_area_brim
581 && elements[comp_idx].component.y-elements[comp_idx].touch_area_brim <= y && y<elements[comp_idx].component.y+elements[comp_idx].component.height+elements[comp_idx].touch_area_brim) {
582
583 // outing the previous over'ed component
584 if (&elements[comp_idx] != G_ux_os.last_touched_not_released_component
585 && G_ux_os.last_touched_not_released_component != NULL((void*)0)) {
586 // only out the previous element if the newly matching will be displayed
587 if (!before_display || before_display(&elements[comp_idx])) {
588 if (io_seproxyhal_touch_out(G_ux_os.last_touched_not_released_component, before_display)) {
589 // previous component is considered released
590 G_ux_os.last_touched_not_released_component = NULL((void*)0);
591 // a display has been issued, avoid double display, wait for another touch event (20ms)
592 return;
593 }
594 }
595 // avoid a non displayed new element to pop out of the blue
596 continue;
597 }
598
599 /*
600 if (io_seproxyhal_spi_is_status_sent()) {
601 // continue instead of return to process all elements and therefore discard last touched element
602 continue;
603 }
604 */
605
606 // callback the hal to notify the component impacted by the user input
607 else if (event_kind == SEPROXYHAL_TAG_FINGER_EVENT_RELEASE0x02) {
608 if (io_seproxyhal_touch_tap(&elements[comp_idx], before_display)) {
609 // unmark the last component, we've been notified TOUCH
610 G_ux_os.last_touched_not_released_component = NULL((void*)0);
611 return;
612 }
613 }
614 else if (event_kind == SEPROXYHAL_TAG_FINGER_EVENT_TOUCH0x01) {
615 // ask for overing
616 if (io_seproxyhal_touch_over(&elements[comp_idx], before_display)) {
617 // remember the last touched component
618 G_ux_os.last_touched_not_released_component = (bagl_element_t*)&elements[comp_idx];
619 return;
620 }
621 }
622 }
623 }
624
625 // if overing out of component or over another component, the out event is sent after the over event of the previous component
626 if(last_touched_not_released_component_was_in_current_array
627 && G_ux_os.last_touched_not_released_component != NULL((void*)0)) {
628
629 // we won't be able to notify the out, don't do it, in case a diplay refused the dra of the relased element and the position matched another element of the array (in autocomplete for example)
630 if (io_seproxyhal_spi_is_status_sentio_seph_is_status_sent()) {
631 return;
632 }
633
634 if (io_seproxyhal_touch_out(G_ux_os.last_touched_not_released_component, before_display)) {
635 // ok component out has been emitted
636 G_ux_os.last_touched_not_released_component = NULL((void*)0);
637 }
638 }
639
640 // not processed
641}
642#endif // TARGET_BLUE
643
644void io_seproxyhal_display_bitmap(int x, int y, unsigned int w, unsigned int h, unsigned int* color_index, unsigned int bit_per_pixel, unsigned char* bitmap) {
645 // component type = ICON
646 // component icon id = 0
647 // => bitmap transmitted
648 if (w && h) {
649 bagl_component_t c;
650 bagl_icon_details_t d;
651 memset(&c, 0, sizeof(c));
652 c.type = BAGL_ICON;
653 c.x = x;
654 c.y = y;
655 c.width = w;
656 c.height = h;
657 // done by memset // c.icon_id = 0;
658 d.width = w;
659 d.height = h;
660 d.bpp = bit_per_pixel;
661 d.colors = color_index;
662 d.bitmap = bitmap;
663
664 io_seproxyhal_display_icon(&c, &d);
665 /*
666 // color index size
667 h = ((1<<bit_per_pixel)*sizeof(unsigned int));
668 // bitmap size
669 w = ((w*c.height*bit_per_pixel)/8)+((w*c.height*bit_per_pixel)%8?1:0);
670 unsigned short length = sizeof(bagl_component_t)
671 +1 // bpp
672 +h // color index
673 +w; // image bitmap
674 G_io_seproxyhal_spi_buffer[0] = SEPROXYHAL_TAG_SCREEN_DISPLAY_STATUS;
675 G_io_seproxyhal_spi_buffer[1] = length>>8;
676 G_io_seproxyhal_spi_buffer[2] = length;
677 io_seproxyhal_spi_send(G_io_seproxyhal_spi_buffer, 3);
678 io_seproxyhal_spi_send((unsigned char*)&c, sizeof(bagl_component_t));
679 G_io_seproxyhal_spi_buffer[0] = bit_per_pixel;
680 io_seproxyhal_spi_send(G_io_seproxyhal_spi_buffer, 1);
681 io_seproxyhal_spi_send((unsigned char*)color_index, h);
682 io_seproxyhal_spi_send(bitmap, w);
683 */
684 }
685}
686
687#ifdef SEPROXYHAL_TAG_SCREEN_DISPLAY_RAW_STATUS
688unsigned int io_seproxyhal_display_icon_header_and_colors(bagl_component_t* icon_component, bagl_icon_details_t* icon_details, unsigned int* icon_len) {
689 unsigned int len;
690
691 struct display_raw_s {
692 struct {
693 struct {
694 unsigned char tag;
695 unsigned char len[2];
696 } seph;
697 unsigned char type;
698 } header;
699 union {
700 short val;
701 char b[2];
702 } x;
703 union {
704 short val;
705 char b[2];
706 } y;
707 union {
708 unsigned short val;
709 char b[2];
710 } w;
711 union {
712 unsigned short val;
713 char b[2];
714 } h;
715 unsigned char bpp;
716 } __attribute__((packed)) raw;
717
718 raw.header.seph.tag = SEPROXYHAL_TAG_SCREEN_DISPLAY_RAW_STATUS;
719 raw.header.type = SEPROXYHAL_TAG_SCREEN_DISPLAY_RAW_STATUS_START;
720 raw.x.val = icon_component->x;
721 raw.y.val = icon_component->y;
722 raw.w.val = icon_component->width;
723 raw.h.val = icon_component->height;
724 raw.bpp = icon_details->bpp;
725
726
727 *icon_len = raw.w.val*raw.h.val*raw.bpp/8 + (((raw.w.val*raw.h.val*raw.bpp)%8)?1:0);
728
729 // optional, don't send too much on a single packet for MCU to receive it. when stream mode will be on, this will be useless
730 // min of remaining space in the packet vs. total icon size + color index size
731 len = MIN(sizeof(G_io_seproxyhal_spi_buffer) - sizeof(raw), *icon_len + (1<<raw.bpp)*4)((sizeof(G_io_seproxyhal_spi_buffer) - sizeof(raw)) < (*icon_len
+ (1<<raw.bpp)*4) ? (sizeof(G_io_seproxyhal_spi_buffer
) - sizeof(raw)) : (*icon_len + (1<<raw.bpp)*4))
;
732
733 // sizeof packet
734 raw.header.seph.len[0] = (len + sizeof(raw) - sizeof(raw.header.seph)) >> 8;
735 raw.header.seph.len[1] = (len + sizeof(raw) - sizeof(raw.header.seph));
736
737 // swap endianess of coordinates (make it big endian)
738 SWAP(raw.x.b[0], raw.x.b[1]){ raw.x.b[0] ^= raw.x.b[1]; raw.x.b[1] ^= raw.x.b[0]; raw.x.b
[0] ^= raw.x.b[1]; }
;
739 SWAP(raw.y.b[0], raw.y.b[1]){ raw.y.b[0] ^= raw.y.b[1]; raw.y.b[1] ^= raw.y.b[0]; raw.y.b
[0] ^= raw.y.b[1]; }
;
740 SWAP(raw.w.b[0], raw.w.b[1]){ raw.w.b[0] ^= raw.w.b[1]; raw.w.b[1] ^= raw.w.b[0]; raw.w.b
[0] ^= raw.w.b[1]; }
;
741 SWAP(raw.h.b[0], raw.h.b[1]){ raw.h.b[0] ^= raw.h.b[1]; raw.h.b[1] ^= raw.h.b[0]; raw.h.b
[0] ^= raw.h.b[1]; }
;
742
743 io_seproxyhal_spi_sendio_seph_send((unsigned char*)&raw, sizeof(raw));
744 io_seproxyhal_spi_sendio_seph_send((unsigned char*)(PIC(icon_details->colors)pic((void *)icon_details->colors)), (1<<raw.bpp)*4);
745 len -= (1<<raw.bpp)*4;
746
747 // remaining length of bitmap bits to be displayed
748 return len;
749}
750#endif // SEPROXYHAL_TAG_SCREEN_DISPLAY_RAW_STATUS
751
752void io_seproxyhal_display_icon(bagl_component_t* icon_component, bagl_icon_details_t* icon_det) {
753 bagl_component_t icon_component_mod;
754 const bagl_icon_details_t* icon_details = (bagl_icon_details_t*)PIC(icon_det)pic((void *)icon_det);
755
756 if (icon_details && icon_details->bitmap) {
757 // ensure not being out of bounds in the icon component agianst the declared icon real size
758 memcpy(&icon_component_mod, (void *)PIC(icon_component)pic((void *)icon_component), sizeof(bagl_component_t));
759 icon_component_mod.width = icon_details->width;
760 icon_component_mod.height = icon_details->height;
761 icon_component = &icon_component_mod;
Value stored to 'icon_component' is never read
762
763#ifdef SEPROXYHAL_TAG_SCREEN_DISPLAY_RAW_STATUS
764 unsigned int len;
765 unsigned int icon_len;
766 unsigned int icon_off=0;
767
768 len = io_seproxyhal_display_icon_header_and_colors(icon_component, (bagl_icon_details_t*)icon_details, &icon_len);
769 io_seproxyhal_spi_sendio_seph_send(PIC(icon_details->bitmap)pic((void *)icon_details->bitmap), len);
770 // advance in the bitmap to be transmitted
771 icon_len -= len;
772 icon_off += len;
773
774 // still some bitmap data to transmit
775 while(icon_len) {
776 // wait displayed event
777 io_seproxyhal_spi_recvio_seph_recv(G_io_seproxyhal_spi_buffer, sizeof(G_io_seproxyhal_spi_buffer), 0);
778
779 G_io_seproxyhal_spi_buffer[0] = SEPROXYHAL_TAG_SCREEN_DISPLAY_RAW_STATUS;
780 G_io_seproxyhal_spi_buffer[3] = SEPROXYHAL_TAG_SCREEN_DISPLAY_RAW_STATUS_CONT;
781
782 len = MIN((sizeof(G_io_seproxyhal_spi_buffer) - 4), icon_len)(((sizeof(G_io_seproxyhal_spi_buffer) - 4)) < (icon_len) ?
((sizeof(G_io_seproxyhal_spi_buffer) - 4)) : (icon_len))
;
783 G_io_seproxyhal_spi_buffer[1] = (len+1)>>8;
784 G_io_seproxyhal_spi_buffer[2] = (len+1);
785 io_seproxyhal_spi_sendio_seph_send(G_io_seproxyhal_spi_buffer, 4);
786 io_seproxyhal_spi_sendio_seph_send(PIC(icon_details->bitmap)pic((void *)icon_details->bitmap)+icon_off, len);
787
788 icon_len -= len;
789 icon_off += len;
790 }
791#else // !SEPROXYHAL_TAG_SCREEN_DISPLAY_RAW_STATUS
792#ifdef HAVE_SE_SCREEN1
793 bagl_draw_glyph(&icon_component_mod, icon_details);
794#endif // HAVE_SE_SCREEN
795#if !defined(HAVE_SE_SCREEN1) || (defined(HAVE_SE_SCREEN1) && defined(HAVE_PRINTF))
796 if (io_seproxyhal_spi_is_status_sentio_seph_is_status_sent()) {
797 return;
798 }
799 // color index size
800 unsigned int h = (1<<(icon_details->bpp))*sizeof(unsigned int);
801 // bitmap size
802 unsigned int w = ((icon_component->width*icon_component->height*icon_details->bpp)/8)+((icon_component->width*icon_component->height*icon_details->bpp)%8?1:0);
803 unsigned short length = sizeof(bagl_component_t)
804 +1 /* bpp */
805 +h /* color index */
806 +w; /* image bitmap size */
807 G_io_seproxyhal_spi_buffer[0] = SEPROXYHAL_TAG_SCREEN_DISPLAY_STATUS0x65;
808#if defined(HAVE_SE_SCREEN1) && defined(HAVE_PRINTF)
809 G_io_seproxyhal_spi_buffer[0] = SEPROXYHAL_TAG_DBG_SCREEN_DISPLAY_STATUS0x5E;
810#endif // HAVE_SE_SCREEN && HAVE_PRINTF
811 G_io_seproxyhal_spi_buffer[1] = length>>8;
812 G_io_seproxyhal_spi_buffer[2] = length;
813 io_seproxyhal_spi_sendio_seph_send(G_io_seproxyhal_spi_buffer, 3);
814 io_seproxyhal_spi_sendio_seph_send((unsigned char*)icon_component, sizeof(bagl_component_t));
815 G_io_seproxyhal_spi_buffer[0] = icon_details->bpp;
816 io_seproxyhal_spi_sendio_seph_send(G_io_seproxyhal_spi_buffer, 1);
817 io_seproxyhal_spi_sendio_seph_send((unsigned char*)PIC(icon_details->colors)pic((void *)icon_details->colors), h);
818 io_seproxyhal_spi_sendio_seph_send((unsigned char*)PIC(icon_details->bitmap)pic((void *)icon_details->bitmap), w);
819#endif // !HAVE_SE_SCREEN || (HAVE_SE_SCREEN && HAVE_PRINTF)
820#endif // !SEPROXYHAL_TAG_SCREEN_DISPLAY_RAW_STATUS
821 }
822}
823
824void io_seproxyhal_display_default(const bagl_element_t* element) {
825
826 const bagl_element_t* el = (const bagl_element_t*) PIC(element)pic((void *)element);
827 const char* txt = (const char*)PIC(el->text)pic((void *)el->text);
828 // process automagically address from rom and from ram
829 unsigned int type = (el->component.type & ~(BAGL_FLAG_TOUCHABLE));
830
831 if (type != BAGL_NONE) {
832 if (txt != NULL((void*)0)) {
833 // consider an icon details descriptor is pointed by the context
834 if (type == BAGL_ICON && el->component.icon_id == 0) {
835 // SECURITY: due to this wild cast, the code MUST be executed on the application side instead of in
836 // the syscall sides to avoid buffer overflows and a real hard way of checking buffer
837 // belonging in the syscall dispatch
838 io_seproxyhal_display_icon((bagl_component_t*)&el->component, (bagl_icon_details_t*)txt);
839 }
840 else {
841#ifdef HAVE_SE_SCREEN1
842 bagl_draw_with_context(&el->component, txt, strlen(txt), BAGL_ENCODING_LATIN10);
843#endif // HAVE_SE_SCREEN
844#if !defined(HAVE_SE_SCREEN1) || (defined(HAVE_SE_SCREEN1) && defined(HAVE_PRINTF))
845 if (io_seproxyhal_spi_is_status_sentio_seph_is_status_sent()) {
846 return;
847 }
848 unsigned short length = sizeof(bagl_component_t)+strlen((const char*)txt);
849 G_io_seproxyhal_spi_buffer[0] = SEPROXYHAL_TAG_SCREEN_DISPLAY_STATUS0x65;
850#if defined(HAVE_SE_SCREEN1) && defined(HAVE_PRINTF)
851 G_io_seproxyhal_spi_buffer[0] = SEPROXYHAL_TAG_DBG_SCREEN_DISPLAY_STATUS0x5E;
852#endif // HAVE_SE_SCREEN && HAVE_PRINTF
853 G_io_seproxyhal_spi_buffer[1] = length>>8;
854 G_io_seproxyhal_spi_buffer[2] = length;
855 io_seproxyhal_spi_sendio_seph_send(G_io_seproxyhal_spi_buffer, 3);
856 io_seproxyhal_spi_sendio_seph_send((unsigned char*)&el->component, sizeof(bagl_component_t));
857 io_seproxyhal_spi_sendio_seph_send((unsigned char*)txt, length-sizeof(bagl_component_t));
858#endif // !HAVE_SE_SCREEN || (HAVE_SE_SCREEN && HAVE_PRINTF)
859 }
860 }
861 else {
862#ifdef HAVE_SE_SCREEN1
863 bagl_draw_with_context(&el->component, NULL((void*)0), 0, 0);
864#endif // HAVE_SE_SCREEN
865#if !defined(HAVE_SE_SCREEN1) || (defined(HAVE_SE_SCREEN1) && defined(HAVE_PRINTF))
866 if (io_seproxyhal_spi_is_status_sentio_seph_is_status_sent()) {
867 return;
868 }
869 unsigned short length = sizeof(bagl_component_t);
870 G_io_seproxyhal_spi_buffer[0] = SEPROXYHAL_TAG_SCREEN_DISPLAY_STATUS0x65;
871#if defined(HAVE_SE_SCREEN1) && defined(HAVE_PRINTF)
872 G_io_seproxyhal_spi_buffer[0] = SEPROXYHAL_TAG_DBG_SCREEN_DISPLAY_STATUS0x5E;
873#endif // HAVE_SE_SCREEN && HAVE_PRINTF
874 G_io_seproxyhal_spi_buffer[1] = length>>8;
875 G_io_seproxyhal_spi_buffer[2] = length;
876 io_seproxyhal_spi_sendio_seph_send(G_io_seproxyhal_spi_buffer, 3);
877 io_seproxyhal_spi_sendio_seph_send((unsigned char*)&el->component, sizeof(bagl_component_t));
878#endif // !HAVE_SE_SCREEN || (HAVE_SE_SCREEN && HAVE_PRINTF)
879 }
880 }
881}
882
883unsigned int bagl_label_roundtrip_duration_ms(const bagl_element_t* e, unsigned int average_char_width) {
884 return bagl_label_roundtrip_duration_ms_buf(e, e->text, average_char_width);
885}
886
887unsigned int bagl_label_roundtrip_duration_ms_buf(const bagl_element_t* e, const char* str, unsigned int average_char_width) {
888 // not a scrollable label
889 if (e == NULL((void*)0) || (e->component.type != BAGL_LABEL && e->component.type != BAGL_LABELINE)) {
890 return 0;
891 }
892
893 const char *text_adr = (const char *) PIC(str)pic((void *)str);
894 unsigned int textlen = 0;
895
896 // no delay, no text to display
897 if (!text_adr) {
898 return 0;
899 }
900 textlen = strlen(text_adr);
901
902 // no delay, all text fits
903 textlen = textlen * average_char_width;
904 if (textlen <= e->component.width) {
905 return 0;
906 }
907
908 // compute scrolled text length
909 return 2*(textlen - e->component.width)*1000/e->component.icon_id + 2*(e->component.stroke & ~(0x80))*100;
910}
911
912void io_seproxyhal_button_push(button_push_callback_t button_callback, unsigned int new_button_mask) {
913 if (button_callback) {
914 unsigned int button_mask;
915 unsigned int button_same_mask_counter;
916 // enable speeded up long push
917 if (new_button_mask == G_ux_os.button_mask) {
918 // each 100ms ~
919 G_ux_os.button_same_mask_counter++;
920 }
921
922 // when new_button_mask is 0 and
923
924 // append the button mask
925 button_mask = G_ux_os.button_mask | new_button_mask;
926
927 // pre reset variable due to os_sched_exit
928 button_same_mask_counter = G_ux_os.button_same_mask_counter;
929
930 // reset button mask
931 if (new_button_mask == 0) {
932 // reset next state when button are released
933 G_ux_os.button_mask = 0;
934 G_ux_os.button_same_mask_counter=0;
935
936 // notify button released event
937 button_mask |= BUTTON_EVT_RELEASED0x80000000UL;
938 }
939 else {
940 G_ux_os.button_mask = button_mask;
941 }
942
943 // reset counter when button mask changes
944 if (new_button_mask != G_ux_os.button_mask) {
945 G_ux_os.button_same_mask_counter=0;
946 }
947
948 if (button_same_mask_counter >= BUTTON_FAST_THRESHOLD_CS8) {
949 // fast bit when pressing and timing is right
950 if ((button_same_mask_counter%BUTTON_FAST_ACTION_CS3) == 0) {
951 button_mask |= BUTTON_EVT_FAST0x40000000UL;
952 }
953
954 /*
955 // fast bit when releasing and threshold has been exceeded
956 if ((button_mask & BUTTON_EVT_RELEASED)) {
957 button_mask |= BUTTON_EVT_FAST;
958 }
959 */
960
961 // discard the release event after a fastskip has been detected, to avoid strange at release behavior
962 // and also to enable user to cancel an operation by starting triggering the fast skip
963 button_mask &= ~BUTTON_EVT_RELEASED0x80000000UL;
964 }
965
966 // indicate if button have been released
967 button_callback(button_mask, button_same_mask_counter);
968
969 }
970}
971
972#endif // HAVE_BAGL
973
974void io_seproxyhal_setup_ticker(unsigned int interval_ms) {
975 G_io_seproxyhal_spi_buffer[0] = SEPROXYHAL_TAG_SET_TICKER_INTERVAL0x4E;
976 G_io_seproxyhal_spi_buffer[1] = 0;
977 G_io_seproxyhal_spi_buffer[2] = 2;
978 G_io_seproxyhal_spi_buffer[3] = (interval_ms>>8)&0xff;
979 G_io_seproxyhal_spi_buffer[4] = (interval_ms)&0xff;
980 io_seproxyhal_spi_sendio_seph_send(G_io_seproxyhal_spi_buffer, 5);
981}
982
983static const unsigned char seph_io_device_off[] = {
984 SEPROXYHAL_TAG_DEVICE_OFF0x4B,
985 0,
986 0,
987};
988void io_seproxyhal_power_off(void) {
989 io_seproxyhal_spi_sendio_seph_send(seph_io_device_off, sizeof(seph_io_device_off));
990 for(;;);
991}
992
993static const unsigned char seph_io_se_reset[]= {
994 SEPROXYHAL_TAG_SE_POWER_OFF0x46,
995 0,
996 0,
997};
998void io_seproxyhal_se_reset(void) {
999 io_seproxyhal_spi_sendio_seph_send(seph_io_se_reset, sizeof(seph_io_se_reset));
1000 for(;;);
1001}
1002
1003#ifdef HAVE_BLE1
1004void io_seph_ble_enable(unsigned char enable)
1005{
1006 G_io_seproxyhal_spi_buffer[0] = SEPROXYHAL_TAG_UX_CMD0x5D;
1007 G_io_seproxyhal_spi_buffer[1] = 0;
1008 G_io_seproxyhal_spi_buffer[2] = 1;
1009 G_io_seproxyhal_spi_buffer[3] = (enable ? SEPROXYHAL_TAG_UX_CMD_BLE_ENABLE_ADV0x01 : SEPROXYHAL_TAG_UX_CMD_BLE_DISABLE_ADV0x00);
1010 io_seproxyhal_spi_sendio_seph_send(G_io_seproxyhal_spi_buffer, 4);
1011}
1012
1013void io_seph_ble_clear_bond_db(void)
1014{
1015 G_io_seproxyhal_spi_buffer[0] = SEPROXYHAL_TAG_UX_CMD0x5D;
1016 G_io_seproxyhal_spi_buffer[1] = 0;
1017 G_io_seproxyhal_spi_buffer[2] = 1;
1018 G_io_seproxyhal_spi_buffer[3] = SEPROXYHAL_TAG_UX_CMD_BLE_RESET_PAIRINGS0x02;
1019 io_seproxyhal_spi_sendio_seph_send(G_io_seproxyhal_spi_buffer, 4);
1020}
1021#endif // HAVE_BLE
1022
1023void io_seph_ux_redisplay(void)
1024{
1025 G_io_seproxyhal_spi_buffer[0] = SEPROXYHAL_TAG_UX_CMD0x5D;
1026 G_io_seproxyhal_spi_buffer[1] = 0;
1027 G_io_seproxyhal_spi_buffer[2] = 1;
1028 G_io_seproxyhal_spi_buffer[3] = SEPROXYHAL_TAG_UX_CMD_REDISPLAY0x03;
1029 io_seproxyhal_spi_sendio_seph_send(G_io_seproxyhal_spi_buffer, 4);
1030}
1031
1032static const unsigned char seph_io_usb_disconnect[] = {
1033 SEPROXYHAL_TAG_USB_CONFIG0x4F,
1034 0,
1035 1,
1036 SEPROXYHAL_TAG_USB_CONFIG_DISCONNECT0x02,
1037};
1038void io_seproxyhal_disable_io(void) {
1039 // usb off
1040 io_seproxyhal_spi_sendio_seph_send(seph_io_usb_disconnect, sizeof(seph_io_usb_disconnect));
1041}
1042
1043void io_seproxyhal_backlight(unsigned int flags, unsigned int backlight_percentage) {
1044 G_io_seproxyhal_spi_buffer[0] = SEPROXYHAL_TAG_SET_SCREEN_CONFIG0x3E;
1045 G_io_seproxyhal_spi_buffer[1] = 0;
1046 G_io_seproxyhal_spi_buffer[2] = 2;
1047 G_io_seproxyhal_spi_buffer[3] = (backlight_percentage?0x80:0)|(flags & 0x7F); // power on
1048 G_io_seproxyhal_spi_buffer[4] = backlight_percentage;
1049 io_seproxyhal_spi_sendio_seph_send(G_io_seproxyhal_spi_buffer, 5);
1050}
1051
1052#ifdef HAVE_IO_U2F
1053u2f_service_t G_io_u2f;
1054#endif // HAVE_IO_U2F
1055
1056unsigned int os_io_seproxyhal_get_app_name_and_version(void) __attribute__((weak));
1057unsigned int os_io_seproxyhal_get_app_name_and_version(void) {
1058 unsigned int tx_len, len;
1059 // build the get app name and version reply
1060 tx_len = 0;
1061 G_io_apdu_buffer[tx_len++] = 1; // format ID
1062
1063#ifndef HAVE_BOLOS
1064 // append app name
1065 len = os_registry_get_current_app_tag(BOLOS_TAG_APPNAME0x01, G_io_apdu_buffer+tx_len+1, sizeof(G_io_apdu_buffer)-tx_len-1);
1066 G_io_apdu_buffer[tx_len++] = len;
1067 tx_len += len;
1068 // append app version
1069 len = os_registry_get_current_app_tag(BOLOS_TAG_APPVERSION0x02, G_io_apdu_buffer+tx_len+1, sizeof(G_io_apdu_buffer)-tx_len-1);
1070 G_io_apdu_buffer[tx_len++] = len;
1071 tx_len += len;
1072#else // HAVE_BOLOS
1073 // append app name
1074 len = strlen("BOLOS");
1075 G_io_apdu_buffer[tx_len++] = len;
1076 strcpy((char*)(G_io_apdu_buffer+tx_len), "BOLOS");
1077 tx_len += len;
1078 // append app version
1079 len = strlen(VERSION"dummy");
1080 G_io_apdu_buffer[tx_len++] = len;
1081 strcpy((char*)(G_io_apdu_buffer+tx_len), VERSION"dummy");
1082 tx_len += len;
1083#endif // HAVE_BOLOS
1084
1085#if !defined(HAVE_IO_TASK) || !defined(HAVE_BOLOS)
1086 // to be fixed within io tasks
1087 // return OS flags to notify of platform's global state (pin lock etc)
1088 G_io_apdu_buffer[tx_len++] = 1; // flags length
1089 G_io_apdu_buffer[tx_len++] = os_flags();
1090#endif // !defined(HAVE_IO_TASK) || !defined(HAVE_BOLOS)
1091
1092 // status words
1093 G_io_apdu_buffer[tx_len++] = 0x90;
1094 G_io_apdu_buffer[tx_len++] = 0x00;
1095 return tx_len;
1096}
1097
1098#if !defined(HAVE_BOLOS_NO_DEFAULT_APDU)
1099// This function is used to process the default APDU commands.
1100static bolos_bool_t io_process_default_apdus(unsigned char* channel, unsigned short* tx_len) {
1101 // Indicates whether a command has been processed and need to send an answer.
1102 bolos_bool_t processed = BOLOS_FALSE0x55;
1103
1104 // We handle the default apdus when the CLA byte is correct.
1105 if (DEFAULT_APDU_CLA0xB0 == G_io_apdu_buffer[APDU_OFF_CLA0]) {
1106
1107 // We have several possible commands.
1108 switch (G_io_apdu_buffer[APDU_OFF_INS1]) {
1109
1110 // get name and version
1111 case DEFAULT_APDU_INS_GET_VERSION0x01:
1112 // P1 and P2 shall be set to '00'.
1113 if (!G_io_apdu_buffer[APDU_OFF_P12] && !G_io_apdu_buffer[APDU_OFF_P23]) {
1114 *tx_len = os_io_seproxyhal_get_app_name_and_version();
1115 // disable 'return after tx' and 'asynch reply' flags
1116 *channel &= ~IO_FLAGS0xF8;
1117 processed = BOLOS_TRUE0xaa;
1118 }
1119 break;
1120
1121 // exit app after replied
1122 case DEFAULT_APDU_INS_APP_EXIT0xA7:
1123 // P1 and P2 shall be set to '00'.
1124 if (!G_io_apdu_buffer[APDU_OFF_P12] && !G_io_apdu_buffer[APDU_OFF_P23]) {
1125 *tx_len = 0;
1126 G_io_apdu_buffer[(*tx_len)++] = 0x90;
1127 G_io_apdu_buffer[(*tx_len)++] = 0x00;
1128
1129#if defined(HAVE_BOLOS)
1130 // If this APDU has been received from the dashboard, we don't do
1131 // anything except resetting the IO flags.
1132 *channel &= ~IO_FLAGS0xF8;
1133#else
1134 // We exit the application after having replied.
1135 *channel |= IO_RESET_AFTER_REPLIED0x80;
1136#endif // HAVE_BOLOS
1137
1138 processed = BOLOS_TRUE0xaa;
1139 }
1140 break;
1141
1142 // seed cookie
1143 // host: <nothing>
1144 // device: <format(1B)> <len(1B)> <seed magic cookie if pin is entered(len)> 9000 | 6985
1145#if defined(HAVE_SEED_COOKIE)
1146 case DEFAULT_APDU_INS_GET_SEED_COOKIE:
1147 // P1 and P2 shall be set to '00'.
1148 if (!G_io_apdu_buffer[APDU_OFF_P12] && !G_io_apdu_buffer[APDU_OFF_P23]) {
1149 *tx_len = 0;
1150 if (os_global_pin_is_validated() == BOLOS_UX_OK0xAA) {
1151 unsigned int i;
1152 // format
1153 G_io_apdu_buffer[(*tx_len)++] = 0x01;
1154 i = os_perso_seed_cookie(G_io_apdu_buffer+1+1, MIN(64,sizeof(G_io_apdu_buffer)-1-1-2)((64) < (sizeof(G_io_apdu_buffer)-1-1-2) ? (64) : (sizeof(
G_io_apdu_buffer)-1-1-2))
);
1155
1156 G_io_apdu_buffer[(*tx_len)++] = i;
1157 *tx_len += i;
1158 G_io_apdu_buffer[(*tx_len)++] = 0x90;
1159 G_io_apdu_buffer[(*tx_len)++] = 0x00;
1160 }
1161 else {
1162 G_io_apdu_buffer[(*tx_len)++] = 0x69;
1163 G_io_apdu_buffer[(*tx_len)++] = 0x85;
1164 }
1165 *channel &= ~IO_FLAGS0xF8;
1166 processed = BOLOS_TRUE0xaa;
1167 }
1168 break;
1169#endif // HAVE_SEED_COOKIE
1170
1171#if defined(DEBUG_OS_STACK_CONSUMPTION)
1172 // OS stack consumption.
1173 case DEFAULT_APDU_INS_STACK_CONSUMPTION:
1174 // Initialization.
1175 *tx_len = 2;
1176 U2BE_ENCODE(G_io_apdu_buffer, 0x00, SWO_APD_HDR_0D((0x6000 + 0x0500) + ERR_GEN_ID_0D));
1177
1178 // P2 and Lc shall be set to '00'.
1179 if (!G_io_apdu_buffer[APDU_OFF_P23] && !G_io_apdu_buffer[APDU_OFF_LC4]) {
1180 int s = os_stack_operations(G_io_apdu_buffer[APDU_OFF_P12]);
1181 if (-1 != s) {
1182 u4be_encode(G_io_apdu_buffer, 0x00, s);
1183 *tx_len = sizeof(int);
1184 G_io_apdu_buffer[(*tx_len)++] = 0x90;
1185 G_io_apdu_buffer[(*tx_len)++] = 0x00;
1186 }
1187 }
1188 *channel &= ~IO_FLAGS0xF8;
1189 processed = BOLOS_TRUE0xaa;
1190 break;
1191#endif // DEBUG_OS_STACK_CONSUMPTION
1192
1193 default:
1194 // 'processed' is already initialized.
1195 break;
1196 }
1197 }
1198
1199 return processed;
1200}
1201
1202#endif // HAVE_BOLOS_NO_DEFAULT_APDU
1203
1204unsigned short io_exchange(unsigned char channel, unsigned short tx_len) {
1205 unsigned short rx_len;
1206 unsigned int timeout_ms;
1207
1208#ifdef HAVE_BOLOS_APP_STACK_CANARY1
1209 // behavior upon detected stack overflow is to reset the SE
1210 if (app_stack_canary != APP_STACK_CANARY_MAGIC0xDEAD0031) {
1211 io_seproxyhal_se_reset();
1212 }
1213#endif // HAVE_BOLOS_APP_STACK_CANARY
1214
1215#ifdef DEBUG_APDU
1216 if ((channel&~(IO_FLAGS0xF8)) == CHANNEL_APDU0) {
1217 // ignore tx len
1218
1219 // already received the data of the apdu when received the whole apdu
1220 if ((channel & (CHANNEL_APDU0|IO_RECEIVE_DATA0x40)) == (CHANNEL_APDU0|IO_RECEIVE_DATA0x40)) {
1221 // return apdu data - header
1222 return G_io_apdu_length-5;
1223 }
1224
1225 // fetch next apdu
1226 if (debug_apdus_offset < sizeof(debug_apdus)) {
1227 G_io_apdu_length = debug_apdus[debug_apdus_offset]&0xFF;
1228 memcpy(G_io_apdu_buffer, &debug_apdus[debug_apdus_offset+1], G_io_apdu_length);
1229 debug_apdus_offset += G_io_apdu_length+1;
1230 return G_io_apdu_length;
1231 }
1232 }
1233#endif // DEBUG_APDU
1234
1235reply_apdu:
1236 switch(channel&~(IO_FLAGS0xF8)) {
1237 case CHANNEL_APDU0:
1238 // TODO work up the spi state machine over the HAL proxy until an APDU is available
1239
1240 if (tx_len && !(channel&IO_ASYNCH_REPLY0x10)) {
1241 // ensure it's our turn to send a command/status, could lag a bit before sending the reply
1242 while (io_seproxyhal_spi_is_status_sentio_seph_is_status_sent()) {
1243 io_seproxyhal_spi_recvio_seph_recv(G_io_seproxyhal_spi_buffer, sizeof(G_io_seproxyhal_spi_buffer), 0);
1244 // process without sending status on tickers etc, to ensure keeping the hand
1245 os_io_seph_recv_and_process(1);
1246 }
1247
1248 // reinit sending timeout for APDU replied within io_exchange
1249 timeout_ms = G_io_app.ms + IO_RAPDU_TRANSMIT_TIMEOUT_MS2000UL;
1250
1251 // until the whole RAPDU is transmitted, send chunks using the current mode for communication
1252 for (;;) {
1253 switch(G_io_app.apdu_state) {
1254 default:
1255 // delegate to the hal in case of not generic transport mode (or asynch)
1256 if (io_exchange_al(channel, tx_len) == 0) {
1257 goto break_send;
1258 }
1259 __attribute__((fallthrough));
1260 case APDU_IDLE:
1261 LOG("invalid state for APDU reply\n");
1262 THROW(INVALID_STATE)os_longjmp(0x4);
1263 break;
1264
1265 case APDU_RAW:
1266 if (tx_len > sizeof(G_io_apdu_buffer)) {
1267 THROW(INVALID_PARAMETER)os_longjmp(0x2);
1268 }
1269 // reply the RAW APDU over SEPROXYHAL protocol
1270 G_io_seproxyhal_spi_buffer[0] = SEPROXYHAL_TAG_RAPDU0x53;
1271 G_io_seproxyhal_spi_buffer[1] = (tx_len)>>8;
1272 G_io_seproxyhal_spi_buffer[2] = (tx_len);
1273 io_seproxyhal_spi_sendio_seph_send(G_io_seproxyhal_spi_buffer, 3);
1274 io_seproxyhal_spi_sendio_seph_send(G_io_apdu_buffer, tx_len);
1275
1276 // isngle packet reply, mark immediate idle
1277 G_io_app.apdu_state = APDU_IDLE;
1278 // finished, no chunking
1279 goto break_send;
1280
1281#ifdef HAVE_USB_APDU1
1282 case APDU_USB_HID:
1283 // only send, don't perform synchronous reception of the next command (will be done later by the seproxyhal packet processing)
1284 io_usb_hid_send(io_usb_send_apdu_data, tx_len);
1285 goto break_send;
1286#ifdef HAVE_USB_CLASS_CCID
1287 case APDU_USB_CCID:
1288 io_usb_ccid_reply(G_io_apdu_buffer, tx_len);
1289 goto break_send;
1290#endif // HAVE_USB_CLASS_CCID
1291#ifdef HAVE_WEBUSB1
1292 case APDU_USB_WEBUSB:
1293 io_usb_hid_send(io_usb_send_apdu_data_ep0x83, tx_len);
1294 goto break_send;
1295#endif // HAVE_WEBUSB
1296#endif // HAVE_USB_APDU
1297
1298#ifdef HAVE_BLE_APDU1 // versus U2F BLE
1299 case APDU_BLE:
1300 LEDGER_BLE_send(G_io_apdu_buffer, tx_len);
1301 goto break_send;
1302#endif // HAVE_BLE_APDU
1303
1304
1305#ifdef HAVE_IO_U2F
1306 // case to handle U2F channels. u2f apdu to be dispatched in the upper layers
1307 case APDU_U2F:
1308 // prepare reply, the remaining segments will be pumped during USB/BLE events handling while waiting for the next APDU
1309
1310 // the reply has been prepared by the application, stop sending anti timeouts
1311 u2f_message_set_autoreply_wait_user_presence(&G_io_u2f, false0);
1312
1313 // continue processing currently received command until completely received.
1314 while(!u2f_message_repliable(&G_io_u2f)) {
1315
1316 io_seproxyhal_general_status();
1317 do {
1318 io_seproxyhal_spi_recvio_seph_recv(G_io_seproxyhal_spi_buffer, sizeof(G_io_seproxyhal_spi_buffer), 0);
1319 // check for reply timeout
1320 if (G_io_app.ms >= timeout_ms) {
1321 THROW(EXCEPTION_IO_RESET)os_longjmp(0x5);
1322 }
1323 // avoid a general status to be replied
1324 io_seproxyhal_handle_event();
1325 } while (io_seproxyhal_spi_is_status_sentio_seph_is_status_sent());
1326 }
1327#ifdef U2F_PROXY_MAGIC
1328
1329 // user presence + counter + rapdu + sw must fit the apdu buffer
1330 if (1U+ 4U+ tx_len +2U > sizeof(G_io_apdu_buffer)) {
1331 THROW(INVALID_PARAMETER)os_longjmp(0x2);
1332 }
1333
1334 // u2F tunnel needs the status words to be included in the signature response BLOB, do it now.
1335 // always return 9000 in the signature to avoid error @ transport level in u2f layers.
1336 G_io_apdu_buffer[tx_len] = 0x90; //G_io_apdu_buffer[tx_len-2];
1337 G_io_apdu_buffer[tx_len+1] = 0x00; //G_io_apdu_buffer[tx_len-1];
1338 tx_len += 2;
1339 memmove(G_io_apdu_buffer + APDU_OFF_DATA5, G_io_apdu_buffer, tx_len);
1340 // zeroize user presence and counter
1341 memset(G_io_apdu_buffer, 0, APDU_OFF_DATA5);
1342 u2f_message_reply(&G_io_u2f, U2F_CMD_MSG, G_io_apdu_buffer, tx_len+5);
1343
1344#else // U2F_PROXY_MAGIC
1345 u2f_message_reply(&G_io_u2f, U2F_CMD_MSG, G_io_apdu_buffer, tx_len);
1346#endif // U2F_PROXY_MAGIC
1347 goto break_send;
1348#endif // HAVE_IO_U2F
1349 }
1350 continue;
1351
1352 break_send:
1353
1354 // wait end of reply transmission
1355 // TODO: add timeout here to avoid spending too much time when host has disconnected
1356 while (G_io_app.apdu_state != APDU_IDLE) {
1357 io_seproxyhal_general_status();
1358 do {
1359 io_seproxyhal_spi_recvio_seph_recv(G_io_seproxyhal_spi_buffer, sizeof(G_io_seproxyhal_spi_buffer), 0);
1360 // check for reply timeout (when asynch reply (over hid or u2f for example))
1361 // this case shall be covered by usb_ep_timeout but is not, investigate that
1362 if (G_io_app.ms >= timeout_ms) {
1363 THROW(EXCEPTION_IO_RESET)os_longjmp(0x5);
1364 }
1365 // avoid a general status to be replied
1366 io_seproxyhal_handle_event();
1367 } while (io_seproxyhal_spi_is_status_sentio_seph_is_status_sent());
1368 }
1369 // reset apdu state
1370 G_io_app.apdu_state = APDU_IDLE;
1371 G_io_app.apdu_media = IO_APDU_MEDIA_NONE;
1372
1373 G_io_app.apdu_length = 0;
1374
1375 // continue sending commands, don't issue status yet
1376 if (channel & IO_RETURN_AFTER_TX0x20) {
1377 return 0;
1378 }
1379 // acknowledge the write request (general status OK) and no more command to follow (wait until another APDU container is received to continue unwrapping)
1380 io_seproxyhal_general_status();
1381 break;
1382 }
1383
1384 // perform reset after io exchange
1385 if (channel & IO_RESET_AFTER_REPLIED0x80) {
1386 // The error cast is retrocompatible with the previous value.
1387 os_sched_exit((bolos_task_status_t)EXCEPTION_IO_RESET0x5);
1388 //reset();
1389 }
1390 }
1391
1392 if (!(channel&IO_ASYNCH_REPLY0x10)) {
1393
1394 // already received the data of the apdu when received the whole apdu
1395 if ((channel & (CHANNEL_APDU0|IO_RECEIVE_DATA0x40)) == (CHANNEL_APDU0|IO_RECEIVE_DATA0x40)) {
1396 // return apdu data - header
1397 return G_io_app.apdu_length-5;
1398 }
1399
1400 // reply has ended, proceed to next apdu reception (reset status only after asynch reply)
1401 G_io_app.apdu_state = APDU_IDLE;
1402 G_io_app.apdu_media = IO_APDU_MEDIA_NONE;
1403 }
1404
1405 // reset the received apdu length
1406 G_io_app.apdu_length = 0;
1407
1408 // ensure ready to receive an event (after an apdu processing with asynch flag, it may occur if the channel is not correctly managed)
1409
1410 // until a new whole CAPDU is received
1411 for (;;) {
1412 io_seproxyhal_general_status();
1413 // wait until a SPI packet is available
1414 // NOTE: on ST31, dual wait ISO & RF (ISO instead of SPI)
1415 rx_len = io_seproxyhal_spi_recvio_seph_recv(G_io_seproxyhal_spi_buffer, sizeof(G_io_seproxyhal_spi_buffer), 0);
1416
1417 // can't process split TLV, continue
1418 if (rx_len < 3 || rx_len != U2(G_io_seproxyhal_spi_buffer[1],G_io_seproxyhal_spi_buffer[2])((((G_io_seproxyhal_spi_buffer[1])&0xFFu) << 8) | (
(G_io_seproxyhal_spi_buffer[2])&0xFFu))
+3U) {
1419 LOG("invalid TLV format\n");
1420 G_io_app.apdu_state = APDU_IDLE;
1421 G_io_app.apdu_length = 0;
1422 continue;
1423 }
1424
1425 io_seproxyhal_handle_event();
1426
1427 // An apdu has been received asynchroneously.
1428 if (G_io_app.apdu_state != APDU_IDLE && G_io_app.apdu_length > 0) {
1429#if !defined(HAVE_BOLOS_NO_DEFAULT_APDU)
1430 // If a default command is received and processed within this call,
1431 // then we send the answer.
1432 if (io_process_default_apdus(&channel, &tx_len) == BOLOS_TRUE0xaa) {
1433 goto reply_apdu;
1434 }
1435#endif // ! HAVE_BOLOS_NO_DEFAULT_APDU
1436
1437 return G_io_app.apdu_length;
1438 }
1439 }
1440 break;
1441
1442 default:
1443 return io_exchange_al(channel, tx_len);
1444 }
1445}
1446
1447unsigned int os_io_seph_recv_and_process(unsigned int dont_process_ux_events) {
1448 // send general status before receiving next event
1449 io_seproxyhal_general_status();
1450
1451 io_seproxyhal_spi_recvio_seph_recv(G_io_seproxyhal_spi_buffer, sizeof(G_io_seproxyhal_spi_buffer), 0);
1452
1453 switch (G_io_seproxyhal_spi_buffer[0]) {
1454 case SEPROXYHAL_TAG_FINGER_EVENT0x0C:
1455 case SEPROXYHAL_TAG_BUTTON_PUSH_EVENT0x05:
1456 case SEPROXYHAL_TAG_TICKER_EVENT0x0E:
1457 case SEPROXYHAL_TAG_DISPLAY_PROCESSED_EVENT0x0D:
1458 case SEPROXYHAL_TAG_STATUS_EVENT0x15:
1459 // perform UX event on these ones, don't process as an IO event
1460 if (dont_process_ux_events) {
1461 return 0;
1462 }
1463 __attribute__((fallthrough));
1464
1465 default:
1466 // if malformed, then a stall is likely to occur
1467 if (io_seproxyhal_handle_event()) {
1468 return 1;
1469 }
1470 }
1471 return 0;
1472}
1473
1474#if !defined(APP_UX)
1475unsigned int os_ux_blocking(bolos_ux_params_t* params) {
1476 unsigned int ret;
1477
1478 // until a real status is returned
1479 os_ux(params);
1480 ret = os_sched_last_status(TASK_BOLOS_UX);
1481 while(ret == BOLOS_UX_IGNORE0x97
1482 || ret == BOLOS_UX_CONTINUE0) {
1483 // if the IO task is not running, then need to pump events manually
1484 if (os_sched_is_running(TASK_SUBTASKS_START) != BOLOS_TRUE0xaa) {
1485 // send general status before receiving next event
1486 io_seproxyhal_general_status();
1487 io_seproxyhal_spi_recvio_seph_recv(G_io_seproxyhal_spi_buffer, sizeof(G_io_seproxyhal_spi_buffer), 0);
1488 io_event(0);
1489 }
1490 else
1491 {
1492 // wait until UX takes some process time and update it's status
1493 os_sched_yield(BOLOS_UX_OK0xAA);
1494 }
1495 // only retrieve the current UX state
1496 ret = os_sched_last_status(TASK_BOLOS_UX);
1497 }
1498
1499 return ret;
1500}
1501#endif // !defined(APP_UX)
1502
1503#ifdef HAVE_PRINTF
1504void mcu_usb_prints(const char* str, unsigned int charcount) {
1505 unsigned char buf[4];
1506
1507 buf[0] = SEPROXYHAL_TAG_PRINTF0x5F;
1508 buf[1] = charcount >> 8;
1509 buf[2] = charcount;
1510 io_seproxyhal_spi_sendio_seph_send(buf, 3);
1511 io_seproxyhal_spi_sendio_seph_send((unsigned char*)str, charcount);
1512}
1513#endif // HAVE_PRINTF
1514
1515void io_seproxyhal_io_heartbeat(void) {
1516 io_seproxyhal_general_status();
1517 do {
1518 io_seproxyhal_spi_recvio_seph_recv(G_io_seproxyhal_spi_buffer, sizeof(G_io_seproxyhal_spi_buffer), 0);
1519 // avoid a general status to be replied
1520 if(G_io_seproxyhal_spi_buffer[0] != SEPROXYHAL_TAG_TICKER_EVENT0x0E) {
1521 io_seproxyhal_handle_event();
1522 }
1523 } while (io_seproxyhal_spi_is_status_sentio_seph_is_status_sent());
1524}
1525#endif // OS_IO_SEPROXYHAL
diff --git a/app/output-scan-build/2022-05-16-071046-61-1/scanview.css b/app/output-scan-build/2022-05-16-071046-61-1/scanview.css new file mode 100644 index 00000000..cf8a5a6a --- /dev/null +++ b/app/output-scan-build/2022-05-16-071046-61-1/scanview.css @@ -0,0 +1,62 @@ +body { color:#000000; background-color:#ffffff } +body { font-family: Helvetica, sans-serif; font-size:9pt } +h1 { font-size: 14pt; } +h2 { font-size: 12pt; } +table { font-size:9pt } +table { border-spacing: 0px; border: 1px solid black } +th, table thead { + background-color:#eee; color:#666666; + font-weight: bold; cursor: default; + text-align:center; + font-weight: bold; font-family: Verdana; + white-space:nowrap; +} +.W { font-size:0px } +th, td { padding:5px; padding-left:8px; text-align:left } +td.SUMM_DESC { padding-left:12px } +td.DESC { white-space:pre } +td.Q { text-align:right } +td { text-align:left } +tbody.scrollContent { overflow:auto } + +table.form_group { + background-color: #ccc; + border: 1px solid #333; + padding: 2px; +} + +table.form_inner_group { + background-color: #ccc; + border: 1px solid #333; + padding: 0px; +} + +table.form { + background-color: #999; + border: 1px solid #333; + padding: 2px; +} + +td.form_label { + text-align: right; + vertical-align: top; +} +/* For one line entires */ +td.form_clabel { + text-align: right; + vertical-align: center; +} +td.form_value { + text-align: left; + vertical-align: top; +} +td.form_submit { + text-align: right; + vertical-align: top; +} + +h1.SubmitFail { + color: #f00; +} +h1.SubmitOk { +} diff --git a/app/output-scan-build/2022-05-16-071046-61-1/sorttable.js b/app/output-scan-build/2022-05-16-071046-61-1/sorttable.js new file mode 100644 index 00000000..32faa078 --- /dev/null +++ b/app/output-scan-build/2022-05-16-071046-61-1/sorttable.js @@ -0,0 +1,492 @@ +/* + SortTable + version 2 + 7th April 2007 + Stuart Langridge, http://www.kryogenix.org/code/browser/sorttable/ + + Instructions: + Download this file + Add to your HTML + Add class="sortable" to any table you'd like to make sortable + Click on the headers to sort + + Thanks to many, many people for contributions and suggestions. + Licenced as X11: http://www.kryogenix.org/code/browser/licence.html + This basically means: do what you want with it. +*/ + + +var stIsIE = /*@cc_on!@*/false; + +sorttable = { + init: function() { + // quit if this function has already been called + if (arguments.callee.done) return; + // flag this function so we don't do the same thing twice + arguments.callee.done = true; + // kill the timer + if (_timer) clearInterval(_timer); + + if (!document.createElement || !document.getElementsByTagName) return; + + sorttable.DATE_RE = /^(\d\d?)[\/\.-](\d\d?)[\/\.-]((\d\d)?\d\d)$/; + + forEach(document.getElementsByTagName('table'), function(table) { + if (table.className.search(/\bsortable\b/) != -1) { + sorttable.makeSortable(table); + } + }); + + }, + + makeSortable: function(table) { + if (table.getElementsByTagName('thead').length == 0) { + // table doesn't have a tHead. Since it should have, create one and + // put the first table row in it. + the = document.createElement('thead'); + the.appendChild(table.rows[0]); + table.insertBefore(the,table.firstChild); + } + // Safari doesn't support table.tHead, sigh + if (table.tHead == null) table.tHead = table.getElementsByTagName('thead')[0]; + + if (table.tHead.rows.length != 1) return; // can't cope with two header rows + + // Sorttable v1 put rows with a class of "sortbottom" at the bottom (as + // "total" rows, for example). This is B&R, since what you're supposed + // to do is put them in a tfoot. So, if there are sortbottom rows, + // for backward compatibility, move them to tfoot (creating it if needed). + sortbottomrows = []; + for (var i=0; i5' : ' ▴'; + this.appendChild(sortrevind); + return; + } + if (this.className.search(/\bsorttable_sorted_reverse\b/) != -1) { + // if we're already sorted by this column in reverse, just + // re-reverse the table, which is quicker + sorttable.reverse(this.sorttable_tbody); + this.className = this.className.replace('sorttable_sorted_reverse', + 'sorttable_sorted'); + this.removeChild(document.getElementById('sorttable_sortrevind')); + sortfwdind = document.createElement('span'); + sortfwdind.id = "sorttable_sortfwdind"; + sortfwdind.innerHTML = stIsIE ? ' 6' : ' ▾'; + this.appendChild(sortfwdind); + return; + } + + // remove sorttable_sorted classes + theadrow = this.parentNode; + forEach(theadrow.childNodes, function(cell) { + if (cell.nodeType == 1) { // an element + cell.className = cell.className.replace('sorttable_sorted_reverse',''); + cell.className = cell.className.replace('sorttable_sorted',''); + } + }); + sortfwdind = document.getElementById('sorttable_sortfwdind'); + if (sortfwdind) { sortfwdind.parentNode.removeChild(sortfwdind); } + sortrevind = document.getElementById('sorttable_sortrevind'); + if (sortrevind) { sortrevind.parentNode.removeChild(sortrevind); } + + this.className += ' sorttable_sorted'; + sortfwdind = document.createElement('span'); + sortfwdind.id = "sorttable_sortfwdind"; + sortfwdind.innerHTML = stIsIE ? ' 6' : ' ▾'; + this.appendChild(sortfwdind); + + // build an array to sort. This is a Schwartzian transform thing, + // i.e., we "decorate" each row with the actual sort key, + // sort based on the sort keys, and then put the rows back in order + // which is a lot faster because you only do getInnerText once per row + row_array = []; + col = this.sorttable_columnindex; + rows = this.sorttable_tbody.rows; + for (var j=0; j 12) { + // definitely dd/mm + return sorttable.sort_ddmm; + } else if (second > 12) { + return sorttable.sort_mmdd; + } else { + // looks like a date, but we can't tell which, so assume + // that it's dd/mm (English imperialism!) and keep looking + sortfn = sorttable.sort_ddmm; + } + } + } + } + return sortfn; + }, + + getInnerText: function(node) { + // gets the text we want to use for sorting for a cell. + // strips leading and trailing whitespace. + // this is *not* a generic getInnerText function; it's special to sorttable. + // for example, you can override the cell text with a customkey attribute. + // it also gets .value for fields. + + hasInputs = (typeof node.getElementsByTagName == 'function') && + node.getElementsByTagName('input').length; + + if (node.getAttribute("sorttable_customkey") != null) { + return node.getAttribute("sorttable_customkey"); + } + else if (typeof node.textContent != 'undefined' && !hasInputs) { + return node.textContent.replace(/^\s+|\s+$/g, ''); + } + else if (typeof node.innerText != 'undefined' && !hasInputs) { + return node.innerText.replace(/^\s+|\s+$/g, ''); + } + else if (typeof node.text != 'undefined' && !hasInputs) { + return node.text.replace(/^\s+|\s+$/g, ''); + } + else { + switch (node.nodeType) { + case 3: + if (node.nodeName.toLowerCase() == 'input') { + return node.value.replace(/^\s+|\s+$/g, ''); + } + case 4: + return node.nodeValue.replace(/^\s+|\s+$/g, ''); + break; + case 1: + case 11: + var innerText = ''; + for (var i = 0; i < node.childNodes.length; i++) { + innerText += sorttable.getInnerText(node.childNodes[i]); + } + return innerText.replace(/^\s+|\s+$/g, ''); + break; + default: + return ''; + } + } + }, + + reverse: function(tbody) { + // reverse the rows in a tbody + newrows = []; + for (var i=0; i=0; i--) { + tbody.appendChild(newrows[i]); + } + delete newrows; + }, + + /* sort functions + each sort function takes two parameters, a and b + you are comparing a[0] and b[0] */ + sort_numeric: function(a,b) { + aa = parseFloat(a[0].replace(/[^0-9.-]/g,'')); + if (isNaN(aa)) aa = 0; + bb = parseFloat(b[0].replace(/[^0-9.-]/g,'')); + if (isNaN(bb)) bb = 0; + return aa-bb; + }, + sort_alpha: function(a,b) { + if (a[0]==b[0]) return 0; + if (a[0] 0 ) { + var q = list[i]; list[i] = list[i+1]; list[i+1] = q; + swap = true; + } + } // for + t--; + + if (!swap) break; + + for(var i = t; i > b; --i) { + if ( comp_func(list[i], list[i-1]) < 0 ) { + var q = list[i]; list[i] = list[i-1]; list[i-1] = q; + swap = true; + } + } // for + b++; + + } // while(swap) + } +} + +/* ****************************************************************** + Supporting functions: bundled here to avoid depending on a library + ****************************************************************** */ + +// Dean Edwards/Matthias Miller/John Resig + +/* for Mozilla/Opera9 */ +if (document.addEventListener) { + document.addEventListener("DOMContentLoaded", sorttable.init, false); +} + +/* for Internet Explorer */ +/*@cc_on @*/ +/*@if (@_win32) + document.write(" + + + + +

app - scan-build results

+ + + + + + + +
User:unknown@00d651b2e6fc
Working Directory:/app
Command Line:make default
Clang Version:Ubuntu clang version 12.0.0-3ubuntu1~20.04.5 +
Date:Mon May 16 07:12:32 2022
+

Bug Summary

+ + + + +
Bug TypeQuantityDisplay?
All Bugs1
Dead store
Dead assignment1
+

Reports

+ + + + + + + + + + + + + + + + + +
Bug GroupBug Type ▾FileFunction/MethodLinePath Length
Dead storeDead assignmentos_io_seproxyhal.cio_seproxyhal_display_icon7611View Report
+ + diff --git a/app/output-scan-build/2022-05-16-071232-98-1/report-660403.html b/app/output-scan-build/2022-05-16-071232-98-1/report-660403.html new file mode 100644 index 00000000..87ae1c36 --- /dev/null +++ b/app/output-scan-build/2022-05-16-071232-98-1/report-660403.html @@ -0,0 +1,1880 @@ + + + +/opt/nanosplus-secure-sdk/src/os_io_seproxyhal.c + + + + + + + + + + + + + + + + + + + + + + + + + + +

Bug Summary

+ + + + +
File:os_io_seproxyhal.c
Warning:line 761, column 5
Value stored to 'icon_component' is never read
+ +

Annotated Source Code

+

Press '?' + to see keyboard shortcuts

+ + +
clang -cc1 -cc1 -triple thumbv8m.main-none-unknown-eabi -analyze -disable-free -disable-llvm-verifier -discard-value-names -main-file-name os_io_seproxyhal.c -analyzer-store=region -analyzer-opt-analyze-nested-blocks -analyzer-checker=core -analyzer-checker=apiModeling -analyzer-checker=unix -analyzer-checker=deadcode -analyzer-checker=security.insecureAPI.UncheckedReturn -analyzer-checker=security.insecureAPI.getpw -analyzer-checker=security.insecureAPI.gets -analyzer-checker=security.insecureAPI.mktemp -analyzer-checker=security.insecureAPI.mkstemp -analyzer-checker=security.insecureAPI.vfork -analyzer-checker=nullability.NullPassedToNonnull -analyzer-checker=nullability.NullReturnedFromNonnull -analyzer-output plist -w -setup-static-analyzer -mrelocation-model ropi-rwpi -fropi -frwpi -fhalf-no-semantic-interposition -fno-jump-tables -mframe-pointer=none -fmath-errno -fno-rounding-math -fno-verbose-asm -mconstructor-aliases -nostdsysteminc -target-cpu cortex-m35p -target-feature +soft-float -target-feature +soft-float-abi -target-feature -crc -target-feature -sha2 -target-feature -aes -target-feature -ras -target-feature -sb -target-feature -i8mm -target-feature -lob -target-feature -cdecp0 -target-feature -cdecp1 -target-feature -cdecp2 -target-feature -cdecp3 -target-feature -cdecp4 -target-feature -cdecp5 -target-feature -cdecp6 -target-feature -cdecp7 -target-feature -hwdiv-arm -target-feature +hwdiv -target-feature -dsp -target-feature -vfp2 -target-feature -vfp2sp -target-feature -vfp3 -target-feature -vfp3d16 -target-feature -vfp3d16sp -target-feature -vfp3sp -target-feature -fp16 -target-feature -vfp4 -target-feature -vfp4d16 -target-feature -vfp4d16sp -target-feature -vfp4sp -target-feature -fp-armv8 -target-feature -fp-armv8d16 -target-feature -fp-armv8d16sp -target-feature -fp-armv8sp -target-feature -fullfp16 -target-feature -fp64 -target-feature -d32 -target-feature -neon -target-feature -crypto -target-feature -dotprod -target-feature -fp16fml -target-feature -bf16 -target-feature -mve -target-feature -mve.fp -target-feature -fpregs -target-feature +strict-align -target-feature +no-movt -target-abi aapcs -msoft-float -mfloat-abi soft -fallow-half-arguments-and-returns -fno-split-dwarf-inlining -debugger-tuning=gdb -ffunction-sections -fdata-sections -resource-dir /usr/lib/llvm-12/lib/clang/12.0.0 -D gcc -D __IO=volatile -D NDEBUG -D BAGL_WIDTH=128 -D BAGL_HEIGHT=64 -D HAVE_BAGL_ELLIPSIS -D HAVE_BAGL_FONT_OPEN_SANS_REGULAR_11PX -D HAVE_BAGL_FONT_OPEN_SANS_EXTRABOLD_11PX -D HAVE_BAGL_FONT_OPEN_SANS_LIGHT_16PX -D HAVE_UX_FLOW -D HAVE_SE_SCREEN -D HAVE_SE_BUTTON -D HAVE_MCU_SERIAL_STORAGE -D HAVE_FONTS -D HAVE_BATTERY -D HAVE_NES_CRYPT -D HAVE_ST_EDES_PLUS -D HAVE_ST_AES -D NATIVE_LITTLE_ENDIAN -D HAVE_CRC -D HAVE_HASH -D HAVE_RIPEMD160 -D HAVE_SHA224 -D HAVE_SHA256 -D HAVE_SHA3 -D HAVE_SHA384 -D HAVE_SHA512 -D HAVE_SHA512_WITH_BLOCK_ALT_METHOD -D HAVE_SHA512_WITH_BLOCK_ALT_METHOD_M0 -D HAVE_BLAKE2 -D HAVE_HMAC -D HAVE_PBKDF2 -D HAVE_DES -D HAVE_AES -D HAVE_MATH -D HAVE_RNG -D HAVE_RNG_RFC6979 -D HAVE_RNG_SP800_90A -D HAVE_ECC -D HAVE_ECC_WEIERSTRASS -D HAVE_ECC_TWISTED_EDWARDS -D HAVE_ECC_MONTGOMERY -D HAVE_SECP256K1_CURVE -D HAVE_SECP256R1_CURVE -D HAVE_SECP384R1_CURVE -D HAVE_SECP521R1_CURVE -D HAVE_FR256V1_CURVE -D HAVE_STARK256_CURVE -D HAVE_BRAINPOOL_P256R1_CURVE -D HAVE_BRAINPOOL_P256T1_CURVE -D HAVE_BRAINPOOL_P320R1_CURVE -D HAVE_BRAINPOOL_P320T1_CURVE -D HAVE_BRAINPOOL_P384R1_CURVE -D HAVE_BRAINPOOL_P384T1_CURVE -D HAVE_BRAINPOOL_P512R1_CURVE -D HAVE_BRAINPOOL_P512T1_CURVE -D HAVE_BLS12_381_G1_CURVE -D HAVE_CV25519_CURVE -D HAVE_CV448_CURVE -D HAVE_ED25519_CURVE -D HAVE_ED448_CURVE -D HAVE_ECDH -D HAVE_ECDSA -D HAVE_EDDSA -D HAVE_ECSCHNORR -D HAVE_X25519 -D HAVE_X448 -D HAVE_AES_GCM -D HAVE_AEAD -D APP_CONSUMER -D UNUSED(x)=(void)x -D PRINTF(...)= -D APPVERSION="0.9.13" -D OS_IO_SEPROXYHAL -D HAVE_BAGL -D HAVE_SPRINTF -D HAVE_IO_USB -D HAVE_L4_USBLIB -D IO_USB_MAX_ENDPOINTS=7 -D IO_HID_EP_LENGTH=64 -D HAVE_USB_APDU -D LEDGER_MAJOR_VERSION=0 -D LEDGER_MINOR_VERSION=9 -D LEDGER_PATCH_VERSION=13 -D USB_SEGMENT_SIZE=64 -D HAVE_BOLOS_APP_STACK_CANARY -D HAVE_WEBUSB -D WEBUSB_URL_SIZE_B=0 -D WEBUSB_URL= -D IO_SEPROXYHAL_BUFFER_SIZE_B=300 -D HAVE_GLO096 -D HAVE_BAGL -D BAGL_WIDTH=128 -D BAGL_HEIGHT=64 -D HAVE_BAGL_ELLIPSIS -D HAVE_BAGL_FONT_OPEN_SANS_REGULAR_11PX -D HAVE_BAGL_FONT_OPEN_SANS_EXTRABOLD_11PX -D HAVE_BAGL_FONT_OPEN_SANS_LIGHT_16PX -D HAVE_UX_FLOW -D LEDGER_SPECIFIC -I .//glyphs -I /opt/nanosplus-secure-sdk/lib_cxng/include -I /opt/nanosplus-secure-sdk/lib_stusb/ -I /opt/nanosplus-secure-sdk/lib_stusb/STM32_USB_Device_Library/Class/CCID/inc/ -I /opt/nanosplus-secure-sdk/lib_stusb/STM32_USB_Device_Library/Class/CCID/inc/ -I /opt/nanosplus-secure-sdk/lib_stusb/STM32_USB_Device_Library/Class/CCID/inc/ -I /opt/nanosplus-secure-sdk/lib_stusb/STM32_USB_Device_Library/Class/CCID/inc/ -I /opt/nanosplus-secure-sdk/lib_stusb/STM32_USB_Device_Library/Class/HID/Inc/ -I /opt/nanosplus-secure-sdk/lib_stusb/STM32_USB_Device_Library/Core/Inc/ -I /opt/nanosplus-secure-sdk/lib_stusb/STM32_USB_Device_Library/Core/Inc/ -I /opt/nanosplus-secure-sdk/lib_stusb/STM32_USB_Device_Library/Core/Inc/ -I /opt/nanosplus-secure-sdk/lib_stusb/STM32_USB_Device_Library/Core/Inc/ -I /opt/nanosplus-secure-sdk/lib_stusb/STM32_USB_Device_Library/Core/Inc/ -I /opt/nanosplus-secure-sdk/lib_stusb_impl/ -I /opt/nanosplus-secure-sdk/lib_stusb_impl/ -I /opt/nanosplus-secure-sdk/lib_stusb_impl/ -I /opt/nanosplus-secure-sdk/lib_ux/include/ -I /opt/nanosplus-secure-sdk/lib_ux/include/ -I /opt/nanosplus-secure-sdk/lib_ux/include/ -I /opt/nanosplus-secure-sdk/lib_ux/include/ -I /opt/nanosplus-secure-sdk/lib_ux/src/ -I include -I /opt/nanosplus-secure-sdk/include -I /opt/nanosplus-secure-sdk/include/arm -I .//src/ -I .//src/json/ -I .//src/ -I .//src/ -I .//src/ -I .//src/ -I .//src/ -I .//src/ -I .//src/ -I .//src/ -I .//src/ -I .//src/ -I .//src/ -I .//src/common/ -I .//src/common/ -I .//src/common/ -I .//../deps/ledger-zxlib/include/ -I .//../deps/ledger-zxlib/include/ -I .//../deps/ledger-zxlib/include/ -I .//../deps/ledger-zxlib/include/ -I .//../deps/ledger-zxlib/include/ -I .//../deps/ledger-zxlib/include/ -I .//../deps/ledger-zxlib/include/ -I .//../deps/ledger-zxlib/include/ -I .//../deps/ledger-zxlib/include/ -I .//../deps/ledger-zxlib/include/ -I .//../deps/ledger-zxlib/include/ -I .//../deps/ledger-zxlib/include/ -I .//../deps/ledger-zxlib/include/ -I .//../deps/ledger-zxlib/include/ -I .//../deps/ledger-zxlib/include/ -I .//../deps/ledger-zxlib/include/ -I .//../deps/ledger-zxlib/include/ -I .//../deps/ledger-zxlib/include/ -I .//../deps/ledger-zxlib/include/ -I .//../deps/ledger-zxlib/include/ -I .//../deps/ledger-zxlib/include/ -I .//../deps/ledger-zxlib/include/ -I .//../deps/ledger-zxlib/app/common/ -I .//../deps/ledger-zxlib/app/common/ -I .//../deps/jsmn/src/ -isysroot /opt/gcc-arm-none-eabi-10.3-2021.10/bin/../arm-none-eabi -internal-isystem /usr/lib/llvm-12/lib/clang/12.0.0/include -internal-isystem /opt/gcc-arm-none-eabi-10.3-2021.10/bin/../arm-none-eabi/include -Os -Wno-main -Wno-unknown-pragmas -std=gnu99 -fdebug-compilation-dir /app -ferror-limit 19 -fshort-enums -fno-signed-char -fgnuc-version=4.2.1 -vectorize-loops -vectorize-slp -analyzer-checker security -analyzer-checker unix -analyzer-checker valist -analyzer-opt-analyze-headers -analyzer-output=html -faddrsig -o /app/output-scan-build/2022-05-16-071232-98-1 -x c /opt/nanosplus-secure-sdk/src/os_io_seproxyhal.c +
+ + + +
+ + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
1
2/*******************************************************************************
3* Ledger Nano S - Secure firmware
4* (c) 2022 Ledger
5*
6* Licensed under the Apache License, Version 2.0 (the "License");
7* you may not use this file except in compliance with the License.
8* You may obtain a copy of the License at
9*
10* http://www.apache.org/licenses/LICENSE-2.0
11*
12* Unless required by applicable law or agreed to in writing, software
13* distributed under the License is distributed on an "AS IS" BASIS,
14* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
15* See the License for the specific language governing permissions and
16* limitations under the License.
17********************************************************************************/
18
19#include "bolos_target.h"
20
21#ifdef TARGET_NANOX
22#ifndef HAVE_SEPROXYHAL_MCU
23# define HAVE_SEPROXYHAL_MCU
24#endif // HAVE_SEPROXYHAL_MCU
25#ifndef HAVE_MCU_PROTECT
26#define HAVE_MCU_PROTECT
27#endif // HAVE_MCU_PROTECT
28#endif // TARGET_NANOX
29
30#include "errors.h"
31#include "exceptions.h"
32#include "os_apdu.h"
33#include "os_apilevel.h"
34
35#if defined(DEBUG_OS_STACK_CONSUMPTION)
36# include "os_debug.h"
37#endif // DEBUG_OS_STACK_CONSUMPTION
38
39#include "os_id.h"
40#include "os_io.h"
41#include "os_io_usb.h"
42#include "os_pic.h"
43#include "os_pin.h"
44#include "os_registry.h"
45#include "os_seed.h"
46#include "os_utils.h"
47#include <string.h>
48
49#ifdef OS_IO_SEPROXYHAL1
50
51#include "os_io_seproxyhal.h"
52
53#ifdef HAVE_BLE
54#include "ledger_ble.h"
55#endif // HAVE_BLE
56
57#include "ux.h"
58#include "checks.h"
59
60#ifdef HAVE_IO_U2F
61#include "u2f_processing.h"
62#include "u2f_transport.h"
63#endif
64
65#ifndef VERSION"dummy"
66#define VERSION"dummy" "dummy"
67#endif // VERSION
68
69#ifdef DEBUG
70#define LOG printf
71#else
72#define LOG(...)
73#endif
74
75#ifdef HAVE_IO_USB1
76#ifdef HAVE_L4_USBLIB1
77#include "usbd_def.h"
78#include "usbd_core.h"
79extern USBD_HandleTypeDef USBD_Device;
80#endif
81#endif
82
83#if !defined(HAVE_BOLOS_NO_DEFAULT_APDU)
84# define DEFAULT_APDU_CLA0xB0 0xB0
85# define DEFAULT_APDU_INS_GET_VERSION0x01 0x01
86
87# if defined(HAVE_SEED_COOKIE)
88# define DEFAULT_APDU_INS_GET_SEED_COOKIE 0x02
89# endif
90
91# if defined(DEBUG_OS_STACK_CONSUMPTION)
92# define DEFAULT_APDU_INS_STACK_CONSUMPTION 0x57
93# endif // DEBUG_OS_STACK_CONSUMPTION
94
95# define DEFAULT_APDU_INS_APP_EXIT0xA7 0xA7
96#endif // !HAVE_BOLOS_NO_DEFAULT_APDU
97
98void io_seproxyhal_handle_ble_event(void);
99
100unsigned int os_io_seph_recv_and_process(unsigned int dont_process_ux_events);
101
102#ifndef HAVE_BOLOS
103io_seph_app_t G_io_app;
104#endif // ! HAVE_BOLOS
105
106 // usb endpoint buffer
107unsigned char G_io_usb_ep_buffer[MAX(USB_SEGMENT_SIZE, BLE_SEGMENT_SIZE)((64) > (64) ? (64) : (64))];
108
109ux_seph_os_and_app_t G_ux_os;
110
111#ifndef IO_RAPDU_TRANSMIT_TIMEOUT_MS2000UL
112#define IO_RAPDU_TRANSMIT_TIMEOUT_MS2000UL 2000UL
113#endif // IO_RAPDU_TRANSMIT_TIMEOUT_MS
114
115static const unsigned char seph_io_general_status[]= {
116 SEPROXYHAL_TAG_GENERAL_STATUS0x60,
117 0,
118 2,
119 SEPROXYHAL_TAG_GENERAL_STATUS_LAST_COMMAND0x0000>>8,
120 SEPROXYHAL_TAG_GENERAL_STATUS_LAST_COMMAND0x0000,
121};
122void io_seproxyhal_general_status(void) {
123 // send the general status
124 io_seproxyhal_spi_sendio_seph_send(seph_io_general_status, sizeof(seph_io_general_status));
125}
126
127static const unsigned char seph_io_request_status[]= {
128 SEPROXYHAL_TAG_REQUEST_STATUS0x52,
129 0,
130 0,
131};
132void io_seproxyhal_request_mcu_status(void) {
133 // send the general status
134 io_seproxyhal_spi_sendio_seph_send(seph_io_request_status, sizeof(seph_io_request_status));
135}
136
137#ifdef HAVE_IO_USB1
138#ifdef HAVE_L4_USBLIB1
139
140void io_seproxyhal_handle_usb_event(void) {
141 switch(G_io_seproxyhal_spi_buffer[3]) {
142 case SEPROXYHAL_TAG_USB_EVENT_RESET0x01:
143 USBD_LL_SetSpeed(&USBD_Device, USBD_SPEED_FULL);
144 USBD_LL_Reset(&USBD_Device);
145 // ongoing APDU detected, throw a reset, even if not the media. to avoid potential troubles.
146 if (G_io_app.apdu_media != IO_APDU_MEDIA_NONE) {
147 THROW(EXCEPTION_IO_RESET)os_longjmp(0x5);
148 }
149 memset(G_io_app.usb_ep_xfer_len, 0, sizeof(G_io_app.usb_ep_xfer_len));
150 memset(G_io_app.usb_ep_timeouts, 0, sizeof(G_io_app.usb_ep_timeouts));
151 break;
152 case SEPROXYHAL_TAG_USB_EVENT_SOF0x02:
153 USBD_LL_SOF(&USBD_Device);
154 break;
155 case SEPROXYHAL_TAG_USB_EVENT_SUSPENDED0x04:
156 USBD_LL_Suspend(&USBD_Device);
157 break;
158 case SEPROXYHAL_TAG_USB_EVENT_RESUMED0x08:
159 USBD_LL_Resume(&USBD_Device);
160 break;
161 }
162}
163
164uint16_t io_seproxyhal_get_ep_rx_size(uint8_t epnum) {
165 if ((epnum & 0x7F) < IO_USB_MAX_ENDPOINTS7) {
166 return G_io_app.usb_ep_xfer_len[epnum&0x7F];
167 }
168 return 0;
169}
170
171void io_seproxyhal_handle_usb_ep_xfer_event(void) {
172 uint8_t epnum;
173
174 epnum = G_io_seproxyhal_spi_buffer[3] & 0x7F;
175
176 switch(G_io_seproxyhal_spi_buffer[4]) {
177 /* This event is received when a new SETUP token had been received on a control endpoint */
178 case SEPROXYHAL_TAG_USB_EP_XFER_SETUP0x01:
179 // assume length of setup packet, and that it is on endpoint 0
180 USBD_LL_SetupStage(&USBD_Device, &G_io_seproxyhal_spi_buffer[6]);
181 break;
182
183 /* This event is received after the prepare data packet has been flushed to the usb host */
184 case SEPROXYHAL_TAG_USB_EP_XFER_IN0x02:
185 if (epnum < IO_USB_MAX_ENDPOINTS7) {
186 // discard ep timeout as we received the sent packet confirmation
187 G_io_app.usb_ep_timeouts[epnum].timeout = 0;
188 // propagate sending ack of the data
189 USBD_LL_DataInStage(&USBD_Device, epnum, &G_io_seproxyhal_spi_buffer[6]);
190 }
191 break;
192
193 /* This event is received when a new DATA token is received on an endpoint */
194 case SEPROXYHAL_TAG_USB_EP_XFER_OUT0x04:
195 if (epnum < IO_USB_MAX_ENDPOINTS7) {
196 // saved just in case it is needed ...
197#if IO_SEPROXYHAL_BUFFER_SIZE_B300 - 6 >= 256
198 G_io_app.usb_ep_xfer_len[epnum] = G_io_seproxyhal_spi_buffer[5];
199#else
200 G_io_app.usb_ep_xfer_len[epnum] = MIN(G_io_seproxyhal_spi_buffer[5], IO_SEPROXYHAL_BUFFER_SIZE_B - 6)((G_io_seproxyhal_spi_buffer[5]) < (300 - 6) ? (G_io_seproxyhal_spi_buffer
[5]) : (300 - 6))
;
201#endif
202 // prepare reception
203 USBD_LL_DataOutStage(&USBD_Device, epnum, &G_io_seproxyhal_spi_buffer[6]);
204 }
205 break;
206 }
207}
208
209#else
210//no usb lib: X86 for example
211
212void io_seproxyhal_handle_usb_event(void) {
213}
214void io_seproxyhal_handle_usb_ep_xfer_event(void) {
215}
216
217#endif // HAVE_L4_USBLIB
218
219// TODO, refactor this using the USB DataIn event like for the U2F tunnel
220// TODO add a blocking parameter, for HID KBD sending, or use a USB busy flag per channel to know if
221// the transfer has been processed or not. and move on to the next transfer on the same endpoint
222void io_usb_send_ep(unsigned int ep, unsigned char* buffer, unsigned short length, unsigned int timeout) {
223
224 // don't spoil the timeout :)
225 if (timeout) {
226 timeout++;
227 }
228
229 // won't send if overflowing seproxyhal buffer format
230 if (length > 255) {
231 return;
232 }
233
234 G_io_seproxyhal_spi_buffer[0] = SEPROXYHAL_TAG_USB_EP_PREPARE0x50;
235 G_io_seproxyhal_spi_buffer[1] = (3+length)>>8;
236 G_io_seproxyhal_spi_buffer[2] = (3+length);
237 G_io_seproxyhal_spi_buffer[3] = ep|0x80;
238 G_io_seproxyhal_spi_buffer[4] = SEPROXYHAL_TAG_USB_EP_PREPARE_DIR_IN0x20;
239 G_io_seproxyhal_spi_buffer[5] = length;
240 io_seproxyhal_spi_sendio_seph_send(G_io_seproxyhal_spi_buffer, 6);
241 io_seproxyhal_spi_sendio_seph_send(buffer, length);
242 // setup timeout of the endpoint
243 G_io_app.usb_ep_timeouts[ep&0x7F].timeout = IO_RAPDU_TRANSMIT_TIMEOUT_MS2000UL;
244}
245
246void io_usb_send_apdu_data(unsigned char* buffer, unsigned short length) {
247 // wait for 20 events before hanging up and timeout (~2 seconds of timeout)
248 io_usb_send_ep(0x82, buffer, length, 20);
249}
250
251#ifdef HAVE_WEBUSB1
252void io_usb_send_apdu_data_ep0x83(unsigned char* buffer, unsigned short length) {
253 // wait for 20 events before hanging up and timeout (~2 seconds of timeout)
254 io_usb_send_ep(0x83, buffer, length, 20);
255}
256#endif // HAVE_WEBUSB
257
258#endif // HAVE_IO_USB
259
260void io_seproxyhal_handle_capdu_event(void) {
261 if (G_io_app.apdu_state == APDU_IDLE) {
262 size_t max = MIN(sizeof(G_io_apdu_buffer)-3, sizeof(G_io_seproxyhal_spi_buffer)-3)((sizeof(G_io_apdu_buffer)-3) < (sizeof(G_io_seproxyhal_spi_buffer
)-3) ? (sizeof(G_io_apdu_buffer)-3) : (sizeof(G_io_seproxyhal_spi_buffer
)-3))
;
263 size_t size = U2BE(G_io_seproxyhal_spi_buffer, 1);
264
265 G_io_app.apdu_media = IO_APDU_MEDIA_RAW; // for application code
266 G_io_app.apdu_state = APDU_RAW; // for next call to io_exchange
267 G_io_app.apdu_length = MIN(size, max)((size) < (max) ? (size) : (max));
268 // copy apdu to apdu buffer
269 memcpy(G_io_apdu_buffer, G_io_seproxyhal_spi_buffer+3, G_io_app.apdu_length);
270 }
271}
272
273unsigned int io_seproxyhal_handle_event(void) {
274#if defined(HAVE_IO_USB1) || defined(HAVE_BLE)
275 unsigned int rx_len = U2BE(G_io_seproxyhal_spi_buffer, 1);
276#endif
277
278 switch(G_io_seproxyhal_spi_buffer[0]) {
279 #ifdef HAVE_IO_USB1
280 case SEPROXYHAL_TAG_USB_EVENT0x0F:
281 if (rx_len != 1) {
282 return 0;
283 }
284 io_seproxyhal_handle_usb_event();
285 return 1;
286
287 case SEPROXYHAL_TAG_USB_EP_XFER_EVENT0x10:
288 if (rx_len < 3) {
289 // error !
290 return 0;
291 }
292 io_seproxyhal_handle_usb_ep_xfer_event();
293 return 1;
294 #endif // HAVE_IO_USB
295
296 #ifdef HAVE_BLE
297 case SEPROXYHAL_TAG_BLE_RECV_EVENT0x18:
298 LEDGER_BLE_receive();
299 return 1;
300 #endif // HAVE_BLE
301
302 case SEPROXYHAL_TAG_UX_EVENT0x1A:
303 switch (G_io_seproxyhal_spi_buffer[3]) {
304
305#ifdef HAVE_BLE
306 case SEPROXYHAL_TAG_UX_CMD_BLE_DISABLE_ADV0x00:
307 LEDGER_BLE_enable_advertising(0);
308 return 1;
309 break;
310
311 case SEPROXYHAL_TAG_UX_CMD_BLE_ENABLE_ADV0x01:
312 LEDGER_BLE_enable_advertising(1);
313 return 1;
314 break;
315
316 case SEPROXYHAL_TAG_UX_CMD_BLE_RESET_PAIRINGS0x02:
317 LEDGER_BLE_reset_pairings();
318 return 1;
319 break;
320#endif // HAVE_BLE
321
322#ifndef HAVE_BOLOS
323 case SEPROXYHAL_TAG_UX_CMD_REDISPLAY0x03:
324 ux_stack_redisplay();
325 return 1;
326 break;
327#endif // HAVE_BOLOS
328
329 default:
330 return io_event(CHANNEL_SPI2);
331 break;
332 }
333 break;
334
335 case SEPROXYHAL_TAG_CAPDU_EVENT0x16:
336 io_seproxyhal_handle_capdu_event();
337 return 1;
338
339 // ask the user if not processed here
340 case SEPROXYHAL_TAG_TICKER_EVENT0x0E:
341 // process ticker events to timeout the IO transfers, and forward to the user io_event function too
342 G_io_app.ms += 100; // value is by default, don't change the ticker configuration
343#ifdef HAVE_IO_USB1
344 {
345 unsigned int i = IO_USB_MAX_ENDPOINTS7;
346 while(i--) {
347 if (G_io_app.usb_ep_timeouts[i].timeout) {
348 G_io_app.usb_ep_timeouts[i].timeout-=MIN(G_io_app.usb_ep_timeouts[i].timeout, 100)((G_io_app.usb_ep_timeouts[i].timeout) < (100) ? (G_io_app
.usb_ep_timeouts[i].timeout) : (100))
;
349 if (!G_io_app.usb_ep_timeouts[i].timeout) {
350 // timeout !
351 G_io_app.apdu_state = APDU_IDLE;
352 THROW(EXCEPTION_IO_RESET)os_longjmp(0x5);
353 }
354 }
355 }
356 }
357#endif // HAVE_IO_USB
358#ifdef HAVE_BLE_APDU
359 {
360 if (G_io_app.ble_xfer_timeout) {
361 G_io_app.ble_xfer_timeout -= MIN(G_io_app.ble_xfer_timeout, 100)((G_io_app.ble_xfer_timeout) < (100) ? (G_io_app.ble_xfer_timeout
) : (100))
;
362 if (!G_io_app.ble_xfer_timeout) {
363 G_io_app.apdu_state = APDU_IDLE;
364 THROW(EXCEPTION_IO_RESET)os_longjmp(0x5);
365 }
366 }
367 }
368#endif // HAVE_BLE_APDU
369 __attribute__((fallthrough));
370 // no break is intentional
371 default:
372 return io_event(CHANNEL_SPI2);
373 }
374 // defaultly return as not processed
375 return 0;
376}
377
378//#define DEBUG_APDU
379#ifdef DEBUG_APDU
380volatile unsigned int debug_apdus_offset;
381const char debug_apdus[] = {
382 5, 0xE0, 0x40, 0x00, 0x00, 0x00,
383 //9, 0xe0, 0x22, 0x00, 0x00, 0x04, 0x31, 0x32, 0x33, 0x34,
384};
385#endif // DEBUG_APDU
386
387#ifdef HAVE_BOLOS_APP_STACK_CANARY1
388#define APP_STACK_CANARY_MAGIC0xDEAD0031 0xDEAD0031
389extern unsigned int app_stack_canary;
390#endif // HAVE_BOLOS_APP_STACK_CANARY
391
392#if (!defined(HAVE_BOLOS) && defined(HAVE_MCU_PROTECT))
393static const unsigned char seph_io_mcu_protect[]= {
394 SEPROXYHAL_TAG_MCU,
395 0,
396 1,
397 SEPROXYHAL_TAG_MCU_TYPE_PROTECT,
398};
399#endif // (!defined(HAVE_BOLOS) && defined(HAVE_MCU_PROTECT))
400
401void io_seproxyhal_init(void) {
402#ifndef HAVE_BOLOS
403 // Enforce OS compatibility
404 check_api_level(CX_COMPAT_APILEVEL12);
405
406#ifdef HAVE_MCU_PROTECT
407 // engage RDP2 on MCU
408 io_seproxyhal_spi_sendio_seph_send(seph_io_mcu_protect, sizeof(seph_io_mcu_protect));
409#endif // HAVE_MCU_PROTECT
410#endif // HAVE_BOLOS
411
412#ifdef HAVE_BOLOS_APP_STACK_CANARY1
413 app_stack_canary = APP_STACK_CANARY_MAGIC0xDEAD0031;
414#endif // HAVE_BOLOS_APP_STACK_CANARY
415
416 // wipe the io structure before it's used
417#ifdef HAVE_BLE
418 unsigned int plane = G_io_app.plane_mode;
419#endif // HAVE_BLE
420 memset(&G_io_app, 0, sizeof(G_io_app));
421#ifdef HAVE_BLE
422 G_io_app.plane_mode = plane;
423#endif // HAVE_BLE
424
425 G_io_app.apdu_state = APDU_IDLE;
426 G_io_app.apdu_length = 0;
427 G_io_app.apdu_media = IO_APDU_MEDIA_NONE;
428
429 G_io_app.ms = 0;
430
431 #ifdef DEBUG_APDU
432 debug_apdus_offset = 0;
433 #endif // DEBUG_APDU
434
435 #ifdef HAVE_USB_APDU1
436 io_usb_hid_init();
437 #endif // HAVE_USB_APDU
438
439 io_seproxyhal_init_ux();
440 io_seproxyhal_init_button();
441
442#if !defined(HAVE_BOLOS) && defined(HAVE_PENDING_REVIEW_SCREEN)
443 check_audited_app();
444#endif // !defined(HAVE_BOLOS) && defined(HAVE_PENDING_REVIEW_SCREEN)
445}
446
447void io_seproxyhal_init_ux(void) {
448#ifdef TARGET_BLUE
449 // initialize the touch part
450 G_ux_os.last_touched_not_released_component = NULL((void*)0);
451#endif // TARGET_BLUE
452}
453
454void io_seproxyhal_init_button(void) {
455 // no button push so far
456 G_ux_os.button_mask = 0;
457 G_ux_os.button_same_mask_counter = 0;
458}
459
460#ifdef HAVE_BAGL1
461
462#ifdef TARGET_BLUE
463unsigned int io_seproxyhal_touch_out(const bagl_element_t* element, bagl_element_callback_t before_display) {
464 const bagl_element_t* el;
465 if (element->out != NULL((void*)0)) {
466 el = (const bagl_element_t*)PIC(((bagl_element_callback_t)PIC(element->out))(element))pic((void *)((bagl_element_callback_t)pic((void *)element->
out))(element))
;
467 // backward compatible with samples and such
468 if (! el) {
469 return 0;
470 }
471 if ((unsigned int)el != 1) {
472 element = el;
473 }
474 }
475
476 // out function might have triggered a draw of its own during a display callback
477 if (before_display) {
478 el = before_display(element);
479 if (!el) {
480 return 0;
481 }
482 if ((unsigned int)el != 1) {
483 element = el;
484 }
485 }
486
487 io_seproxyhal_display(element);
488 return 1;
489}
490
491unsigned int io_seproxyhal_touch_over(const bagl_element_t* element, bagl_element_callback_t before_display) {
492 bagl_element_t e;
493 const bagl_element_t* el;
494 if (element->over != NULL((void*)0)) {
495 el = (const bagl_element_t*)PIC(((bagl_element_callback_t)PIC(element->over))(element))pic((void *)((bagl_element_callback_t)pic((void *)element->
over))(element))
;
496 // backward compatible with samples and such
497 if (!el) {
498 return 0;
499 }
500 if ((unsigned int)el != 1) {
501 element = el;
502 }
503 }
504
505 // over function might have triggered a draw of its own during a display callback
506 if (before_display) {
507 el = before_display(element);
508 element = &e;
509 if (!el) {
510 return 0;
511 }
512 // problem for default screen_before_before_display where we return the given element, it have could been modified. but we don't know here
513 if ((unsigned int)el != 1) {
514 element = el;
515 }
516 }
517
518 // swap colors
519 memcpy(&e, element, sizeof(bagl_element_t));
520 e.component.fgcolor = element->overfgcolor;
521 e.component.bgcolor = element->overbgcolor;
522
523 io_seproxyhal_display(&e);
524 return 1;
525}
526
527unsigned int io_seproxyhal_touch_tap(const bagl_element_t* element, bagl_element_callback_t before_display) {
528 const bagl_element_t* el;
529 if (element->tap != NULL((void*)0)) {
530 el = (const bagl_element_t*)PIC(((bagl_element_callback_t)PIC(element->tap))(element))pic((void *)((bagl_element_callback_t)pic((void *)element->
tap))(element))
;
531 // backward compatible with samples and such
532 if (!el) {
533 return 0;
534 }
535 if ((unsigned int)el != 1) {
536 element = el;
537 }
538 }
539
540 // tap function might have triggered a draw of its own during a display callback
541 if (before_display) {
542 el = before_display(element);
543 if (!el) {
544 return 0;
545 }
546 if ((unsigned int)el != 1) {
547 element = el;
548 }
549 }
550 io_seproxyhal_display(element);
551 return 1;
552}
553
554void io_seproxyhal_touch(const bagl_element_t* elements, unsigned short element_count, unsigned short x, unsigned short y, unsigned char event_kind) {
555 io_seproxyhal_touch_element_callback(elements, element_count, x, y, event_kind, NULL((void*)0));
556}
557
558// browse all elements and until an element has changed state, continue browsing
559// return if processed or not
560void io_seproxyhal_touch_element_callback(const bagl_element_t* elements, unsigned short element_count, unsigned short x, unsigned short y, unsigned char event_kind, bagl_element_callback_t before_display) {
561 unsigned char comp_idx;
562 unsigned char last_touched_not_released_component_was_in_current_array = 0;
563
564 // find the first empty entry
565 for (comp_idx=0; comp_idx < element_count; comp_idx++) {
566 // process all components matching the x/y/w/h (no break) => fishy for the released out of zone
567 // continue processing only if a status has not been sent
568 if (io_seproxyhal_spi_is_status_sentio_seph_is_status_sent()) {
569 // continue instead of return to process all elemnts and therefore discard last touched element
570 break;
571 }
572
573 // only perform out callback when element was in the current array, else, leave it be
574 if (&elements[comp_idx] == G_ux_os.last_touched_not_released_component) {
575 last_touched_not_released_component_was_in_current_array = 1;
576 }
577
578 // the first component drawn with a
579 if ((elements[comp_idx].component.type & BAGL_FLAG_TOUCHABLE)
580 && elements[comp_idx].component.x-elements[comp_idx].touch_area_brim <= x && x<elements[comp_idx].component.x+elements[comp_idx].component.width+elements[comp_idx].touch_area_brim
581 && elements[comp_idx].component.y-elements[comp_idx].touch_area_brim <= y && y<elements[comp_idx].component.y+elements[comp_idx].component.height+elements[comp_idx].touch_area_brim) {
582
583 // outing the previous over'ed component
584 if (&elements[comp_idx] != G_ux_os.last_touched_not_released_component
585 && G_ux_os.last_touched_not_released_component != NULL((void*)0)) {
586 // only out the previous element if the newly matching will be displayed
587 if (!before_display || before_display(&elements[comp_idx])) {
588 if (io_seproxyhal_touch_out(G_ux_os.last_touched_not_released_component, before_display)) {
589 // previous component is considered released
590 G_ux_os.last_touched_not_released_component = NULL((void*)0);
591 // a display has been issued, avoid double display, wait for another touch event (20ms)
592 return;
593 }
594 }
595 // avoid a non displayed new element to pop out of the blue
596 continue;
597 }
598
599 /*
600 if (io_seproxyhal_spi_is_status_sent()) {
601 // continue instead of return to process all elements and therefore discard last touched element
602 continue;
603 }
604 */
605
606 // callback the hal to notify the component impacted by the user input
607 else if (event_kind == SEPROXYHAL_TAG_FINGER_EVENT_RELEASE0x02) {
608 if (io_seproxyhal_touch_tap(&elements[comp_idx], before_display)) {
609 // unmark the last component, we've been notified TOUCH
610 G_ux_os.last_touched_not_released_component = NULL((void*)0);
611 return;
612 }
613 }
614 else if (event_kind == SEPROXYHAL_TAG_FINGER_EVENT_TOUCH0x01) {
615 // ask for overing
616 if (io_seproxyhal_touch_over(&elements[comp_idx], before_display)) {
617 // remember the last touched component
618 G_ux_os.last_touched_not_released_component = &elements[comp_idx];
619 return;
620 }
621 }
622 }
623 }
624
625 // if overing out of component or over another component, the out event is sent after the over event of the previous component
626 if(last_touched_not_released_component_was_in_current_array
627 && G_ux_os.last_touched_not_released_component != NULL((void*)0)) {
628
629 // we won't be able to notify the out, don't do it, in case a diplay refused the dra of the relased element and the position matched another element of the array (in autocomplete for example)
630 if (io_seproxyhal_spi_is_status_sentio_seph_is_status_sent()) {
631 return;
632 }
633
634 if (io_seproxyhal_touch_out(G_ux_os.last_touched_not_released_component, before_display)) {
635 // ok component out has been emitted
636 G_ux_os.last_touched_not_released_component = NULL((void*)0);
637 }
638 }
639
640 // not processed
641}
642#endif // TARGET_BLUE
643
644void io_seproxyhal_display_bitmap(int x, int y, unsigned int w, unsigned int h, unsigned int* color_index, unsigned int bit_per_pixel, unsigned char* bitmap) {
645 // component type = ICON
646 // component icon id = 0
647 // => bitmap transmitted
648 if (w && h) {
649 bagl_component_t c;
650 bagl_icon_details_t d;
651 memset(&c, 0, sizeof(c));
652 c.type = BAGL_ICON;
653 c.x = x;
654 c.y = y;
655 c.width = w;
656 c.height = h;
657 // done by memset // c.icon_id = 0;
658 d.width = w;
659 d.height = h;
660 d.bpp = bit_per_pixel;
661 d.colors = color_index;
662 d.bitmap = bitmap;
663
664 io_seproxyhal_display_icon(&c, &d);
665 /*
666 // color index size
667 h = ((1<<bit_per_pixel)*sizeof(unsigned int));
668 // bitmap size
669 w = ((w*c.height*bit_per_pixel)/8)+((w*c.height*bit_per_pixel)%8?1:0);
670 unsigned short length = sizeof(bagl_component_t)
671 +1 // bpp
672 +h // color index
673 +w; // image bitmap
674 G_io_seproxyhal_spi_buffer[0] = SEPROXYHAL_TAG_SCREEN_DISPLAY_STATUS;
675 G_io_seproxyhal_spi_buffer[1] = length>>8;
676 G_io_seproxyhal_spi_buffer[2] = length;
677 io_seproxyhal_spi_send(G_io_seproxyhal_spi_buffer, 3);
678 io_seproxyhal_spi_send((unsigned char*)&c, sizeof(bagl_component_t));
679 G_io_seproxyhal_spi_buffer[0] = bit_per_pixel;
680 io_seproxyhal_spi_send(G_io_seproxyhal_spi_buffer, 1);
681 io_seproxyhal_spi_send((unsigned char*)color_index, h);
682 io_seproxyhal_spi_send(bitmap, w);
683 */
684 }
685}
686
687#ifdef SEPROXYHAL_TAG_SCREEN_DISPLAY_RAW_STATUS
688unsigned int io_seproxyhal_display_icon_header_and_colors(const bagl_component_t* icon_component, const bagl_icon_details_t* icon_details, unsigned int* icon_len) {
689 unsigned int len;
690
691 struct display_raw_s {
692 struct {
693 struct {
694 unsigned char tag;
695 unsigned char len[2];
696 } seph;
697 unsigned char type;
698 } header;
699 union {
700 short val;
701 char b[2];
702 } x;
703 union {
704 short val;
705 char b[2];
706 } y;
707 union {
708 unsigned short val;
709 char b[2];
710 } w;
711 union {
712 unsigned short val;
713 char b[2];
714 } h;
715 unsigned char bpp;
716 } __attribute__((packed)) raw;
717
718 raw.header.seph.tag = SEPROXYHAL_TAG_SCREEN_DISPLAY_RAW_STATUS;
719 raw.header.type = SEPROXYHAL_TAG_SCREEN_DISPLAY_RAW_STATUS_START;
720 raw.x.val = icon_component->x;
721 raw.y.val = icon_component->y;
722 raw.w.val = icon_component->width;
723 raw.h.val = icon_component->height;
724 raw.bpp = icon_details->bpp;
725
726
727 *icon_len = raw.w.val*raw.h.val*raw.bpp/8 + (((raw.w.val*raw.h.val*raw.bpp)%8)?1:0);
728
729 // optional, don't send too much on a single packet for MCU to receive it. when stream mode will be on, this will be useless
730 // min of remaining space in the packet vs. total icon size + color index size
731 len = MIN(sizeof(G_io_seproxyhal_spi_buffer) - sizeof(raw), *icon_len + (1<<raw.bpp)*4)((sizeof(G_io_seproxyhal_spi_buffer) - sizeof(raw)) < (*icon_len
+ (1<<raw.bpp)*4) ? (sizeof(G_io_seproxyhal_spi_buffer
) - sizeof(raw)) : (*icon_len + (1<<raw.bpp)*4))
;
732
733 // sizeof packet
734 raw.header.seph.len[0] = (len + sizeof(raw) - sizeof(raw.header.seph)) >> 8;
735 raw.header.seph.len[1] = (len + sizeof(raw) - sizeof(raw.header.seph));
736
737 // swap endianess of coordinates (make it big endian)
738 SWAP(raw.x.b[0], raw.x.b[1]){ raw.x.b[0] ^= raw.x.b[1]; raw.x.b[1] ^= raw.x.b[0]; raw.x.b
[0] ^= raw.x.b[1]; }
;
739 SWAP(raw.y.b[0], raw.y.b[1]){ raw.y.b[0] ^= raw.y.b[1]; raw.y.b[1] ^= raw.y.b[0]; raw.y.b
[0] ^= raw.y.b[1]; }
;
740 SWAP(raw.w.b[0], raw.w.b[1]){ raw.w.b[0] ^= raw.w.b[1]; raw.w.b[1] ^= raw.w.b[0]; raw.w.b
[0] ^= raw.w.b[1]; }
;
741 SWAP(raw.h.b[0], raw.h.b[1]){ raw.h.b[0] ^= raw.h.b[1]; raw.h.b[1] ^= raw.h.b[0]; raw.h.b
[0] ^= raw.h.b[1]; }
;
742
743 io_seproxyhal_spi_sendio_seph_send((unsigned char*)&raw, sizeof(raw));
744 io_seproxyhal_spi_sendio_seph_send((const uint8_t *) PIC(icon_details->colors)pic((void *)icon_details->colors), (1<<raw.bpp)*4);
745 len -= (1<<raw.bpp)*4;
746
747 // remaining length of bitmap bits to be displayed
748 return len;
749}
750#endif // SEPROXYHAL_TAG_SCREEN_DISPLAY_RAW_STATUS
751
752void io_seproxyhal_display_icon(const bagl_component_t* icon_component, const bagl_icon_details_t* icon_det) {
753 bagl_component_t icon_component_mod;
754 const bagl_icon_details_t* icon_details = (const bagl_icon_details_t *)PIC(icon_det)pic((void *)icon_det);
755
756 if (icon_details && icon_details->bitmap) {
757 // ensure not being out of bounds in the icon component agianst the declared icon real size
758 memcpy(&icon_component_mod, PIC(icon_component)pic((void *)icon_component), sizeof(bagl_component_t));
759 icon_component_mod.width = icon_details->width;
760 icon_component_mod.height = icon_details->height;
761 icon_component = &icon_component_mod;
Value stored to 'icon_component' is never read
762
763#ifdef SEPROXYHAL_TAG_SCREEN_DISPLAY_RAW_STATUS
764 unsigned int len;
765 unsigned int icon_len;
766 unsigned int icon_off=0;
767
768 len = io_seproxyhal_display_icon_header_and_colors(icon_component, icon_details, &icon_len);
769 io_seproxyhal_spi_sendio_seph_send(PIC(icon_details->bitmap)pic((void *)icon_details->bitmap), len);
770 // advance in the bitmap to be transmitted
771 icon_len -= len;
772 icon_off += len;
773
774 // still some bitmap data to transmit
775 while(icon_len) {
776 // wait displayed event
777 io_seproxyhal_spi_recvio_seph_recv(G_io_seproxyhal_spi_buffer, sizeof(G_io_seproxyhal_spi_buffer), 0);
778
779 G_io_seproxyhal_spi_buffer[0] = SEPROXYHAL_TAG_SCREEN_DISPLAY_RAW_STATUS;
780 G_io_seproxyhal_spi_buffer[3] = SEPROXYHAL_TAG_SCREEN_DISPLAY_RAW_STATUS_CONT;
781
782 len = MIN((sizeof(G_io_seproxyhal_spi_buffer) - 4), icon_len)(((sizeof(G_io_seproxyhal_spi_buffer) - 4)) < (icon_len) ?
((sizeof(G_io_seproxyhal_spi_buffer) - 4)) : (icon_len))
;
783 G_io_seproxyhal_spi_buffer[1] = (len+1)>>8;
784 G_io_seproxyhal_spi_buffer[2] = (len+1);
785 io_seproxyhal_spi_sendio_seph_send(G_io_seproxyhal_spi_buffer, 4);
786 io_seproxyhal_spi_sendio_seph_send(PIC(icon_details->bitmap)pic((void *)icon_details->bitmap)+icon_off, len);
787
788 icon_len -= len;
789 icon_off += len;
790 }
791#else // !SEPROXYHAL_TAG_SCREEN_DISPLAY_RAW_STATUS
792#ifdef HAVE_SE_SCREEN1
793 bagl_draw_glyph(&icon_component_mod, icon_details);
794#endif // HAVE_SE_SCREEN
795#if !defined(HAVE_SE_SCREEN1) || (defined(HAVE_SE_SCREEN1) && defined(HAVE_PRINTF))
796 if (io_seproxyhal_spi_is_status_sentio_seph_is_status_sent()) {
797 return;
798 }
799 // color index size
800 unsigned int h = (1<<(icon_details->bpp))*sizeof(unsigned int);
801 // bitmap size
802 unsigned int w = ((icon_component->width*icon_component->height*icon_details->bpp)/8)+((icon_component->width*icon_component->height*icon_details->bpp)%8?1:0);
803 unsigned short length = sizeof(bagl_component_t)
804 +1 /* bpp */
805 +h /* color index */
806 +w; /* image bitmap size */
807 G_io_seproxyhal_spi_buffer[0] = SEPROXYHAL_TAG_SCREEN_DISPLAY_STATUS0x65;
808#if defined(HAVE_SE_SCREEN1) && defined(HAVE_PRINTF)
809 G_io_seproxyhal_spi_buffer[0] = SEPROXYHAL_TAG_DBG_SCREEN_DISPLAY_STATUS0x5E;
810#endif // HAVE_SE_SCREEN && HAVE_PRINTF
811 G_io_seproxyhal_spi_buffer[1] = length>>8;
812 G_io_seproxyhal_spi_buffer[2] = length;
813 io_seproxyhal_spi_sendio_seph_send(G_io_seproxyhal_spi_buffer, 3);
814 io_seproxyhal_spi_sendio_seph_send((const uint8_t *) icon_component, sizeof(bagl_component_t));
815 G_io_seproxyhal_spi_buffer[0] = icon_details->bpp;
816 io_seproxyhal_spi_sendio_seph_send(G_io_seproxyhal_spi_buffer, 1);
817 io_seproxyhal_spi_sendio_seph_send((const uint8_t *) PIC(icon_details->colors)pic((void *)icon_details->colors), h);
818 io_seproxyhal_spi_sendio_seph_send((const uint8_t *) PIC(icon_details->bitmap)pic((void *)icon_details->bitmap), w);
819#endif // !HAVE_SE_SCREEN || (HAVE_SE_SCREEN && HAVE_PRINTF)
820#endif // !SEPROXYHAL_TAG_SCREEN_DISPLAY_RAW_STATUS
821 }
822}
823
824void io_seproxyhal_display_default(const bagl_element_t* element) {
825
826 const bagl_element_t* el = (const bagl_element_t*) PIC(element)pic((void *)element);
827 const char* txt = (const char*)PIC(el->text)pic((void *)el->text);
828 // process automagically address from rom and from ram
829 unsigned int type = (el->component.type & ~(BAGL_FLAG_TOUCHABLE));
830
831 if (type != BAGL_NONE) {
832 if (txt != NULL((void*)0)) {
833 // consider an icon details descriptor is pointed by the context
834 if (type == BAGL_ICON && el->component.icon_id == 0) {
835 // SECURITY: due to this wild cast, the code MUST be executed on the application side instead of in
836 // the syscall sides to avoid buffer overflows and a real hard way of checking buffer
837 // belonging in the syscall dispatch
838 io_seproxyhal_display_icon(&el->component, (const bagl_icon_details_t *) txt);
839 }
840 else {
841#ifdef HAVE_SE_SCREEN1
842 bagl_draw_with_context(&el->component, txt, strlen(txt), BAGL_ENCODING_LATIN10);
843#endif // HAVE_SE_SCREEN
844#if !defined(HAVE_SE_SCREEN1) || (defined(HAVE_SE_SCREEN1) && defined(HAVE_PRINTF))
845 if (io_seproxyhal_spi_is_status_sentio_seph_is_status_sent()) {
846 return;
847 }
848 unsigned short length = sizeof(bagl_component_t)+strlen((const char*)txt);
849 G_io_seproxyhal_spi_buffer[0] = SEPROXYHAL_TAG_SCREEN_DISPLAY_STATUS0x65;
850#if defined(HAVE_SE_SCREEN1) && defined(HAVE_PRINTF)
851 G_io_seproxyhal_spi_buffer[0] = SEPROXYHAL_TAG_DBG_SCREEN_DISPLAY_STATUS0x5E;
852#endif // HAVE_SE_SCREEN && HAVE_PRINTF
853 G_io_seproxyhal_spi_buffer[1] = length>>8;
854 G_io_seproxyhal_spi_buffer[2] = length;
855 io_seproxyhal_spi_sendio_seph_send(G_io_seproxyhal_spi_buffer, 3);
856 io_seproxyhal_spi_sendio_seph_send((const uint8_t *) &el->component, sizeof(bagl_component_t));
857 io_seproxyhal_spi_sendio_seph_send((const uint8_t *) txt, length-sizeof(bagl_component_t));
858#endif // !HAVE_SE_SCREEN || (HAVE_SE_SCREEN && HAVE_PRINTF)
859 }
860 }
861 else {
862#ifdef HAVE_SE_SCREEN1
863 bagl_draw_with_context(&el->component, NULL((void*)0), 0, 0);
864#endif // HAVE_SE_SCREEN
865#if !defined(HAVE_SE_SCREEN1) || (defined(HAVE_SE_SCREEN1) && defined(HAVE_PRINTF))
866 if (io_seproxyhal_spi_is_status_sentio_seph_is_status_sent()) {
867 return;
868 }
869 unsigned short length = sizeof(bagl_component_t);
870 G_io_seproxyhal_spi_buffer[0] = SEPROXYHAL_TAG_SCREEN_DISPLAY_STATUS0x65;
871#if defined(HAVE_SE_SCREEN1) && defined(HAVE_PRINTF)
872 G_io_seproxyhal_spi_buffer[0] = SEPROXYHAL_TAG_DBG_SCREEN_DISPLAY_STATUS0x5E;
873#endif // HAVE_SE_SCREEN && HAVE_PRINTF
874 G_io_seproxyhal_spi_buffer[1] = length>>8;
875 G_io_seproxyhal_spi_buffer[2] = length;
876 io_seproxyhal_spi_sendio_seph_send(G_io_seproxyhal_spi_buffer, 3);
877 io_seproxyhal_spi_sendio_seph_send((const uint8_t *) &el->component, sizeof(bagl_component_t));
878#endif // !HAVE_SE_SCREEN || (HAVE_SE_SCREEN && HAVE_PRINTF)
879 }
880 }
881}
882
883unsigned int bagl_label_roundtrip_duration_ms(const bagl_element_t* e, unsigned int average_char_width) {
884 return bagl_label_roundtrip_duration_ms_buf(e, e->text, average_char_width);
885}
886
887unsigned int bagl_label_roundtrip_duration_ms_buf(const bagl_element_t* e, const char* str, unsigned int average_char_width) {
888 // not a scrollable label
889 if (e == NULL((void*)0) || (e->component.type != BAGL_LABEL && e->component.type != BAGL_LABELINE)) {
890 return 0;
891 }
892
893 const char *text_adr = (const char *) PIC(str)pic((void *)str);
894 unsigned int textlen = 0;
895
896 // no delay, no text to display
897 if (!text_adr) {
898 return 0;
899 }
900 textlen = strlen(text_adr);
901
902 // no delay, all text fits
903 textlen = textlen * average_char_width;
904 if (textlen <= e->component.width) {
905 return 0;
906 }
907
908 // compute scrolled text length
909 return 2*(textlen - e->component.width)*1000/e->component.icon_id + 2*(e->component.stroke & ~(0x80))*100;
910}
911
912void io_seproxyhal_button_push(button_push_callback_t button_callback, unsigned int new_button_mask) {
913 if (button_callback) {
914 unsigned int button_mask;
915 unsigned int button_same_mask_counter;
916 // enable speeded up long push
917 if (new_button_mask == G_ux_os.button_mask) {
918 // each 100ms ~
919 G_ux_os.button_same_mask_counter++;
920 }
921
922 // when new_button_mask is 0 and
923
924 // append the button mask
925 button_mask = G_ux_os.button_mask | new_button_mask;
926
927 // pre reset variable due to os_sched_exit
928 button_same_mask_counter = G_ux_os.button_same_mask_counter;
929
930 // reset button mask
931 if (new_button_mask == 0) {
932 // reset next state when button are released
933 G_ux_os.button_mask = 0;
934 G_ux_os.button_same_mask_counter=0;
935
936 // notify button released event
937 button_mask |= BUTTON_EVT_RELEASED0x80000000UL;
938 }
939 else {
940 G_ux_os.button_mask = button_mask;
941 }
942
943 // reset counter when button mask changes
944 if (new_button_mask != G_ux_os.button_mask) {
945 G_ux_os.button_same_mask_counter=0;
946 }
947
948 if (button_same_mask_counter >= BUTTON_FAST_THRESHOLD_CS8) {
949 // fast bit when pressing and timing is right
950 if ((button_same_mask_counter%BUTTON_FAST_ACTION_CS3) == 0) {
951 button_mask |= BUTTON_EVT_FAST0x40000000UL;
952 }
953
954 /*
955 // fast bit when releasing and threshold has been exceeded
956 if ((button_mask & BUTTON_EVT_RELEASED)) {
957 button_mask |= BUTTON_EVT_FAST;
958 }
959 */
960
961 // discard the release event after a fastskip has been detected, to avoid strange at release behavior
962 // and also to enable user to cancel an operation by starting triggering the fast skip
963 button_mask &= ~BUTTON_EVT_RELEASED0x80000000UL;
964 }
965
966 // indicate if button have been released
967 button_callback(button_mask, button_same_mask_counter);
968
969 }
970}
971
972#endif // HAVE_BAGL
973
974void io_seproxyhal_setup_ticker(unsigned int interval_ms) {
975 G_io_seproxyhal_spi_buffer[0] = SEPROXYHAL_TAG_SET_TICKER_INTERVAL0x4E;
976 G_io_seproxyhal_spi_buffer[1] = 0;
977 G_io_seproxyhal_spi_buffer[2] = 2;
978 G_io_seproxyhal_spi_buffer[3] = (interval_ms>>8)&0xff;
979 G_io_seproxyhal_spi_buffer[4] = (interval_ms)&0xff;
980 io_seproxyhal_spi_sendio_seph_send(G_io_seproxyhal_spi_buffer, 5);
981}
982
983static const unsigned char seph_io_device_off[] = {
984 SEPROXYHAL_TAG_DEVICE_OFF0x4B,
985 0,
986 0,
987};
988void io_seproxyhal_power_off(void) {
989 io_seproxyhal_spi_sendio_seph_send(seph_io_device_off, sizeof(seph_io_device_off));
990 for(;;);
991}
992
993static const unsigned char seph_io_se_reset[]= {
994 SEPROXYHAL_TAG_SE_POWER_OFF0x46,
995 0,
996 0,
997};
998void io_seproxyhal_se_reset(void) {
999 io_seproxyhal_spi_sendio_seph_send(seph_io_se_reset, sizeof(seph_io_se_reset));
1000 for(;;);
1001}
1002
1003#ifdef HAVE_BLE
1004void io_seph_ble_enable(unsigned char enable)
1005{
1006 G_io_seproxyhal_spi_buffer[0] = SEPROXYHAL_TAG_UX_CMD0x5D;
1007 G_io_seproxyhal_spi_buffer[1] = 0;
1008 G_io_seproxyhal_spi_buffer[2] = 1;
1009 G_io_seproxyhal_spi_buffer[3] = (enable ? SEPROXYHAL_TAG_UX_CMD_BLE_ENABLE_ADV0x01 : SEPROXYHAL_TAG_UX_CMD_BLE_DISABLE_ADV0x00);
1010 io_seproxyhal_spi_sendio_seph_send(G_io_seproxyhal_spi_buffer, 4);
1011}
1012
1013void io_seph_ble_clear_bond_db(void)
1014{
1015 G_io_seproxyhal_spi_buffer[0] = SEPROXYHAL_TAG_UX_CMD0x5D;
1016 G_io_seproxyhal_spi_buffer[1] = 0;
1017 G_io_seproxyhal_spi_buffer[2] = 1;
1018 G_io_seproxyhal_spi_buffer[3] = SEPROXYHAL_TAG_UX_CMD_BLE_RESET_PAIRINGS0x02;
1019 io_seproxyhal_spi_sendio_seph_send(G_io_seproxyhal_spi_buffer, 4);
1020}
1021#endif // HAVE_BLE
1022
1023void io_seph_ux_redisplay(void)
1024{
1025 G_io_seproxyhal_spi_buffer[0] = SEPROXYHAL_TAG_UX_CMD0x5D;
1026 G_io_seproxyhal_spi_buffer[1] = 0;
1027 G_io_seproxyhal_spi_buffer[2] = 1;
1028 G_io_seproxyhal_spi_buffer[3] = SEPROXYHAL_TAG_UX_CMD_REDISPLAY0x03;
1029 io_seproxyhal_spi_sendio_seph_send(G_io_seproxyhal_spi_buffer, 4);
1030}
1031
1032static const unsigned char seph_io_usb_disconnect[] = {
1033 SEPROXYHAL_TAG_USB_CONFIG0x4F,
1034 0,
1035 1,
1036 SEPROXYHAL_TAG_USB_CONFIG_DISCONNECT0x02,
1037};
1038void io_seproxyhal_disable_io(void) {
1039 // usb off
1040 io_seproxyhal_spi_sendio_seph_send(seph_io_usb_disconnect, sizeof(seph_io_usb_disconnect));
1041}
1042
1043void io_seproxyhal_backlight(unsigned int flags, unsigned int backlight_percentage) {
1044 G_io_seproxyhal_spi_buffer[0] = SEPROXYHAL_TAG_SET_SCREEN_CONFIG0x3E;
1045 G_io_seproxyhal_spi_buffer[1] = 0;
1046 G_io_seproxyhal_spi_buffer[2] = 2;
1047 G_io_seproxyhal_spi_buffer[3] = (backlight_percentage?0x80:0)|(flags & 0x7F); // power on
1048 G_io_seproxyhal_spi_buffer[4] = backlight_percentage;
1049 io_seproxyhal_spi_sendio_seph_send(G_io_seproxyhal_spi_buffer, 5);
1050}
1051
1052#ifdef HAVE_IO_U2F
1053u2f_service_t G_io_u2f;
1054#endif // HAVE_IO_U2F
1055
1056unsigned int os_io_seproxyhal_get_app_name_and_version(void) __attribute__((weak));
1057unsigned int os_io_seproxyhal_get_app_name_and_version(void) {
1058 unsigned int tx_len, len;
1059 // build the get app name and version reply
1060 tx_len = 0;
1061 G_io_apdu_buffer[tx_len++] = 1; // format ID
1062
1063#ifndef HAVE_BOLOS
1064 // append app name
1065 len = os_registry_get_current_app_tag(BOLOS_TAG_APPNAME0x01, G_io_apdu_buffer+tx_len+1, sizeof(G_io_apdu_buffer)-tx_len-1);
1066 G_io_apdu_buffer[tx_len++] = len;
1067 tx_len += len;
1068 // append app version
1069 len = os_registry_get_current_app_tag(BOLOS_TAG_APPVERSION0x02, G_io_apdu_buffer+tx_len+1, sizeof(G_io_apdu_buffer)-tx_len-1);
1070 G_io_apdu_buffer[tx_len++] = len;
1071 tx_len += len;
1072#else // HAVE_BOLOS
1073 // append app name
1074 len = strlen("BOLOS");
1075 G_io_apdu_buffer[tx_len++] = len;
1076 strcpy((char*)(G_io_apdu_buffer+tx_len), "BOLOS");
1077 tx_len += len;
1078 // append app version
1079 len = strlen(VERSION"dummy");
1080 G_io_apdu_buffer[tx_len++] = len;
1081 strcpy((char*)(G_io_apdu_buffer+tx_len), VERSION"dummy");
1082 tx_len += len;
1083#endif // HAVE_BOLOS
1084
1085#if !defined(HAVE_IO_TASK) || !defined(HAVE_BOLOS)
1086 // to be fixed within io tasks
1087 // return OS flags to notify of platform's global state (pin lock etc)
1088 G_io_apdu_buffer[tx_len++] = 1; // flags length
1089 G_io_apdu_buffer[tx_len++] = os_flags();
1090#endif // !defined(HAVE_IO_TASK) || !defined(HAVE_BOLOS)
1091
1092 // status words
1093 G_io_apdu_buffer[tx_len++] = 0x90;
1094 G_io_apdu_buffer[tx_len++] = 0x00;
1095 return tx_len;
1096}
1097
1098#if !defined(HAVE_BOLOS_NO_DEFAULT_APDU)
1099// This function is used to process the default APDU commands.
1100static bolos_bool_t io_process_default_apdus(unsigned char* channel, unsigned short* tx_len) {
1101 // Indicates whether a command has been processed and need to send an answer.
1102 bolos_bool_t processed = BOLOS_FALSE0x55;
1103
1104 // We handle the default apdus when the CLA byte is correct.
1105 if (DEFAULT_APDU_CLA0xB0 == G_io_apdu_buffer[APDU_OFF_CLA0]) {
1106
1107 // We have several possible commands.
1108 switch (G_io_apdu_buffer[APDU_OFF_INS1]) {
1109
1110 // get name and version
1111 case DEFAULT_APDU_INS_GET_VERSION0x01:
1112 // P1 and P2 shall be set to '00'.
1113 if (!G_io_apdu_buffer[APDU_OFF_P12] && !G_io_apdu_buffer[APDU_OFF_P23]) {
1114 *tx_len = os_io_seproxyhal_get_app_name_and_version();
1115 // disable 'return after tx' and 'asynch reply' flags
1116 *channel &= ~IO_FLAGS0xF8;
1117 processed = BOLOS_TRUE0xaa;
1118 }
1119 break;
1120
1121 // exit app after replied
1122 case DEFAULT_APDU_INS_APP_EXIT0xA7:
1123 // P1 and P2 shall be set to '00'.
1124 if (!G_io_apdu_buffer[APDU_OFF_P12] && !G_io_apdu_buffer[APDU_OFF_P23]) {
1125 *tx_len = 0;
1126 G_io_apdu_buffer[(*tx_len)++] = 0x90;
1127 G_io_apdu_buffer[(*tx_len)++] = 0x00;
1128
1129#if defined(HAVE_BOLOS)
1130 // If this APDU has been received from the dashboard, we don't do
1131 // anything except resetting the IO flags.
1132 *channel &= ~IO_FLAGS0xF8;
1133#else
1134 // We exit the application after having replied.
1135 *channel |= IO_RESET_AFTER_REPLIED0x80;
1136#endif // HAVE_BOLOS
1137
1138 processed = BOLOS_TRUE0xaa;
1139 }
1140 break;
1141
1142 // seed cookie
1143 // host: <nothing>
1144 // device: <format(1B)> <len(1B)> <seed magic cookie if pin is entered(len)> 9000 | 6985
1145#if defined(HAVE_SEED_COOKIE)
1146 case DEFAULT_APDU_INS_GET_SEED_COOKIE:
1147 // P1 and P2 shall be set to '00'.
1148 if (!G_io_apdu_buffer[APDU_OFF_P12] && !G_io_apdu_buffer[APDU_OFF_P23]) {
1149 *tx_len = 0;
1150 if (os_global_pin_is_validated() == BOLOS_UX_OK0xAA) {
1151 unsigned int i;
1152 // format
1153 G_io_apdu_buffer[(*tx_len)++] = 0x01;
1154 i = os_perso_seed_cookie(G_io_apdu_buffer+1+1, MIN(64,sizeof(G_io_apdu_buffer)-1-1-2)((64) < (sizeof(G_io_apdu_buffer)-1-1-2) ? (64) : (sizeof(
G_io_apdu_buffer)-1-1-2))
);
1155
1156 G_io_apdu_buffer[(*tx_len)++] = i;
1157 *tx_len += i;
1158 G_io_apdu_buffer[(*tx_len)++] = 0x90;
1159 G_io_apdu_buffer[(*tx_len)++] = 0x00;
1160 }
1161 else {
1162 G_io_apdu_buffer[(*tx_len)++] = 0x69;
1163 G_io_apdu_buffer[(*tx_len)++] = 0x85;
1164 }
1165 *channel &= ~IO_FLAGS0xF8;
1166 processed = BOLOS_TRUE0xaa;
1167 }
1168 break;
1169#endif // HAVE_SEED_COOKIE
1170
1171#if defined(DEBUG_OS_STACK_CONSUMPTION)
1172 // OS stack consumption.
1173 case DEFAULT_APDU_INS_STACK_CONSUMPTION:
1174 // Initialization.
1175 *tx_len = 2;
1176 U2BE_ENCODE(G_io_apdu_buffer, 0x00, SWO_APD_HDR_0D((0x6000 + 0x0500) + ERR_GEN_ID_0D));
1177
1178 // P2 and Lc shall be set to '00'.
1179 if (!G_io_apdu_buffer[APDU_OFF_P23] && !G_io_apdu_buffer[APDU_OFF_LC4]) {
1180 int s = os_stack_operations(G_io_apdu_buffer[APDU_OFF_P12]);
1181 if (-1 != s) {
1182 u4be_encode(G_io_apdu_buffer, 0x00, s);
1183 *tx_len = sizeof(int);
1184 G_io_apdu_buffer[(*tx_len)++] = 0x90;
1185 G_io_apdu_buffer[(*tx_len)++] = 0x00;
1186 }
1187 }
1188 *channel &= ~IO_FLAGS0xF8;
1189 processed = BOLOS_TRUE0xaa;
1190 break;
1191#endif // DEBUG_OS_STACK_CONSUMPTION
1192
1193 default:
1194 // 'processed' is already initialized.
1195 break;
1196 }
1197 }
1198
1199 return processed;
1200}
1201
1202#endif // HAVE_BOLOS_NO_DEFAULT_APDU
1203
1204unsigned short io_exchange(unsigned char channel, unsigned short tx_len) {
1205 unsigned short rx_len;
1206 unsigned int timeout_ms;
1207
1208#ifdef HAVE_BOLOS_APP_STACK_CANARY1
1209 // behavior upon detected stack overflow is to reset the SE
1210 if (app_stack_canary != APP_STACK_CANARY_MAGIC0xDEAD0031) {
1211 io_seproxyhal_se_reset();
1212 }
1213#endif // HAVE_BOLOS_APP_STACK_CANARY
1214
1215#ifdef DEBUG_APDU
1216 if ((channel&~(IO_FLAGS0xF8)) == CHANNEL_APDU0) {
1217 // ignore tx len
1218
1219 // already received the data of the apdu when received the whole apdu
1220 if ((channel & (CHANNEL_APDU0|IO_RECEIVE_DATA0x40)) == (CHANNEL_APDU0|IO_RECEIVE_DATA0x40)) {
1221 // return apdu data - header
1222 return G_io_apdu_length-5;
1223 }
1224
1225 // fetch next apdu
1226 if (debug_apdus_offset < sizeof(debug_apdus)) {
1227 G_io_apdu_length = debug_apdus[debug_apdus_offset]&0xFF;
1228 memcpy(G_io_apdu_buffer, &debug_apdus[debug_apdus_offset+1], G_io_apdu_length);
1229 debug_apdus_offset += G_io_apdu_length+1;
1230 return G_io_apdu_length;
1231 }
1232 }
1233#endif // DEBUG_APDU
1234
1235reply_apdu:
1236 switch(channel&~(IO_FLAGS0xF8)) {
1237 case CHANNEL_APDU0:
1238 // TODO work up the spi state machine over the HAL proxy until an APDU is available
1239
1240 if (tx_len && !(channel&IO_ASYNCH_REPLY0x10)) {
1241 // ensure it's our turn to send a command/status, could lag a bit before sending the reply
1242 while (io_seproxyhal_spi_is_status_sentio_seph_is_status_sent()) {
1243 io_seproxyhal_spi_recvio_seph_recv(G_io_seproxyhal_spi_buffer, sizeof(G_io_seproxyhal_spi_buffer), 0);
1244 // process without sending status on tickers etc, to ensure keeping the hand
1245 os_io_seph_recv_and_process(1);
1246 }
1247
1248 // reinit sending timeout for APDU replied within io_exchange
1249 timeout_ms = G_io_app.ms + IO_RAPDU_TRANSMIT_TIMEOUT_MS2000UL;
1250
1251 // until the whole RAPDU is transmitted, send chunks using the current mode for communication
1252 for (;;) {
1253 switch(G_io_app.apdu_state) {
1254 default:
1255 // delegate to the hal in case of not generic transport mode (or asynch)
1256 if (io_exchange_al(channel, tx_len) == 0) {
1257 goto break_send;
1258 }
1259 __attribute__((fallthrough));
1260 case APDU_IDLE:
1261 LOG("invalid state for APDU reply\n");
1262 THROW(INVALID_STATE)os_longjmp(0x4);
1263 break;
1264
1265 case APDU_RAW:
1266 if (tx_len > sizeof(G_io_apdu_buffer)) {
1267 THROW(INVALID_PARAMETER)os_longjmp(0x2);
1268 }
1269 // reply the RAW APDU over SEPROXYHAL protocol
1270 G_io_seproxyhal_spi_buffer[0] = SEPROXYHAL_TAG_RAPDU0x53;
1271 G_io_seproxyhal_spi_buffer[1] = (tx_len)>>8;
1272 G_io_seproxyhal_spi_buffer[2] = (tx_len);
1273 io_seproxyhal_spi_sendio_seph_send(G_io_seproxyhal_spi_buffer, 3);
1274 io_seproxyhal_spi_sendio_seph_send(G_io_apdu_buffer, tx_len);
1275
1276 // isngle packet reply, mark immediate idle
1277 G_io_app.apdu_state = APDU_IDLE;
1278 // finished, no chunking
1279 goto break_send;
1280
1281#ifdef HAVE_USB_APDU1
1282 case APDU_USB_HID:
1283 // only send, don't perform synchronous reception of the next command (will be done later by the seproxyhal packet processing)
1284 io_usb_hid_send(io_usb_send_apdu_data, tx_len);
1285 goto break_send;
1286#ifdef HAVE_USB_CLASS_CCID
1287 case APDU_USB_CCID:
1288 io_usb_ccid_reply(G_io_apdu_buffer, tx_len);
1289 goto break_send;
1290#endif // HAVE_USB_CLASS_CCID
1291#ifdef HAVE_WEBUSB1
1292 case APDU_USB_WEBUSB:
1293 io_usb_hid_send(io_usb_send_apdu_data_ep0x83, tx_len);
1294 goto break_send;
1295#endif // HAVE_WEBUSB
1296#endif // HAVE_USB_APDU
1297
1298#ifdef HAVE_BLE_APDU // versus U2F BLE
1299 case APDU_BLE:
1300 LEDGER_BLE_send(G_io_apdu_buffer, tx_len);
1301 goto break_send;
1302#endif // HAVE_BLE_APDU
1303
1304
1305#ifdef HAVE_IO_U2F
1306 // case to handle U2F channels. u2f apdu to be dispatched in the upper layers
1307 case APDU_U2F:
1308 // prepare reply, the remaining segments will be pumped during USB/BLE events handling while waiting for the next APDU
1309
1310 // the reply has been prepared by the application, stop sending anti timeouts
1311 u2f_message_set_autoreply_wait_user_presence(&G_io_u2f, false0);
1312
1313 // continue processing currently received command until completely received.
1314 while(!u2f_message_repliable(&G_io_u2f)) {
1315
1316 io_seproxyhal_general_status();
1317 do {
1318 io_seproxyhal_spi_recvio_seph_recv(G_io_seproxyhal_spi_buffer, sizeof(G_io_seproxyhal_spi_buffer), 0);
1319 // check for reply timeout
1320 if (G_io_app.ms >= timeout_ms) {
1321 THROW(EXCEPTION_IO_RESET)os_longjmp(0x5);
1322 }
1323 // avoid a general status to be replied
1324 io_seproxyhal_handle_event();
1325 } while (io_seproxyhal_spi_is_status_sentio_seph_is_status_sent());
1326 }
1327#ifdef U2F_PROXY_MAGIC
1328
1329 // user presence + counter + rapdu + sw must fit the apdu buffer
1330 if (1U+ 4U+ tx_len +2U > sizeof(G_io_apdu_buffer)) {
1331 THROW(INVALID_PARAMETER)os_longjmp(0x2);
1332 }
1333
1334 // u2F tunnel needs the status words to be included in the signature response BLOB, do it now.
1335 // always return 9000 in the signature to avoid error @ transport level in u2f layers.
1336 G_io_apdu_buffer[tx_len] = 0x90; //G_io_apdu_buffer[tx_len-2];
1337 G_io_apdu_buffer[tx_len+1] = 0x00; //G_io_apdu_buffer[tx_len-1];
1338 tx_len += 2;
1339 memmove(G_io_apdu_buffer + APDU_OFF_DATA5, G_io_apdu_buffer, tx_len);
1340 // zeroize user presence and counter
1341 memset(G_io_apdu_buffer, 0, APDU_OFF_DATA5);
1342 u2f_message_reply(&G_io_u2f, U2F_CMD_MSG, G_io_apdu_buffer, tx_len+5);
1343
1344#else // U2F_PROXY_MAGIC
1345 u2f_message_reply(&G_io_u2f, U2F_CMD_MSG, G_io_apdu_buffer, tx_len);
1346#endif // U2F_PROXY_MAGIC
1347 goto break_send;
1348#endif // HAVE_IO_U2F
1349 }
1350 continue;
1351
1352 break_send:
1353
1354 // wait end of reply transmission
1355 // TODO: add timeout here to avoid spending too much time when host has disconnected
1356 while (G_io_app.apdu_state != APDU_IDLE) {
1357 io_seproxyhal_general_status();
1358 do {
1359 io_seproxyhal_spi_recvio_seph_recv(G_io_seproxyhal_spi_buffer, sizeof(G_io_seproxyhal_spi_buffer), 0);
1360 // check for reply timeout (when asynch reply (over hid or u2f for example))
1361 // this case shall be covered by usb_ep_timeout but is not, investigate that
1362 if (G_io_app.ms >= timeout_ms) {
1363 THROW(EXCEPTION_IO_RESET)os_longjmp(0x5);
1364 }
1365 // avoid a general status to be replied
1366 io_seproxyhal_handle_event();
1367 } while (io_seproxyhal_spi_is_status_sentio_seph_is_status_sent());
1368 }
1369 // reset apdu state
1370 G_io_app.apdu_state = APDU_IDLE;
1371 G_io_app.apdu_media = IO_APDU_MEDIA_NONE;
1372
1373 G_io_app.apdu_length = 0;
1374
1375 // continue sending commands, don't issue status yet
1376 if (channel & IO_RETURN_AFTER_TX0x20) {
1377 return 0;
1378 }
1379 // acknowledge the write request (general status OK) and no more command to follow (wait until another APDU container is received to continue unwrapping)
1380 io_seproxyhal_general_status();
1381 break;
1382 }
1383
1384 // perform reset after io exchange
1385 if (channel & IO_RESET_AFTER_REPLIED0x80) {
1386 // The error cast is retrocompatible with the previous value.
1387 os_sched_exit((bolos_task_status_t)EXCEPTION_IO_RESET0x5);
1388 //reset();
1389 }
1390 }
1391
1392 if (!(channel&IO_ASYNCH_REPLY0x10)) {
1393
1394 // already received the data of the apdu when received the whole apdu
1395 if ((channel & (CHANNEL_APDU0|IO_RECEIVE_DATA0x40)) == (CHANNEL_APDU0|IO_RECEIVE_DATA0x40)) {
1396 // return apdu data - header
1397 return G_io_app.apdu_length-5;
1398 }
1399
1400 // reply has ended, proceed to next apdu reception (reset status only after asynch reply)
1401 G_io_app.apdu_state = APDU_IDLE;
1402 G_io_app.apdu_media = IO_APDU_MEDIA_NONE;
1403 }
1404
1405 // reset the received apdu length
1406 G_io_app.apdu_length = 0;
1407
1408 // ensure ready to receive an event (after an apdu processing with asynch flag, it may occur if the channel is not correctly managed)
1409
1410 // until a new whole CAPDU is received
1411 for (;;) {
1412 io_seproxyhal_general_status();
1413 // wait until a SPI packet is available
1414 // NOTE: on ST31, dual wait ISO & RF (ISO instead of SPI)
1415 rx_len = io_seproxyhal_spi_recvio_seph_recv(G_io_seproxyhal_spi_buffer, sizeof(G_io_seproxyhal_spi_buffer), 0);
1416
1417 // can't process split TLV, continue
1418 if (rx_len < 3 || rx_len != U2(G_io_seproxyhal_spi_buffer[1],G_io_seproxyhal_spi_buffer[2])((((G_io_seproxyhal_spi_buffer[1])&0xFFu) << 8) | (
(G_io_seproxyhal_spi_buffer[2])&0xFFu))
+3U) {
1419 LOG("invalid TLV format\n");
1420 G_io_app.apdu_state = APDU_IDLE;
1421 G_io_app.apdu_length = 0;
1422 continue;
1423 }
1424
1425 io_seproxyhal_handle_event();
1426
1427 // An apdu has been received asynchroneously.
1428 if (G_io_app.apdu_state != APDU_IDLE && G_io_app.apdu_length > 0) {
1429#if !defined(HAVE_BOLOS_NO_DEFAULT_APDU)
1430 // If a default command is received and processed within this call,
1431 // then we send the answer.
1432 if (io_process_default_apdus(&channel, &tx_len) == BOLOS_TRUE0xaa) {
1433 goto reply_apdu;
1434 }
1435#endif // ! HAVE_BOLOS_NO_DEFAULT_APDU
1436
1437 return G_io_app.apdu_length;
1438 }
1439 }
1440 break;
1441
1442 default:
1443 return io_exchange_al(channel, tx_len);
1444 }
1445}
1446
1447unsigned int os_io_seph_recv_and_process(unsigned int dont_process_ux_events) {
1448 // send general status before receiving next event
1449 io_seproxyhal_general_status();
1450
1451 io_seproxyhal_spi_recvio_seph_recv(G_io_seproxyhal_spi_buffer, sizeof(G_io_seproxyhal_spi_buffer), 0);
1452
1453 switch (G_io_seproxyhal_spi_buffer[0]) {
1454 case SEPROXYHAL_TAG_FINGER_EVENT0x0C:
1455 case SEPROXYHAL_TAG_BUTTON_PUSH_EVENT0x05:
1456 case SEPROXYHAL_TAG_TICKER_EVENT0x0E:
1457 case SEPROXYHAL_TAG_DISPLAY_PROCESSED_EVENT0x0D:
1458 case SEPROXYHAL_TAG_STATUS_EVENT0x15:
1459 // perform UX event on these ones, don't process as an IO event
1460 if (dont_process_ux_events) {
1461 return 0;
1462 }
1463 __attribute__((fallthrough));
1464
1465 default:
1466 // if malformed, then a stall is likely to occur
1467 if (io_seproxyhal_handle_event()) {
1468 return 1;
1469 }
1470 }
1471 return 0;
1472}
1473
1474#if !defined(APP_UX)
1475unsigned int os_ux_blocking(bolos_ux_params_t* params) {
1476 unsigned int ret;
1477
1478 // until a real status is returned
1479 os_ux(params);
1480 ret = os_sched_last_status(TASK_BOLOS_UX);
1481 while(ret == BOLOS_UX_IGNORE0x97
1482 || ret == BOLOS_UX_CONTINUE0) {
1483 // if the IO task is not running, then need to pump events manually
1484 if (os_sched_is_running(TASK_SUBTASKS_START) != BOLOS_TRUE0xaa) {
1485 // send general status before receiving next event
1486 io_seproxyhal_general_status();
1487 io_seproxyhal_spi_recvio_seph_recv(G_io_seproxyhal_spi_buffer, sizeof(G_io_seproxyhal_spi_buffer), 0);
1488 io_event(0);
1489 }
1490 else
1491 {
1492 // wait until UX takes some process time and update it's status
1493 os_sched_yield(BOLOS_UX_OK0xAA);
1494 }
1495 // only retrieve the current UX state
1496 ret = os_sched_last_status(TASK_BOLOS_UX);
1497 }
1498
1499 return ret;
1500}
1501#endif // !defined(APP_UX)
1502
1503#ifdef HAVE_PRINTF
1504void mcu_usb_prints(const char* str, unsigned int charcount) {
1505 unsigned char buf[4];
1506#ifdef TARGET_NANOS
1507 buf[0] = SEPROXYHAL_TAG_PRINTF_STATUS0x66;
1508#else
1509 buf[0] = SEPROXYHAL_TAG_PRINTF0x5F;
1510#endif
1511 buf[1] = charcount >> 8;
1512 buf[2] = charcount;
1513 io_seproxyhal_spi_sendio_seph_send(buf, 3);
1514 io_seproxyhal_spi_sendio_seph_send((const uint8_t *) str, charcount);
1515}
1516#endif // HAVE_PRINTF
1517
1518void io_seproxyhal_io_heartbeat(void) {
1519 io_seproxyhal_general_status();
1520 do {
1521 io_seproxyhal_spi_recvio_seph_recv(G_io_seproxyhal_spi_buffer, sizeof(G_io_seproxyhal_spi_buffer), 0);
1522 // avoid a general status to be replied
1523 if(G_io_seproxyhal_spi_buffer[0] != SEPROXYHAL_TAG_TICKER_EVENT0x0E) {
1524 io_seproxyhal_handle_event();
1525 }
1526 } while (io_seproxyhal_spi_is_status_sentio_seph_is_status_sent());
1527}
1528#endif // OS_IO_SEPROXYHAL
diff --git a/app/output-scan-build/2022-05-16-071232-98-1/scanview.css b/app/output-scan-build/2022-05-16-071232-98-1/scanview.css new file mode 100644 index 00000000..cf8a5a6a --- /dev/null +++ b/app/output-scan-build/2022-05-16-071232-98-1/scanview.css @@ -0,0 +1,62 @@ +body { color:#000000; background-color:#ffffff } +body { font-family: Helvetica, sans-serif; font-size:9pt } +h1 { font-size: 14pt; } +h2 { font-size: 12pt; } +table { font-size:9pt } +table { border-spacing: 0px; border: 1px solid black } +th, table thead { + background-color:#eee; color:#666666; + font-weight: bold; cursor: default; + text-align:center; + font-weight: bold; font-family: Verdana; + white-space:nowrap; +} +.W { font-size:0px } +th, td { padding:5px; padding-left:8px; text-align:left } +td.SUMM_DESC { padding-left:12px } +td.DESC { white-space:pre } +td.Q { text-align:right } +td { text-align:left } +tbody.scrollContent { overflow:auto } + +table.form_group { + background-color: #ccc; + border: 1px solid #333; + padding: 2px; +} + +table.form_inner_group { + background-color: #ccc; + border: 1px solid #333; + padding: 0px; +} + +table.form { + background-color: #999; + border: 1px solid #333; + padding: 2px; +} + +td.form_label { + text-align: right; + vertical-align: top; +} +/* For one line entires */ +td.form_clabel { + text-align: right; + vertical-align: center; +} +td.form_value { + text-align: left; + vertical-align: top; +} +td.form_submit { + text-align: right; + vertical-align: top; +} + +h1.SubmitFail { + color: #f00; +} +h1.SubmitOk { +} diff --git a/app/output-scan-build/2022-05-16-071232-98-1/sorttable.js b/app/output-scan-build/2022-05-16-071232-98-1/sorttable.js new file mode 100644 index 00000000..32faa078 --- /dev/null +++ b/app/output-scan-build/2022-05-16-071232-98-1/sorttable.js @@ -0,0 +1,492 @@ +/* + SortTable + version 2 + 7th April 2007 + Stuart Langridge, http://www.kryogenix.org/code/browser/sorttable/ + + Instructions: + Download this file + Add to your HTML + Add class="sortable" to any table you'd like to make sortable + Click on the headers to sort + + Thanks to many, many people for contributions and suggestions. + Licenced as X11: http://www.kryogenix.org/code/browser/licence.html + This basically means: do what you want with it. +*/ + + +var stIsIE = /*@cc_on!@*/false; + +sorttable = { + init: function() { + // quit if this function has already been called + if (arguments.callee.done) return; + // flag this function so we don't do the same thing twice + arguments.callee.done = true; + // kill the timer + if (_timer) clearInterval(_timer); + + if (!document.createElement || !document.getElementsByTagName) return; + + sorttable.DATE_RE = /^(\d\d?)[\/\.-](\d\d?)[\/\.-]((\d\d)?\d\d)$/; + + forEach(document.getElementsByTagName('table'), function(table) { + if (table.className.search(/\bsortable\b/) != -1) { + sorttable.makeSortable(table); + } + }); + + }, + + makeSortable: function(table) { + if (table.getElementsByTagName('thead').length == 0) { + // table doesn't have a tHead. Since it should have, create one and + // put the first table row in it. + the = document.createElement('thead'); + the.appendChild(table.rows[0]); + table.insertBefore(the,table.firstChild); + } + // Safari doesn't support table.tHead, sigh + if (table.tHead == null) table.tHead = table.getElementsByTagName('thead')[0]; + + if (table.tHead.rows.length != 1) return; // can't cope with two header rows + + // Sorttable v1 put rows with a class of "sortbottom" at the bottom (as + // "total" rows, for example). This is B&R, since what you're supposed + // to do is put them in a tfoot. So, if there are sortbottom rows, + // for backward compatibility, move them to tfoot (creating it if needed). + sortbottomrows = []; + for (var i=0; i5' : ' ▴'; + this.appendChild(sortrevind); + return; + } + if (this.className.search(/\bsorttable_sorted_reverse\b/) != -1) { + // if we're already sorted by this column in reverse, just + // re-reverse the table, which is quicker + sorttable.reverse(this.sorttable_tbody); + this.className = this.className.replace('sorttable_sorted_reverse', + 'sorttable_sorted'); + this.removeChild(document.getElementById('sorttable_sortrevind')); + sortfwdind = document.createElement('span'); + sortfwdind.id = "sorttable_sortfwdind"; + sortfwdind.innerHTML = stIsIE ? ' 6' : ' ▾'; + this.appendChild(sortfwdind); + return; + } + + // remove sorttable_sorted classes + theadrow = this.parentNode; + forEach(theadrow.childNodes, function(cell) { + if (cell.nodeType == 1) { // an element + cell.className = cell.className.replace('sorttable_sorted_reverse',''); + cell.className = cell.className.replace('sorttable_sorted',''); + } + }); + sortfwdind = document.getElementById('sorttable_sortfwdind'); + if (sortfwdind) { sortfwdind.parentNode.removeChild(sortfwdind); } + sortrevind = document.getElementById('sorttable_sortrevind'); + if (sortrevind) { sortrevind.parentNode.removeChild(sortrevind); } + + this.className += ' sorttable_sorted'; + sortfwdind = document.createElement('span'); + sortfwdind.id = "sorttable_sortfwdind"; + sortfwdind.innerHTML = stIsIE ? ' 6' : ' ▾'; + this.appendChild(sortfwdind); + + // build an array to sort. This is a Schwartzian transform thing, + // i.e., we "decorate" each row with the actual sort key, + // sort based on the sort keys, and then put the rows back in order + // which is a lot faster because you only do getInnerText once per row + row_array = []; + col = this.sorttable_columnindex; + rows = this.sorttable_tbody.rows; + for (var j=0; j 12) { + // definitely dd/mm + return sorttable.sort_ddmm; + } else if (second > 12) { + return sorttable.sort_mmdd; + } else { + // looks like a date, but we can't tell which, so assume + // that it's dd/mm (English imperialism!) and keep looking + sortfn = sorttable.sort_ddmm; + } + } + } + } + return sortfn; + }, + + getInnerText: function(node) { + // gets the text we want to use for sorting for a cell. + // strips leading and trailing whitespace. + // this is *not* a generic getInnerText function; it's special to sorttable. + // for example, you can override the cell text with a customkey attribute. + // it also gets .value for fields. + + hasInputs = (typeof node.getElementsByTagName == 'function') && + node.getElementsByTagName('input').length; + + if (node.getAttribute("sorttable_customkey") != null) { + return node.getAttribute("sorttable_customkey"); + } + else if (typeof node.textContent != 'undefined' && !hasInputs) { + return node.textContent.replace(/^\s+|\s+$/g, ''); + } + else if (typeof node.innerText != 'undefined' && !hasInputs) { + return node.innerText.replace(/^\s+|\s+$/g, ''); + } + else if (typeof node.text != 'undefined' && !hasInputs) { + return node.text.replace(/^\s+|\s+$/g, ''); + } + else { + switch (node.nodeType) { + case 3: + if (node.nodeName.toLowerCase() == 'input') { + return node.value.replace(/^\s+|\s+$/g, ''); + } + case 4: + return node.nodeValue.replace(/^\s+|\s+$/g, ''); + break; + case 1: + case 11: + var innerText = ''; + for (var i = 0; i < node.childNodes.length; i++) { + innerText += sorttable.getInnerText(node.childNodes[i]); + } + return innerText.replace(/^\s+|\s+$/g, ''); + break; + default: + return ''; + } + } + }, + + reverse: function(tbody) { + // reverse the rows in a tbody + newrows = []; + for (var i=0; i=0; i--) { + tbody.appendChild(newrows[i]); + } + delete newrows; + }, + + /* sort functions + each sort function takes two parameters, a and b + you are comparing a[0] and b[0] */ + sort_numeric: function(a,b) { + aa = parseFloat(a[0].replace(/[^0-9.-]/g,'')); + if (isNaN(aa)) aa = 0; + bb = parseFloat(b[0].replace(/[^0-9.-]/g,'')); + if (isNaN(bb)) bb = 0; + return aa-bb; + }, + sort_alpha: function(a,b) { + if (a[0]==b[0]) return 0; + if (a[0] 0 ) { + var q = list[i]; list[i] = list[i+1]; list[i+1] = q; + swap = true; + } + } // for + t--; + + if (!swap) break; + + for(var i = t; i > b; --i) { + if ( comp_func(list[i], list[i-1]) < 0 ) { + var q = list[i]; list[i] = list[i-1]; list[i-1] = q; + swap = true; + } + } // for + b++; + + } // while(swap) + } +} + +/* ****************************************************************** + Supporting functions: bundled here to avoid depending on a library + ****************************************************************** */ + +// Dean Edwards/Matthias Miller/John Resig + +/* for Mozilla/Opera9 */ +if (document.addEventListener) { + document.addEventListener("DOMContentLoaded", sorttable.init, false); +} + +/* for Internet Explorer */ +/*@cc_on @*/ +/*@if (@_win32) + document.write(" - - - - -

app - scan-build results

- - - - - - - -
User:unknown@c095cbd396f2
Working Directory:/app
Command Line:make default
Clang Version:Ubuntu clang version 12.0.0-3ubuntu1~20.04.5 -
Date:Mon May 16 07:10:46 2022
-

Bug Summary

- - - - -
Bug TypeQuantityDisplay?
All Bugs2
Dead store
Dead assignment2
-

Reports

- - - - - - - - - - - - - - - - - - - - -
Bug GroupBug Type ▾FileFunction/MethodLinePath Length
Dead storeDead assignmentlib_bagl/src/bagl.cbagl_draw_with_context7901View Report
Dead storeDead assignmentsrc/os_io_seproxyhal.cio_seproxyhal_display_icon7611View Report
- - diff --git a/app/output-scan-build/2022-05-16-071046-61-1/report-05ba52.html b/app/output-scan-build/2022-05-16-071046-61-1/report-05ba52.html deleted file mode 100644 index 027fd03f..00000000 --- a/app/output-scan-build/2022-05-16-071046-61-1/report-05ba52.html +++ /dev/null @@ -1,1431 +0,0 @@ - - - -/opt/nanox-secure-sdk/lib_bagl/src/bagl.c - - - - - - - - - - - - - - - - - - - - - - - - - - -

Bug Summary

- - - - -
File:lib_bagl/src/bagl.c
Warning:line 790, column 11
Value stored to 'pos' is never read
- -

Annotated Source Code

-

Press '?' - to see keyboard shortcuts

- - -
clang -cc1 -cc1 -triple thumbv6m-none-unknown-eabi -analyze -disable-free -disable-llvm-verifier -discard-value-names -main-file-name bagl.c -analyzer-store=region -analyzer-opt-analyze-nested-blocks -analyzer-checker=core -analyzer-checker=apiModeling -analyzer-checker=unix -analyzer-checker=deadcode -analyzer-checker=security.insecureAPI.UncheckedReturn -analyzer-checker=security.insecureAPI.getpw -analyzer-checker=security.insecureAPI.gets -analyzer-checker=security.insecureAPI.mktemp -analyzer-checker=security.insecureAPI.mkstemp -analyzer-checker=security.insecureAPI.vfork -analyzer-checker=nullability.NullPassedToNonnull -analyzer-checker=nullability.NullReturnedFromNonnull -analyzer-output plist -w -setup-static-analyzer -mrelocation-model ropi-rwpi -fropi -frwpi -fhalf-no-semantic-interposition -fno-jump-tables -mframe-pointer=none -fmath-errno -fno-rounding-math -fno-verbose-asm -mconstructor-aliases -nostdsysteminc -target-cpu cortex-m0plus -target-feature +soft-float -target-feature +soft-float-abi -target-feature -crc -target-feature -sha2 -target-feature -aes -target-feature -dsp -target-feature -ras -target-feature -sb -target-feature -i8mm -target-feature -lob -target-feature -cdecp0 -target-feature -cdecp1 -target-feature -cdecp2 -target-feature -cdecp3 -target-feature -cdecp4 -target-feature -cdecp5 -target-feature -cdecp6 -target-feature -cdecp7 -target-feature -hwdiv-arm -target-feature -hwdiv -target-feature -vfp2 -target-feature -vfp2sp -target-feature -vfp3 -target-feature -vfp3d16 -target-feature -vfp3d16sp -target-feature -vfp3sp -target-feature -fp16 -target-feature -vfp4 -target-feature -vfp4d16 -target-feature -vfp4d16sp -target-feature -vfp4sp -target-feature -fp-armv8 -target-feature -fp-armv8d16 -target-feature -fp-armv8d16sp -target-feature -fp-armv8sp -target-feature -fullfp16 -target-feature -fp64 -target-feature -d32 -target-feature -neon -target-feature -crypto -target-feature -dotprod -target-feature -fp16fml -target-feature -bf16 -target-feature -mve -target-feature -mve.fp -target-feature -fpregs -target-feature +strict-align -target-abi aapcs -msoft-float -mfloat-abi soft -fallow-half-arguments-and-returns -fno-split-dwarf-inlining -debugger-tuning=gdb -ffunction-sections -fdata-sections -resource-dir /usr/lib/llvm-12/lib/clang/12.0.0 -D gcc -D __IO=volatile -D NDEBUG -D HAVE_SE_SCREEN -D HAVE_SE_BUTTON -D HAVE_MCU_SERIAL_STORAGE -D HAVE_FONTS -D HAVE_BATTERY -D HAVE_NES_CRYPT -D HAVE_ST_EDES_PLUS -D HAVE_ST_AES -D NATIVE_LITTLE_ENDIAN -D HAVE_CRC -D HAVE_HASH -D HAVE_RIPEMD160 -D HAVE_SHA224 -D HAVE_SHA256 -D HAVE_SHA3 -D HAVE_SHA384 -D HAVE_SHA512 -D HAVE_SHA512_WITH_BLOCK_ALT_METHOD -D HAVE_SHA512_WITH_BLOCK_ALT_METHOD_M0 -D HAVE_BLAKE2 -D HAVE_HMAC -D HAVE_PBKDF2 -D HAVE_DES -D HAVE_AES -D HAVE_MATH -D HAVE_RNG -D HAVE_RNG_RFC6979 -D HAVE_RNG_SP800_90A -D HAVE_ECC -D HAVE_ECC_WEIERSTRASS -D HAVE_ECC_TWISTED_EDWARDS -D HAVE_ECC_MONTGOMERY -D HAVE_SECP256K1_CURVE -D HAVE_SECP256R1_CURVE -D HAVE_SECP384R1_CURVE -D HAVE_SECP521R1_CURVE -D HAVE_FR256V1_CURVE -D HAVE_STARK256_CURVE -D HAVE_BRAINPOOL_P256R1_CURVE -D HAVE_BRAINPOOL_P256T1_CURVE -D HAVE_BRAINPOOL_P320R1_CURVE -D HAVE_BRAINPOOL_P320T1_CURVE -D HAVE_BRAINPOOL_P384R1_CURVE -D HAVE_BRAINPOOL_P384T1_CURVE -D HAVE_BRAINPOOL_P512R1_CURVE -D HAVE_BRAINPOOL_P512T1_CURVE -D HAVE_BLS12_381_G1_CURVE -D HAVE_CV25519_CURVE -D HAVE_CV448_CURVE -D HAVE_ED25519_CURVE -D HAVE_ED448_CURVE -D HAVE_ECDH -D HAVE_ECDSA -D HAVE_EDDSA -D HAVE_ECSCHNORR -D HAVE_X25519 -D HAVE_X448 -D APP_CONSUMER -D UNUSED(x)=(void)x -D PRINTF(...)= -D APPVERSION="0.9.13" -D OS_IO_SEPROXYHAL -D HAVE_BAGL -D HAVE_SPRINTF -D HAVE_IO_USB -D HAVE_L4_USBLIB -D IO_USB_MAX_ENDPOINTS=7 -D IO_HID_EP_LENGTH=64 -D HAVE_USB_APDU -D LEDGER_MAJOR_VERSION=0 -D LEDGER_MINOR_VERSION=9 -D LEDGER_PATCH_VERSION=13 -D USB_SEGMENT_SIZE=64 -D HAVE_BOLOS_APP_STACK_CANARY -D HAVE_WEBUSB -D WEBUSB_URL_SIZE_B=0 -D WEBUSB_URL= -D HAVE_BLE -D HAVE_BLE_APDU -D BLE_COMMAND_TIMEOUT_MS=2000 -D IO_SEPROXYHAL_BUFFER_SIZE_B=300 -D HAVE_GLO096 -D HAVE_BAGL -D BAGL_WIDTH=128 -D BAGL_HEIGHT=64 -D HAVE_BAGL_ELLIPSIS -D HAVE_BAGL_FONT_OPEN_SANS_REGULAR_11PX -D HAVE_BAGL_FONT_OPEN_SANS_EXTRABOLD_11PX -D HAVE_BAGL_FONT_OPEN_SANS_LIGHT_16PX -D HAVE_UX_FLOW -D LEDGER_SPECIFIC -I .//glyphs -I /opt/nanox-secure-sdk/lib_cxng/include -I /opt/nanox-secure-sdk/lib_blewbxx/ -I /opt/nanox-secure-sdk/lib_blewbxx/core/template/ -I /opt/nanox-secure-sdk/lib_blewbxx/core/template/ -I /opt/nanox-secure-sdk/lib_blewbxx/core/template/ -I /opt/nanox-secure-sdk/lib_blewbxx/core/ -I /opt/nanox-secure-sdk/lib_blewbxx/core/ -I /opt/nanox-secure-sdk/lib_blewbxx/core/ -I /opt/nanox-secure-sdk/lib_blewbxx/core/auto/ -I /opt/nanox-secure-sdk/lib_blewbxx/core/auto/ -I /opt/nanox-secure-sdk/lib_blewbxx/core/auto/ -I /opt/nanox-secure-sdk/lib_blewbxx/core/auto/ -I /opt/nanox-secure-sdk/lib_blewbxx/core/auto/ -I /opt/nanox-secure-sdk/lib_blewbxx/core/auto/ -I /opt/nanox-secure-sdk/lib_blewbxx/core/ -I /opt/nanox-secure-sdk/lib_blewbxx/core/ -I /opt/nanox-secure-sdk/lib_blewbxx/ -I /opt/nanox-secure-sdk/lib_blewbxx_impl/include/ -I /opt/nanox-secure-sdk/lib_blewbxx_impl/ -I /opt/nanox-secure-sdk/lib_stusb/ -I /opt/nanox-secure-sdk/lib_stusb/STM32_USB_Device_Library/Class/CCID/inc/ -I /opt/nanox-secure-sdk/lib_stusb/STM32_USB_Device_Library/Class/CCID/inc/ -I /opt/nanox-secure-sdk/lib_stusb/STM32_USB_Device_Library/Class/CCID/inc/ -I /opt/nanox-secure-sdk/lib_stusb/STM32_USB_Device_Library/Class/CCID/inc/ -I /opt/nanox-secure-sdk/lib_stusb/STM32_USB_Device_Library/Class/HID/Inc/ -I /opt/nanox-secure-sdk/lib_stusb/STM32_USB_Device_Library/Core/Inc/ -I /opt/nanox-secure-sdk/lib_stusb/STM32_USB_Device_Library/Core/Inc/ -I /opt/nanox-secure-sdk/lib_stusb/STM32_USB_Device_Library/Core/Inc/ -I /opt/nanox-secure-sdk/lib_stusb/STM32_USB_Device_Library/Core/Inc/ -I /opt/nanox-secure-sdk/lib_stusb/STM32_USB_Device_Library/Core/Inc/ -I /opt/nanox-secure-sdk/lib_stusb_impl/ -I /opt/nanox-secure-sdk/lib_stusb_impl/ -I /opt/nanox-secure-sdk/lib_stusb_impl/ -I /opt/nanox-secure-sdk/lib_ux/include/ -I /opt/nanox-secure-sdk/lib_ux/include/ -I /opt/nanox-secure-sdk/lib_ux/include/ -I /opt/nanox-secure-sdk/lib_ux/include/ -I /opt/nanox-secure-sdk/lib_ux/src/ -I include -I /opt/nanox-secure-sdk/include -I /opt/nanox-secure-sdk/include/arm -I .//src/ -I .//src/json/ -I .//src/ -I .//src/ -I .//src/ -I .//src/ -I .//src/ -I .//src/ -I .//src/ -I .//src/ -I .//src/ -I .//src/ -I .//src/ -I .//src/common/ -I .//src/common/ -I .//src/common/ -I .//../deps/ledger-zxlib/include/ -I .//../deps/ledger-zxlib/include/ -I .//../deps/ledger-zxlib/include/ -I .//../deps/ledger-zxlib/include/ -I .//../deps/ledger-zxlib/include/ -I .//../deps/ledger-zxlib/include/ -I .//../deps/ledger-zxlib/include/ -I .//../deps/ledger-zxlib/include/ -I .//../deps/ledger-zxlib/include/ -I .//../deps/ledger-zxlib/include/ -I .//../deps/ledger-zxlib/include/ -I .//../deps/ledger-zxlib/include/ -I .//../deps/ledger-zxlib/include/ -I .//../deps/ledger-zxlib/include/ -I .//../deps/ledger-zxlib/include/ -I .//../deps/ledger-zxlib/include/ -I .//../deps/ledger-zxlib/include/ -I .//../deps/ledger-zxlib/include/ -I .//../deps/ledger-zxlib/include/ -I .//../deps/ledger-zxlib/include/ -I .//../deps/ledger-zxlib/include/ -I .//../deps/ledger-zxlib/include/ -I .//../deps/ledger-zxlib/app/common/ -I .//../deps/ledger-zxlib/app/common/ -I .//../deps/jsmn/src/ -isysroot /opt/gcc-arm-none-eabi-10.3-2021.10/bin/../arm-none-eabi -internal-isystem /usr/lib/llvm-12/lib/clang/12.0.0/include -internal-isystem /opt/gcc-arm-none-eabi-10.3-2021.10/bin/../arm-none-eabi/include -Os -Wno-main -Wno-unknown-pragmas -std=gnu99 -fdebug-compilation-dir /app -ferror-limit 19 -fshort-enums -fno-signed-char -fgnuc-version=4.2.1 -vectorize-loops -vectorize-slp -analyzer-checker security -analyzer-checker unix -analyzer-checker valist -analyzer-opt-analyze-headers -analyzer-output=html -faddrsig -o /app/output-scan-build/2022-05-16-071046-61-1 -x c /opt/nanox-secure-sdk/lib_bagl/src/bagl.c -
- - - -
- - -
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
1
2/*******************************************************************************
3* Ledger Nano S - Secure firmware
4* (c) 2022 Ledger
5*
6* Licensed under the Apache License, Version 2.0 (the "License");
7* you may not use this file except in compliance with the License.
8* You may obtain a copy of the License at
9*
10* http://www.apache.org/licenses/LICENSE-2.0
11*
12* Unless required by applicable law or agreed to in writing, software
13* distributed under the License is distributed on an "AS IS" BASIS,
14* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
15* See the License for the specific language governing permissions and
16* limitations under the License.
17********************************************************************************/
18
19#ifdef HAVE_BAGL1
20
21#include "bagl.h"
22#include <string.h>
23#include <stdio.h>
24
25#include "os.h"
26
27/**
28 Coordinate system for BAGL:
29 ===========================
30
31 0 X axis
32 0 +----->
33 |
34Y axis | #####
35 v #######
36 ## ##
37 #######
38 #####
39*/
40
41
42// --------------------------------------------------------------------------------------
43// Checks
44// --------------------------------------------------------------------------------------
45
46/*
47#ifndef BAGL_COMPONENT_MAXCOUNT
48#error BAGL_COMPONENT_MAXCOUNT not set
49#endif // !BAGL_COMPONENT_MAXCOUNT
50*/
51
52#ifndef BAGL_WIDTH128
53#error BAGL_WIDTH128 not set
54#endif // !BAGL_WIDTH
55
56#ifndef BAGL_HEIGHT64
57#error BAGL_HEIGHT64 not set
58#endif // !BAGL_HEIGHT
59
60// --------------------------------------------------------------------------------------
61// Definitions
62// --------------------------------------------------------------------------------------
63
64#define ICON_WIDTH0 0
65#ifndef MIN
66#define MIN(x,y)((x) < (y) ? (x) : (y)) ((x)<(y)?(x):(y))
67#endif
68#ifndef MAX
69#define MAX(x,y)((x) > (y) ? (x) : (y)) ((x)>(y)?(x):(y))
70#endif
71#ifndef U2BE
72#define U2BE(buf, off)((((buf)[off]&0xFF)<<8) | ((buf)[off+1]&0xFF) ) ((((buf)[off]&0xFF)<<8) | ((buf)[off+1]&0xFF) )
73#endif
74#ifndef U4BE
75#define U4BE(buf, off)((((((buf)[off]&0xFF)<<8) | ((buf)[off+1]&0xFF)
)<<16) | (((((buf)[off+2]&0xFF)<<8) | ((buf)
[off+2 +1]&0xFF) )&0xFFFF))
((U2BE(buf, off)((((buf)[off]&0xFF)<<8) | ((buf)[off+1]&0xFF) )<<16) | (U2BE(buf, off+2)((((buf)[off+2]&0xFF)<<8) | ((buf)[off+2 +1]&0xFF
) )
&0xFFFF))
76#endif
77
78// --------------------------------------------------------------------------------------
79// Variables
80// --------------------------------------------------------------------------------------
81
82#ifdef HAVE_BAGL_GLYPH_ARRAY
83const bagl_glyph_array_entry_t* G_glyph_array;
84unsigned int G_glyph_count;
85#endif // HAVE_BAGL_GLYPH_ARRAY
86
87// --------------------------------------------------------------------------------------
88// API
89// --------------------------------------------------------------------------------------
90
91// --------------------------------------------------------------------------------------
92void bagl_draw_bg(unsigned int color) {
93 bagl_component_t c;
94 memset(&c, 0, sizeof(c));
95 c.type = BAGL_RECTANGLE;
96 c.userid = BAGL_NONE;
97 c.fgcolor = color;
98 c.x = 0;
99 c.y = 0;
100 c.width = BAGL_WIDTH128;
101 c.height = BAGL_HEIGHT64;
102 c.fill = BAGL_FILL1;
103 // draw the rect
104 bagl_draw_with_context(&c, NULL((void*)0), 0, 0);
105}
106
107#ifdef HAVE_BAGL_GLYPH_ARRAY
108// --------------------------------------------------------------------------------------
109// internal helper, get the glyph entry from the glyph id (sparse glyph array support)
110const bagl_glyph_array_entry_t* bagl_get_glyph(unsigned int icon_id, const bagl_glyph_array_entry_t* glyph_array, unsigned int glyph_count) {
111 unsigned int i=glyph_count;
112
113 while(i--) {
114 // font id match this entry (non linear)
115 if (glyph_array[i].icon_id == icon_id) {
116 return &glyph_array[i];
117 }
118 }
119
120 // id not found
121 return NULL((void*)0);
122}
123#endif // HAVE_BAGL_GLYPH_ARRAY
124
125// --------------------------------------------------------------------------------------
126// internal helper, get the font entry from the font id (sparse font array support)
127const bagl_font_t* bagl_get_font(unsigned int font_id) {
128 unsigned int i=C_bagl_fonts_count;
129 font_id &= BAGL_FONT_ID_MASK0x0FFF;
130
131 while(i--) {
132 // font id match this entry (non indexed array)
133 if (PIC_FONT(C_bagl_fonts[i])((bagl_font_t const *)pic((void *)C_bagl_fonts[i]))->font_id == font_id) {
134 return PIC_FONT(C_bagl_fonts[i])((bagl_font_t const *)pic((void *)C_bagl_fonts[i]));
135 }
136 }
137
138 // id not found
139 return NULL((void*)0);
140}
141
142// --------------------------------------------------------------------------------------
143// return the width of a text (first line only) for alignment processing
144unsigned short bagl_compute_line_width(unsigned short font_id, unsigned short width, const void * text, unsigned char text_length, unsigned char text_encoding) {
145 unsigned short xx;
146 const bagl_font_t *font = bagl_get_font(font_id);
147 if (font == NULL((void*)0)) {
148 return 0;
149 }
150
151 // initialize first index
152 xx = 0;
153
154 //printf("display text: %s\n", text);
155
156 // depending on encoding
157 while (text_length--) {
158 unsigned int ch = 0;
159 // TODO support other encoding than ascii ISO8859 Latin
160 switch(text_encoding) {
161 default:
162 case BAGL_ENCODING_LATIN10:
163 ch = *((unsigned char*)text);
164 text = (void*)(((unsigned char*)text)+1);
165 break;
166 }
167
168 unsigned char ch_width = 0;
169 if (ch < font->first_char || ch > font->last_char) {
170 // only proceed the first line width, not the whole paragraph
171 if (ch == '\n' || ch == '\r') {
172 return xx;
173 }
174
175 // else use the low bits as an extra spacing value
176 if (ch >= 0xC0) {
177 ch_width = ch&0x3F;
178 }
179 else if (ch >= 0x80) {
180 // open the glyph font
181 const bagl_font_t *font_symbols = bagl_get_font((ch&0x20)?BAGL_FONT_SYMBOLS_1:BAGL_FONT_SYMBOLS_0);
182 if (font_symbols != NULL((void*)0)) {
183 // extract the size of the symbols' font character
184 ch_width = PIC_CHAR(font_symbols->characters)((const bagl_font_character_t *)pic((void *)font_symbols->
characters))
[ch & 0x1F].char_width;
185 }
186 }
187 }
188 else {
189 // compute the index in the bitmap array
190 ch -= font->first_char;
191 ch_width = PIC_CHAR(font->characters)((const bagl_font_character_t *)pic((void *)font->characters
))
[ch].char_width;
192 }
193
194 // retrieve the char bitmap
195
196 // go to next line if needed, kerning is not used here
197 if (width > 0 && xx + ch_width > width) {
198 return xx;
199 }
200
201 // prepare for next char
202 xx += ch_width;
203 }
204 return xx;
205}
206
207// --------------------------------------------------------------------------------------
208// draw char until a char fit before reaching width
209// TODO support hyphenation ??
210int bagl_draw_string(unsigned short font_id, unsigned int fgcolor, unsigned int bgcolor, int x, int y, unsigned int width, unsigned int height, const void* text, unsigned int text_length, unsigned char text_encoding) {
211 int xx;
212 unsigned int colors[16];
213 colors[0] = bgcolor;
214 colors[1] = fgcolor;
215 unsigned int ch = 0;
216
217 const bagl_font_t *font = bagl_get_font(font_id);
218 if (font == NULL((void*)0)) {
219 return 0;
220 }
221
222
223#ifdef BAGL_MULTICHROME
224 if (font->bpp > 1) {
225 // fgcolor = 0x7e7ecc
226 // bgcolor = 0xeca529
227 // $1 = {0xeca529, 0xc6985f, 0xa28b95, 0x7e7ecc}
228
229 unsigned int color_count = 1<<(font->bpp);
230 memset(colors, 0, sizeof(colors));
231 colors[0] = bgcolor;
232 colors[color_count-1] = fgcolor;
233
234 // compute for all base colors
235 int off;
236 for (off = 0; off < 3; off++) {
237
238 int cfg = (fgcolor>>(off*8))&0xFF;
239 int cbg = (bgcolor>>(off*8))&0xFF;
240
241 int crange = MAX(cfg,cbg)((cfg) > (cbg) ? (cfg) : (cbg))-MIN(cfg,cbg)((cfg) < (cbg) ? (cfg) : (cbg))+1;
242 int cinc = crange/(color_count-1UL);
243
244 if (cfg > cbg) {
245 unsigned int i;
246 for (i=1; i < color_count-1UL; i++) {
247 colors[i] |= MIN(0xFF, cbg+i*cinc)((0xFF) < (cbg+i*cinc) ? (0xFF) : (cbg+i*cinc))<<(off*8);
248 }
249 }
250 else {
251 unsigned int i;
252
253 for (i=1; i < color_count-1UL; i++) {
254 colors[i] |= MIN(0xFF, cfg+(color_count-1UL-i)*cinc)((0xFF) < (cfg+(color_count-1UL-i)*cinc) ? (0xFF) : (cfg+(
color_count-1UL-i)*cinc))
<<(off*8);
255 }
256 }
257 }
258 }
259#endif // BAGL_MULTICHROME // for the blue
260
261 // always comparing this way, very optimized etc
262 width += x;
263 height += y;
264
265 // initialize first index
266 xx = x;
267
268 //printf("display text: %s\n", text);
269
270
271 // depending on encoding
272 while (text_length--) {
273 // TODO support other encoding than ascii ISO8859 Latin
274 switch(text_encoding) {
275 default:
276 case BAGL_ENCODING_LATIN10:
277 // avoid 2 new line on \r and \n for windows familiar users
278 if (ch == '\r') {
279 ch = *((unsigned char*)text);
280 if (ch == '\n') {
281 text = (void*)(((unsigned int)text)+1);
282 continue;
283 }
284 }
285 else {
286 ch = *((unsigned char*)text);
287 }
288 text = (void*)(((unsigned int)text)+1);
289 break;
290 }
291
292 unsigned char ch_height = font->char_height;
293 unsigned char ch_kerning = 0;
294 unsigned char ch_width = 0;
295 const unsigned char * ch_bitmap = NULL((void*)0);
296 int ch_y = y;
297
298 if (ch < font->first_char || ch > font->last_char) {
299 //printf("invalid char");
300 // can't proceed
301 if (ch == '\n' || ch == '\r') {
302 y += ch_height; // no interleave
303
304 // IGNORED for first line
305 if (y + ch_height > (int)height) {
306 // we're writing half height of the last line ... probably better to put some dashes
307 return (y<<16)|(xx&0xFFFF);
308 }
309
310 // newline starts back at first x offset
311 xx = x;
312 continue;
313 }
314
315 if (ch >= 0xC0) {
316 ch_width = ch & 0x3F;
317 }
318 else if (ch >= 0x80) {
319 // open the glyph font
320 const bagl_font_t *font_symbols = bagl_get_font((ch&0x20)?BAGL_FONT_SYMBOLS_1:BAGL_FONT_SYMBOLS_0);
321 if (font_symbols != NULL((void*)0)) {
322 ch_bitmap = &PIC_BMP(font_symbols->bitmap)((unsigned char const *)pic((void *)font_symbols->bitmap))[PIC_CHAR(font_symbols->characters)((const bagl_font_character_t *)pic((void *)font_symbols->
characters))
[ch & 0x1F].bitmap_offset];
323 ch_width = PIC_CHAR(font_symbols->characters)((const bagl_font_character_t *)pic((void *)font_symbols->
characters))
[ch & 0x1F].char_width;
324 ch_height = font_symbols->char_height;
325 // align baselines
326 ch_y = y + font->baseline_height - font_symbols->baseline_height;
327 }
328 }
329 }
330 else {
331 ch -= font->first_char;
332 ch_bitmap = &PIC_BMP(font->bitmap)((unsigned char const *)pic((void *)font->bitmap))[PIC_CHAR(font->characters)((const bagl_font_character_t *)pic((void *)font->characters
))
[ch].bitmap_offset];
333 ch_width = PIC_CHAR(font->characters)((const bagl_font_character_t *)pic((void *)font->characters
))
[ch].char_width;
334 ch_kerning = font->char_kerning;
335 }
336
337 // retrieve the char bitmap
338
339 // go to next line if needed
340 if (xx + ch_width > (int)width) {
341 y += ch_height; // no interleave
342
343 // IGNORED for first line
344 if (y + ch_height > (int)height) {
345 // we're writing half height of the last line ... probably better to put some dashes
346 return (y<<16)|(xx&0xFFFF);
347 }
348
349 // newline starts back at first x offset
350 xx = x;
351 ch_y = y;
352 }
353
354 /* IGNORED for first line
355 if (y + ch_height > height) {
356 // we're writing half height of the last line ... probably better to put some dashes
357 return;
358 }
359 */
360
361 // chars are storred LSB to MSB in each char, packed chars. horizontal scan
362 if (ch_bitmap) {
363 bagl_hal_draw_bitmap_within_rect(xx, ch_y, ch_width, ch_height, (1<<font->bpp), colors, font->bpp, ch_bitmap, font->bpp*ch_width*ch_height); // note, last parameter is computable could be avoided
364 }
365 else {
366 bagl_hal_draw_rect(bgcolor, xx, ch_y, ch_width, ch_height);
367 }
368 // prepare for next char
369 xx += ch_width + ch_kerning;
370 }
371
372 // return newest position, for upcoming printf
373 return (y<<16)|(xx&0xFFFF);
374}
375
376// --------------------------------------------------------------------------------------
377
378// draw round or circle. unaliased.
379// if radiusint is !=0 then draw a circle of color outline, and colorint inside
380void bagl_draw_circle_helper(unsigned int color, int x_center, int y_center, unsigned int radius, unsigned char octants, unsigned int radiusint, unsigned int colorint) {
381
382/*
383 128 ***** 32
384 * *
385 64 * * 16
386 * *
387 * *
388 4 * * 1
389 * *
390 8 ***** 2
391*/
392
393 int last_x;
394 int x = radius;
395 int y = 0;
396 int decisionOver2 = 1 - x; // Decision criterion divided by 2 evaluated at x=r, y=0
397 int dradius = radius-radiusint;
398 last_x = x;
399 unsigned int drawint = (radiusint > 0 && dradius > 0 /*&& xint <= yint*/);
400
401 while( y <= x )
402 {
403 if (octants & 1) { //
404 if (drawint) {
405 bagl_hal_draw_rect(colorint, x_center, y+y_center, x-(dradius-1), 1);
406 bagl_hal_draw_rect(color, x_center+x-(dradius-1), y+y_center, dradius, 1);
407 }
408 else {
409 bagl_hal_draw_rect(color, x_center, y+y_center-1, x, 1);
410 }
411 }
412 if (octants & 2) { //
413 if (drawint) {
414 if (last_x != x) {
415 bagl_hal_draw_rect(colorint, x_center, x+y_center, y-(dradius-1), 1);
416 }
417 bagl_hal_draw_rect(color, x_center+y-(dradius-1), x+y_center, dradius, 1);
418 }
419 else {
420 bagl_hal_draw_rect(color, x_center, x+y_center-1, y, 1);
421 }
422 }
423 if (octants & 4) { //
424 if (drawint) {
425 bagl_hal_draw_rect(colorint, x_center-x, y+y_center, x-(dradius-1), 1);
426 bagl_hal_draw_rect(color, x_center-x-(dradius-1), y+y_center, dradius, 1);
427 }
428 else {
429 bagl_hal_draw_rect(color, x_center-x, y+y_center-1, x, 1);
430 }
431 }
432 if (octants & 8) { //
433 if (drawint) {
434 if (last_x != x) {
435 bagl_hal_draw_rect(colorint, x_center-y, x+y_center, y-(dradius-1), 1);
436 }
437 bagl_hal_draw_rect(color, x_center-y-(dradius-1), x+y_center, dradius, 1);
438 }
439 else {
440 bagl_hal_draw_rect(color, x_center-y, x+y_center-1, y, 1);
441 }
442 }
443 if (octants & 16) { //
444 if (drawint) {
445 bagl_hal_draw_rect(colorint, x_center, y_center-y, x-(dradius-1), 1);
446 bagl_hal_draw_rect(color, x_center+x-(dradius-1), y_center-y, dradius, 1);
447 }
448 else {
449 bagl_hal_draw_rect(color, x_center, y_center-y, x, 1);
450 }
451 }
452 if (octants & 32) { //
453 if (drawint) {
454 if (last_x != x) {
455 bagl_hal_draw_rect(colorint, x_center, y_center-x, y-(dradius-1), 1);
456 }
457 bagl_hal_draw_rect(color, x_center+y-(dradius-1), y_center-x, dradius, 1);
458 }
459 else {
460 bagl_hal_draw_rect(color, x_center, y_center-x, y, 1);
461 }
462 }
463 if (octants & 64) { //
464 if (drawint) {
465 bagl_hal_draw_rect(colorint, x_center-x, y_center-y, x-(dradius-1), 1);
466 bagl_hal_draw_rect(color, x_center-x-(dradius-1), y_center-y, dradius, 1);
467 }
468 else {
469 bagl_hal_draw_rect(color, x_center-x, y_center-y, x, 1);
470 }
471 }
472 if (octants & 128) { //
473 if (drawint) {
474 if (last_x != x) {
475 bagl_hal_draw_rect(colorint, x_center-y, y_center-x, y-(dradius-1), 1);
476 }
477 bagl_hal_draw_rect(color, x_center-y-(dradius-1), y_center-x, dradius, 1);
478 }
479 else {
480 bagl_hal_draw_rect(color, x_center-y, y_center-x, y, 1);
481 }
482 }
483
484 last_x = x;
485 y++;
486 if (decisionOver2<=0)
487 {
488 decisionOver2 += 2 * y + 1; // Change in decision criterion for y -> y+1
489 }
490 else
491 {
492 x--;
493 decisionOver2 += 2 * (y - x) + 1; // Change for y -> y+1, x -> x-1
494 }
495 }
496}
497
498// --------------------------------------------------------------------------------------
499
500#ifdef HAVE_BAGL_GLYPH_ARRAY
501void bagl_set_glyph_array(const bagl_glyph_array_entry_t* array, unsigned int count) {
502 G_glyph_array = array;
503 G_glyph_count = count;
504}
505#endif // HAVE_BAGL_GLYPH_ARRAY
506
507// --------------------------------------------------------------------------------------
508
509void bagl_draw_with_context(const bagl_component_t* component, const void* context, unsigned short context_length, unsigned char context_encoding) {
510 //unsigned char comp_idx;
511 int halignment=0;
512 int valignment=0;
513#ifdef HAVE_BAGL_GLYPH_ARRAY
514 int x,y;
515#endif // HAVE_BAGL_GLYPH_ARRAY
516 int baseline=0;
517 unsigned int height_to_draw=0;
518 int strwidth = 0;
519 unsigned int ellipsis_1_len = 0;
520#ifdef HAVE_BAGL_ELLIPSIS1
521 const char* ellipsis_2_start = NULL((void*)0);
522#endif // HAVE_BAGL_ELLIPSIS
523
524#ifdef HAVE_BAGL_GLYPH_ARRAY
525 const bagl_glyph_array_entry_t* glyph=NULL((void*)0);
526#endif // HAVE_BAGL_GLYPH_ARRAY
527
528 // DESIGN NOTE: always consider drawing onto a bg color filled image. (done upon undraw)
529
530 /*
531 // check if userid already exist, if yes, reuse entry
532 for (comp_idx=0; comp_idx < BAGL_COMPONENT_MAXCOUNT; comp_idx++) {
533 if (bagl_components[comp_idx].userid == component->userid) {
534 goto idx_ok;
535 }
536 }
537
538 // find the first empty entry
539 for (comp_idx=0; comp_idx < BAGL_COMPONENT_MAXCOUNT; comp_idx++) {
540 if (bagl_components[comp_idx].userid == BAGL_NONE) {
541 goto idx_ok;
542 }
543 }
544 // no more space :(
545 //BAGL_THROW(NO_SPACE);
546 return;
547
548
549idx_ok:
550 */
551
552 // strip the flags to match kinds
553 unsigned int type = component->type&~(BAGL_TYPE_FLAGS_MASK0x80);
554
555 // compute alignment if text provided and requiring special alignment
556 if (type != BAGL_ICON) {
557 const bagl_font_t* font = bagl_get_font(component->font_id);
558 if (font) {
559 baseline = font->baseline_height;
560 height_to_draw = component->height;
561
562 if (context && context_length) {
563 // compute with some margin to fit other characters and check if ellipsis algorithm is required
564 strwidth = bagl_compute_line_width(component->font_id, component->width+100, context, context_length, context_encoding);
565 ellipsis_1_len = context_length;
566
567#ifdef HAVE_BAGL_ELLIPSIS1
568 // ellipsis mode (ensure something is to be splitted!)
569 if (strwidth > component->width && context_length>4) {
570 unsigned int robin = 0; // remove char by char either on the left or right side
571 unsigned int dots_len = bagl_compute_line_width(component->font_id, 100 /*probably larger than ... whatever the font*/, "...", 3, context_encoding);
572 ellipsis_1_len = context_length/2;
573 ellipsis_2_start = ((char*)context) + context_length/2;
574 // split line in 2 halves, strip a char from end of left part, and from start of right part, reassemble with ... , repeat until it fits.
575 // NOTE: algorithm is wrong if special blank chars are inserted, they should be removed first
576 while (strwidth > component->width && ellipsis_1_len && (context_length - ((unsigned int)ellipsis_2_start-(unsigned int)context) )) {
577 unsigned int left_part = bagl_compute_line_width(component->font_id, component->width, context, ellipsis_1_len, context_encoding);
578 unsigned int right_part = bagl_compute_line_width(component->font_id, component->width, ellipsis_2_start, (context_length - ((unsigned int)ellipsis_2_start-(unsigned int)context) ), context_encoding);
579 // update to check and to compute alignement if needed
580 strwidth = left_part + dots_len + right_part;
581 // only start to split if the middle char if odd context_length removal is not sufficient
582 if (strwidth > component->width) {
583 // either remove a left char, OR remove a right char
584 switch(robin) {
585 case 0:
586 // remove a left char
587 ellipsis_1_len--;
588 break;
589 case 1:
590 // remove a right char
591 ellipsis_2_start++;
592 break;
593 }
594 robin = (robin+1)%2;
595 }
596 }
597 // we've computed split positions
598 }
599#endif // HAVE_BAGL_ELLIPSIS
600
601 switch (component->font_id & BAGL_FONT_ALIGNMENT_HORIZONTAL_MASK0xC000 ) {
602 default:
603 case BAGL_FONT_ALIGNMENT_LEFT0x0000:
604 halignment = 0;
605 break;
606 case BAGL_FONT_ALIGNMENT_RIGHT0x4000:
607 halignment = MAX(0,component->width - strwidth)((0) > (component->width - strwidth) ? (0) : (component
->width - strwidth))
;
608 break;
609 case BAGL_FONT_ALIGNMENT_CENTER0x8000:
610 // x xalign strwidth width
611 // ' ' ' '
612 // ^
613 // xalign = x+ (width/2) - (strwidth/2) => align -x
614 halignment = MAX(0,component->width/2 - strwidth/2)((0) > (component->width/2 - strwidth/2) ? (0) : (component
->width/2 - strwidth/2))
;
615 break;
616 }
617
618 switch (component->font_id & BAGL_FONT_ALIGNMENT_VERTICAL_MASK0x3000 ) {
619 default:
620 case BAGL_FONT_ALIGNMENT_TOP0x0000:
621 valignment = 0;
622 break;
623 case BAGL_FONT_ALIGNMENT_BOTTOM0x1000:
624 valignment = component->height - baseline;
625 break;
626 case BAGL_FONT_ALIGNMENT_MIDDLE0x2000:
627 // y yalign charheight height
628 // ' ' v ' '
629 // baseline
630 // yalign = y+ (height/2) - (baseline/2) => align - y
631 valignment = component->height/2 - baseline/2 - 1;
632 break;
633 }
634 }
635 }
636 }
637
638 unsigned int radius = component->radius;
639 radius = MIN(radius, MIN(component->width/2, component->height/2))((radius) < (((component->width/2) < (component->
height/2) ? (component->width/2) : (component->height/2
))) ? (radius) : (((component->width/2) < (component->
height/2) ? (component->width/2) : (component->height/2
))))
;
640
641 // Check the type only, ignore the touchable flag
642 switch (type) {
643 /*
644 button (B)
645 < |Icon|Space|Textstring| >
646 I.w W.w T.w
647 I.x = B.x+B.w/2-(I.w+W.w+T.w)/2
648 W.x = I.x+I.w
649 T.x = W.x+W.w = I.x+I.w+W.w = B.x+B.w/2-(I.w+W.w+T.w)/2+I.w+W.w = B.x+B.w/2-T.w/2+(I.w+W.w)/2
650 */
651
652 // Following types are supposed to draw a rectangle or write text or both
653 case BAGL_BUTTON:
654 case BAGL_LABEL:
655 case BAGL_RECTANGLE:
656 case BAGL_LINE:
657 case BAGL_LABELINE:
658 if((type == BAGL_LINE) && (component->radius == 0)) {
659 bagl_hal_draw_rect(component->fgcolor,
660 component->x, component->y,
661 component->width, component->height);
662 break;
663 }
664
665 if ((type == BAGL_LABEL) || (type == BAGL_LABELINE)) {
666 /*if (component->fill == BAGL_FILL)*/ {
667 bagl_hal_draw_rect(component->bgcolor,
668 component->x, component->y-(type==BAGL_LABELINE?(baseline):0),
669 component->width, (type==BAGL_LABELINE? height_to_draw : component->height));
670 }
671 }
672 else {
673 // Draw the rounded or not, filled or not rectangle
674 if (component->fill != BAGL_FILL1) {
675 // inner
676 // centered top to bottom
677 bagl_hal_draw_rect(component->bgcolor,
678 component->x+radius, component->y,
679 component->width-2*radius, component->height);
680 // left to center rect
681 bagl_hal_draw_rect(component->bgcolor,
682 component->x, component->y+radius,
683 radius, component->height-2*radius);
684 // center rect to right
685 bagl_hal_draw_rect(component->bgcolor,
686 component->x+component->width-radius-1, component->y+radius,
687 radius, component->height-2*radius);
688
689 // outline
690 // 4 rectangles (with last pixel of each corner not set)
691 bagl_hal_draw_rect(component->fgcolor,
692 component->x+radius, component->y,
693 component->width-2*radius, component->stroke); // top
694 bagl_hal_draw_rect(component->fgcolor,
695 component->x+radius, component->y+component->height-1,
696 component->width-2*radius, component->stroke); // bottom
697 bagl_hal_draw_rect(component->fgcolor,
698 component->x, component->y+radius,
699 component->stroke, component->height-2*radius); // left
700 bagl_hal_draw_rect(component->fgcolor,
701 component->x+component->width-1, component->y+radius,
702 component->stroke, component->height-2*radius); // right
703 }
704 else {
705 // centered top to bottom
706 bagl_hal_draw_rect(component->fgcolor,
707 component->x+radius, component->y,
708 component->width-2*radius, component->height);
709 // left to center rect
710 bagl_hal_draw_rect(component->fgcolor,
711 component->x, component->y+radius,
712 radius, component->height-2*radius);
713
714 // center rect to right
715 bagl_hal_draw_rect(component->fgcolor,
716 component->x+component->width-radius, component->y+radius,
717 radius, component->height-2*radius);
718 }
719
720 // draw corners
721 if (radius > 1) {
722 unsigned int radiusint = 0;
723 // carve round when not filling
724 if ((component->fill != BAGL_FILL1) && (component->stroke < radius)) {
725 radiusint = radius-component->stroke;
726 }
727 bagl_draw_circle_helper(component->fgcolor,
728 component->x+radius,
729 component->y+radius,
730 radius, BAGL_FILL_CIRCLE_PI2_PI(64 | 128), radiusint,
731 component->bgcolor);
732 bagl_draw_circle_helper(component->fgcolor,
733 component->x+component->width-radius-component->stroke,
734 component->y+radius,
735 radius, BAGL_FILL_CIRCLE_0_PI2(16 | 32), radiusint,
736 component->bgcolor);
737 bagl_draw_circle_helper(component->fgcolor,
738 component->x+radius,
739 component->y+component->height-radius-component->stroke,
740 radius, BAGL_FILL_CIRCLE_PI_3PI2(4 | 8), radiusint,
741 component->bgcolor);
742 bagl_draw_circle_helper(component->fgcolor,
743 component->x+component->width-radius-component->stroke,
744 component->y+component->height-radius-component->stroke,
745 radius, BAGL_FILL_CIRCLE_3PI2_2PI(1 | 2), radiusint,
746 component->bgcolor);
747 }
748 }
749
750 if (type == BAGL_LINE) {
751 // No text for this type
752 break;
753 }
754
755 // Text display
756 if (context && context_length) {
757 unsigned int pos = 0;
758 unsigned int fgcolor = component->fgcolor;
759 unsigned int bgcolor = component->bgcolor;
760
761 // Invert colors of text when rectangle/button is filled
762 if ( ((type == BAGL_BUTTON) || (type == BAGL_RECTANGLE))
763 && (component->fill == BAGL_FILL1)) {
764 fgcolor = component->bgcolor;
765 bgcolor = component->fgcolor;
766 }
767
768 pos = bagl_draw_string(component->font_id,
769 fgcolor, bgcolor,
770 component->x + halignment,
771 component->y + ((type==BAGL_LABELINE)?-(baseline):valignment),
772 component->width - halignment,
773 component->height - ((type==BAGL_LABELINE)?0:valignment),
774 context,
775 ellipsis_1_len,
776 context_encoding);
777#ifdef HAVE_BAGL_ELLIPSIS1
778 if (ellipsis_2_start) {
779 // draw ellipsis
780 pos = bagl_draw_string(component->font_id,
781 fgcolor, bgcolor,
782 (pos & 0xFFFF),
783 component->y + ((type==BAGL_LABELINE)?-(baseline):valignment),
784 component->width - halignment,
785 component->height - (type==BAGL_LABELINE?0:valignment),
786 "...",
787 3,
788 context_encoding);
789 // draw the right part
790 pos = bagl_draw_string(component->font_id,
Value stored to 'pos' is never read
791 fgcolor, bgcolor,
792 (pos & 0xFFFF),
793 component->y + ((type==BAGL_LABELINE)?-(baseline):valignment),
794 component->width - halignment,
795 component->height - ((type==BAGL_LABELINE)?0:valignment),
796 ellipsis_2_start,
797 (context_length - ((unsigned int)ellipsis_2_start-(unsigned int)context) ),
798 context_encoding);
799 }
800#endif // HAVE_BAGL_ELLIPSIS
801 }
802 break;
803
804#ifdef HAVE_BAGL_GLYPH_ARRAY
805 case BAGL_ICON:
806 // icon data follows are in the context
807 if (component->icon_id != 0) {
808
809 // select the default or custom glyph array
810 if (context_encoding && G_glyph_array && G_glyph_count > 0) {
811 glyph = bagl_get_glyph(component->icon_id, G_glyph_array, G_glyph_count);
812 }
813 else {
814 glyph = bagl_get_glyph(component->icon_id, C_glyph_array, C_glyph_count);
815 }
816
817 // 404 glyph not found
818 if (glyph == NULL((void*)0)) {
819 break;
820 }
821
822 // color accounted as bytes in the context length
823 if (context_length) {
824 if ((1<<glyph->bits_per_pixel)*4 != context_length) {
825 // invalid color count
826 break;
827 }
828 context_length /= 4;
829 }
830 // use default colors
831 if (!context_length || !context) {
832 context_length = 1<<(glyph->bits_per_pixel);
833 context = glyph->default_colors;
834 }
835
836 // center glyph in rect
837 // draw the glyph from the bitmap using the context for colors
838 bagl_hal_draw_bitmap_within_rect(component->x + (component->width / 2 - glyph->width / 2),
839 component->y + (component->height / 2 - glyph->height / 2),
840 glyph->width,
841 glyph->height,
842 context_length,
843 (unsigned int*)context, // Endianness remarkably ignored !
844 glyph->bits_per_pixel,
845 glyph->bitmap,
846 glyph->bits_per_pixel*(glyph->width*glyph->height));
847 }
848 else {
849 // context: <bitperpixel> [color_count*4 bytes (LE encoding)] <icon bitmap (raw scan, LE)>
850
851 unsigned int colors[4];
852 unsigned int bpp = ((unsigned char*)context)[0];
853 // no space to display that
854 if (bpp > 2) {
855 break;
856 }
857 unsigned int i=1<<bpp;
858 while(i--) {
859 colors[i] = U4BE((unsigned char*)context, 1+i*4)(((((((unsigned char*)context)[1+i*4]&0xFF)<<8) | (
((unsigned char*)context)[1+i*4 +1]&0xFF) )<<16) | (
(((((unsigned char*)context)[1+i*4 +2]&0xFF)<<8) | (
((unsigned char*)context)[1+i*4 +2 +1]&0xFF) )&0xFFFF
))
;
860 }
861
862 // draw the glyph from the bitmap using the context for colors
863 bagl_hal_draw_bitmap_within_rect(component->x, component->y,
864 component->width, component->height,
865 1<<bpp, colors, bpp,
866 ((unsigned char*)context)+1+(1<<bpp)*4,
867 bpp*(component->width*component->height));
868 }
869 break;
870#endif // HAVE_BAGL_GLYPH_ARRAY
871
872 case BAGL_CIRCLE:
873 // draw the circle (all 8 octants)
874 bagl_draw_circle_helper(component->fgcolor,
875 component->x+component->radius, component->y+component->radius,
876 component->radius, 0xFF,
877 ((component->fill != BAGL_FILL1 && component->stroke < component->radius)?component->radius-component->stroke:0),
878 component->bgcolor);
879 break;
880
881 default:
882 break;
883 }
884}
885
886// --------------------------------------------------------------------------------------
887void bagl_draw_glyph(const bagl_component_t* component, const bagl_icon_details_t* icon_details) {
888 // no space to display that
889 if (icon_details->bpp > 2) {
890 return;
891 }
892
893 /*
894 // take into account the remaining bits not byte aligned
895 unsigned int w = ((component->width*component->height*icon_details->bpp)/8);
896 if (w%8) {
897 w++;
898 }
899 */
900
901 // draw the glyph from the bitmap using the context for colors
902 bagl_hal_draw_bitmap_within_rect(component->x,
903 component->y,
904 icon_details->width,
905 icon_details->height,
906 1<<(icon_details->bpp),
907 (unsigned int*)PIC((unsigned int)icon_details->colors)pic((void *)(unsigned int)icon_details->colors),
908 icon_details->bpp,
909 (unsigned char*)PIC((unsigned int)icon_details->bitmap)pic((void *)(unsigned int)icon_details->bitmap),
910 icon_details->bpp*(icon_details->width*icon_details->height));
911}
912
913
914// --------------------------------------------------------------------------------------
915
916void bagl_animate(bagl_animated_t* anim, unsigned int timestamp_ms, unsigned int interval_ms) {
917 // nothing to be animated right now (or no horizontal scrolling speed defined)
918 if ((anim->next_ms != 0 && anim->next_ms > timestamp_ms) || anim->c.width == 0 || anim->c.icon_id == 0 || (anim->current_x & 0xF0000000)==0x40000000) {
919 return;
920 }
921
922 // when starting the animation, perform a pause on the left of the string
923 if (anim->next_ms == 0) {
924 anim->next_ms = timestamp_ms + (anim->c.stroke&0x7F)*100;
925 anim->current_x = 0x0;
926 anim->current_char_idx = 0;
927 }
928
929 unsigned int a,b;
930 unsigned int valignment=0;
931 unsigned int baseline=0;
932 //unsigned int char_height=0;
933 unsigned int totalwidth = 0;
934 unsigned int remwidth = 0;
935 unsigned int charwidth=0;
936 unsigned int type = anim->c.type&~(BAGL_TYPE_FLAGS_MASK0x80);
937
938 // compute alignment if text provided and requiring special alignment
939 if (anim->text && anim->text_length && (type == BAGL_LABELINE || type == BAGL_LABEL)) {
940 const bagl_font_t* font = bagl_get_font(anim->c.font_id);
941 // invalid font, nothing to animate :(
942 if (font == NULL((void*)0)) {
943 return;
944 }
945 unsigned int maxcharwidth = bagl_compute_line_width(anim->c.font_id, 0, "W", 1, anim->text_encoding)+1;
946 baseline = font->baseline_height;
947 //char_height = font->char_height;
948
949 totalwidth = bagl_compute_line_width(anim->c.font_id, 0, anim->text, anim->text_length, anim->text_encoding);
950
951 // nothing to be animated here, text is already fully drawn in its text box
952 if (totalwidth <= anim->c.width) {
953 return;
954 }
955 if (anim->current_char_idx > anim->text_length) {
956 anim->current_char_idx = 0;
957 }
958
959 remwidth = bagl_compute_line_width(anim->c.font_id, 0, anim->text+anim->current_char_idx, anim->text_length-anim->current_char_idx, anim->text_encoding);
960 charwidth = bagl_compute_line_width(anim->c.font_id, 0, anim->text+anim->current_char_idx, 1, anim->text_encoding);
961
962 switch (anim->c.font_id & BAGL_FONT_ALIGNMENT_VERTICAL_MASK0x3000 ) {
963 default:
964 case BAGL_FONT_ALIGNMENT_TOP0x0000:
965 valignment = 0;
966 break;
967 case BAGL_FONT_ALIGNMENT_BOTTOM0x1000:
968 valignment = anim->c.height - baseline;
969 break;
970 case BAGL_FONT_ALIGNMENT_MIDDLE0x2000:
971 // y yalign charheight height
972 // ' ' v ' '
973 // baseline
974 // yalign = y+ (height/2) - (baseline/2) => align - y
975 valignment = anim->c.height/2 - baseline/2 - 1;
976 break;
977 }
978
979 // consider the current char of the string has been displayed on the screen (or at least a part of it)
980 // viewport | < width > |
981 // totalwidth | a text that does not fit the viewport |
982 // rem width |xt that does not fit the viewport | s
983 //
984 unsigned int current_char_displayed_width = (anim->current_x & ~(0xF0000000)) - (totalwidth - remwidth);
985
986 // draw a bg rectangle on the area before painting the animated value, to clearup glitches on both sides
987
988 a = anim->c.y + (type==BAGL_LABELINE?-(baseline):valignment);
989 b = anim->c.height- (type==BAGL_LABELINE?0/*-char_height*/:valignment);
990 bagl_draw_string(anim->c.font_id,
991 anim->c.fgcolor,
992 anim->c.bgcolor,
993 anim->c.x - current_char_displayed_width,
994 a,
995 anim->c.width + current_char_displayed_width + charwidth /*- 2*component->stroke*/,
996 b,
997 anim->text+anim->current_char_idx, anim->text_length-anim->current_char_idx, anim->text_encoding);
998
999 // crop the viewport
1000 bagl_hal_draw_rect(anim->c.bgcolor,
1001 anim->c.x-maxcharwidth,
1002 a,
1003 maxcharwidth,
1004 b);
1005 bagl_hal_draw_rect(anim->c.bgcolor,
1006 anim->c.x+anim->c.width,
1007 a,
1008 maxcharwidth,
1009 b);
1010
1011 // report on screen
1012 screen_update();
1013 unsigned int step_ms=interval_ms;
1014 unsigned int step_x=anim->c.icon_id * step_ms/1000;
1015 while(step_x == 0) {
1016 step_ms += interval_ms;
1017 step_x = anim->c.icon_id * step_ms / 1000;
1018 }
1019
1020 switch (anim->current_x & 0xF0000000) {
1021 // left to right
1022 case 0:
1023 anim->next_ms += step_ms;
1024 if (current_char_displayed_width >= charwidth) {
1025 anim->current_char_idx++;
1026 // if text fits, then stop scrolling and wait a bit
1027 if (remwidth - current_char_displayed_width <= anim->c.width) {
1028 anim->current_x = (totalwidth-remwidth+current_char_displayed_width) | 0x10000000;
1029 break;
1030 }
1031 }
1032 anim->current_x += step_x;
1033 break;
1034
1035 // pause after finished left to right
1036 case 0x10000000:
1037 anim->next_ms += (anim->c.stroke&0x7F)*100;
1038 anim->current_x = (totalwidth-remwidth+current_char_displayed_width) | 0x20000000;
1039 break;
1040
1041 // right to left
1042 case 0x20000000:
1043 anim->next_ms += step_ms;
1044 if (current_char_displayed_width >= charwidth) {
1045 // we're displaying from the start
1046 if (remwidth >= totalwidth) {
1047 anim->current_x = 0x30000000;
1048 anim->current_char_idx = 0;
1049 break;
1050 }
1051 anim->current_char_idx--;
1052 }
1053 anim->current_x = ((anim->current_x & ~(0xF0000000)) - step_x) | 0x20000000;
1054 break;
1055
1056 // pause after finished right to left
1057 case 0x30000000:
1058 anim->next_ms += (anim->c.stroke&0x7F)*100;
1059 anim->current_x = 0;
1060 // not going for another scroll anim
1061 if (anim->c.stroke & 0x80) {
1062 anim->current_x = 0x40000000;
1063 }
1064 break;
1065 case 0x40000000:
1066 // stalled, nothing to do
1067 break;
1068 }
1069 }
1070}
1071
1072// --------------------------------------------------------------------------------------
1073
1074void bagl_draw(const bagl_component_t* component) {
1075 // component without text
1076 bagl_draw_with_context(component, NULL((void*)0), 0, 0);
1077}
1078
1079#endif // HAVE_BAGL
diff --git a/app/output-scan-build/2022-05-16-071046-61-1/report-8e376d.html b/app/output-scan-build/2022-05-16-071046-61-1/report-8e376d.html deleted file mode 100644 index bdbad4f1..00000000 --- a/app/output-scan-build/2022-05-16-071046-61-1/report-8e376d.html +++ /dev/null @@ -1,1877 +0,0 @@ - - - -/opt/nanox-secure-sdk/src/os_io_seproxyhal.c - - - - - - - - - - - - - - - - - - - - - - - - - - -

Bug Summary

- - - - -
File:src/os_io_seproxyhal.c
Warning:line 761, column 5
Value stored to 'icon_component' is never read
- -

Annotated Source Code

-

Press '?' - to see keyboard shortcuts

- - -
clang -cc1 -cc1 -triple thumbv6m-none-unknown-eabi -analyze -disable-free -disable-llvm-verifier -discard-value-names -main-file-name os_io_seproxyhal.c -analyzer-store=region -analyzer-opt-analyze-nested-blocks -analyzer-checker=core -analyzer-checker=apiModeling -analyzer-checker=unix -analyzer-checker=deadcode -analyzer-checker=security.insecureAPI.UncheckedReturn -analyzer-checker=security.insecureAPI.getpw -analyzer-checker=security.insecureAPI.gets -analyzer-checker=security.insecureAPI.mktemp -analyzer-checker=security.insecureAPI.mkstemp -analyzer-checker=security.insecureAPI.vfork -analyzer-checker=nullability.NullPassedToNonnull -analyzer-checker=nullability.NullReturnedFromNonnull -analyzer-output plist -w -setup-static-analyzer -mrelocation-model ropi-rwpi -fropi -frwpi -fhalf-no-semantic-interposition -fno-jump-tables -mframe-pointer=none -fmath-errno -fno-rounding-math -fno-verbose-asm -mconstructor-aliases -nostdsysteminc -target-cpu cortex-m0plus -target-feature +soft-float -target-feature +soft-float-abi -target-feature -crc -target-feature -sha2 -target-feature -aes -target-feature -dsp -target-feature -ras -target-feature -sb -target-feature -i8mm -target-feature -lob -target-feature -cdecp0 -target-feature -cdecp1 -target-feature -cdecp2 -target-feature -cdecp3 -target-feature -cdecp4 -target-feature -cdecp5 -target-feature -cdecp6 -target-feature -cdecp7 -target-feature -hwdiv-arm -target-feature -hwdiv -target-feature -vfp2 -target-feature -vfp2sp -target-feature -vfp3 -target-feature -vfp3d16 -target-feature -vfp3d16sp -target-feature -vfp3sp -target-feature -fp16 -target-feature -vfp4 -target-feature -vfp4d16 -target-feature -vfp4d16sp -target-feature -vfp4sp -target-feature -fp-armv8 -target-feature -fp-armv8d16 -target-feature -fp-armv8d16sp -target-feature -fp-armv8sp -target-feature -fullfp16 -target-feature -fp64 -target-feature -d32 -target-feature -neon -target-feature -crypto -target-feature -dotprod -target-feature -fp16fml -target-feature -bf16 -target-feature -mve -target-feature -mve.fp -target-feature -fpregs -target-feature +strict-align -target-abi aapcs -msoft-float -mfloat-abi soft -fallow-half-arguments-and-returns -fno-split-dwarf-inlining -debugger-tuning=gdb -ffunction-sections -fdata-sections -resource-dir /usr/lib/llvm-12/lib/clang/12.0.0 -D gcc -D __IO=volatile -D NDEBUG -D HAVE_SE_SCREEN -D HAVE_SE_BUTTON -D HAVE_MCU_SERIAL_STORAGE -D HAVE_FONTS -D HAVE_BATTERY -D HAVE_NES_CRYPT -D HAVE_ST_EDES_PLUS -D HAVE_ST_AES -D NATIVE_LITTLE_ENDIAN -D HAVE_CRC -D HAVE_HASH -D HAVE_RIPEMD160 -D HAVE_SHA224 -D HAVE_SHA256 -D HAVE_SHA3 -D HAVE_SHA384 -D HAVE_SHA512 -D HAVE_SHA512_WITH_BLOCK_ALT_METHOD -D HAVE_SHA512_WITH_BLOCK_ALT_METHOD_M0 -D HAVE_BLAKE2 -D HAVE_HMAC -D HAVE_PBKDF2 -D HAVE_DES -D HAVE_AES -D HAVE_MATH -D HAVE_RNG -D HAVE_RNG_RFC6979 -D HAVE_RNG_SP800_90A -D HAVE_ECC -D HAVE_ECC_WEIERSTRASS -D HAVE_ECC_TWISTED_EDWARDS -D HAVE_ECC_MONTGOMERY -D HAVE_SECP256K1_CURVE -D HAVE_SECP256R1_CURVE -D HAVE_SECP384R1_CURVE -D HAVE_SECP521R1_CURVE -D HAVE_FR256V1_CURVE -D HAVE_STARK256_CURVE -D HAVE_BRAINPOOL_P256R1_CURVE -D HAVE_BRAINPOOL_P256T1_CURVE -D HAVE_BRAINPOOL_P320R1_CURVE -D HAVE_BRAINPOOL_P320T1_CURVE -D HAVE_BRAINPOOL_P384R1_CURVE -D HAVE_BRAINPOOL_P384T1_CURVE -D HAVE_BRAINPOOL_P512R1_CURVE -D HAVE_BRAINPOOL_P512T1_CURVE -D HAVE_BLS12_381_G1_CURVE -D HAVE_CV25519_CURVE -D HAVE_CV448_CURVE -D HAVE_ED25519_CURVE -D HAVE_ED448_CURVE -D HAVE_ECDH -D HAVE_ECDSA -D HAVE_EDDSA -D HAVE_ECSCHNORR -D HAVE_X25519 -D HAVE_X448 -D APP_CONSUMER -D UNUSED(x)=(void)x -D PRINTF(...)= -D APPVERSION="0.9.13" -D OS_IO_SEPROXYHAL -D HAVE_BAGL -D HAVE_SPRINTF -D HAVE_IO_USB -D HAVE_L4_USBLIB -D IO_USB_MAX_ENDPOINTS=7 -D IO_HID_EP_LENGTH=64 -D HAVE_USB_APDU -D LEDGER_MAJOR_VERSION=0 -D LEDGER_MINOR_VERSION=9 -D LEDGER_PATCH_VERSION=13 -D USB_SEGMENT_SIZE=64 -D HAVE_BOLOS_APP_STACK_CANARY -D HAVE_WEBUSB -D WEBUSB_URL_SIZE_B=0 -D WEBUSB_URL= -D HAVE_BLE -D HAVE_BLE_APDU -D BLE_COMMAND_TIMEOUT_MS=2000 -D IO_SEPROXYHAL_BUFFER_SIZE_B=300 -D HAVE_GLO096 -D HAVE_BAGL -D BAGL_WIDTH=128 -D BAGL_HEIGHT=64 -D HAVE_BAGL_ELLIPSIS -D HAVE_BAGL_FONT_OPEN_SANS_REGULAR_11PX -D HAVE_BAGL_FONT_OPEN_SANS_EXTRABOLD_11PX -D HAVE_BAGL_FONT_OPEN_SANS_LIGHT_16PX -D HAVE_UX_FLOW -D LEDGER_SPECIFIC -I .//glyphs -I /opt/nanox-secure-sdk/lib_cxng/include -I /opt/nanox-secure-sdk/lib_blewbxx/ -I /opt/nanox-secure-sdk/lib_blewbxx/core/template/ -I /opt/nanox-secure-sdk/lib_blewbxx/core/template/ -I /opt/nanox-secure-sdk/lib_blewbxx/core/template/ -I /opt/nanox-secure-sdk/lib_blewbxx/core/ -I /opt/nanox-secure-sdk/lib_blewbxx/core/ -I /opt/nanox-secure-sdk/lib_blewbxx/core/ -I /opt/nanox-secure-sdk/lib_blewbxx/core/auto/ -I /opt/nanox-secure-sdk/lib_blewbxx/core/auto/ -I /opt/nanox-secure-sdk/lib_blewbxx/core/auto/ -I /opt/nanox-secure-sdk/lib_blewbxx/core/auto/ -I /opt/nanox-secure-sdk/lib_blewbxx/core/auto/ -I /opt/nanox-secure-sdk/lib_blewbxx/core/auto/ -I /opt/nanox-secure-sdk/lib_blewbxx/core/ -I /opt/nanox-secure-sdk/lib_blewbxx/core/ -I /opt/nanox-secure-sdk/lib_blewbxx/ -I /opt/nanox-secure-sdk/lib_blewbxx_impl/include/ -I /opt/nanox-secure-sdk/lib_blewbxx_impl/ -I /opt/nanox-secure-sdk/lib_stusb/ -I /opt/nanox-secure-sdk/lib_stusb/STM32_USB_Device_Library/Class/CCID/inc/ -I /opt/nanox-secure-sdk/lib_stusb/STM32_USB_Device_Library/Class/CCID/inc/ -I /opt/nanox-secure-sdk/lib_stusb/STM32_USB_Device_Library/Class/CCID/inc/ -I /opt/nanox-secure-sdk/lib_stusb/STM32_USB_Device_Library/Class/CCID/inc/ -I /opt/nanox-secure-sdk/lib_stusb/STM32_USB_Device_Library/Class/HID/Inc/ -I /opt/nanox-secure-sdk/lib_stusb/STM32_USB_Device_Library/Core/Inc/ -I /opt/nanox-secure-sdk/lib_stusb/STM32_USB_Device_Library/Core/Inc/ -I /opt/nanox-secure-sdk/lib_stusb/STM32_USB_Device_Library/Core/Inc/ -I /opt/nanox-secure-sdk/lib_stusb/STM32_USB_Device_Library/Core/Inc/ -I /opt/nanox-secure-sdk/lib_stusb/STM32_USB_Device_Library/Core/Inc/ -I /opt/nanox-secure-sdk/lib_stusb_impl/ -I /opt/nanox-secure-sdk/lib_stusb_impl/ -I /opt/nanox-secure-sdk/lib_stusb_impl/ -I /opt/nanox-secure-sdk/lib_ux/include/ -I /opt/nanox-secure-sdk/lib_ux/include/ -I /opt/nanox-secure-sdk/lib_ux/include/ -I /opt/nanox-secure-sdk/lib_ux/include/ -I /opt/nanox-secure-sdk/lib_ux/src/ -I include -I /opt/nanox-secure-sdk/include -I /opt/nanox-secure-sdk/include/arm -I .//src/ -I .//src/json/ -I .//src/ -I .//src/ -I .//src/ -I .//src/ -I .//src/ -I .//src/ -I .//src/ -I .//src/ -I .//src/ -I .//src/ -I .//src/ -I .//src/common/ -I .//src/common/ -I .//src/common/ -I .//../deps/ledger-zxlib/include/ -I .//../deps/ledger-zxlib/include/ -I .//../deps/ledger-zxlib/include/ -I .//../deps/ledger-zxlib/include/ -I .//../deps/ledger-zxlib/include/ -I .//../deps/ledger-zxlib/include/ -I .//../deps/ledger-zxlib/include/ -I .//../deps/ledger-zxlib/include/ -I .//../deps/ledger-zxlib/include/ -I .//../deps/ledger-zxlib/include/ -I .//../deps/ledger-zxlib/include/ -I .//../deps/ledger-zxlib/include/ -I .//../deps/ledger-zxlib/include/ -I .//../deps/ledger-zxlib/include/ -I .//../deps/ledger-zxlib/include/ -I .//../deps/ledger-zxlib/include/ -I .//../deps/ledger-zxlib/include/ -I .//../deps/ledger-zxlib/include/ -I .//../deps/ledger-zxlib/include/ -I .//../deps/ledger-zxlib/include/ -I .//../deps/ledger-zxlib/include/ -I .//../deps/ledger-zxlib/include/ -I .//../deps/ledger-zxlib/app/common/ -I .//../deps/ledger-zxlib/app/common/ -I .//../deps/jsmn/src/ -isysroot /opt/gcc-arm-none-eabi-10.3-2021.10/bin/../arm-none-eabi -internal-isystem /usr/lib/llvm-12/lib/clang/12.0.0/include -internal-isystem /opt/gcc-arm-none-eabi-10.3-2021.10/bin/../arm-none-eabi/include -Os -Wno-main -Wno-unknown-pragmas -std=gnu99 -fdebug-compilation-dir /app -ferror-limit 19 -fshort-enums -fno-signed-char -fgnuc-version=4.2.1 -vectorize-loops -vectorize-slp -analyzer-checker security -analyzer-checker unix -analyzer-checker valist -analyzer-opt-analyze-headers -analyzer-output=html -faddrsig -o /app/output-scan-build/2022-05-16-071046-61-1 -x c /opt/nanox-secure-sdk/src/os_io_seproxyhal.c -
- - - -
- - -
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
1
2/*******************************************************************************
3* Ledger Nano S - Secure firmware
4* (c) 2022 Ledger
5*
6* Licensed under the Apache License, Version 2.0 (the "License");
7* you may not use this file except in compliance with the License.
8* You may obtain a copy of the License at
9*
10* http://www.apache.org/licenses/LICENSE-2.0
11*
12* Unless required by applicable law or agreed to in writing, software
13* distributed under the License is distributed on an "AS IS" BASIS,
14* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
15* See the License for the specific language governing permissions and
16* limitations under the License.
17********************************************************************************/
18
19#include "bolos_target.h"
20
21#ifdef TARGET_NANOX
22#ifndef HAVE_SEPROXYHAL_MCU
23# define HAVE_SEPROXYHAL_MCU
24#endif // HAVE_SEPROXYHAL_MCU
25#ifndef HAVE_MCU_PROTECT
26#define HAVE_MCU_PROTECT
27#endif // HAVE_MCU_PROTECT
28#endif // TARGET_NANOX
29
30#include "errors.h"
31#include "exceptions.h"
32#include "os_apdu.h"
33#include "os_apilevel.h"
34
35#if defined(DEBUG_OS_STACK_CONSUMPTION)
36# include "os_debug.h"
37#endif // DEBUG_OS_STACK_CONSUMPTION
38
39#include "os_id.h"
40#include "os_io.h"
41#include "os_io_usb.h"
42#include "os_pic.h"
43#include "os_pin.h"
44#include "os_registry.h"
45#include "os_seed.h"
46#include "os_utils.h"
47#include <string.h>
48
49#ifdef OS_IO_SEPROXYHAL1
50
51#include "os_io_seproxyhal.h"
52
53#ifdef HAVE_BLE1
54#include "ledger_ble.h"
55#endif // HAVE_BLE
56
57#include "ux.h"
58#include "checks.h"
59
60#ifdef HAVE_IO_U2F
61#include "u2f_processing.h"
62#include "u2f_transport.h"
63#endif
64
65#ifndef VERSION"dummy"
66#define VERSION"dummy" "dummy"
67#endif // VERSION
68
69#ifdef DEBUG
70#define LOG printf
71#else
72#define LOG(...)
73#endif
74
75#ifdef HAVE_IO_USB1
76#ifdef HAVE_L4_USBLIB1
77#include "usbd_def.h"
78#include "usbd_core.h"
79extern USBD_HandleTypeDef USBD_Device;
80#endif
81#endif
82
83#if !defined(HAVE_BOLOS_NO_DEFAULT_APDU)
84# define DEFAULT_APDU_CLA0xB0 0xB0
85# define DEFAULT_APDU_INS_GET_VERSION0x01 0x01
86
87# if defined(HAVE_SEED_COOKIE)
88# define DEFAULT_APDU_INS_GET_SEED_COOKIE 0x02
89# endif
90
91# if defined(DEBUG_OS_STACK_CONSUMPTION)
92# define DEFAULT_APDU_INS_STACK_CONSUMPTION 0x57
93# endif // DEBUG_OS_STACK_CONSUMPTION
94
95# define DEFAULT_APDU_INS_APP_EXIT0xA7 0xA7
96#endif // !HAVE_BOLOS_NO_DEFAULT_APDU
97
98void io_seproxyhal_handle_ble_event(void);
99
100unsigned int os_io_seph_recv_and_process(unsigned int dont_process_ux_events);
101
102#ifndef HAVE_BOLOS
103io_seph_app_t G_io_app;
104#endif // ! HAVE_BOLOS
105
106 // usb endpoint buffer
107unsigned char G_io_usb_ep_buffer[MAX(USB_SEGMENT_SIZE, BLE_SEGMENT_SIZE)((64) > (64) ? (64) : (64))];
108
109ux_seph_os_and_app_t G_ux_os;
110
111#ifndef IO_RAPDU_TRANSMIT_TIMEOUT_MS2000UL
112#define IO_RAPDU_TRANSMIT_TIMEOUT_MS2000UL 2000UL
113#endif // IO_RAPDU_TRANSMIT_TIMEOUT_MS
114
115static const unsigned char seph_io_general_status[]= {
116 SEPROXYHAL_TAG_GENERAL_STATUS0x60,
117 0,
118 2,
119 SEPROXYHAL_TAG_GENERAL_STATUS_LAST_COMMAND0x0000>>8,
120 SEPROXYHAL_TAG_GENERAL_STATUS_LAST_COMMAND0x0000,
121};
122void io_seproxyhal_general_status(void) {
123 // send the general status
124 io_seproxyhal_spi_sendio_seph_send(seph_io_general_status, sizeof(seph_io_general_status));
125}
126
127static const unsigned char seph_io_request_status[]= {
128 SEPROXYHAL_TAG_REQUEST_STATUS0x52,
129 0,
130 0,
131};
132void io_seproxyhal_request_mcu_status(void) {
133 // send the general status
134 io_seproxyhal_spi_sendio_seph_send(seph_io_request_status, sizeof(seph_io_request_status));
135}
136
137#ifdef HAVE_IO_USB1
138#ifdef HAVE_L4_USBLIB1
139
140void io_seproxyhal_handle_usb_event(void) {
141 switch(G_io_seproxyhal_spi_buffer[3]) {
142 case SEPROXYHAL_TAG_USB_EVENT_RESET0x01:
143 USBD_LL_SetSpeed(&USBD_Device, USBD_SPEED_FULL);
144 USBD_LL_Reset(&USBD_Device);
145 // ongoing APDU detected, throw a reset, even if not the media. to avoid potential troubles.
146 if (G_io_app.apdu_media != IO_APDU_MEDIA_NONE) {
147 THROW(EXCEPTION_IO_RESET)os_longjmp(0x5);
148 }
149 memset(G_io_app.usb_ep_xfer_len, 0, sizeof(G_io_app.usb_ep_xfer_len));
150 memset(G_io_app.usb_ep_timeouts, 0, sizeof(G_io_app.usb_ep_timeouts));
151 break;
152 case SEPROXYHAL_TAG_USB_EVENT_SOF0x02:
153 USBD_LL_SOF(&USBD_Device);
154 break;
155 case SEPROXYHAL_TAG_USB_EVENT_SUSPENDED0x04:
156 USBD_LL_Suspend(&USBD_Device);
157 break;
158 case SEPROXYHAL_TAG_USB_EVENT_RESUMED0x08:
159 USBD_LL_Resume(&USBD_Device);
160 break;
161 }
162}
163
164uint16_t io_seproxyhal_get_ep_rx_size(uint8_t epnum) {
165 if ((epnum & 0x7F) < IO_USB_MAX_ENDPOINTS7) {
166 return G_io_app.usb_ep_xfer_len[epnum&0x7F];
167 }
168 return 0;
169}
170
171void io_seproxyhal_handle_usb_ep_xfer_event(void) {
172 uint8_t epnum;
173
174 epnum = G_io_seproxyhal_spi_buffer[3] & 0x7F;
175
176 switch(G_io_seproxyhal_spi_buffer[4]) {
177 /* This event is received when a new SETUP token had been received on a control endpoint */
178 case SEPROXYHAL_TAG_USB_EP_XFER_SETUP0x01:
179 // assume length of setup packet, and that it is on endpoint 0
180 USBD_LL_SetupStage(&USBD_Device, &G_io_seproxyhal_spi_buffer[6]);
181 break;
182
183 /* This event is received after the prepare data packet has been flushed to the usb host */
184 case SEPROXYHAL_TAG_USB_EP_XFER_IN0x02:
185 if (epnum < IO_USB_MAX_ENDPOINTS7) {
186 // discard ep timeout as we received the sent packet confirmation
187 G_io_app.usb_ep_timeouts[epnum].timeout = 0;
188 // propagate sending ack of the data
189 USBD_LL_DataInStage(&USBD_Device, epnum, &G_io_seproxyhal_spi_buffer[6]);
190 }
191 break;
192
193 /* This event is received when a new DATA token is received on an endpoint */
194 case SEPROXYHAL_TAG_USB_EP_XFER_OUT0x04:
195 if (epnum < IO_USB_MAX_ENDPOINTS7) {
196 // saved just in case it is needed ...
197#if IO_SEPROXYHAL_BUFFER_SIZE_B300 - 6 >= 256
198 G_io_app.usb_ep_xfer_len[epnum] = G_io_seproxyhal_spi_buffer[5];
199#else
200 G_io_app.usb_ep_xfer_len[epnum] = MIN(G_io_seproxyhal_spi_buffer[5], IO_SEPROXYHAL_BUFFER_SIZE_B - 6)((G_io_seproxyhal_spi_buffer[5]) < (300 - 6) ? (G_io_seproxyhal_spi_buffer
[5]) : (300 - 6))
;
201#endif
202 // prepare reception
203 USBD_LL_DataOutStage(&USBD_Device, epnum, &G_io_seproxyhal_spi_buffer[6]);
204 }
205 break;
206 }
207}
208
209#else
210//no usb lib: X86 for example
211
212void io_seproxyhal_handle_usb_event(void) {
213}
214void io_seproxyhal_handle_usb_ep_xfer_event(void) {
215}
216
217#endif // HAVE_L4_USBLIB
218
219// TODO, refactor this using the USB DataIn event like for the U2F tunnel
220// TODO add a blocking parameter, for HID KBD sending, or use a USB busy flag per channel to know if
221// the transfer has been processed or not. and move on to the next transfer on the same endpoint
222void io_usb_send_ep(unsigned int ep, unsigned char* buffer, unsigned short length, unsigned int timeout) {
223
224 // don't spoil the timeout :)
225 if (timeout) {
226 timeout++;
227 }
228
229 // won't send if overflowing seproxyhal buffer format
230 if (length > 255) {
231 return;
232 }
233
234 G_io_seproxyhal_spi_buffer[0] = SEPROXYHAL_TAG_USB_EP_PREPARE0x50;
235 G_io_seproxyhal_spi_buffer[1] = (3+length)>>8;
236 G_io_seproxyhal_spi_buffer[2] = (3+length);
237 G_io_seproxyhal_spi_buffer[3] = ep|0x80;
238 G_io_seproxyhal_spi_buffer[4] = SEPROXYHAL_TAG_USB_EP_PREPARE_DIR_IN0x20;
239 G_io_seproxyhal_spi_buffer[5] = length;
240 io_seproxyhal_spi_sendio_seph_send(G_io_seproxyhal_spi_buffer, 6);
241 io_seproxyhal_spi_sendio_seph_send(buffer, length);
242 // setup timeout of the endpoint
243 G_io_app.usb_ep_timeouts[ep&0x7F].timeout = IO_RAPDU_TRANSMIT_TIMEOUT_MS2000UL;
244}
245
246void io_usb_send_apdu_data(unsigned char* buffer, unsigned short length) {
247 // wait for 20 events before hanging up and timeout (~2 seconds of timeout)
248 io_usb_send_ep(0x82, buffer, length, 20);
249}
250
251#ifdef HAVE_WEBUSB1
252void io_usb_send_apdu_data_ep0x83(unsigned char* buffer, unsigned short length) {
253 // wait for 20 events before hanging up and timeout (~2 seconds of timeout)
254 io_usb_send_ep(0x83, buffer, length, 20);
255}
256#endif // HAVE_WEBUSB
257
258#endif // HAVE_IO_USB
259
260void io_seproxyhal_handle_capdu_event(void) {
261 if (G_io_app.apdu_state == APDU_IDLE) {
262 size_t max = MIN(sizeof(G_io_apdu_buffer)-3, sizeof(G_io_seproxyhal_spi_buffer)-3)((sizeof(G_io_apdu_buffer)-3) < (sizeof(G_io_seproxyhal_spi_buffer
)-3) ? (sizeof(G_io_apdu_buffer)-3) : (sizeof(G_io_seproxyhal_spi_buffer
)-3))
;
263 size_t size = U2BE(G_io_seproxyhal_spi_buffer, 1);
264
265 G_io_app.apdu_media = IO_APDU_MEDIA_RAW; // for application code
266 G_io_app.apdu_state = APDU_RAW; // for next call to io_exchange
267 G_io_app.apdu_length = MIN(size, max)((size) < (max) ? (size) : (max));
268 // copy apdu to apdu buffer
269 memcpy(G_io_apdu_buffer, G_io_seproxyhal_spi_buffer+3, G_io_app.apdu_length);
270 }
271}
272
273unsigned int io_seproxyhal_handle_event(void) {
274#if defined(HAVE_IO_USB1) || defined(HAVE_BLE1)
275 unsigned int rx_len = U2BE(G_io_seproxyhal_spi_buffer, 1);
276#endif
277
278 switch(G_io_seproxyhal_spi_buffer[0]) {
279 #ifdef HAVE_IO_USB1
280 case SEPROXYHAL_TAG_USB_EVENT0x0F:
281 if (rx_len != 1) {
282 return 0;
283 }
284 io_seproxyhal_handle_usb_event();
285 return 1;
286
287 case SEPROXYHAL_TAG_USB_EP_XFER_EVENT0x10:
288 if (rx_len < 3) {
289 // error !
290 return 0;
291 }
292 io_seproxyhal_handle_usb_ep_xfer_event();
293 return 1;
294 #endif // HAVE_IO_USB
295
296 #ifdef HAVE_BLE1
297 case SEPROXYHAL_TAG_BLE_RECV_EVENT0x18:
298 LEDGER_BLE_receive();
299 return 1;
300 #endif // HAVE_BLE
301
302 case SEPROXYHAL_TAG_UX_EVENT0x1A:
303 switch (G_io_seproxyhal_spi_buffer[3]) {
304
305#ifdef HAVE_BLE1
306 case SEPROXYHAL_TAG_UX_CMD_BLE_DISABLE_ADV0x00:
307 LEDGER_BLE_enable_advertising(0);
308 return 1;
309 break;
310
311 case SEPROXYHAL_TAG_UX_CMD_BLE_ENABLE_ADV0x01:
312 LEDGER_BLE_enable_advertising(1);
313 return 1;
314 break;
315
316 case SEPROXYHAL_TAG_UX_CMD_BLE_RESET_PAIRINGS0x02:
317 LEDGER_BLE_reset_pairings();
318 return 1;
319 break;
320#endif // HAVE_BLE
321
322#ifndef HAVE_BOLOS
323 case SEPROXYHAL_TAG_UX_CMD_REDISPLAY0x03:
324 ux_stack_redisplay();
325 return 1;
326 break;
327#endif // HAVE_BOLOS
328
329 default:
330 return io_event(CHANNEL_SPI2);
331 break;
332 }
333 break;
334
335 case SEPROXYHAL_TAG_CAPDU_EVENT0x16:
336 io_seproxyhal_handle_capdu_event();
337 return 1;
338
339 // ask the user if not processed here
340 case SEPROXYHAL_TAG_TICKER_EVENT0x0E:
341 // process ticker events to timeout the IO transfers, and forward to the user io_event function too
342 G_io_app.ms += 100; // value is by default, don't change the ticker configuration
343#ifdef HAVE_IO_USB1
344 {
345 unsigned int i = IO_USB_MAX_ENDPOINTS7;
346 while(i--) {
347 if (G_io_app.usb_ep_timeouts[i].timeout) {
348 G_io_app.usb_ep_timeouts[i].timeout-=MIN(G_io_app.usb_ep_timeouts[i].timeout, 100)((G_io_app.usb_ep_timeouts[i].timeout) < (100) ? (G_io_app
.usb_ep_timeouts[i].timeout) : (100))
;
349 if (!G_io_app.usb_ep_timeouts[i].timeout) {
350 // timeout !
351 G_io_app.apdu_state = APDU_IDLE;
352 THROW(EXCEPTION_IO_RESET)os_longjmp(0x5);
353 }
354 }
355 }
356 }
357#endif // HAVE_IO_USB
358#ifdef HAVE_BLE_APDU1
359 {
360 if (G_io_app.ble_xfer_timeout) {
361 G_io_app.ble_xfer_timeout -= MIN(G_io_app.ble_xfer_timeout, 100)((G_io_app.ble_xfer_timeout) < (100) ? (G_io_app.ble_xfer_timeout
) : (100))
;
362 if (!G_io_app.ble_xfer_timeout) {
363 G_io_app.apdu_state = APDU_IDLE;
364 THROW(EXCEPTION_IO_RESET)os_longjmp(0x5);
365 }
366 }
367 }
368#endif // HAVE_BLE_APDU
369 __attribute__((fallthrough));
370 // no break is intentional
371 default:
372 return io_event(CHANNEL_SPI2);
373 }
374 // defaultly return as not processed
375 return 0;
376}
377
378//#define DEBUG_APDU
379#ifdef DEBUG_APDU
380volatile unsigned int debug_apdus_offset;
381const char debug_apdus[] = {
382 5, 0xE0, 0x40, 0x00, 0x00, 0x00,
383 //9, 0xe0, 0x22, 0x00, 0x00, 0x04, 0x31, 0x32, 0x33, 0x34,
384};
385#endif // DEBUG_APDU
386
387#ifdef HAVE_BOLOS_APP_STACK_CANARY1
388#define APP_STACK_CANARY_MAGIC0xDEAD0031 0xDEAD0031
389extern unsigned int app_stack_canary;
390#endif // HAVE_BOLOS_APP_STACK_CANARY
391
392#if (!defined(HAVE_BOLOS) && defined(HAVE_MCU_PROTECT))
393static const unsigned char seph_io_mcu_protect[]= {
394 SEPROXYHAL_TAG_MCU0x31,
395 0,
396 1,
397 SEPROXYHAL_TAG_MCU_TYPE_PROTECT0x02,
398};
399#endif // (!defined(HAVE_BOLOS) && defined(HAVE_MCU_PROTECT))
400
401void io_seproxyhal_init(void) {
402#ifndef HAVE_BOLOS
403 // Enforce OS compatibility
404 check_api_level(CX_COMPAT_APILEVEL12);
405
406#ifdef HAVE_MCU_PROTECT
407 // engage RDP2 on MCU
408 io_seproxyhal_spi_sendio_seph_send(seph_io_mcu_protect, sizeof(seph_io_mcu_protect));
409#endif // HAVE_MCU_PROTECT
410#endif // HAVE_BOLOS
411
412#ifdef HAVE_BOLOS_APP_STACK_CANARY1
413 app_stack_canary = APP_STACK_CANARY_MAGIC0xDEAD0031;
414#endif // HAVE_BOLOS_APP_STACK_CANARY
415
416 // wipe the io structure before it's used
417#ifdef HAVE_BLE1
418 unsigned int plane = G_io_app.plane_mode;
419#endif // HAVE_BLE
420 memset(&G_io_app, 0, sizeof(G_io_app));
421#ifdef HAVE_BLE1
422 G_io_app.plane_mode = plane;
423#endif // HAVE_BLE
424
425 G_io_app.apdu_state = APDU_IDLE;
426 G_io_app.apdu_length = 0;
427 G_io_app.apdu_media = IO_APDU_MEDIA_NONE;
428
429 G_io_app.ms = 0;
430
431 #ifdef DEBUG_APDU
432 debug_apdus_offset = 0;
433 #endif // DEBUG_APDU
434
435 #ifdef HAVE_USB_APDU1
436 io_usb_hid_init();
437 #endif // HAVE_USB_APDU
438
439 io_seproxyhal_init_ux();
440 io_seproxyhal_init_button();
441
442#if !defined(HAVE_BOLOS) && defined(HAVE_PENDING_REVIEW_SCREEN)
443 check_audited_app();
444#endif // !defined(HAVE_BOLOS) && defined(HAVE_PENDING_REVIEW_SCREEN)
445}
446
447void io_seproxyhal_init_ux(void) {
448#ifdef TARGET_BLUE
449 // initialize the touch part
450 G_ux_os.last_touched_not_released_component = NULL((void*)0);
451#endif // TARGET_BLUE
452}
453
454void io_seproxyhal_init_button(void) {
455 // no button push so far
456 G_ux_os.button_mask = 0;
457 G_ux_os.button_same_mask_counter = 0;
458}
459
460#ifdef HAVE_BAGL1
461
462#ifdef TARGET_BLUE
463unsigned int io_seproxyhal_touch_out(const bagl_element_t* element, bagl_element_callback_t before_display) {
464 const bagl_element_t* el;
465 if (element->out != NULL((void*)0)) {
466 el = (const bagl_element_t*)PIC(((bagl_element_callback_t)PIC(element->out))(element))pic((void *)((bagl_element_callback_t)pic((void *)element->
out))(element))
;
467 // backward compatible with samples and such
468 if (! el) {
469 return 0;
470 }
471 if ((unsigned int)el != 1) {
472 element = el;
473 }
474 }
475
476 // out function might have triggered a draw of its own during a display callback
477 if (before_display) {
478 el = before_display(element);
479 if (!el) {
480 return 0;
481 }
482 if ((unsigned int)el != 1) {
483 element = el;
484 }
485 }
486
487 io_seproxyhal_display(element);
488 return 1;
489}
490
491unsigned int io_seproxyhal_touch_over(const bagl_element_t* element, bagl_element_callback_t before_display) {
492 bagl_element_t e;
493 const bagl_element_t* el;
494 if (element->over != NULL((void*)0)) {
495 el = (const bagl_element_t*)PIC(((bagl_element_callback_t)PIC(element->over))(element))pic((void *)((bagl_element_callback_t)pic((void *)element->
over))(element))
;
496 // backward compatible with samples and such
497 if (!el) {
498 return 0;
499 }
500 if ((unsigned int)el != 1) {
501 element = el;
502 }
503 }
504
505 // over function might have triggered a draw of its own during a display callback
506 if (before_display) {
507 el = before_display(element);
508 element = &e;
509 if (!el) {
510 return 0;
511 }
512 // problem for default screen_before_before_display where we return the given element, it have could been modified. but we don't know here
513 if ((unsigned int)el != 1) {
514 element = el;
515 }
516 }
517
518 // swap colors
519 memcpy(&e, (void*)element, sizeof(bagl_element_t));
520 e.component.fgcolor = element->overfgcolor;
521 e.component.bgcolor = element->overbgcolor;
522
523 io_seproxyhal_display(&e);
524 return 1;
525}
526
527unsigned int io_seproxyhal_touch_tap(const bagl_element_t* element, bagl_element_callback_t before_display) {
528 const bagl_element_t* el;
529 if (element->tap != NULL((void*)0)) {
530 el = (const bagl_element_t*)PIC(((bagl_element_callback_t)PIC(element->tap))(element))pic((void *)((bagl_element_callback_t)pic((void *)element->
tap))(element))
;
531 // backward compatible with samples and such
532 if (!el) {
533 return 0;
534 }
535 if ((unsigned int)el != 1) {
536 element = el;
537 }
538 }
539
540 // tap function might have triggered a draw of its own during a display callback
541 if (before_display) {
542 el = before_display(element);
543 if (!el) {
544 return 0;
545 }
546 if ((unsigned int)el != 1) {
547 element = el;
548 }
549 }
550 io_seproxyhal_display(element);
551 return 1;
552}
553
554void io_seproxyhal_touch(const bagl_element_t* elements, unsigned short element_count, unsigned short x, unsigned short y, unsigned char event_kind) {
555 io_seproxyhal_touch_element_callback(elements, element_count, x, y, event_kind, NULL((void*)0));
556}
557
558// browse all elements and until an element has changed state, continue browsing
559// return if processed or not
560void io_seproxyhal_touch_element_callback(const bagl_element_t* elements, unsigned short element_count, unsigned short x, unsigned short y, unsigned char event_kind, bagl_element_callback_t before_display) {
561 unsigned char comp_idx;
562 unsigned char last_touched_not_released_component_was_in_current_array = 0;
563
564 // find the first empty entry
565 for (comp_idx=0; comp_idx < element_count; comp_idx++) {
566 // process all components matching the x/y/w/h (no break) => fishy for the released out of zone
567 // continue processing only if a status has not been sent
568 if (io_seproxyhal_spi_is_status_sentio_seph_is_status_sent()) {
569 // continue instead of return to process all elemnts and therefore discard last touched element
570 break;
571 }
572
573 // only perform out callback when element was in the current array, else, leave it be
574 if (&elements[comp_idx] == G_ux_os.last_touched_not_released_component) {
575 last_touched_not_released_component_was_in_current_array = 1;
576 }
577
578 // the first component drawn with a
579 if ((elements[comp_idx].component.type & BAGL_FLAG_TOUCHABLE)
580 && elements[comp_idx].component.x-elements[comp_idx].touch_area_brim <= x && x<elements[comp_idx].component.x+elements[comp_idx].component.width+elements[comp_idx].touch_area_brim
581 && elements[comp_idx].component.y-elements[comp_idx].touch_area_brim <= y && y<elements[comp_idx].component.y+elements[comp_idx].component.height+elements[comp_idx].touch_area_brim) {
582
583 // outing the previous over'ed component
584 if (&elements[comp_idx] != G_ux_os.last_touched_not_released_component
585 && G_ux_os.last_touched_not_released_component != NULL((void*)0)) {
586 // only out the previous element if the newly matching will be displayed
587 if (!before_display || before_display(&elements[comp_idx])) {
588 if (io_seproxyhal_touch_out(G_ux_os.last_touched_not_released_component, before_display)) {
589 // previous component is considered released
590 G_ux_os.last_touched_not_released_component = NULL((void*)0);
591 // a display has been issued, avoid double display, wait for another touch event (20ms)
592 return;
593 }
594 }
595 // avoid a non displayed new element to pop out of the blue
596 continue;
597 }
598
599 /*
600 if (io_seproxyhal_spi_is_status_sent()) {
601 // continue instead of return to process all elements and therefore discard last touched element
602 continue;
603 }
604 */
605
606 // callback the hal to notify the component impacted by the user input
607 else if (event_kind == SEPROXYHAL_TAG_FINGER_EVENT_RELEASE0x02) {
608 if (io_seproxyhal_touch_tap(&elements[comp_idx], before_display)) {
609 // unmark the last component, we've been notified TOUCH
610 G_ux_os.last_touched_not_released_component = NULL((void*)0);
611 return;
612 }
613 }
614 else if (event_kind == SEPROXYHAL_TAG_FINGER_EVENT_TOUCH0x01) {
615 // ask for overing
616 if (io_seproxyhal_touch_over(&elements[comp_idx], before_display)) {
617 // remember the last touched component
618 G_ux_os.last_touched_not_released_component = (bagl_element_t*)&elements[comp_idx];
619 return;
620 }
621 }
622 }
623 }
624
625 // if overing out of component or over another component, the out event is sent after the over event of the previous component
626 if(last_touched_not_released_component_was_in_current_array
627 && G_ux_os.last_touched_not_released_component != NULL((void*)0)) {
628
629 // we won't be able to notify the out, don't do it, in case a diplay refused the dra of the relased element and the position matched another element of the array (in autocomplete for example)
630 if (io_seproxyhal_spi_is_status_sentio_seph_is_status_sent()) {
631 return;
632 }
633
634 if (io_seproxyhal_touch_out(G_ux_os.last_touched_not_released_component, before_display)) {
635 // ok component out has been emitted
636 G_ux_os.last_touched_not_released_component = NULL((void*)0);
637 }
638 }
639
640 // not processed
641}
642#endif // TARGET_BLUE
643
644void io_seproxyhal_display_bitmap(int x, int y, unsigned int w, unsigned int h, unsigned int* color_index, unsigned int bit_per_pixel, unsigned char* bitmap) {
645 // component type = ICON
646 // component icon id = 0
647 // => bitmap transmitted
648 if (w && h) {
649 bagl_component_t c;
650 bagl_icon_details_t d;
651 memset(&c, 0, sizeof(c));
652 c.type = BAGL_ICON;
653 c.x = x;
654 c.y = y;
655 c.width = w;
656 c.height = h;
657 // done by memset // c.icon_id = 0;
658 d.width = w;
659 d.height = h;
660 d.bpp = bit_per_pixel;
661 d.colors = color_index;
662 d.bitmap = bitmap;
663
664 io_seproxyhal_display_icon(&c, &d);
665 /*
666 // color index size
667 h = ((1<<bit_per_pixel)*sizeof(unsigned int));
668 // bitmap size
669 w = ((w*c.height*bit_per_pixel)/8)+((w*c.height*bit_per_pixel)%8?1:0);
670 unsigned short length = sizeof(bagl_component_t)
671 +1 // bpp
672 +h // color index
673 +w; // image bitmap
674 G_io_seproxyhal_spi_buffer[0] = SEPROXYHAL_TAG_SCREEN_DISPLAY_STATUS;
675 G_io_seproxyhal_spi_buffer[1] = length>>8;
676 G_io_seproxyhal_spi_buffer[2] = length;
677 io_seproxyhal_spi_send(G_io_seproxyhal_spi_buffer, 3);
678 io_seproxyhal_spi_send((unsigned char*)&c, sizeof(bagl_component_t));
679 G_io_seproxyhal_spi_buffer[0] = bit_per_pixel;
680 io_seproxyhal_spi_send(G_io_seproxyhal_spi_buffer, 1);
681 io_seproxyhal_spi_send((unsigned char*)color_index, h);
682 io_seproxyhal_spi_send(bitmap, w);
683 */
684 }
685}
686
687#ifdef SEPROXYHAL_TAG_SCREEN_DISPLAY_RAW_STATUS
688unsigned int io_seproxyhal_display_icon_header_and_colors(bagl_component_t* icon_component, bagl_icon_details_t* icon_details, unsigned int* icon_len) {
689 unsigned int len;
690
691 struct display_raw_s {
692 struct {
693 struct {
694 unsigned char tag;
695 unsigned char len[2];
696 } seph;
697 unsigned char type;
698 } header;
699 union {
700 short val;
701 char b[2];
702 } x;
703 union {
704 short val;
705 char b[2];
706 } y;
707 union {
708 unsigned short val;
709 char b[2];
710 } w;
711 union {
712 unsigned short val;
713 char b[2];
714 } h;
715 unsigned char bpp;
716 } __attribute__((packed)) raw;
717
718 raw.header.seph.tag = SEPROXYHAL_TAG_SCREEN_DISPLAY_RAW_STATUS;
719 raw.header.type = SEPROXYHAL_TAG_SCREEN_DISPLAY_RAW_STATUS_START;
720 raw.x.val = icon_component->x;
721 raw.y.val = icon_component->y;
722 raw.w.val = icon_component->width;
723 raw.h.val = icon_component->height;
724 raw.bpp = icon_details->bpp;
725
726
727 *icon_len = raw.w.val*raw.h.val*raw.bpp/8 + (((raw.w.val*raw.h.val*raw.bpp)%8)?1:0);
728
729 // optional, don't send too much on a single packet for MCU to receive it. when stream mode will be on, this will be useless
730 // min of remaining space in the packet vs. total icon size + color index size
731 len = MIN(sizeof(G_io_seproxyhal_spi_buffer) - sizeof(raw), *icon_len + (1<<raw.bpp)*4)((sizeof(G_io_seproxyhal_spi_buffer) - sizeof(raw)) < (*icon_len
+ (1<<raw.bpp)*4) ? (sizeof(G_io_seproxyhal_spi_buffer
) - sizeof(raw)) : (*icon_len + (1<<raw.bpp)*4))
;
732
733 // sizeof packet
734 raw.header.seph.len[0] = (len + sizeof(raw) - sizeof(raw.header.seph)) >> 8;
735 raw.header.seph.len[1] = (len + sizeof(raw) - sizeof(raw.header.seph));
736
737 // swap endianess of coordinates (make it big endian)
738 SWAP(raw.x.b[0], raw.x.b[1]){ raw.x.b[0] ^= raw.x.b[1]; raw.x.b[1] ^= raw.x.b[0]; raw.x.b
[0] ^= raw.x.b[1]; }
;
739 SWAP(raw.y.b[0], raw.y.b[1]){ raw.y.b[0] ^= raw.y.b[1]; raw.y.b[1] ^= raw.y.b[0]; raw.y.b
[0] ^= raw.y.b[1]; }
;
740 SWAP(raw.w.b[0], raw.w.b[1]){ raw.w.b[0] ^= raw.w.b[1]; raw.w.b[1] ^= raw.w.b[0]; raw.w.b
[0] ^= raw.w.b[1]; }
;
741 SWAP(raw.h.b[0], raw.h.b[1]){ raw.h.b[0] ^= raw.h.b[1]; raw.h.b[1] ^= raw.h.b[0]; raw.h.b
[0] ^= raw.h.b[1]; }
;
742
743 io_seproxyhal_spi_sendio_seph_send((unsigned char*)&raw, sizeof(raw));
744 io_seproxyhal_spi_sendio_seph_send((unsigned char*)(PIC(icon_details->colors)pic((void *)icon_details->colors)), (1<<raw.bpp)*4);
745 len -= (1<<raw.bpp)*4;
746
747 // remaining length of bitmap bits to be displayed
748 return len;
749}
750#endif // SEPROXYHAL_TAG_SCREEN_DISPLAY_RAW_STATUS
751
752void io_seproxyhal_display_icon(bagl_component_t* icon_component, bagl_icon_details_t* icon_det) {
753 bagl_component_t icon_component_mod;
754 const bagl_icon_details_t* icon_details = (bagl_icon_details_t*)PIC(icon_det)pic((void *)icon_det);
755
756 if (icon_details && icon_details->bitmap) {
757 // ensure not being out of bounds in the icon component agianst the declared icon real size
758 memcpy(&icon_component_mod, (void *)PIC(icon_component)pic((void *)icon_component), sizeof(bagl_component_t));
759 icon_component_mod.width = icon_details->width;
760 icon_component_mod.height = icon_details->height;
761 icon_component = &icon_component_mod;
Value stored to 'icon_component' is never read
762
763#ifdef SEPROXYHAL_TAG_SCREEN_DISPLAY_RAW_STATUS
764 unsigned int len;
765 unsigned int icon_len;
766 unsigned int icon_off=0;
767
768 len = io_seproxyhal_display_icon_header_and_colors(icon_component, (bagl_icon_details_t*)icon_details, &icon_len);
769 io_seproxyhal_spi_sendio_seph_send(PIC(icon_details->bitmap)pic((void *)icon_details->bitmap), len);
770 // advance in the bitmap to be transmitted
771 icon_len -= len;
772 icon_off += len;
773
774 // still some bitmap data to transmit
775 while(icon_len) {
776 // wait displayed event
777 io_seproxyhal_spi_recvio_seph_recv(G_io_seproxyhal_spi_buffer, sizeof(G_io_seproxyhal_spi_buffer), 0);
778
779 G_io_seproxyhal_spi_buffer[0] = SEPROXYHAL_TAG_SCREEN_DISPLAY_RAW_STATUS;
780 G_io_seproxyhal_spi_buffer[3] = SEPROXYHAL_TAG_SCREEN_DISPLAY_RAW_STATUS_CONT;
781
782 len = MIN((sizeof(G_io_seproxyhal_spi_buffer) - 4), icon_len)(((sizeof(G_io_seproxyhal_spi_buffer) - 4)) < (icon_len) ?
((sizeof(G_io_seproxyhal_spi_buffer) - 4)) : (icon_len))
;
783 G_io_seproxyhal_spi_buffer[1] = (len+1)>>8;
784 G_io_seproxyhal_spi_buffer[2] = (len+1);
785 io_seproxyhal_spi_sendio_seph_send(G_io_seproxyhal_spi_buffer, 4);
786 io_seproxyhal_spi_sendio_seph_send(PIC(icon_details->bitmap)pic((void *)icon_details->bitmap)+icon_off, len);
787
788 icon_len -= len;
789 icon_off += len;
790 }
791#else // !SEPROXYHAL_TAG_SCREEN_DISPLAY_RAW_STATUS
792#ifdef HAVE_SE_SCREEN1
793 bagl_draw_glyph(&icon_component_mod, icon_details);
794#endif // HAVE_SE_SCREEN
795#if !defined(HAVE_SE_SCREEN1) || (defined(HAVE_SE_SCREEN1) && defined(HAVE_PRINTF))
796 if (io_seproxyhal_spi_is_status_sentio_seph_is_status_sent()) {
797 return;
798 }
799 // color index size
800 unsigned int h = (1<<(icon_details->bpp))*sizeof(unsigned int);
801 // bitmap size
802 unsigned int w = ((icon_component->width*icon_component->height*icon_details->bpp)/8)+((icon_component->width*icon_component->height*icon_details->bpp)%8?1:0);
803 unsigned short length = sizeof(bagl_component_t)
804 +1 /* bpp */
805 +h /* color index */
806 +w; /* image bitmap size */
807 G_io_seproxyhal_spi_buffer[0] = SEPROXYHAL_TAG_SCREEN_DISPLAY_STATUS0x65;
808#if defined(HAVE_SE_SCREEN1) && defined(HAVE_PRINTF)
809 G_io_seproxyhal_spi_buffer[0] = SEPROXYHAL_TAG_DBG_SCREEN_DISPLAY_STATUS0x5E;
810#endif // HAVE_SE_SCREEN && HAVE_PRINTF
811 G_io_seproxyhal_spi_buffer[1] = length>>8;
812 G_io_seproxyhal_spi_buffer[2] = length;
813 io_seproxyhal_spi_sendio_seph_send(G_io_seproxyhal_spi_buffer, 3);
814 io_seproxyhal_spi_sendio_seph_send((unsigned char*)icon_component, sizeof(bagl_component_t));
815 G_io_seproxyhal_spi_buffer[0] = icon_details->bpp;
816 io_seproxyhal_spi_sendio_seph_send(G_io_seproxyhal_spi_buffer, 1);
817 io_seproxyhal_spi_sendio_seph_send((unsigned char*)PIC(icon_details->colors)pic((void *)icon_details->colors), h);
818 io_seproxyhal_spi_sendio_seph_send((unsigned char*)PIC(icon_details->bitmap)pic((void *)icon_details->bitmap), w);
819#endif // !HAVE_SE_SCREEN || (HAVE_SE_SCREEN && HAVE_PRINTF)
820#endif // !SEPROXYHAL_TAG_SCREEN_DISPLAY_RAW_STATUS
821 }
822}
823
824void io_seproxyhal_display_default(const bagl_element_t* element) {
825
826 const bagl_element_t* el = (const bagl_element_t*) PIC(element)pic((void *)element);
827 const char* txt = (const char*)PIC(el->text)pic((void *)el->text);
828 // process automagically address from rom and from ram
829 unsigned int type = (el->component.type & ~(BAGL_FLAG_TOUCHABLE));
830
831 if (type != BAGL_NONE) {
832 if (txt != NULL((void*)0)) {
833 // consider an icon details descriptor is pointed by the context
834 if (type == BAGL_ICON && el->component.icon_id == 0) {
835 // SECURITY: due to this wild cast, the code MUST be executed on the application side instead of in
836 // the syscall sides to avoid buffer overflows and a real hard way of checking buffer
837 // belonging in the syscall dispatch
838 io_seproxyhal_display_icon((bagl_component_t*)&el->component, (bagl_icon_details_t*)txt);
839 }
840 else {
841#ifdef HAVE_SE_SCREEN1
842 bagl_draw_with_context(&el->component, txt, strlen(txt), BAGL_ENCODING_LATIN10);
843#endif // HAVE_SE_SCREEN
844#if !defined(HAVE_SE_SCREEN1) || (defined(HAVE_SE_SCREEN1) && defined(HAVE_PRINTF))
845 if (io_seproxyhal_spi_is_status_sentio_seph_is_status_sent()) {
846 return;
847 }
848 unsigned short length = sizeof(bagl_component_t)+strlen((const char*)txt);
849 G_io_seproxyhal_spi_buffer[0] = SEPROXYHAL_TAG_SCREEN_DISPLAY_STATUS0x65;
850#if defined(HAVE_SE_SCREEN1) && defined(HAVE_PRINTF)
851 G_io_seproxyhal_spi_buffer[0] = SEPROXYHAL_TAG_DBG_SCREEN_DISPLAY_STATUS0x5E;
852#endif // HAVE_SE_SCREEN && HAVE_PRINTF
853 G_io_seproxyhal_spi_buffer[1] = length>>8;
854 G_io_seproxyhal_spi_buffer[2] = length;
855 io_seproxyhal_spi_sendio_seph_send(G_io_seproxyhal_spi_buffer, 3);
856 io_seproxyhal_spi_sendio_seph_send((unsigned char*)&el->component, sizeof(bagl_component_t));
857 io_seproxyhal_spi_sendio_seph_send((unsigned char*)txt, length-sizeof(bagl_component_t));
858#endif // !HAVE_SE_SCREEN || (HAVE_SE_SCREEN && HAVE_PRINTF)
859 }
860 }
861 else {
862#ifdef HAVE_SE_SCREEN1
863 bagl_draw_with_context(&el->component, NULL((void*)0), 0, 0);
864#endif // HAVE_SE_SCREEN
865#if !defined(HAVE_SE_SCREEN1) || (defined(HAVE_SE_SCREEN1) && defined(HAVE_PRINTF))
866 if (io_seproxyhal_spi_is_status_sentio_seph_is_status_sent()) {
867 return;
868 }
869 unsigned short length = sizeof(bagl_component_t);
870 G_io_seproxyhal_spi_buffer[0] = SEPROXYHAL_TAG_SCREEN_DISPLAY_STATUS0x65;
871#if defined(HAVE_SE_SCREEN1) && defined(HAVE_PRINTF)
872 G_io_seproxyhal_spi_buffer[0] = SEPROXYHAL_TAG_DBG_SCREEN_DISPLAY_STATUS0x5E;
873#endif // HAVE_SE_SCREEN && HAVE_PRINTF
874 G_io_seproxyhal_spi_buffer[1] = length>>8;
875 G_io_seproxyhal_spi_buffer[2] = length;
876 io_seproxyhal_spi_sendio_seph_send(G_io_seproxyhal_spi_buffer, 3);
877 io_seproxyhal_spi_sendio_seph_send((unsigned char*)&el->component, sizeof(bagl_component_t));
878#endif // !HAVE_SE_SCREEN || (HAVE_SE_SCREEN && HAVE_PRINTF)
879 }
880 }
881}
882
883unsigned int bagl_label_roundtrip_duration_ms(const bagl_element_t* e, unsigned int average_char_width) {
884 return bagl_label_roundtrip_duration_ms_buf(e, e->text, average_char_width);
885}
886
887unsigned int bagl_label_roundtrip_duration_ms_buf(const bagl_element_t* e, const char* str, unsigned int average_char_width) {
888 // not a scrollable label
889 if (e == NULL((void*)0) || (e->component.type != BAGL_LABEL && e->component.type != BAGL_LABELINE)) {
890 return 0;
891 }
892
893 const char *text_adr = (const char *) PIC(str)pic((void *)str);
894 unsigned int textlen = 0;
895
896 // no delay, no text to display
897 if (!text_adr) {
898 return 0;
899 }
900 textlen = strlen(text_adr);
901
902 // no delay, all text fits
903 textlen = textlen * average_char_width;
904 if (textlen <= e->component.width) {
905 return 0;
906 }
907
908 // compute scrolled text length
909 return 2*(textlen - e->component.width)*1000/e->component.icon_id + 2*(e->component.stroke & ~(0x80))*100;
910}
911
912void io_seproxyhal_button_push(button_push_callback_t button_callback, unsigned int new_button_mask) {
913 if (button_callback) {
914 unsigned int button_mask;
915 unsigned int button_same_mask_counter;
916 // enable speeded up long push
917 if (new_button_mask == G_ux_os.button_mask) {
918 // each 100ms ~
919 G_ux_os.button_same_mask_counter++;
920 }
921
922 // when new_button_mask is 0 and
923
924 // append the button mask
925 button_mask = G_ux_os.button_mask | new_button_mask;
926
927 // pre reset variable due to os_sched_exit
928 button_same_mask_counter = G_ux_os.button_same_mask_counter;
929
930 // reset button mask
931 if (new_button_mask == 0) {
932 // reset next state when button are released
933 G_ux_os.button_mask = 0;
934 G_ux_os.button_same_mask_counter=0;
935
936 // notify button released event
937 button_mask |= BUTTON_EVT_RELEASED0x80000000UL;
938 }
939 else {
940 G_ux_os.button_mask = button_mask;
941 }
942
943 // reset counter when button mask changes
944 if (new_button_mask != G_ux_os.button_mask) {
945 G_ux_os.button_same_mask_counter=0;
946 }
947
948 if (button_same_mask_counter >= BUTTON_FAST_THRESHOLD_CS8) {
949 // fast bit when pressing and timing is right
950 if ((button_same_mask_counter%BUTTON_FAST_ACTION_CS3) == 0) {
951 button_mask |= BUTTON_EVT_FAST0x40000000UL;
952 }
953
954 /*
955 // fast bit when releasing and threshold has been exceeded
956 if ((button_mask & BUTTON_EVT_RELEASED)) {
957 button_mask |= BUTTON_EVT_FAST;
958 }
959 */
960
961 // discard the release event after a fastskip has been detected, to avoid strange at release behavior
962 // and also to enable user to cancel an operation by starting triggering the fast skip
963 button_mask &= ~BUTTON_EVT_RELEASED0x80000000UL;
964 }
965
966 // indicate if button have been released
967 button_callback(button_mask, button_same_mask_counter);
968
969 }
970}
971
972#endif // HAVE_BAGL
973
974void io_seproxyhal_setup_ticker(unsigned int interval_ms) {
975 G_io_seproxyhal_spi_buffer[0] = SEPROXYHAL_TAG_SET_TICKER_INTERVAL0x4E;
976 G_io_seproxyhal_spi_buffer[1] = 0;
977 G_io_seproxyhal_spi_buffer[2] = 2;
978 G_io_seproxyhal_spi_buffer[3] = (interval_ms>>8)&0xff;
979 G_io_seproxyhal_spi_buffer[4] = (interval_ms)&0xff;
980 io_seproxyhal_spi_sendio_seph_send(G_io_seproxyhal_spi_buffer, 5);
981}
982
983static const unsigned char seph_io_device_off[] = {
984 SEPROXYHAL_TAG_DEVICE_OFF0x4B,
985 0,
986 0,
987};
988void io_seproxyhal_power_off(void) {
989 io_seproxyhal_spi_sendio_seph_send(seph_io_device_off, sizeof(seph_io_device_off));
990 for(;;);
991}
992
993static const unsigned char seph_io_se_reset[]= {
994 SEPROXYHAL_TAG_SE_POWER_OFF0x46,
995 0,
996 0,
997};
998void io_seproxyhal_se_reset(void) {
999 io_seproxyhal_spi_sendio_seph_send(seph_io_se_reset, sizeof(seph_io_se_reset));
1000 for(;;);
1001}
1002
1003#ifdef HAVE_BLE1
1004void io_seph_ble_enable(unsigned char enable)
1005{
1006 G_io_seproxyhal_spi_buffer[0] = SEPROXYHAL_TAG_UX_CMD0x5D;
1007 G_io_seproxyhal_spi_buffer[1] = 0;
1008 G_io_seproxyhal_spi_buffer[2] = 1;
1009 G_io_seproxyhal_spi_buffer[3] = (enable ? SEPROXYHAL_TAG_UX_CMD_BLE_ENABLE_ADV0x01 : SEPROXYHAL_TAG_UX_CMD_BLE_DISABLE_ADV0x00);
1010 io_seproxyhal_spi_sendio_seph_send(G_io_seproxyhal_spi_buffer, 4);
1011}
1012
1013void io_seph_ble_clear_bond_db(void)
1014{
1015 G_io_seproxyhal_spi_buffer[0] = SEPROXYHAL_TAG_UX_CMD0x5D;
1016 G_io_seproxyhal_spi_buffer[1] = 0;
1017 G_io_seproxyhal_spi_buffer[2] = 1;
1018 G_io_seproxyhal_spi_buffer[3] = SEPROXYHAL_TAG_UX_CMD_BLE_RESET_PAIRINGS0x02;
1019 io_seproxyhal_spi_sendio_seph_send(G_io_seproxyhal_spi_buffer, 4);
1020}
1021#endif // HAVE_BLE
1022
1023void io_seph_ux_redisplay(void)
1024{
1025 G_io_seproxyhal_spi_buffer[0] = SEPROXYHAL_TAG_UX_CMD0x5D;
1026 G_io_seproxyhal_spi_buffer[1] = 0;
1027 G_io_seproxyhal_spi_buffer[2] = 1;
1028 G_io_seproxyhal_spi_buffer[3] = SEPROXYHAL_TAG_UX_CMD_REDISPLAY0x03;
1029 io_seproxyhal_spi_sendio_seph_send(G_io_seproxyhal_spi_buffer, 4);
1030}
1031
1032static const unsigned char seph_io_usb_disconnect[] = {
1033 SEPROXYHAL_TAG_USB_CONFIG0x4F,
1034 0,
1035 1,
1036 SEPROXYHAL_TAG_USB_CONFIG_DISCONNECT0x02,
1037};
1038void io_seproxyhal_disable_io(void) {
1039 // usb off
1040 io_seproxyhal_spi_sendio_seph_send(seph_io_usb_disconnect, sizeof(seph_io_usb_disconnect));
1041}
1042
1043void io_seproxyhal_backlight(unsigned int flags, unsigned int backlight_percentage) {
1044 G_io_seproxyhal_spi_buffer[0] = SEPROXYHAL_TAG_SET_SCREEN_CONFIG0x3E;
1045 G_io_seproxyhal_spi_buffer[1] = 0;
1046 G_io_seproxyhal_spi_buffer[2] = 2;
1047 G_io_seproxyhal_spi_buffer[3] = (backlight_percentage?0x80:0)|(flags & 0x7F); // power on
1048 G_io_seproxyhal_spi_buffer[4] = backlight_percentage;
1049 io_seproxyhal_spi_sendio_seph_send(G_io_seproxyhal_spi_buffer, 5);
1050}
1051
1052#ifdef HAVE_IO_U2F
1053u2f_service_t G_io_u2f;
1054#endif // HAVE_IO_U2F
1055
1056unsigned int os_io_seproxyhal_get_app_name_and_version(void) __attribute__((weak));
1057unsigned int os_io_seproxyhal_get_app_name_and_version(void) {
1058 unsigned int tx_len, len;
1059 // build the get app name and version reply
1060 tx_len = 0;
1061 G_io_apdu_buffer[tx_len++] = 1; // format ID
1062
1063#ifndef HAVE_BOLOS
1064 // append app name
1065 len = os_registry_get_current_app_tag(BOLOS_TAG_APPNAME0x01, G_io_apdu_buffer+tx_len+1, sizeof(G_io_apdu_buffer)-tx_len-1);
1066 G_io_apdu_buffer[tx_len++] = len;
1067 tx_len += len;
1068 // append app version
1069 len = os_registry_get_current_app_tag(BOLOS_TAG_APPVERSION0x02, G_io_apdu_buffer+tx_len+1, sizeof(G_io_apdu_buffer)-tx_len-1);
1070 G_io_apdu_buffer[tx_len++] = len;
1071 tx_len += len;
1072#else // HAVE_BOLOS
1073 // append app name
1074 len = strlen("BOLOS");
1075 G_io_apdu_buffer[tx_len++] = len;
1076 strcpy((char*)(G_io_apdu_buffer+tx_len), "BOLOS");
1077 tx_len += len;
1078 // append app version
1079 len = strlen(VERSION"dummy");
1080 G_io_apdu_buffer[tx_len++] = len;
1081 strcpy((char*)(G_io_apdu_buffer+tx_len), VERSION"dummy");
1082 tx_len += len;
1083#endif // HAVE_BOLOS
1084
1085#if !defined(HAVE_IO_TASK) || !defined(HAVE_BOLOS)
1086 // to be fixed within io tasks
1087 // return OS flags to notify of platform's global state (pin lock etc)
1088 G_io_apdu_buffer[tx_len++] = 1; // flags length
1089 G_io_apdu_buffer[tx_len++] = os_flags();
1090#endif // !defined(HAVE_IO_TASK) || !defined(HAVE_BOLOS)
1091
1092 // status words
1093 G_io_apdu_buffer[tx_len++] = 0x90;
1094 G_io_apdu_buffer[tx_len++] = 0x00;
1095 return tx_len;
1096}
1097
1098#if !defined(HAVE_BOLOS_NO_DEFAULT_APDU)
1099// This function is used to process the default APDU commands.
1100static bolos_bool_t io_process_default_apdus(unsigned char* channel, unsigned short* tx_len) {
1101 // Indicates whether a command has been processed and need to send an answer.
1102 bolos_bool_t processed = BOLOS_FALSE0x55;
1103
1104 // We handle the default apdus when the CLA byte is correct.
1105 if (DEFAULT_APDU_CLA0xB0 == G_io_apdu_buffer[APDU_OFF_CLA0]) {
1106
1107 // We have several possible commands.
1108 switch (G_io_apdu_buffer[APDU_OFF_INS1]) {
1109
1110 // get name and version
1111 case DEFAULT_APDU_INS_GET_VERSION0x01:
1112 // P1 and P2 shall be set to '00'.
1113 if (!G_io_apdu_buffer[APDU_OFF_P12] && !G_io_apdu_buffer[APDU_OFF_P23]) {
1114 *tx_len = os_io_seproxyhal_get_app_name_and_version();
1115 // disable 'return after tx' and 'asynch reply' flags
1116 *channel &= ~IO_FLAGS0xF8;
1117 processed = BOLOS_TRUE0xaa;
1118 }
1119 break;
1120
1121 // exit app after replied
1122 case DEFAULT_APDU_INS_APP_EXIT0xA7:
1123 // P1 and P2 shall be set to '00'.
1124 if (!G_io_apdu_buffer[APDU_OFF_P12] && !G_io_apdu_buffer[APDU_OFF_P23]) {
1125 *tx_len = 0;
1126 G_io_apdu_buffer[(*tx_len)++] = 0x90;
1127 G_io_apdu_buffer[(*tx_len)++] = 0x00;
1128
1129#if defined(HAVE_BOLOS)
1130 // If this APDU has been received from the dashboard, we don't do
1131 // anything except resetting the IO flags.
1132 *channel &= ~IO_FLAGS0xF8;
1133#else
1134 // We exit the application after having replied.
1135 *channel |= IO_RESET_AFTER_REPLIED0x80;
1136#endif // HAVE_BOLOS
1137
1138 processed = BOLOS_TRUE0xaa;
1139 }
1140 break;
1141
1142 // seed cookie
1143 // host: <nothing>
1144 // device: <format(1B)> <len(1B)> <seed magic cookie if pin is entered(len)> 9000 | 6985
1145#if defined(HAVE_SEED_COOKIE)
1146 case DEFAULT_APDU_INS_GET_SEED_COOKIE:
1147 // P1 and P2 shall be set to '00'.
1148 if (!G_io_apdu_buffer[APDU_OFF_P12] && !G_io_apdu_buffer[APDU_OFF_P23]) {
1149 *tx_len = 0;
1150 if (os_global_pin_is_validated() == BOLOS_UX_OK0xAA) {
1151 unsigned int i;
1152 // format
1153 G_io_apdu_buffer[(*tx_len)++] = 0x01;
1154 i = os_perso_seed_cookie(G_io_apdu_buffer+1+1, MIN(64,sizeof(G_io_apdu_buffer)-1-1-2)((64) < (sizeof(G_io_apdu_buffer)-1-1-2) ? (64) : (sizeof(
G_io_apdu_buffer)-1-1-2))
);
1155
1156 G_io_apdu_buffer[(*tx_len)++] = i;
1157 *tx_len += i;
1158 G_io_apdu_buffer[(*tx_len)++] = 0x90;
1159 G_io_apdu_buffer[(*tx_len)++] = 0x00;
1160 }
1161 else {
1162 G_io_apdu_buffer[(*tx_len)++] = 0x69;
1163 G_io_apdu_buffer[(*tx_len)++] = 0x85;
1164 }
1165 *channel &= ~IO_FLAGS0xF8;
1166 processed = BOLOS_TRUE0xaa;
1167 }
1168 break;
1169#endif // HAVE_SEED_COOKIE
1170
1171#if defined(DEBUG_OS_STACK_CONSUMPTION)
1172 // OS stack consumption.
1173 case DEFAULT_APDU_INS_STACK_CONSUMPTION:
1174 // Initialization.
1175 *tx_len = 2;
1176 U2BE_ENCODE(G_io_apdu_buffer, 0x00, SWO_APD_HDR_0D((0x6000 + 0x0500) + ERR_GEN_ID_0D));
1177
1178 // P2 and Lc shall be set to '00'.
1179 if (!G_io_apdu_buffer[APDU_OFF_P23] && !G_io_apdu_buffer[APDU_OFF_LC4]) {
1180 int s = os_stack_operations(G_io_apdu_buffer[APDU_OFF_P12]);
1181 if (-1 != s) {
1182 u4be_encode(G_io_apdu_buffer, 0x00, s);
1183 *tx_len = sizeof(int);
1184 G_io_apdu_buffer[(*tx_len)++] = 0x90;
1185 G_io_apdu_buffer[(*tx_len)++] = 0x00;
1186 }
1187 }
1188 *channel &= ~IO_FLAGS0xF8;
1189 processed = BOLOS_TRUE0xaa;
1190 break;
1191#endif // DEBUG_OS_STACK_CONSUMPTION
1192
1193 default:
1194 // 'processed' is already initialized.
1195 break;
1196 }
1197 }
1198
1199 return processed;
1200}
1201
1202#endif // HAVE_BOLOS_NO_DEFAULT_APDU
1203
1204unsigned short io_exchange(unsigned char channel, unsigned short tx_len) {
1205 unsigned short rx_len;
1206 unsigned int timeout_ms;
1207
1208#ifdef HAVE_BOLOS_APP_STACK_CANARY1
1209 // behavior upon detected stack overflow is to reset the SE
1210 if (app_stack_canary != APP_STACK_CANARY_MAGIC0xDEAD0031) {
1211 io_seproxyhal_se_reset();
1212 }
1213#endif // HAVE_BOLOS_APP_STACK_CANARY
1214
1215#ifdef DEBUG_APDU
1216 if ((channel&~(IO_FLAGS0xF8)) == CHANNEL_APDU0) {
1217 // ignore tx len
1218
1219 // already received the data of the apdu when received the whole apdu
1220 if ((channel & (CHANNEL_APDU0|IO_RECEIVE_DATA0x40)) == (CHANNEL_APDU0|IO_RECEIVE_DATA0x40)) {
1221 // return apdu data - header
1222 return G_io_apdu_length-5;
1223 }
1224
1225 // fetch next apdu
1226 if (debug_apdus_offset < sizeof(debug_apdus)) {
1227 G_io_apdu_length = debug_apdus[debug_apdus_offset]&0xFF;
1228 memcpy(G_io_apdu_buffer, &debug_apdus[debug_apdus_offset+1], G_io_apdu_length);
1229 debug_apdus_offset += G_io_apdu_length+1;
1230 return G_io_apdu_length;
1231 }
1232 }
1233#endif // DEBUG_APDU
1234
1235reply_apdu:
1236 switch(channel&~(IO_FLAGS0xF8)) {
1237 case CHANNEL_APDU0:
1238 // TODO work up the spi state machine over the HAL proxy until an APDU is available
1239
1240 if (tx_len && !(channel&IO_ASYNCH_REPLY0x10)) {
1241 // ensure it's our turn to send a command/status, could lag a bit before sending the reply
1242 while (io_seproxyhal_spi_is_status_sentio_seph_is_status_sent()) {
1243 io_seproxyhal_spi_recvio_seph_recv(G_io_seproxyhal_spi_buffer, sizeof(G_io_seproxyhal_spi_buffer), 0);
1244 // process without sending status on tickers etc, to ensure keeping the hand
1245 os_io_seph_recv_and_process(1);
1246 }
1247
1248 // reinit sending timeout for APDU replied within io_exchange
1249 timeout_ms = G_io_app.ms + IO_RAPDU_TRANSMIT_TIMEOUT_MS2000UL;
1250
1251 // until the whole RAPDU is transmitted, send chunks using the current mode for communication
1252 for (;;) {
1253 switch(G_io_app.apdu_state) {
1254 default:
1255 // delegate to the hal in case of not generic transport mode (or asynch)
1256 if (io_exchange_al(channel, tx_len) == 0) {
1257 goto break_send;
1258 }
1259 __attribute__((fallthrough));
1260 case APDU_IDLE:
1261 LOG("invalid state for APDU reply\n");
1262 THROW(INVALID_STATE)os_longjmp(0x4);
1263 break;
1264
1265 case APDU_RAW:
1266 if (tx_len > sizeof(G_io_apdu_buffer)) {
1267 THROW(INVALID_PARAMETER)os_longjmp(0x2);
1268 }
1269 // reply the RAW APDU over SEPROXYHAL protocol
1270 G_io_seproxyhal_spi_buffer[0] = SEPROXYHAL_TAG_RAPDU0x53;
1271 G_io_seproxyhal_spi_buffer[1] = (tx_len)>>8;
1272 G_io_seproxyhal_spi_buffer[2] = (tx_len);
1273 io_seproxyhal_spi_sendio_seph_send(G_io_seproxyhal_spi_buffer, 3);
1274 io_seproxyhal_spi_sendio_seph_send(G_io_apdu_buffer, tx_len);
1275
1276 // isngle packet reply, mark immediate idle
1277 G_io_app.apdu_state = APDU_IDLE;
1278 // finished, no chunking
1279 goto break_send;
1280
1281#ifdef HAVE_USB_APDU1
1282 case APDU_USB_HID:
1283 // only send, don't perform synchronous reception of the next command (will be done later by the seproxyhal packet processing)
1284 io_usb_hid_send(io_usb_send_apdu_data, tx_len);
1285 goto break_send;
1286#ifdef HAVE_USB_CLASS_CCID
1287 case APDU_USB_CCID:
1288 io_usb_ccid_reply(G_io_apdu_buffer, tx_len);
1289 goto break_send;
1290#endif // HAVE_USB_CLASS_CCID
1291#ifdef HAVE_WEBUSB1
1292 case APDU_USB_WEBUSB:
1293 io_usb_hid_send(io_usb_send_apdu_data_ep0x83, tx_len);
1294 goto break_send;
1295#endif // HAVE_WEBUSB
1296#endif // HAVE_USB_APDU
1297
1298#ifdef HAVE_BLE_APDU1 // versus U2F BLE
1299 case APDU_BLE:
1300 LEDGER_BLE_send(G_io_apdu_buffer, tx_len);
1301 goto break_send;
1302#endif // HAVE_BLE_APDU
1303
1304
1305#ifdef HAVE_IO_U2F
1306 // case to handle U2F channels. u2f apdu to be dispatched in the upper layers
1307 case APDU_U2F:
1308 // prepare reply, the remaining segments will be pumped during USB/BLE events handling while waiting for the next APDU
1309
1310 // the reply has been prepared by the application, stop sending anti timeouts
1311 u2f_message_set_autoreply_wait_user_presence(&G_io_u2f, false0);
1312
1313 // continue processing currently received command until completely received.
1314 while(!u2f_message_repliable(&G_io_u2f)) {
1315
1316 io_seproxyhal_general_status();
1317 do {
1318 io_seproxyhal_spi_recvio_seph_recv(G_io_seproxyhal_spi_buffer, sizeof(G_io_seproxyhal_spi_buffer), 0);
1319 // check for reply timeout
1320 if (G_io_app.ms >= timeout_ms) {
1321 THROW(EXCEPTION_IO_RESET)os_longjmp(0x5);
1322 }
1323 // avoid a general status to be replied
1324 io_seproxyhal_handle_event();
1325 } while (io_seproxyhal_spi_is_status_sentio_seph_is_status_sent());
1326 }
1327#ifdef U2F_PROXY_MAGIC
1328
1329 // user presence + counter + rapdu + sw must fit the apdu buffer
1330 if (1U+ 4U+ tx_len +2U > sizeof(G_io_apdu_buffer)) {
1331 THROW(INVALID_PARAMETER)os_longjmp(0x2);
1332 }
1333
1334 // u2F tunnel needs the status words to be included in the signature response BLOB, do it now.
1335 // always return 9000 in the signature to avoid error @ transport level in u2f layers.
1336 G_io_apdu_buffer[tx_len] = 0x90; //G_io_apdu_buffer[tx_len-2];
1337 G_io_apdu_buffer[tx_len+1] = 0x00; //G_io_apdu_buffer[tx_len-1];
1338 tx_len += 2;
1339 memmove(G_io_apdu_buffer + APDU_OFF_DATA5, G_io_apdu_buffer, tx_len);
1340 // zeroize user presence and counter
1341 memset(G_io_apdu_buffer, 0, APDU_OFF_DATA5);
1342 u2f_message_reply(&G_io_u2f, U2F_CMD_MSG, G_io_apdu_buffer, tx_len+5);
1343
1344#else // U2F_PROXY_MAGIC
1345 u2f_message_reply(&G_io_u2f, U2F_CMD_MSG, G_io_apdu_buffer, tx_len);
1346#endif // U2F_PROXY_MAGIC
1347 goto break_send;
1348#endif // HAVE_IO_U2F
1349 }
1350 continue;
1351
1352 break_send:
1353
1354 // wait end of reply transmission
1355 // TODO: add timeout here to avoid spending too much time when host has disconnected
1356 while (G_io_app.apdu_state != APDU_IDLE) {
1357 io_seproxyhal_general_status();
1358 do {
1359 io_seproxyhal_spi_recvio_seph_recv(G_io_seproxyhal_spi_buffer, sizeof(G_io_seproxyhal_spi_buffer), 0);
1360 // check for reply timeout (when asynch reply (over hid or u2f for example))
1361 // this case shall be covered by usb_ep_timeout but is not, investigate that
1362 if (G_io_app.ms >= timeout_ms) {
1363 THROW(EXCEPTION_IO_RESET)os_longjmp(0x5);
1364 }
1365 // avoid a general status to be replied
1366 io_seproxyhal_handle_event();
1367 } while (io_seproxyhal_spi_is_status_sentio_seph_is_status_sent());
1368 }
1369 // reset apdu state
1370 G_io_app.apdu_state = APDU_IDLE;
1371 G_io_app.apdu_media = IO_APDU_MEDIA_NONE;
1372
1373 G_io_app.apdu_length = 0;
1374
1375 // continue sending commands, don't issue status yet
1376 if (channel & IO_RETURN_AFTER_TX0x20) {
1377 return 0;
1378 }
1379 // acknowledge the write request (general status OK) and no more command to follow (wait until another APDU container is received to continue unwrapping)
1380 io_seproxyhal_general_status();
1381 break;
1382 }
1383
1384 // perform reset after io exchange
1385 if (channel & IO_RESET_AFTER_REPLIED0x80) {
1386 // The error cast is retrocompatible with the previous value.
1387 os_sched_exit((bolos_task_status_t)EXCEPTION_IO_RESET0x5);
1388 //reset();
1389 }
1390 }
1391
1392 if (!(channel&IO_ASYNCH_REPLY0x10)) {
1393
1394 // already received the data of the apdu when received the whole apdu
1395 if ((channel & (CHANNEL_APDU0|IO_RECEIVE_DATA0x40)) == (CHANNEL_APDU0|IO_RECEIVE_DATA0x40)) {
1396 // return apdu data - header
1397 return G_io_app.apdu_length-5;
1398 }
1399
1400 // reply has ended, proceed to next apdu reception (reset status only after asynch reply)
1401 G_io_app.apdu_state = APDU_IDLE;
1402 G_io_app.apdu_media = IO_APDU_MEDIA_NONE;
1403 }
1404
1405 // reset the received apdu length
1406 G_io_app.apdu_length = 0;
1407
1408 // ensure ready to receive an event (after an apdu processing with asynch flag, it may occur if the channel is not correctly managed)
1409
1410 // until a new whole CAPDU is received
1411 for (;;) {
1412 io_seproxyhal_general_status();
1413 // wait until a SPI packet is available
1414 // NOTE: on ST31, dual wait ISO & RF (ISO instead of SPI)
1415 rx_len = io_seproxyhal_spi_recvio_seph_recv(G_io_seproxyhal_spi_buffer, sizeof(G_io_seproxyhal_spi_buffer), 0);
1416
1417 // can't process split TLV, continue
1418 if (rx_len < 3 || rx_len != U2(G_io_seproxyhal_spi_buffer[1],G_io_seproxyhal_spi_buffer[2])((((G_io_seproxyhal_spi_buffer[1])&0xFFu) << 8) | (
(G_io_seproxyhal_spi_buffer[2])&0xFFu))
+3U) {
1419 LOG("invalid TLV format\n");
1420 G_io_app.apdu_state = APDU_IDLE;
1421 G_io_app.apdu_length = 0;
1422 continue;
1423 }
1424
1425 io_seproxyhal_handle_event();
1426
1427 // An apdu has been received asynchroneously.
1428 if (G_io_app.apdu_state != APDU_IDLE && G_io_app.apdu_length > 0) {
1429#if !defined(HAVE_BOLOS_NO_DEFAULT_APDU)
1430 // If a default command is received and processed within this call,
1431 // then we send the answer.
1432 if (io_process_default_apdus(&channel, &tx_len) == BOLOS_TRUE0xaa) {
1433 goto reply_apdu;
1434 }
1435#endif // ! HAVE_BOLOS_NO_DEFAULT_APDU
1436
1437 return G_io_app.apdu_length;
1438 }
1439 }
1440 break;
1441
1442 default:
1443 return io_exchange_al(channel, tx_len);
1444 }
1445}
1446
1447unsigned int os_io_seph_recv_and_process(unsigned int dont_process_ux_events) {
1448 // send general status before receiving next event
1449 io_seproxyhal_general_status();
1450
1451 io_seproxyhal_spi_recvio_seph_recv(G_io_seproxyhal_spi_buffer, sizeof(G_io_seproxyhal_spi_buffer), 0);
1452
1453 switch (G_io_seproxyhal_spi_buffer[0]) {
1454 case SEPROXYHAL_TAG_FINGER_EVENT0x0C:
1455 case SEPROXYHAL_TAG_BUTTON_PUSH_EVENT0x05:
1456 case SEPROXYHAL_TAG_TICKER_EVENT0x0E:
1457 case SEPROXYHAL_TAG_DISPLAY_PROCESSED_EVENT0x0D:
1458 case SEPROXYHAL_TAG_STATUS_EVENT0x15:
1459 // perform UX event on these ones, don't process as an IO event
1460 if (dont_process_ux_events) {
1461 return 0;
1462 }
1463 __attribute__((fallthrough));
1464
1465 default:
1466 // if malformed, then a stall is likely to occur
1467 if (io_seproxyhal_handle_event()) {
1468 return 1;
1469 }
1470 }
1471 return 0;
1472}
1473
1474#if !defined(APP_UX)
1475unsigned int os_ux_blocking(bolos_ux_params_t* params) {
1476 unsigned int ret;
1477
1478 // until a real status is returned
1479 os_ux(params);
1480 ret = os_sched_last_status(TASK_BOLOS_UX);
1481 while(ret == BOLOS_UX_IGNORE0x97
1482 || ret == BOLOS_UX_CONTINUE0) {
1483 // if the IO task is not running, then need to pump events manually
1484 if (os_sched_is_running(TASK_SUBTASKS_START) != BOLOS_TRUE0xaa) {
1485 // send general status before receiving next event
1486 io_seproxyhal_general_status();
1487 io_seproxyhal_spi_recvio_seph_recv(G_io_seproxyhal_spi_buffer, sizeof(G_io_seproxyhal_spi_buffer), 0);
1488 io_event(0);
1489 }
1490 else
1491 {
1492 // wait until UX takes some process time and update it's status
1493 os_sched_yield(BOLOS_UX_OK0xAA);
1494 }
1495 // only retrieve the current UX state
1496 ret = os_sched_last_status(TASK_BOLOS_UX);
1497 }
1498
1499 return ret;
1500}
1501#endif // !defined(APP_UX)
1502
1503#ifdef HAVE_PRINTF
1504void mcu_usb_prints(const char* str, unsigned int charcount) {
1505 unsigned char buf[4];
1506
1507 buf[0] = SEPROXYHAL_TAG_PRINTF0x5F;
1508 buf[1] = charcount >> 8;
1509 buf[2] = charcount;
1510 io_seproxyhal_spi_sendio_seph_send(buf, 3);
1511 io_seproxyhal_spi_sendio_seph_send((unsigned char*)str, charcount);
1512}
1513#endif // HAVE_PRINTF
1514
1515void io_seproxyhal_io_heartbeat(void) {
1516 io_seproxyhal_general_status();
1517 do {
1518 io_seproxyhal_spi_recvio_seph_recv(G_io_seproxyhal_spi_buffer, sizeof(G_io_seproxyhal_spi_buffer), 0);
1519 // avoid a general status to be replied
1520 if(G_io_seproxyhal_spi_buffer[0] != SEPROXYHAL_TAG_TICKER_EVENT0x0E) {
1521 io_seproxyhal_handle_event();
1522 }
1523 } while (io_seproxyhal_spi_is_status_sentio_seph_is_status_sent());
1524}
1525#endif // OS_IO_SEPROXYHAL
diff --git a/app/output-scan-build/2022-05-16-071046-61-1/scanview.css b/app/output-scan-build/2022-05-16-071046-61-1/scanview.css deleted file mode 100644 index cf8a5a6a..00000000 --- a/app/output-scan-build/2022-05-16-071046-61-1/scanview.css +++ /dev/null @@ -1,62 +0,0 @@ -body { color:#000000; background-color:#ffffff } -body { font-family: Helvetica, sans-serif; font-size:9pt } -h1 { font-size: 14pt; } -h2 { font-size: 12pt; } -table { font-size:9pt } -table { border-spacing: 0px; border: 1px solid black } -th, table thead { - background-color:#eee; color:#666666; - font-weight: bold; cursor: default; - text-align:center; - font-weight: bold; font-family: Verdana; - white-space:nowrap; -} -.W { font-size:0px } -th, td { padding:5px; padding-left:8px; text-align:left } -td.SUMM_DESC { padding-left:12px } -td.DESC { white-space:pre } -td.Q { text-align:right } -td { text-align:left } -tbody.scrollContent { overflow:auto } - -table.form_group { - background-color: #ccc; - border: 1px solid #333; - padding: 2px; -} - -table.form_inner_group { - background-color: #ccc; - border: 1px solid #333; - padding: 0px; -} - -table.form { - background-color: #999; - border: 1px solid #333; - padding: 2px; -} - -td.form_label { - text-align: right; - vertical-align: top; -} -/* For one line entires */ -td.form_clabel { - text-align: right; - vertical-align: center; -} -td.form_value { - text-align: left; - vertical-align: top; -} -td.form_submit { - text-align: right; - vertical-align: top; -} - -h1.SubmitFail { - color: #f00; -} -h1.SubmitOk { -} diff --git a/app/output-scan-build/2022-05-16-071046-61-1/sorttable.js b/app/output-scan-build/2022-05-16-071046-61-1/sorttable.js deleted file mode 100644 index 32faa078..00000000 --- a/app/output-scan-build/2022-05-16-071046-61-1/sorttable.js +++ /dev/null @@ -1,492 +0,0 @@ -/* - SortTable - version 2 - 7th April 2007 - Stuart Langridge, http://www.kryogenix.org/code/browser/sorttable/ - - Instructions: - Download this file - Add to your HTML - Add class="sortable" to any table you'd like to make sortable - Click on the headers to sort - - Thanks to many, many people for contributions and suggestions. - Licenced as X11: http://www.kryogenix.org/code/browser/licence.html - This basically means: do what you want with it. -*/ - - -var stIsIE = /*@cc_on!@*/false; - -sorttable = { - init: function() { - // quit if this function has already been called - if (arguments.callee.done) return; - // flag this function so we don't do the same thing twice - arguments.callee.done = true; - // kill the timer - if (_timer) clearInterval(_timer); - - if (!document.createElement || !document.getElementsByTagName) return; - - sorttable.DATE_RE = /^(\d\d?)[\/\.-](\d\d?)[\/\.-]((\d\d)?\d\d)$/; - - forEach(document.getElementsByTagName('table'), function(table) { - if (table.className.search(/\bsortable\b/) != -1) { - sorttable.makeSortable(table); - } - }); - - }, - - makeSortable: function(table) { - if (table.getElementsByTagName('thead').length == 0) { - // table doesn't have a tHead. Since it should have, create one and - // put the first table row in it. - the = document.createElement('thead'); - the.appendChild(table.rows[0]); - table.insertBefore(the,table.firstChild); - } - // Safari doesn't support table.tHead, sigh - if (table.tHead == null) table.tHead = table.getElementsByTagName('thead')[0]; - - if (table.tHead.rows.length != 1) return; // can't cope with two header rows - - // Sorttable v1 put rows with a class of "sortbottom" at the bottom (as - // "total" rows, for example). This is B&R, since what you're supposed - // to do is put them in a tfoot. So, if there are sortbottom rows, - // for backward compatibility, move them to tfoot (creating it if needed). - sortbottomrows = []; - for (var i=0; i5' : ' ▴'; - this.appendChild(sortrevind); - return; - } - if (this.className.search(/\bsorttable_sorted_reverse\b/) != -1) { - // if we're already sorted by this column in reverse, just - // re-reverse the table, which is quicker - sorttable.reverse(this.sorttable_tbody); - this.className = this.className.replace('sorttable_sorted_reverse', - 'sorttable_sorted'); - this.removeChild(document.getElementById('sorttable_sortrevind')); - sortfwdind = document.createElement('span'); - sortfwdind.id = "sorttable_sortfwdind"; - sortfwdind.innerHTML = stIsIE ? ' 6' : ' ▾'; - this.appendChild(sortfwdind); - return; - } - - // remove sorttable_sorted classes - theadrow = this.parentNode; - forEach(theadrow.childNodes, function(cell) { - if (cell.nodeType == 1) { // an element - cell.className = cell.className.replace('sorttable_sorted_reverse',''); - cell.className = cell.className.replace('sorttable_sorted',''); - } - }); - sortfwdind = document.getElementById('sorttable_sortfwdind'); - if (sortfwdind) { sortfwdind.parentNode.removeChild(sortfwdind); } - sortrevind = document.getElementById('sorttable_sortrevind'); - if (sortrevind) { sortrevind.parentNode.removeChild(sortrevind); } - - this.className += ' sorttable_sorted'; - sortfwdind = document.createElement('span'); - sortfwdind.id = "sorttable_sortfwdind"; - sortfwdind.innerHTML = stIsIE ? ' 6' : ' ▾'; - this.appendChild(sortfwdind); - - // build an array to sort. This is a Schwartzian transform thing, - // i.e., we "decorate" each row with the actual sort key, - // sort based on the sort keys, and then put the rows back in order - // which is a lot faster because you only do getInnerText once per row - row_array = []; - col = this.sorttable_columnindex; - rows = this.sorttable_tbody.rows; - for (var j=0; j 12) { - // definitely dd/mm - return sorttable.sort_ddmm; - } else if (second > 12) { - return sorttable.sort_mmdd; - } else { - // looks like a date, but we can't tell which, so assume - // that it's dd/mm (English imperialism!) and keep looking - sortfn = sorttable.sort_ddmm; - } - } - } - } - return sortfn; - }, - - getInnerText: function(node) { - // gets the text we want to use for sorting for a cell. - // strips leading and trailing whitespace. - // this is *not* a generic getInnerText function; it's special to sorttable. - // for example, you can override the cell text with a customkey attribute. - // it also gets .value for fields. - - hasInputs = (typeof node.getElementsByTagName == 'function') && - node.getElementsByTagName('input').length; - - if (node.getAttribute("sorttable_customkey") != null) { - return node.getAttribute("sorttable_customkey"); - } - else if (typeof node.textContent != 'undefined' && !hasInputs) { - return node.textContent.replace(/^\s+|\s+$/g, ''); - } - else if (typeof node.innerText != 'undefined' && !hasInputs) { - return node.innerText.replace(/^\s+|\s+$/g, ''); - } - else if (typeof node.text != 'undefined' && !hasInputs) { - return node.text.replace(/^\s+|\s+$/g, ''); - } - else { - switch (node.nodeType) { - case 3: - if (node.nodeName.toLowerCase() == 'input') { - return node.value.replace(/^\s+|\s+$/g, ''); - } - case 4: - return node.nodeValue.replace(/^\s+|\s+$/g, ''); - break; - case 1: - case 11: - var innerText = ''; - for (var i = 0; i < node.childNodes.length; i++) { - innerText += sorttable.getInnerText(node.childNodes[i]); - } - return innerText.replace(/^\s+|\s+$/g, ''); - break; - default: - return ''; - } - } - }, - - reverse: function(tbody) { - // reverse the rows in a tbody - newrows = []; - for (var i=0; i=0; i--) { - tbody.appendChild(newrows[i]); - } - delete newrows; - }, - - /* sort functions - each sort function takes two parameters, a and b - you are comparing a[0] and b[0] */ - sort_numeric: function(a,b) { - aa = parseFloat(a[0].replace(/[^0-9.-]/g,'')); - if (isNaN(aa)) aa = 0; - bb = parseFloat(b[0].replace(/[^0-9.-]/g,'')); - if (isNaN(bb)) bb = 0; - return aa-bb; - }, - sort_alpha: function(a,b) { - if (a[0]==b[0]) return 0; - if (a[0] 0 ) { - var q = list[i]; list[i] = list[i+1]; list[i+1] = q; - swap = true; - } - } // for - t--; - - if (!swap) break; - - for(var i = t; i > b; --i) { - if ( comp_func(list[i], list[i-1]) < 0 ) { - var q = list[i]; list[i] = list[i-1]; list[i-1] = q; - swap = true; - } - } // for - b++; - - } // while(swap) - } -} - -/* ****************************************************************** - Supporting functions: bundled here to avoid depending on a library - ****************************************************************** */ - -// Dean Edwards/Matthias Miller/John Resig - -/* for Mozilla/Opera9 */ -if (document.addEventListener) { - document.addEventListener("DOMContentLoaded", sorttable.init, false); -} - -/* for Internet Explorer */ -/*@cc_on @*/ -/*@if (@_win32) - document.write(" - - - - -

app - scan-build results

- - - - - - - -
User:unknown@00d651b2e6fc
Working Directory:/app
Command Line:make default
Clang Version:Ubuntu clang version 12.0.0-3ubuntu1~20.04.5 -
Date:Mon May 16 07:12:32 2022
-

Bug Summary

- - - - -
Bug TypeQuantityDisplay?
All Bugs1
Dead store
Dead assignment1
-

Reports

- - - - - - - - - - - - - - - - - -
Bug GroupBug Type ▾FileFunction/MethodLinePath Length
Dead storeDead assignmentos_io_seproxyhal.cio_seproxyhal_display_icon7611View Report
- - diff --git a/app/output-scan-build/2022-05-16-071232-98-1/report-660403.html b/app/output-scan-build/2022-05-16-071232-98-1/report-660403.html deleted file mode 100644 index 87ae1c36..00000000 --- a/app/output-scan-build/2022-05-16-071232-98-1/report-660403.html +++ /dev/null @@ -1,1880 +0,0 @@ - - - -/opt/nanosplus-secure-sdk/src/os_io_seproxyhal.c - - - - - - - - - - - - - - - - - - - - - - - - - - -

Bug Summary

- - - - -
File:os_io_seproxyhal.c
Warning:line 761, column 5
Value stored to 'icon_component' is never read
- -

Annotated Source Code

-

Press '?' - to see keyboard shortcuts

- - -
clang -cc1 -cc1 -triple thumbv8m.main-none-unknown-eabi -analyze -disable-free -disable-llvm-verifier -discard-value-names -main-file-name os_io_seproxyhal.c -analyzer-store=region -analyzer-opt-analyze-nested-blocks -analyzer-checker=core -analyzer-checker=apiModeling -analyzer-checker=unix -analyzer-checker=deadcode -analyzer-checker=security.insecureAPI.UncheckedReturn -analyzer-checker=security.insecureAPI.getpw -analyzer-checker=security.insecureAPI.gets -analyzer-checker=security.insecureAPI.mktemp -analyzer-checker=security.insecureAPI.mkstemp -analyzer-checker=security.insecureAPI.vfork -analyzer-checker=nullability.NullPassedToNonnull -analyzer-checker=nullability.NullReturnedFromNonnull -analyzer-output plist -w -setup-static-analyzer -mrelocation-model ropi-rwpi -fropi -frwpi -fhalf-no-semantic-interposition -fno-jump-tables -mframe-pointer=none -fmath-errno -fno-rounding-math -fno-verbose-asm -mconstructor-aliases -nostdsysteminc -target-cpu cortex-m35p -target-feature +soft-float -target-feature +soft-float-abi -target-feature -crc -target-feature -sha2 -target-feature -aes -target-feature -ras -target-feature -sb -target-feature -i8mm -target-feature -lob -target-feature -cdecp0 -target-feature -cdecp1 -target-feature -cdecp2 -target-feature -cdecp3 -target-feature -cdecp4 -target-feature -cdecp5 -target-feature -cdecp6 -target-feature -cdecp7 -target-feature -hwdiv-arm -target-feature +hwdiv -target-feature -dsp -target-feature -vfp2 -target-feature -vfp2sp -target-feature -vfp3 -target-feature -vfp3d16 -target-feature -vfp3d16sp -target-feature -vfp3sp -target-feature -fp16 -target-feature -vfp4 -target-feature -vfp4d16 -target-feature -vfp4d16sp -target-feature -vfp4sp -target-feature -fp-armv8 -target-feature -fp-armv8d16 -target-feature -fp-armv8d16sp -target-feature -fp-armv8sp -target-feature -fullfp16 -target-feature -fp64 -target-feature -d32 -target-feature -neon -target-feature -crypto -target-feature -dotprod -target-feature -fp16fml -target-feature -bf16 -target-feature -mve -target-feature -mve.fp -target-feature -fpregs -target-feature +strict-align -target-feature +no-movt -target-abi aapcs -msoft-float -mfloat-abi soft -fallow-half-arguments-and-returns -fno-split-dwarf-inlining -debugger-tuning=gdb -ffunction-sections -fdata-sections -resource-dir /usr/lib/llvm-12/lib/clang/12.0.0 -D gcc -D __IO=volatile -D NDEBUG -D BAGL_WIDTH=128 -D BAGL_HEIGHT=64 -D HAVE_BAGL_ELLIPSIS -D HAVE_BAGL_FONT_OPEN_SANS_REGULAR_11PX -D HAVE_BAGL_FONT_OPEN_SANS_EXTRABOLD_11PX -D HAVE_BAGL_FONT_OPEN_SANS_LIGHT_16PX -D HAVE_UX_FLOW -D HAVE_SE_SCREEN -D HAVE_SE_BUTTON -D HAVE_MCU_SERIAL_STORAGE -D HAVE_FONTS -D HAVE_BATTERY -D HAVE_NES_CRYPT -D HAVE_ST_EDES_PLUS -D HAVE_ST_AES -D NATIVE_LITTLE_ENDIAN -D HAVE_CRC -D HAVE_HASH -D HAVE_RIPEMD160 -D HAVE_SHA224 -D HAVE_SHA256 -D HAVE_SHA3 -D HAVE_SHA384 -D HAVE_SHA512 -D HAVE_SHA512_WITH_BLOCK_ALT_METHOD -D HAVE_SHA512_WITH_BLOCK_ALT_METHOD_M0 -D HAVE_BLAKE2 -D HAVE_HMAC -D HAVE_PBKDF2 -D HAVE_DES -D HAVE_AES -D HAVE_MATH -D HAVE_RNG -D HAVE_RNG_RFC6979 -D HAVE_RNG_SP800_90A -D HAVE_ECC -D HAVE_ECC_WEIERSTRASS -D HAVE_ECC_TWISTED_EDWARDS -D HAVE_ECC_MONTGOMERY -D HAVE_SECP256K1_CURVE -D HAVE_SECP256R1_CURVE -D HAVE_SECP384R1_CURVE -D HAVE_SECP521R1_CURVE -D HAVE_FR256V1_CURVE -D HAVE_STARK256_CURVE -D HAVE_BRAINPOOL_P256R1_CURVE -D HAVE_BRAINPOOL_P256T1_CURVE -D HAVE_BRAINPOOL_P320R1_CURVE -D HAVE_BRAINPOOL_P320T1_CURVE -D HAVE_BRAINPOOL_P384R1_CURVE -D HAVE_BRAINPOOL_P384T1_CURVE -D HAVE_BRAINPOOL_P512R1_CURVE -D HAVE_BRAINPOOL_P512T1_CURVE -D HAVE_BLS12_381_G1_CURVE -D HAVE_CV25519_CURVE -D HAVE_CV448_CURVE -D HAVE_ED25519_CURVE -D HAVE_ED448_CURVE -D HAVE_ECDH -D HAVE_ECDSA -D HAVE_EDDSA -D HAVE_ECSCHNORR -D HAVE_X25519 -D HAVE_X448 -D HAVE_AES_GCM -D HAVE_AEAD -D APP_CONSUMER -D UNUSED(x)=(void)x -D PRINTF(...)= -D APPVERSION="0.9.13" -D OS_IO_SEPROXYHAL -D HAVE_BAGL -D HAVE_SPRINTF -D HAVE_IO_USB -D HAVE_L4_USBLIB -D IO_USB_MAX_ENDPOINTS=7 -D IO_HID_EP_LENGTH=64 -D HAVE_USB_APDU -D LEDGER_MAJOR_VERSION=0 -D LEDGER_MINOR_VERSION=9 -D LEDGER_PATCH_VERSION=13 -D USB_SEGMENT_SIZE=64 -D HAVE_BOLOS_APP_STACK_CANARY -D HAVE_WEBUSB -D WEBUSB_URL_SIZE_B=0 -D WEBUSB_URL= -D IO_SEPROXYHAL_BUFFER_SIZE_B=300 -D HAVE_GLO096 -D HAVE_BAGL -D BAGL_WIDTH=128 -D BAGL_HEIGHT=64 -D HAVE_BAGL_ELLIPSIS -D HAVE_BAGL_FONT_OPEN_SANS_REGULAR_11PX -D HAVE_BAGL_FONT_OPEN_SANS_EXTRABOLD_11PX -D HAVE_BAGL_FONT_OPEN_SANS_LIGHT_16PX -D HAVE_UX_FLOW -D LEDGER_SPECIFIC -I .//glyphs -I /opt/nanosplus-secure-sdk/lib_cxng/include -I /opt/nanosplus-secure-sdk/lib_stusb/ -I /opt/nanosplus-secure-sdk/lib_stusb/STM32_USB_Device_Library/Class/CCID/inc/ -I /opt/nanosplus-secure-sdk/lib_stusb/STM32_USB_Device_Library/Class/CCID/inc/ -I /opt/nanosplus-secure-sdk/lib_stusb/STM32_USB_Device_Library/Class/CCID/inc/ -I /opt/nanosplus-secure-sdk/lib_stusb/STM32_USB_Device_Library/Class/CCID/inc/ -I /opt/nanosplus-secure-sdk/lib_stusb/STM32_USB_Device_Library/Class/HID/Inc/ -I /opt/nanosplus-secure-sdk/lib_stusb/STM32_USB_Device_Library/Core/Inc/ -I /opt/nanosplus-secure-sdk/lib_stusb/STM32_USB_Device_Library/Core/Inc/ -I /opt/nanosplus-secure-sdk/lib_stusb/STM32_USB_Device_Library/Core/Inc/ -I /opt/nanosplus-secure-sdk/lib_stusb/STM32_USB_Device_Library/Core/Inc/ -I /opt/nanosplus-secure-sdk/lib_stusb/STM32_USB_Device_Library/Core/Inc/ -I /opt/nanosplus-secure-sdk/lib_stusb_impl/ -I /opt/nanosplus-secure-sdk/lib_stusb_impl/ -I /opt/nanosplus-secure-sdk/lib_stusb_impl/ -I /opt/nanosplus-secure-sdk/lib_ux/include/ -I /opt/nanosplus-secure-sdk/lib_ux/include/ -I /opt/nanosplus-secure-sdk/lib_ux/include/ -I /opt/nanosplus-secure-sdk/lib_ux/include/ -I /opt/nanosplus-secure-sdk/lib_ux/src/ -I include -I /opt/nanosplus-secure-sdk/include -I /opt/nanosplus-secure-sdk/include/arm -I .//src/ -I .//src/json/ -I .//src/ -I .//src/ -I .//src/ -I .//src/ -I .//src/ -I .//src/ -I .//src/ -I .//src/ -I .//src/ -I .//src/ -I .//src/ -I .//src/common/ -I .//src/common/ -I .//src/common/ -I .//../deps/ledger-zxlib/include/ -I .//../deps/ledger-zxlib/include/ -I .//../deps/ledger-zxlib/include/ -I .//../deps/ledger-zxlib/include/ -I .//../deps/ledger-zxlib/include/ -I .//../deps/ledger-zxlib/include/ -I .//../deps/ledger-zxlib/include/ -I .//../deps/ledger-zxlib/include/ -I .//../deps/ledger-zxlib/include/ -I .//../deps/ledger-zxlib/include/ -I .//../deps/ledger-zxlib/include/ -I .//../deps/ledger-zxlib/include/ -I .//../deps/ledger-zxlib/include/ -I .//../deps/ledger-zxlib/include/ -I .//../deps/ledger-zxlib/include/ -I .//../deps/ledger-zxlib/include/ -I .//../deps/ledger-zxlib/include/ -I .//../deps/ledger-zxlib/include/ -I .//../deps/ledger-zxlib/include/ -I .//../deps/ledger-zxlib/include/ -I .//../deps/ledger-zxlib/include/ -I .//../deps/ledger-zxlib/include/ -I .//../deps/ledger-zxlib/app/common/ -I .//../deps/ledger-zxlib/app/common/ -I .//../deps/jsmn/src/ -isysroot /opt/gcc-arm-none-eabi-10.3-2021.10/bin/../arm-none-eabi -internal-isystem /usr/lib/llvm-12/lib/clang/12.0.0/include -internal-isystem /opt/gcc-arm-none-eabi-10.3-2021.10/bin/../arm-none-eabi/include -Os -Wno-main -Wno-unknown-pragmas -std=gnu99 -fdebug-compilation-dir /app -ferror-limit 19 -fshort-enums -fno-signed-char -fgnuc-version=4.2.1 -vectorize-loops -vectorize-slp -analyzer-checker security -analyzer-checker unix -analyzer-checker valist -analyzer-opt-analyze-headers -analyzer-output=html -faddrsig -o /app/output-scan-build/2022-05-16-071232-98-1 -x c /opt/nanosplus-secure-sdk/src/os_io_seproxyhal.c -
- - - -
- - -
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
1
2/*******************************************************************************
3* Ledger Nano S - Secure firmware
4* (c) 2022 Ledger
5*
6* Licensed under the Apache License, Version 2.0 (the "License");
7* you may not use this file except in compliance with the License.
8* You may obtain a copy of the License at
9*
10* http://www.apache.org/licenses/LICENSE-2.0
11*
12* Unless required by applicable law or agreed to in writing, software
13* distributed under the License is distributed on an "AS IS" BASIS,
14* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
15* See the License for the specific language governing permissions and
16* limitations under the License.
17********************************************************************************/
18
19#include "bolos_target.h"
20
21#ifdef TARGET_NANOX
22#ifndef HAVE_SEPROXYHAL_MCU
23# define HAVE_SEPROXYHAL_MCU
24#endif // HAVE_SEPROXYHAL_MCU
25#ifndef HAVE_MCU_PROTECT
26#define HAVE_MCU_PROTECT
27#endif // HAVE_MCU_PROTECT
28#endif // TARGET_NANOX
29
30#include "errors.h"
31#include "exceptions.h"
32#include "os_apdu.h"
33#include "os_apilevel.h"
34
35#if defined(DEBUG_OS_STACK_CONSUMPTION)
36# include "os_debug.h"
37#endif // DEBUG_OS_STACK_CONSUMPTION
38
39#include "os_id.h"
40#include "os_io.h"
41#include "os_io_usb.h"
42#include "os_pic.h"
43#include "os_pin.h"
44#include "os_registry.h"
45#include "os_seed.h"
46#include "os_utils.h"
47#include <string.h>
48
49#ifdef OS_IO_SEPROXYHAL1
50
51#include "os_io_seproxyhal.h"
52
53#ifdef HAVE_BLE
54#include "ledger_ble.h"
55#endif // HAVE_BLE
56
57#include "ux.h"
58#include "checks.h"
59
60#ifdef HAVE_IO_U2F
61#include "u2f_processing.h"
62#include "u2f_transport.h"
63#endif
64
65#ifndef VERSION"dummy"
66#define VERSION"dummy" "dummy"
67#endif // VERSION
68
69#ifdef DEBUG
70#define LOG printf
71#else
72#define LOG(...)
73#endif
74
75#ifdef HAVE_IO_USB1
76#ifdef HAVE_L4_USBLIB1
77#include "usbd_def.h"
78#include "usbd_core.h"
79extern USBD_HandleTypeDef USBD_Device;
80#endif
81#endif
82
83#if !defined(HAVE_BOLOS_NO_DEFAULT_APDU)
84# define DEFAULT_APDU_CLA0xB0 0xB0
85# define DEFAULT_APDU_INS_GET_VERSION0x01 0x01
86
87# if defined(HAVE_SEED_COOKIE)
88# define DEFAULT_APDU_INS_GET_SEED_COOKIE 0x02
89# endif
90
91# if defined(DEBUG_OS_STACK_CONSUMPTION)
92# define DEFAULT_APDU_INS_STACK_CONSUMPTION 0x57
93# endif // DEBUG_OS_STACK_CONSUMPTION
94
95# define DEFAULT_APDU_INS_APP_EXIT0xA7 0xA7
96#endif // !HAVE_BOLOS_NO_DEFAULT_APDU
97
98void io_seproxyhal_handle_ble_event(void);
99
100unsigned int os_io_seph_recv_and_process(unsigned int dont_process_ux_events);
101
102#ifndef HAVE_BOLOS
103io_seph_app_t G_io_app;
104#endif // ! HAVE_BOLOS
105
106 // usb endpoint buffer
107unsigned char G_io_usb_ep_buffer[MAX(USB_SEGMENT_SIZE, BLE_SEGMENT_SIZE)((64) > (64) ? (64) : (64))];
108
109ux_seph_os_and_app_t G_ux_os;
110
111#ifndef IO_RAPDU_TRANSMIT_TIMEOUT_MS2000UL
112#define IO_RAPDU_TRANSMIT_TIMEOUT_MS2000UL 2000UL
113#endif // IO_RAPDU_TRANSMIT_TIMEOUT_MS
114
115static const unsigned char seph_io_general_status[]= {
116 SEPROXYHAL_TAG_GENERAL_STATUS0x60,
117 0,
118 2,
119 SEPROXYHAL_TAG_GENERAL_STATUS_LAST_COMMAND0x0000>>8,
120 SEPROXYHAL_TAG_GENERAL_STATUS_LAST_COMMAND0x0000,
121};
122void io_seproxyhal_general_status(void) {
123 // send the general status
124 io_seproxyhal_spi_sendio_seph_send(seph_io_general_status, sizeof(seph_io_general_status));
125}
126
127static const unsigned char seph_io_request_status[]= {
128 SEPROXYHAL_TAG_REQUEST_STATUS0x52,
129 0,
130 0,
131};
132void io_seproxyhal_request_mcu_status(void) {
133 // send the general status
134 io_seproxyhal_spi_sendio_seph_send(seph_io_request_status, sizeof(seph_io_request_status));
135}
136
137#ifdef HAVE_IO_USB1
138#ifdef HAVE_L4_USBLIB1
139
140void io_seproxyhal_handle_usb_event(void) {
141 switch(G_io_seproxyhal_spi_buffer[3]) {
142 case SEPROXYHAL_TAG_USB_EVENT_RESET0x01:
143 USBD_LL_SetSpeed(&USBD_Device, USBD_SPEED_FULL);
144 USBD_LL_Reset(&USBD_Device);
145 // ongoing APDU detected, throw a reset, even if not the media. to avoid potential troubles.
146 if (G_io_app.apdu_media != IO_APDU_MEDIA_NONE) {
147 THROW(EXCEPTION_IO_RESET)os_longjmp(0x5);
148 }
149 memset(G_io_app.usb_ep_xfer_len, 0, sizeof(G_io_app.usb_ep_xfer_len));
150 memset(G_io_app.usb_ep_timeouts, 0, sizeof(G_io_app.usb_ep_timeouts));
151 break;
152 case SEPROXYHAL_TAG_USB_EVENT_SOF0x02:
153 USBD_LL_SOF(&USBD_Device);
154 break;
155 case SEPROXYHAL_TAG_USB_EVENT_SUSPENDED0x04:
156 USBD_LL_Suspend(&USBD_Device);
157 break;
158 case SEPROXYHAL_TAG_USB_EVENT_RESUMED0x08:
159 USBD_LL_Resume(&USBD_Device);
160 break;
161 }
162}
163
164uint16_t io_seproxyhal_get_ep_rx_size(uint8_t epnum) {
165 if ((epnum & 0x7F) < IO_USB_MAX_ENDPOINTS7) {
166 return G_io_app.usb_ep_xfer_len[epnum&0x7F];
167 }
168 return 0;
169}
170
171void io_seproxyhal_handle_usb_ep_xfer_event(void) {
172 uint8_t epnum;
173
174 epnum = G_io_seproxyhal_spi_buffer[3] & 0x7F;
175
176 switch(G_io_seproxyhal_spi_buffer[4]) {
177 /* This event is received when a new SETUP token had been received on a control endpoint */
178 case SEPROXYHAL_TAG_USB_EP_XFER_SETUP0x01:
179 // assume length of setup packet, and that it is on endpoint 0
180 USBD_LL_SetupStage(&USBD_Device, &G_io_seproxyhal_spi_buffer[6]);
181 break;
182
183 /* This event is received after the prepare data packet has been flushed to the usb host */
184 case SEPROXYHAL_TAG_USB_EP_XFER_IN0x02:
185 if (epnum < IO_USB_MAX_ENDPOINTS7) {
186 // discard ep timeout as we received the sent packet confirmation
187 G_io_app.usb_ep_timeouts[epnum].timeout = 0;
188 // propagate sending ack of the data
189 USBD_LL_DataInStage(&USBD_Device, epnum, &G_io_seproxyhal_spi_buffer[6]);
190 }
191 break;
192
193 /* This event is received when a new DATA token is received on an endpoint */
194 case SEPROXYHAL_TAG_USB_EP_XFER_OUT0x04:
195 if (epnum < IO_USB_MAX_ENDPOINTS7) {
196 // saved just in case it is needed ...
197#if IO_SEPROXYHAL_BUFFER_SIZE_B300 - 6 >= 256
198 G_io_app.usb_ep_xfer_len[epnum] = G_io_seproxyhal_spi_buffer[5];
199#else
200 G_io_app.usb_ep_xfer_len[epnum] = MIN(G_io_seproxyhal_spi_buffer[5], IO_SEPROXYHAL_BUFFER_SIZE_B - 6)((G_io_seproxyhal_spi_buffer[5]) < (300 - 6) ? (G_io_seproxyhal_spi_buffer
[5]) : (300 - 6))
;
201#endif
202 // prepare reception
203 USBD_LL_DataOutStage(&USBD_Device, epnum, &G_io_seproxyhal_spi_buffer[6]);
204 }
205 break;
206 }
207}
208
209#else
210//no usb lib: X86 for example
211
212void io_seproxyhal_handle_usb_event(void) {
213}
214void io_seproxyhal_handle_usb_ep_xfer_event(void) {
215}
216
217#endif // HAVE_L4_USBLIB
218
219// TODO, refactor this using the USB DataIn event like for the U2F tunnel
220// TODO add a blocking parameter, for HID KBD sending, or use a USB busy flag per channel to know if
221// the transfer has been processed or not. and move on to the next transfer on the same endpoint
222void io_usb_send_ep(unsigned int ep, unsigned char* buffer, unsigned short length, unsigned int timeout) {
223
224 // don't spoil the timeout :)
225 if (timeout) {
226 timeout++;
227 }
228
229 // won't send if overflowing seproxyhal buffer format
230 if (length > 255) {
231 return;
232 }
233
234 G_io_seproxyhal_spi_buffer[0] = SEPROXYHAL_TAG_USB_EP_PREPARE0x50;
235 G_io_seproxyhal_spi_buffer[1] = (3+length)>>8;
236 G_io_seproxyhal_spi_buffer[2] = (3+length);
237 G_io_seproxyhal_spi_buffer[3] = ep|0x80;
238 G_io_seproxyhal_spi_buffer[4] = SEPROXYHAL_TAG_USB_EP_PREPARE_DIR_IN0x20;
239 G_io_seproxyhal_spi_buffer[5] = length;
240 io_seproxyhal_spi_sendio_seph_send(G_io_seproxyhal_spi_buffer, 6);
241 io_seproxyhal_spi_sendio_seph_send(buffer, length);
242 // setup timeout of the endpoint
243 G_io_app.usb_ep_timeouts[ep&0x7F].timeout = IO_RAPDU_TRANSMIT_TIMEOUT_MS2000UL;
244}
245
246void io_usb_send_apdu_data(unsigned char* buffer, unsigned short length) {
247 // wait for 20 events before hanging up and timeout (~2 seconds of timeout)
248 io_usb_send_ep(0x82, buffer, length, 20);
249}
250
251#ifdef HAVE_WEBUSB1
252void io_usb_send_apdu_data_ep0x83(unsigned char* buffer, unsigned short length) {
253 // wait for 20 events before hanging up and timeout (~2 seconds of timeout)
254 io_usb_send_ep(0x83, buffer, length, 20);
255}
256#endif // HAVE_WEBUSB
257
258#endif // HAVE_IO_USB
259
260void io_seproxyhal_handle_capdu_event(void) {
261 if (G_io_app.apdu_state == APDU_IDLE) {
262 size_t max = MIN(sizeof(G_io_apdu_buffer)-3, sizeof(G_io_seproxyhal_spi_buffer)-3)((sizeof(G_io_apdu_buffer)-3) < (sizeof(G_io_seproxyhal_spi_buffer
)-3) ? (sizeof(G_io_apdu_buffer)-3) : (sizeof(G_io_seproxyhal_spi_buffer
)-3))
;
263 size_t size = U2BE(G_io_seproxyhal_spi_buffer, 1);
264
265 G_io_app.apdu_media = IO_APDU_MEDIA_RAW; // for application code
266 G_io_app.apdu_state = APDU_RAW; // for next call to io_exchange
267 G_io_app.apdu_length = MIN(size, max)((size) < (max) ? (size) : (max));
268 // copy apdu to apdu buffer
269 memcpy(G_io_apdu_buffer, G_io_seproxyhal_spi_buffer+3, G_io_app.apdu_length);
270 }
271}
272
273unsigned int io_seproxyhal_handle_event(void) {
274#if defined(HAVE_IO_USB1) || defined(HAVE_BLE)
275 unsigned int rx_len = U2BE(G_io_seproxyhal_spi_buffer, 1);
276#endif
277
278 switch(G_io_seproxyhal_spi_buffer[0]) {
279 #ifdef HAVE_IO_USB1
280 case SEPROXYHAL_TAG_USB_EVENT0x0F:
281 if (rx_len != 1) {
282 return 0;
283 }
284 io_seproxyhal_handle_usb_event();
285 return 1;
286
287 case SEPROXYHAL_TAG_USB_EP_XFER_EVENT0x10:
288 if (rx_len < 3) {
289 // error !
290 return 0;
291 }
292 io_seproxyhal_handle_usb_ep_xfer_event();
293 return 1;
294 #endif // HAVE_IO_USB
295
296 #ifdef HAVE_BLE
297 case SEPROXYHAL_TAG_BLE_RECV_EVENT0x18:
298 LEDGER_BLE_receive();
299 return 1;
300 #endif // HAVE_BLE
301
302 case SEPROXYHAL_TAG_UX_EVENT0x1A:
303 switch (G_io_seproxyhal_spi_buffer[3]) {
304
305#ifdef HAVE_BLE
306 case SEPROXYHAL_TAG_UX_CMD_BLE_DISABLE_ADV0x00:
307 LEDGER_BLE_enable_advertising(0);
308 return 1;
309 break;
310
311 case SEPROXYHAL_TAG_UX_CMD_BLE_ENABLE_ADV0x01:
312 LEDGER_BLE_enable_advertising(1);
313 return 1;
314 break;
315
316 case SEPROXYHAL_TAG_UX_CMD_BLE_RESET_PAIRINGS0x02:
317 LEDGER_BLE_reset_pairings();
318 return 1;
319 break;
320#endif // HAVE_BLE
321
322#ifndef HAVE_BOLOS
323 case SEPROXYHAL_TAG_UX_CMD_REDISPLAY0x03:
324 ux_stack_redisplay();
325 return 1;
326 break;
327#endif // HAVE_BOLOS
328
329 default:
330 return io_event(CHANNEL_SPI2);
331 break;
332 }
333 break;
334
335 case SEPROXYHAL_TAG_CAPDU_EVENT0x16:
336 io_seproxyhal_handle_capdu_event();
337 return 1;
338
339 // ask the user if not processed here
340 case SEPROXYHAL_TAG_TICKER_EVENT0x0E:
341 // process ticker events to timeout the IO transfers, and forward to the user io_event function too
342 G_io_app.ms += 100; // value is by default, don't change the ticker configuration
343#ifdef HAVE_IO_USB1
344 {
345 unsigned int i = IO_USB_MAX_ENDPOINTS7;
346 while(i--) {
347 if (G_io_app.usb_ep_timeouts[i].timeout) {
348 G_io_app.usb_ep_timeouts[i].timeout-=MIN(G_io_app.usb_ep_timeouts[i].timeout, 100)((G_io_app.usb_ep_timeouts[i].timeout) < (100) ? (G_io_app
.usb_ep_timeouts[i].timeout) : (100))
;
349 if (!G_io_app.usb_ep_timeouts[i].timeout) {
350 // timeout !
351 G_io_app.apdu_state = APDU_IDLE;
352 THROW(EXCEPTION_IO_RESET)os_longjmp(0x5);
353 }
354 }
355 }
356 }
357#endif // HAVE_IO_USB
358#ifdef HAVE_BLE_APDU
359 {
360 if (G_io_app.ble_xfer_timeout) {
361 G_io_app.ble_xfer_timeout -= MIN(G_io_app.ble_xfer_timeout, 100)((G_io_app.ble_xfer_timeout) < (100) ? (G_io_app.ble_xfer_timeout
) : (100))
;
362 if (!G_io_app.ble_xfer_timeout) {
363 G_io_app.apdu_state = APDU_IDLE;
364 THROW(EXCEPTION_IO_RESET)os_longjmp(0x5);
365 }
366 }
367 }
368#endif // HAVE_BLE_APDU
369 __attribute__((fallthrough));
370 // no break is intentional
371 default:
372 return io_event(CHANNEL_SPI2);
373 }
374 // defaultly return as not processed
375 return 0;
376}
377
378//#define DEBUG_APDU
379#ifdef DEBUG_APDU
380volatile unsigned int debug_apdus_offset;
381const char debug_apdus[] = {
382 5, 0xE0, 0x40, 0x00, 0x00, 0x00,
383 //9, 0xe0, 0x22, 0x00, 0x00, 0x04, 0x31, 0x32, 0x33, 0x34,
384};
385#endif // DEBUG_APDU
386
387#ifdef HAVE_BOLOS_APP_STACK_CANARY1
388#define APP_STACK_CANARY_MAGIC0xDEAD0031 0xDEAD0031
389extern unsigned int app_stack_canary;
390#endif // HAVE_BOLOS_APP_STACK_CANARY
391
392#if (!defined(HAVE_BOLOS) && defined(HAVE_MCU_PROTECT))
393static const unsigned char seph_io_mcu_protect[]= {
394 SEPROXYHAL_TAG_MCU,
395 0,
396 1,
397 SEPROXYHAL_TAG_MCU_TYPE_PROTECT,
398};
399#endif // (!defined(HAVE_BOLOS) && defined(HAVE_MCU_PROTECT))
400
401void io_seproxyhal_init(void) {
402#ifndef HAVE_BOLOS
403 // Enforce OS compatibility
404 check_api_level(CX_COMPAT_APILEVEL12);
405
406#ifdef HAVE_MCU_PROTECT
407 // engage RDP2 on MCU
408 io_seproxyhal_spi_sendio_seph_send(seph_io_mcu_protect, sizeof(seph_io_mcu_protect));
409#endif // HAVE_MCU_PROTECT
410#endif // HAVE_BOLOS
411
412#ifdef HAVE_BOLOS_APP_STACK_CANARY1
413 app_stack_canary = APP_STACK_CANARY_MAGIC0xDEAD0031;
414#endif // HAVE_BOLOS_APP_STACK_CANARY
415
416 // wipe the io structure before it's used
417#ifdef HAVE_BLE
418 unsigned int plane = G_io_app.plane_mode;
419#endif // HAVE_BLE
420 memset(&G_io_app, 0, sizeof(G_io_app));
421#ifdef HAVE_BLE
422 G_io_app.plane_mode = plane;
423#endif // HAVE_BLE
424
425 G_io_app.apdu_state = APDU_IDLE;
426 G_io_app.apdu_length = 0;
427 G_io_app.apdu_media = IO_APDU_MEDIA_NONE;
428
429 G_io_app.ms = 0;
430
431 #ifdef DEBUG_APDU
432 debug_apdus_offset = 0;
433 #endif // DEBUG_APDU
434
435 #ifdef HAVE_USB_APDU1
436 io_usb_hid_init();
437 #endif // HAVE_USB_APDU
438
439 io_seproxyhal_init_ux();
440 io_seproxyhal_init_button();
441
442#if !defined(HAVE_BOLOS) && defined(HAVE_PENDING_REVIEW_SCREEN)
443 check_audited_app();
444#endif // !defined(HAVE_BOLOS) && defined(HAVE_PENDING_REVIEW_SCREEN)
445}
446
447void io_seproxyhal_init_ux(void) {
448#ifdef TARGET_BLUE
449 // initialize the touch part
450 G_ux_os.last_touched_not_released_component = NULL((void*)0);
451#endif // TARGET_BLUE
452}
453
454void io_seproxyhal_init_button(void) {
455 // no button push so far
456 G_ux_os.button_mask = 0;
457 G_ux_os.button_same_mask_counter = 0;
458}
459
460#ifdef HAVE_BAGL1
461
462#ifdef TARGET_BLUE
463unsigned int io_seproxyhal_touch_out(const bagl_element_t* element, bagl_element_callback_t before_display) {
464 const bagl_element_t* el;
465 if (element->out != NULL((void*)0)) {
466 el = (const bagl_element_t*)PIC(((bagl_element_callback_t)PIC(element->out))(element))pic((void *)((bagl_element_callback_t)pic((void *)element->
out))(element))
;
467 // backward compatible with samples and such
468 if (! el) {
469 return 0;
470 }
471 if ((unsigned int)el != 1) {
472 element = el;
473 }
474 }
475
476 // out function might have triggered a draw of its own during a display callback
477 if (before_display) {
478 el = before_display(element);
479 if (!el) {
480 return 0;
481 }
482 if ((unsigned int)el != 1) {
483 element = el;
484 }
485 }
486
487 io_seproxyhal_display(element);
488 return 1;
489}
490
491unsigned int io_seproxyhal_touch_over(const bagl_element_t* element, bagl_element_callback_t before_display) {
492 bagl_element_t e;
493 const bagl_element_t* el;
494 if (element->over != NULL((void*)0)) {
495 el = (const bagl_element_t*)PIC(((bagl_element_callback_t)PIC(element->over))(element))pic((void *)((bagl_element_callback_t)pic((void *)element->
over))(element))
;
496 // backward compatible with samples and such
497 if (!el) {
498 return 0;
499 }
500 if ((unsigned int)el != 1) {
501 element = el;
502 }
503 }
504
505 // over function might have triggered a draw of its own during a display callback
506 if (before_display) {
507 el = before_display(element);
508 element = &e;
509 if (!el) {
510 return 0;
511 }
512 // problem for default screen_before_before_display where we return the given element, it have could been modified. but we don't know here
513 if ((unsigned int)el != 1) {
514 element = el;
515 }
516 }
517
518 // swap colors
519 memcpy(&e, element, sizeof(bagl_element_t));
520 e.component.fgcolor = element->overfgcolor;
521 e.component.bgcolor = element->overbgcolor;
522
523 io_seproxyhal_display(&e);
524 return 1;
525}
526
527unsigned int io_seproxyhal_touch_tap(const bagl_element_t* element, bagl_element_callback_t before_display) {
528 const bagl_element_t* el;
529 if (element->tap != NULL((void*)0)) {
530 el = (const bagl_element_t*)PIC(((bagl_element_callback_t)PIC(element->tap))(element))pic((void *)((bagl_element_callback_t)pic((void *)element->
tap))(element))
;
531 // backward compatible with samples and such
532 if (!el) {
533 return 0;
534 }
535 if ((unsigned int)el != 1) {
536 element = el;
537 }
538 }
539
540 // tap function might have triggered a draw of its own during a display callback
541 if (before_display) {
542 el = before_display(element);
543 if (!el) {
544 return 0;
545 }
546 if ((unsigned int)el != 1) {
547 element = el;
548 }
549 }
550 io_seproxyhal_display(element);
551 return 1;
552}
553
554void io_seproxyhal_touch(const bagl_element_t* elements, unsigned short element_count, unsigned short x, unsigned short y, unsigned char event_kind) {
555 io_seproxyhal_touch_element_callback(elements, element_count, x, y, event_kind, NULL((void*)0));
556}
557
558// browse all elements and until an element has changed state, continue browsing
559// return if processed or not
560void io_seproxyhal_touch_element_callback(const bagl_element_t* elements, unsigned short element_count, unsigned short x, unsigned short y, unsigned char event_kind, bagl_element_callback_t before_display) {
561 unsigned char comp_idx;
562 unsigned char last_touched_not_released_component_was_in_current_array = 0;
563
564 // find the first empty entry
565 for (comp_idx=0; comp_idx < element_count; comp_idx++) {
566 // process all components matching the x/y/w/h (no break) => fishy for the released out of zone
567 // continue processing only if a status has not been sent
568 if (io_seproxyhal_spi_is_status_sentio_seph_is_status_sent()) {
569 // continue instead of return to process all elemnts and therefore discard last touched element
570 break;
571 }
572
573 // only perform out callback when element was in the current array, else, leave it be
574 if (&elements[comp_idx] == G_ux_os.last_touched_not_released_component) {
575 last_touched_not_released_component_was_in_current_array = 1;
576 }
577
578 // the first component drawn with a
579 if ((elements[comp_idx].component.type & BAGL_FLAG_TOUCHABLE)
580 && elements[comp_idx].component.x-elements[comp_idx].touch_area_brim <= x && x<elements[comp_idx].component.x+elements[comp_idx].component.width+elements[comp_idx].touch_area_brim
581 && elements[comp_idx].component.y-elements[comp_idx].touch_area_brim <= y && y<elements[comp_idx].component.y+elements[comp_idx].component.height+elements[comp_idx].touch_area_brim) {
582
583 // outing the previous over'ed component
584 if (&elements[comp_idx] != G_ux_os.last_touched_not_released_component
585 && G_ux_os.last_touched_not_released_component != NULL((void*)0)) {
586 // only out the previous element if the newly matching will be displayed
587 if (!before_display || before_display(&elements[comp_idx])) {
588 if (io_seproxyhal_touch_out(G_ux_os.last_touched_not_released_component, before_display)) {
589 // previous component is considered released
590 G_ux_os.last_touched_not_released_component = NULL((void*)0);
591 // a display has been issued, avoid double display, wait for another touch event (20ms)
592 return;
593 }
594 }
595 // avoid a non displayed new element to pop out of the blue
596 continue;
597 }
598
599 /*
600 if (io_seproxyhal_spi_is_status_sent()) {
601 // continue instead of return to process all elements and therefore discard last touched element
602 continue;
603 }
604 */
605
606 // callback the hal to notify the component impacted by the user input
607 else if (event_kind == SEPROXYHAL_TAG_FINGER_EVENT_RELEASE0x02) {
608 if (io_seproxyhal_touch_tap(&elements[comp_idx], before_display)) {
609 // unmark the last component, we've been notified TOUCH
610 G_ux_os.last_touched_not_released_component = NULL((void*)0);
611 return;
612 }
613 }
614 else if (event_kind == SEPROXYHAL_TAG_FINGER_EVENT_TOUCH0x01) {
615 // ask for overing
616 if (io_seproxyhal_touch_over(&elements[comp_idx], before_display)) {
617 // remember the last touched component
618 G_ux_os.last_touched_not_released_component = &elements[comp_idx];
619 return;
620 }
621 }
622 }
623 }
624
625 // if overing out of component or over another component, the out event is sent after the over event of the previous component
626 if(last_touched_not_released_component_was_in_current_array
627 && G_ux_os.last_touched_not_released_component != NULL((void*)0)) {
628
629 // we won't be able to notify the out, don't do it, in case a diplay refused the dra of the relased element and the position matched another element of the array (in autocomplete for example)
630 if (io_seproxyhal_spi_is_status_sentio_seph_is_status_sent()) {
631 return;
632 }
633
634 if (io_seproxyhal_touch_out(G_ux_os.last_touched_not_released_component, before_display)) {
635 // ok component out has been emitted
636 G_ux_os.last_touched_not_released_component = NULL((void*)0);
637 }
638 }
639
640 // not processed
641}
642#endif // TARGET_BLUE
643
644void io_seproxyhal_display_bitmap(int x, int y, unsigned int w, unsigned int h, unsigned int* color_index, unsigned int bit_per_pixel, unsigned char* bitmap) {
645 // component type = ICON
646 // component icon id = 0
647 // => bitmap transmitted
648 if (w && h) {
649 bagl_component_t c;
650 bagl_icon_details_t d;
651 memset(&c, 0, sizeof(c));
652 c.type = BAGL_ICON;
653 c.x = x;
654 c.y = y;
655 c.width = w;
656 c.height = h;
657 // done by memset // c.icon_id = 0;
658 d.width = w;
659 d.height = h;
660 d.bpp = bit_per_pixel;
661 d.colors = color_index;
662 d.bitmap = bitmap;
663
664 io_seproxyhal_display_icon(&c, &d);
665 /*
666 // color index size
667 h = ((1<<bit_per_pixel)*sizeof(unsigned int));
668 // bitmap size
669 w = ((w*c.height*bit_per_pixel)/8)+((w*c.height*bit_per_pixel)%8?1:0);
670 unsigned short length = sizeof(bagl_component_t)
671 +1 // bpp
672 +h // color index
673 +w; // image bitmap
674 G_io_seproxyhal_spi_buffer[0] = SEPROXYHAL_TAG_SCREEN_DISPLAY_STATUS;
675 G_io_seproxyhal_spi_buffer[1] = length>>8;
676 G_io_seproxyhal_spi_buffer[2] = length;
677 io_seproxyhal_spi_send(G_io_seproxyhal_spi_buffer, 3);
678 io_seproxyhal_spi_send((unsigned char*)&c, sizeof(bagl_component_t));
679 G_io_seproxyhal_spi_buffer[0] = bit_per_pixel;
680 io_seproxyhal_spi_send(G_io_seproxyhal_spi_buffer, 1);
681 io_seproxyhal_spi_send((unsigned char*)color_index, h);
682 io_seproxyhal_spi_send(bitmap, w);
683 */
684 }
685}
686
687#ifdef SEPROXYHAL_TAG_SCREEN_DISPLAY_RAW_STATUS
688unsigned int io_seproxyhal_display_icon_header_and_colors(const bagl_component_t* icon_component, const bagl_icon_details_t* icon_details, unsigned int* icon_len) {
689 unsigned int len;
690
691 struct display_raw_s {
692 struct {
693 struct {
694 unsigned char tag;
695 unsigned char len[2];
696 } seph;
697 unsigned char type;
698 } header;
699 union {
700 short val;
701 char b[2];
702 } x;
703 union {
704 short val;
705 char b[2];
706 } y;
707 union {
708 unsigned short val;
709 char b[2];
710 } w;
711 union {
712 unsigned short val;
713 char b[2];
714 } h;
715 unsigned char bpp;
716 } __attribute__((packed)) raw;
717
718 raw.header.seph.tag = SEPROXYHAL_TAG_SCREEN_DISPLAY_RAW_STATUS;
719 raw.header.type = SEPROXYHAL_TAG_SCREEN_DISPLAY_RAW_STATUS_START;
720 raw.x.val = icon_component->x;
721 raw.y.val = icon_component->y;
722 raw.w.val = icon_component->width;
723 raw.h.val = icon_component->height;
724 raw.bpp = icon_details->bpp;
725
726
727 *icon_len = raw.w.val*raw.h.val*raw.bpp/8 + (((raw.w.val*raw.h.val*raw.bpp)%8)?1:0);
728
729 // optional, don't send too much on a single packet for MCU to receive it. when stream mode will be on, this will be useless
730 // min of remaining space in the packet vs. total icon size + color index size
731 len = MIN(sizeof(G_io_seproxyhal_spi_buffer) - sizeof(raw), *icon_len + (1<<raw.bpp)*4)((sizeof(G_io_seproxyhal_spi_buffer) - sizeof(raw)) < (*icon_len
+ (1<<raw.bpp)*4) ? (sizeof(G_io_seproxyhal_spi_buffer
) - sizeof(raw)) : (*icon_len + (1<<raw.bpp)*4))
;
732
733 // sizeof packet
734 raw.header.seph.len[0] = (len + sizeof(raw) - sizeof(raw.header.seph)) >> 8;
735 raw.header.seph.len[1] = (len + sizeof(raw) - sizeof(raw.header.seph));
736
737 // swap endianess of coordinates (make it big endian)
738 SWAP(raw.x.b[0], raw.x.b[1]){ raw.x.b[0] ^= raw.x.b[1]; raw.x.b[1] ^= raw.x.b[0]; raw.x.b
[0] ^= raw.x.b[1]; }
;
739 SWAP(raw.y.b[0], raw.y.b[1]){ raw.y.b[0] ^= raw.y.b[1]; raw.y.b[1] ^= raw.y.b[0]; raw.y.b
[0] ^= raw.y.b[1]; }
;
740 SWAP(raw.w.b[0], raw.w.b[1]){ raw.w.b[0] ^= raw.w.b[1]; raw.w.b[1] ^= raw.w.b[0]; raw.w.b
[0] ^= raw.w.b[1]; }
;
741 SWAP(raw.h.b[0], raw.h.b[1]){ raw.h.b[0] ^= raw.h.b[1]; raw.h.b[1] ^= raw.h.b[0]; raw.h.b
[0] ^= raw.h.b[1]; }
;
742
743 io_seproxyhal_spi_sendio_seph_send((unsigned char*)&raw, sizeof(raw));
744 io_seproxyhal_spi_sendio_seph_send((const uint8_t *) PIC(icon_details->colors)pic((void *)icon_details->colors), (1<<raw.bpp)*4);
745 len -= (1<<raw.bpp)*4;
746
747 // remaining length of bitmap bits to be displayed
748 return len;
749}
750#endif // SEPROXYHAL_TAG_SCREEN_DISPLAY_RAW_STATUS
751
752void io_seproxyhal_display_icon(const bagl_component_t* icon_component, const bagl_icon_details_t* icon_det) {
753 bagl_component_t icon_component_mod;
754 const bagl_icon_details_t* icon_details = (const bagl_icon_details_t *)PIC(icon_det)pic((void *)icon_det);
755
756 if (icon_details && icon_details->bitmap) {
757 // ensure not being out of bounds in the icon component agianst the declared icon real size
758 memcpy(&icon_component_mod, PIC(icon_component)pic((void *)icon_component), sizeof(bagl_component_t));
759 icon_component_mod.width = icon_details->width;
760 icon_component_mod.height = icon_details->height;
761 icon_component = &icon_component_mod;
Value stored to 'icon_component' is never read
762
763#ifdef SEPROXYHAL_TAG_SCREEN_DISPLAY_RAW_STATUS
764 unsigned int len;
765 unsigned int icon_len;
766 unsigned int icon_off=0;
767
768 len = io_seproxyhal_display_icon_header_and_colors(icon_component, icon_details, &icon_len);
769 io_seproxyhal_spi_sendio_seph_send(PIC(icon_details->bitmap)pic((void *)icon_details->bitmap), len);
770 // advance in the bitmap to be transmitted
771 icon_len -= len;
772 icon_off += len;
773
774 // still some bitmap data to transmit
775 while(icon_len) {
776 // wait displayed event
777 io_seproxyhal_spi_recvio_seph_recv(G_io_seproxyhal_spi_buffer, sizeof(G_io_seproxyhal_spi_buffer), 0);
778
779 G_io_seproxyhal_spi_buffer[0] = SEPROXYHAL_TAG_SCREEN_DISPLAY_RAW_STATUS;
780 G_io_seproxyhal_spi_buffer[3] = SEPROXYHAL_TAG_SCREEN_DISPLAY_RAW_STATUS_CONT;
781
782 len = MIN((sizeof(G_io_seproxyhal_spi_buffer) - 4), icon_len)(((sizeof(G_io_seproxyhal_spi_buffer) - 4)) < (icon_len) ?
((sizeof(G_io_seproxyhal_spi_buffer) - 4)) : (icon_len))
;
783 G_io_seproxyhal_spi_buffer[1] = (len+1)>>8;
784 G_io_seproxyhal_spi_buffer[2] = (len+1);
785 io_seproxyhal_spi_sendio_seph_send(G_io_seproxyhal_spi_buffer, 4);
786 io_seproxyhal_spi_sendio_seph_send(PIC(icon_details->bitmap)pic((void *)icon_details->bitmap)+icon_off, len);
787
788 icon_len -= len;
789 icon_off += len;
790 }
791#else // !SEPROXYHAL_TAG_SCREEN_DISPLAY_RAW_STATUS
792#ifdef HAVE_SE_SCREEN1
793 bagl_draw_glyph(&icon_component_mod, icon_details);
794#endif // HAVE_SE_SCREEN
795#if !defined(HAVE_SE_SCREEN1) || (defined(HAVE_SE_SCREEN1) && defined(HAVE_PRINTF))
796 if (io_seproxyhal_spi_is_status_sentio_seph_is_status_sent()) {
797 return;
798 }
799 // color index size
800 unsigned int h = (1<<(icon_details->bpp))*sizeof(unsigned int);
801 // bitmap size
802 unsigned int w = ((icon_component->width*icon_component->height*icon_details->bpp)/8)+((icon_component->width*icon_component->height*icon_details->bpp)%8?1:0);
803 unsigned short length = sizeof(bagl_component_t)
804 +1 /* bpp */
805 +h /* color index */
806 +w; /* image bitmap size */
807 G_io_seproxyhal_spi_buffer[0] = SEPROXYHAL_TAG_SCREEN_DISPLAY_STATUS0x65;
808#if defined(HAVE_SE_SCREEN1) && defined(HAVE_PRINTF)
809 G_io_seproxyhal_spi_buffer[0] = SEPROXYHAL_TAG_DBG_SCREEN_DISPLAY_STATUS0x5E;
810#endif // HAVE_SE_SCREEN && HAVE_PRINTF
811 G_io_seproxyhal_spi_buffer[1] = length>>8;
812 G_io_seproxyhal_spi_buffer[2] = length;
813 io_seproxyhal_spi_sendio_seph_send(G_io_seproxyhal_spi_buffer, 3);
814 io_seproxyhal_spi_sendio_seph_send((const uint8_t *) icon_component, sizeof(bagl_component_t));
815 G_io_seproxyhal_spi_buffer[0] = icon_details->bpp;
816 io_seproxyhal_spi_sendio_seph_send(G_io_seproxyhal_spi_buffer, 1);
817 io_seproxyhal_spi_sendio_seph_send((const uint8_t *) PIC(icon_details->colors)pic((void *)icon_details->colors), h);
818 io_seproxyhal_spi_sendio_seph_send((const uint8_t *) PIC(icon_details->bitmap)pic((void *)icon_details->bitmap), w);
819#endif // !HAVE_SE_SCREEN || (HAVE_SE_SCREEN && HAVE_PRINTF)
820#endif // !SEPROXYHAL_TAG_SCREEN_DISPLAY_RAW_STATUS
821 }
822}
823
824void io_seproxyhal_display_default(const bagl_element_t* element) {
825
826 const bagl_element_t* el = (const bagl_element_t*) PIC(element)pic((void *)element);
827 const char* txt = (const char*)PIC(el->text)pic((void *)el->text);
828 // process automagically address from rom and from ram
829 unsigned int type = (el->component.type & ~(BAGL_FLAG_TOUCHABLE));
830
831 if (type != BAGL_NONE) {
832 if (txt != NULL((void*)0)) {
833 // consider an icon details descriptor is pointed by the context
834 if (type == BAGL_ICON && el->component.icon_id == 0) {
835 // SECURITY: due to this wild cast, the code MUST be executed on the application side instead of in
836 // the syscall sides to avoid buffer overflows and a real hard way of checking buffer
837 // belonging in the syscall dispatch
838 io_seproxyhal_display_icon(&el->component, (const bagl_icon_details_t *) txt);
839 }
840 else {
841#ifdef HAVE_SE_SCREEN1
842 bagl_draw_with_context(&el->component, txt, strlen(txt), BAGL_ENCODING_LATIN10);
843#endif // HAVE_SE_SCREEN
844#if !defined(HAVE_SE_SCREEN1) || (defined(HAVE_SE_SCREEN1) && defined(HAVE_PRINTF))
845 if (io_seproxyhal_spi_is_status_sentio_seph_is_status_sent()) {
846 return;
847 }
848 unsigned short length = sizeof(bagl_component_t)+strlen((const char*)txt);
849 G_io_seproxyhal_spi_buffer[0] = SEPROXYHAL_TAG_SCREEN_DISPLAY_STATUS0x65;
850#if defined(HAVE_SE_SCREEN1) && defined(HAVE_PRINTF)
851 G_io_seproxyhal_spi_buffer[0] = SEPROXYHAL_TAG_DBG_SCREEN_DISPLAY_STATUS0x5E;
852#endif // HAVE_SE_SCREEN && HAVE_PRINTF
853 G_io_seproxyhal_spi_buffer[1] = length>>8;
854 G_io_seproxyhal_spi_buffer[2] = length;
855 io_seproxyhal_spi_sendio_seph_send(G_io_seproxyhal_spi_buffer, 3);
856 io_seproxyhal_spi_sendio_seph_send((const uint8_t *) &el->component, sizeof(bagl_component_t));
857 io_seproxyhal_spi_sendio_seph_send((const uint8_t *) txt, length-sizeof(bagl_component_t));
858#endif // !HAVE_SE_SCREEN || (HAVE_SE_SCREEN && HAVE_PRINTF)
859 }
860 }
861 else {
862#ifdef HAVE_SE_SCREEN1
863 bagl_draw_with_context(&el->component, NULL((void*)0), 0, 0);
864#endif // HAVE_SE_SCREEN
865#if !defined(HAVE_SE_SCREEN1) || (defined(HAVE_SE_SCREEN1) && defined(HAVE_PRINTF))
866 if (io_seproxyhal_spi_is_status_sentio_seph_is_status_sent()) {
867 return;
868 }
869 unsigned short length = sizeof(bagl_component_t);
870 G_io_seproxyhal_spi_buffer[0] = SEPROXYHAL_TAG_SCREEN_DISPLAY_STATUS0x65;
871#if defined(HAVE_SE_SCREEN1) && defined(HAVE_PRINTF)
872 G_io_seproxyhal_spi_buffer[0] = SEPROXYHAL_TAG_DBG_SCREEN_DISPLAY_STATUS0x5E;
873#endif // HAVE_SE_SCREEN && HAVE_PRINTF
874 G_io_seproxyhal_spi_buffer[1] = length>>8;
875 G_io_seproxyhal_spi_buffer[2] = length;
876 io_seproxyhal_spi_sendio_seph_send(G_io_seproxyhal_spi_buffer, 3);
877 io_seproxyhal_spi_sendio_seph_send((const uint8_t *) &el->component, sizeof(bagl_component_t));
878#endif // !HAVE_SE_SCREEN || (HAVE_SE_SCREEN && HAVE_PRINTF)
879 }
880 }
881}
882
883unsigned int bagl_label_roundtrip_duration_ms(const bagl_element_t* e, unsigned int average_char_width) {
884 return bagl_label_roundtrip_duration_ms_buf(e, e->text, average_char_width);
885}
886
887unsigned int bagl_label_roundtrip_duration_ms_buf(const bagl_element_t* e, const char* str, unsigned int average_char_width) {
888 // not a scrollable label
889 if (e == NULL((void*)0) || (e->component.type != BAGL_LABEL && e->component.type != BAGL_LABELINE)) {
890 return 0;
891 }
892
893 const char *text_adr = (const char *) PIC(str)pic((void *)str);
894 unsigned int textlen = 0;
895
896 // no delay, no text to display
897 if (!text_adr) {
898 return 0;
899 }
900 textlen = strlen(text_adr);
901
902 // no delay, all text fits
903 textlen = textlen * average_char_width;
904 if (textlen <= e->component.width) {
905 return 0;
906 }
907
908 // compute scrolled text length
909 return 2*(textlen - e->component.width)*1000/e->component.icon_id + 2*(e->component.stroke & ~(0x80))*100;
910}
911
912void io_seproxyhal_button_push(button_push_callback_t button_callback, unsigned int new_button_mask) {
913 if (button_callback) {
914 unsigned int button_mask;
915 unsigned int button_same_mask_counter;
916 // enable speeded up long push
917 if (new_button_mask == G_ux_os.button_mask) {
918 // each 100ms ~
919 G_ux_os.button_same_mask_counter++;
920 }
921
922 // when new_button_mask is 0 and
923
924 // append the button mask
925 button_mask = G_ux_os.button_mask | new_button_mask;
926
927 // pre reset variable due to os_sched_exit
928 button_same_mask_counter = G_ux_os.button_same_mask_counter;
929
930 // reset button mask
931 if (new_button_mask == 0) {
932 // reset next state when button are released
933 G_ux_os.button_mask = 0;
934 G_ux_os.button_same_mask_counter=0;
935
936 // notify button released event
937 button_mask |= BUTTON_EVT_RELEASED0x80000000UL;
938 }
939 else {
940 G_ux_os.button_mask = button_mask;
941 }
942
943 // reset counter when button mask changes
944 if (new_button_mask != G_ux_os.button_mask) {
945 G_ux_os.button_same_mask_counter=0;
946 }
947
948 if (button_same_mask_counter >= BUTTON_FAST_THRESHOLD_CS8) {
949 // fast bit when pressing and timing is right
950 if ((button_same_mask_counter%BUTTON_FAST_ACTION_CS3) == 0) {
951 button_mask |= BUTTON_EVT_FAST0x40000000UL;
952 }
953
954 /*
955 // fast bit when releasing and threshold has been exceeded
956 if ((button_mask & BUTTON_EVT_RELEASED)) {
957 button_mask |= BUTTON_EVT_FAST;
958 }
959 */
960
961 // discard the release event after a fastskip has been detected, to avoid strange at release behavior
962 // and also to enable user to cancel an operation by starting triggering the fast skip
963 button_mask &= ~BUTTON_EVT_RELEASED0x80000000UL;
964 }
965
966 // indicate if button have been released
967 button_callback(button_mask, button_same_mask_counter);
968
969 }
970}
971
972#endif // HAVE_BAGL
973
974void io_seproxyhal_setup_ticker(unsigned int interval_ms) {
975 G_io_seproxyhal_spi_buffer[0] = SEPROXYHAL_TAG_SET_TICKER_INTERVAL0x4E;
976 G_io_seproxyhal_spi_buffer[1] = 0;
977 G_io_seproxyhal_spi_buffer[2] = 2;
978 G_io_seproxyhal_spi_buffer[3] = (interval_ms>>8)&0xff;
979 G_io_seproxyhal_spi_buffer[4] = (interval_ms)&0xff;
980 io_seproxyhal_spi_sendio_seph_send(G_io_seproxyhal_spi_buffer, 5);
981}
982
983static const unsigned char seph_io_device_off[] = {
984 SEPROXYHAL_TAG_DEVICE_OFF0x4B,
985 0,
986 0,
987};
988void io_seproxyhal_power_off(void) {
989 io_seproxyhal_spi_sendio_seph_send(seph_io_device_off, sizeof(seph_io_device_off));
990 for(;;);
991}
992
993static const unsigned char seph_io_se_reset[]= {
994 SEPROXYHAL_TAG_SE_POWER_OFF0x46,
995 0,
996 0,
997};
998void io_seproxyhal_se_reset(void) {
999 io_seproxyhal_spi_sendio_seph_send(seph_io_se_reset, sizeof(seph_io_se_reset));
1000 for(;;);
1001}
1002
1003#ifdef HAVE_BLE
1004void io_seph_ble_enable(unsigned char enable)
1005{
1006 G_io_seproxyhal_spi_buffer[0] = SEPROXYHAL_TAG_UX_CMD0x5D;
1007 G_io_seproxyhal_spi_buffer[1] = 0;
1008 G_io_seproxyhal_spi_buffer[2] = 1;
1009 G_io_seproxyhal_spi_buffer[3] = (enable ? SEPROXYHAL_TAG_UX_CMD_BLE_ENABLE_ADV0x01 : SEPROXYHAL_TAG_UX_CMD_BLE_DISABLE_ADV0x00);
1010 io_seproxyhal_spi_sendio_seph_send(G_io_seproxyhal_spi_buffer, 4);
1011}
1012
1013void io_seph_ble_clear_bond_db(void)
1014{
1015 G_io_seproxyhal_spi_buffer[0] = SEPROXYHAL_TAG_UX_CMD0x5D;
1016 G_io_seproxyhal_spi_buffer[1] = 0;
1017 G_io_seproxyhal_spi_buffer[2] = 1;
1018 G_io_seproxyhal_spi_buffer[3] = SEPROXYHAL_TAG_UX_CMD_BLE_RESET_PAIRINGS0x02;
1019 io_seproxyhal_spi_sendio_seph_send(G_io_seproxyhal_spi_buffer, 4);
1020}
1021#endif // HAVE_BLE
1022
1023void io_seph_ux_redisplay(void)
1024{
1025 G_io_seproxyhal_spi_buffer[0] = SEPROXYHAL_TAG_UX_CMD0x5D;
1026 G_io_seproxyhal_spi_buffer[1] = 0;
1027 G_io_seproxyhal_spi_buffer[2] = 1;
1028 G_io_seproxyhal_spi_buffer[3] = SEPROXYHAL_TAG_UX_CMD_REDISPLAY0x03;
1029 io_seproxyhal_spi_sendio_seph_send(G_io_seproxyhal_spi_buffer, 4);
1030}
1031
1032static const unsigned char seph_io_usb_disconnect[] = {
1033 SEPROXYHAL_TAG_USB_CONFIG0x4F,
1034 0,
1035 1,
1036 SEPROXYHAL_TAG_USB_CONFIG_DISCONNECT0x02,
1037};
1038void io_seproxyhal_disable_io(void) {
1039 // usb off
1040 io_seproxyhal_spi_sendio_seph_send(seph_io_usb_disconnect, sizeof(seph_io_usb_disconnect));
1041}
1042
1043void io_seproxyhal_backlight(unsigned int flags, unsigned int backlight_percentage) {
1044 G_io_seproxyhal_spi_buffer[0] = SEPROXYHAL_TAG_SET_SCREEN_CONFIG0x3E;
1045 G_io_seproxyhal_spi_buffer[1] = 0;
1046 G_io_seproxyhal_spi_buffer[2] = 2;
1047 G_io_seproxyhal_spi_buffer[3] = (backlight_percentage?0x80:0)|(flags & 0x7F); // power on
1048 G_io_seproxyhal_spi_buffer[4] = backlight_percentage;
1049 io_seproxyhal_spi_sendio_seph_send(G_io_seproxyhal_spi_buffer, 5);
1050}
1051
1052#ifdef HAVE_IO_U2F
1053u2f_service_t G_io_u2f;
1054#endif // HAVE_IO_U2F
1055
1056unsigned int os_io_seproxyhal_get_app_name_and_version(void) __attribute__((weak));
1057unsigned int os_io_seproxyhal_get_app_name_and_version(void) {
1058 unsigned int tx_len, len;
1059 // build the get app name and version reply
1060 tx_len = 0;
1061 G_io_apdu_buffer[tx_len++] = 1; // format ID
1062
1063#ifndef HAVE_BOLOS
1064 // append app name
1065 len = os_registry_get_current_app_tag(BOLOS_TAG_APPNAME0x01, G_io_apdu_buffer+tx_len+1, sizeof(G_io_apdu_buffer)-tx_len-1);
1066 G_io_apdu_buffer[tx_len++] = len;
1067 tx_len += len;
1068 // append app version
1069 len = os_registry_get_current_app_tag(BOLOS_TAG_APPVERSION0x02, G_io_apdu_buffer+tx_len+1, sizeof(G_io_apdu_buffer)-tx_len-1);
1070 G_io_apdu_buffer[tx_len++] = len;
1071 tx_len += len;
1072#else // HAVE_BOLOS
1073 // append app name
1074 len = strlen("BOLOS");
1075 G_io_apdu_buffer[tx_len++] = len;
1076 strcpy((char*)(G_io_apdu_buffer+tx_len), "BOLOS");
1077 tx_len += len;
1078 // append app version
1079 len = strlen(VERSION"dummy");
1080 G_io_apdu_buffer[tx_len++] = len;
1081 strcpy((char*)(G_io_apdu_buffer+tx_len), VERSION"dummy");
1082 tx_len += len;
1083#endif // HAVE_BOLOS
1084
1085#if !defined(HAVE_IO_TASK) || !defined(HAVE_BOLOS)
1086 // to be fixed within io tasks
1087 // return OS flags to notify of platform's global state (pin lock etc)
1088 G_io_apdu_buffer[tx_len++] = 1; // flags length
1089 G_io_apdu_buffer[tx_len++] = os_flags();
1090#endif // !defined(HAVE_IO_TASK) || !defined(HAVE_BOLOS)
1091
1092 // status words
1093 G_io_apdu_buffer[tx_len++] = 0x90;
1094 G_io_apdu_buffer[tx_len++] = 0x00;
1095 return tx_len;
1096}
1097
1098#if !defined(HAVE_BOLOS_NO_DEFAULT_APDU)
1099// This function is used to process the default APDU commands.
1100static bolos_bool_t io_process_default_apdus(unsigned char* channel, unsigned short* tx_len) {
1101 // Indicates whether a command has been processed and need to send an answer.
1102 bolos_bool_t processed = BOLOS_FALSE0x55;
1103
1104 // We handle the default apdus when the CLA byte is correct.
1105 if (DEFAULT_APDU_CLA0xB0 == G_io_apdu_buffer[APDU_OFF_CLA0]) {
1106
1107 // We have several possible commands.
1108 switch (G_io_apdu_buffer[APDU_OFF_INS1]) {
1109
1110 // get name and version
1111 case DEFAULT_APDU_INS_GET_VERSION0x01:
1112 // P1 and P2 shall be set to '00'.
1113 if (!G_io_apdu_buffer[APDU_OFF_P12] && !G_io_apdu_buffer[APDU_OFF_P23]) {
1114 *tx_len = os_io_seproxyhal_get_app_name_and_version();
1115 // disable 'return after tx' and 'asynch reply' flags
1116 *channel &= ~IO_FLAGS0xF8;
1117 processed = BOLOS_TRUE0xaa;
1118 }
1119 break;
1120
1121 // exit app after replied
1122 case DEFAULT_APDU_INS_APP_EXIT0xA7:
1123 // P1 and P2 shall be set to '00'.
1124 if (!G_io_apdu_buffer[APDU_OFF_P12] && !G_io_apdu_buffer[APDU_OFF_P23]) {
1125 *tx_len = 0;
1126 G_io_apdu_buffer[(*tx_len)++] = 0x90;
1127 G_io_apdu_buffer[(*tx_len)++] = 0x00;
1128
1129#if defined(HAVE_BOLOS)
1130 // If this APDU has been received from the dashboard, we don't do
1131 // anything except resetting the IO flags.
1132 *channel &= ~IO_FLAGS0xF8;
1133#else
1134 // We exit the application after having replied.
1135 *channel |= IO_RESET_AFTER_REPLIED0x80;
1136#endif // HAVE_BOLOS
1137
1138 processed = BOLOS_TRUE0xaa;
1139 }
1140 break;
1141
1142 // seed cookie
1143 // host: <nothing>
1144 // device: <format(1B)> <len(1B)> <seed magic cookie if pin is entered(len)> 9000 | 6985
1145#if defined(HAVE_SEED_COOKIE)
1146 case DEFAULT_APDU_INS_GET_SEED_COOKIE:
1147 // P1 and P2 shall be set to '00'.
1148 if (!G_io_apdu_buffer[APDU_OFF_P12] && !G_io_apdu_buffer[APDU_OFF_P23]) {
1149 *tx_len = 0;
1150 if (os_global_pin_is_validated() == BOLOS_UX_OK0xAA) {
1151 unsigned int i;
1152 // format
1153 G_io_apdu_buffer[(*tx_len)++] = 0x01;
1154 i = os_perso_seed_cookie(G_io_apdu_buffer+1+1, MIN(64,sizeof(G_io_apdu_buffer)-1-1-2)((64) < (sizeof(G_io_apdu_buffer)-1-1-2) ? (64) : (sizeof(
G_io_apdu_buffer)-1-1-2))
);
1155
1156 G_io_apdu_buffer[(*tx_len)++] = i;
1157 *tx_len += i;
1158 G_io_apdu_buffer[(*tx_len)++] = 0x90;
1159 G_io_apdu_buffer[(*tx_len)++] = 0x00;
1160 }
1161 else {
1162 G_io_apdu_buffer[(*tx_len)++] = 0x69;
1163 G_io_apdu_buffer[(*tx_len)++] = 0x85;
1164 }
1165 *channel &= ~IO_FLAGS0xF8;
1166 processed = BOLOS_TRUE0xaa;
1167 }
1168 break;
1169#endif // HAVE_SEED_COOKIE
1170
1171#if defined(DEBUG_OS_STACK_CONSUMPTION)
1172 // OS stack consumption.
1173 case DEFAULT_APDU_INS_STACK_CONSUMPTION:
1174 // Initialization.
1175 *tx_len = 2;
1176 U2BE_ENCODE(G_io_apdu_buffer, 0x00, SWO_APD_HDR_0D((0x6000 + 0x0500) + ERR_GEN_ID_0D));
1177
1178 // P2 and Lc shall be set to '00'.
1179 if (!G_io_apdu_buffer[APDU_OFF_P23] && !G_io_apdu_buffer[APDU_OFF_LC4]) {
1180 int s = os_stack_operations(G_io_apdu_buffer[APDU_OFF_P12]);
1181 if (-1 != s) {
1182 u4be_encode(G_io_apdu_buffer, 0x00, s);
1183 *tx_len = sizeof(int);
1184 G_io_apdu_buffer[(*tx_len)++] = 0x90;
1185 G_io_apdu_buffer[(*tx_len)++] = 0x00;
1186 }
1187 }
1188 *channel &= ~IO_FLAGS0xF8;
1189 processed = BOLOS_TRUE0xaa;
1190 break;
1191#endif // DEBUG_OS_STACK_CONSUMPTION
1192
1193 default:
1194 // 'processed' is already initialized.
1195 break;
1196 }
1197 }
1198
1199 return processed;
1200}
1201
1202#endif // HAVE_BOLOS_NO_DEFAULT_APDU
1203
1204unsigned short io_exchange(unsigned char channel, unsigned short tx_len) {
1205 unsigned short rx_len;
1206 unsigned int timeout_ms;
1207
1208#ifdef HAVE_BOLOS_APP_STACK_CANARY1
1209 // behavior upon detected stack overflow is to reset the SE
1210 if (app_stack_canary != APP_STACK_CANARY_MAGIC0xDEAD0031) {
1211 io_seproxyhal_se_reset();
1212 }
1213#endif // HAVE_BOLOS_APP_STACK_CANARY
1214
1215#ifdef DEBUG_APDU
1216 if ((channel&~(IO_FLAGS0xF8)) == CHANNEL_APDU0) {
1217 // ignore tx len
1218
1219 // already received the data of the apdu when received the whole apdu
1220 if ((channel & (CHANNEL_APDU0|IO_RECEIVE_DATA0x40)) == (CHANNEL_APDU0|IO_RECEIVE_DATA0x40)) {
1221 // return apdu data - header
1222 return G_io_apdu_length-5;
1223 }
1224
1225 // fetch next apdu
1226 if (debug_apdus_offset < sizeof(debug_apdus)) {
1227 G_io_apdu_length = debug_apdus[debug_apdus_offset]&0xFF;
1228 memcpy(G_io_apdu_buffer, &debug_apdus[debug_apdus_offset+1], G_io_apdu_length);
1229 debug_apdus_offset += G_io_apdu_length+1;
1230 return G_io_apdu_length;
1231 }
1232 }
1233#endif // DEBUG_APDU
1234
1235reply_apdu:
1236 switch(channel&~(IO_FLAGS0xF8)) {
1237 case CHANNEL_APDU0:
1238 // TODO work up the spi state machine over the HAL proxy until an APDU is available
1239
1240 if (tx_len && !(channel&IO_ASYNCH_REPLY0x10)) {
1241 // ensure it's our turn to send a command/status, could lag a bit before sending the reply
1242 while (io_seproxyhal_spi_is_status_sentio_seph_is_status_sent()) {
1243 io_seproxyhal_spi_recvio_seph_recv(G_io_seproxyhal_spi_buffer, sizeof(G_io_seproxyhal_spi_buffer), 0);
1244 // process without sending status on tickers etc, to ensure keeping the hand
1245 os_io_seph_recv_and_process(1);
1246 }
1247
1248 // reinit sending timeout for APDU replied within io_exchange
1249 timeout_ms = G_io_app.ms + IO_RAPDU_TRANSMIT_TIMEOUT_MS2000UL;
1250
1251 // until the whole RAPDU is transmitted, send chunks using the current mode for communication
1252 for (;;) {
1253 switch(G_io_app.apdu_state) {
1254 default:
1255 // delegate to the hal in case of not generic transport mode (or asynch)
1256 if (io_exchange_al(channel, tx_len) == 0) {
1257 goto break_send;
1258 }
1259 __attribute__((fallthrough));
1260 case APDU_IDLE:
1261 LOG("invalid state for APDU reply\n");
1262 THROW(INVALID_STATE)os_longjmp(0x4);
1263 break;
1264
1265 case APDU_RAW:
1266 if (tx_len > sizeof(G_io_apdu_buffer)) {
1267 THROW(INVALID_PARAMETER)os_longjmp(0x2);
1268 }
1269 // reply the RAW APDU over SEPROXYHAL protocol
1270 G_io_seproxyhal_spi_buffer[0] = SEPROXYHAL_TAG_RAPDU0x53;
1271 G_io_seproxyhal_spi_buffer[1] = (tx_len)>>8;
1272 G_io_seproxyhal_spi_buffer[2] = (tx_len);
1273 io_seproxyhal_spi_sendio_seph_send(G_io_seproxyhal_spi_buffer, 3);
1274 io_seproxyhal_spi_sendio_seph_send(G_io_apdu_buffer, tx_len);
1275
1276 // isngle packet reply, mark immediate idle
1277 G_io_app.apdu_state = APDU_IDLE;
1278 // finished, no chunking
1279 goto break_send;
1280
1281#ifdef HAVE_USB_APDU1
1282 case APDU_USB_HID:
1283 // only send, don't perform synchronous reception of the next command (will be done later by the seproxyhal packet processing)
1284 io_usb_hid_send(io_usb_send_apdu_data, tx_len);
1285 goto break_send;
1286#ifdef HAVE_USB_CLASS_CCID
1287 case APDU_USB_CCID:
1288 io_usb_ccid_reply(G_io_apdu_buffer, tx_len);
1289 goto break_send;
1290#endif // HAVE_USB_CLASS_CCID
1291#ifdef HAVE_WEBUSB1
1292 case APDU_USB_WEBUSB:
1293 io_usb_hid_send(io_usb_send_apdu_data_ep0x83, tx_len);
1294 goto break_send;
1295#endif // HAVE_WEBUSB
1296#endif // HAVE_USB_APDU
1297
1298#ifdef HAVE_BLE_APDU // versus U2F BLE
1299 case APDU_BLE:
1300 LEDGER_BLE_send(G_io_apdu_buffer, tx_len);
1301 goto break_send;
1302#endif // HAVE_BLE_APDU
1303
1304
1305#ifdef HAVE_IO_U2F
1306 // case to handle U2F channels. u2f apdu to be dispatched in the upper layers
1307 case APDU_U2F:
1308 // prepare reply, the remaining segments will be pumped during USB/BLE events handling while waiting for the next APDU
1309
1310 // the reply has been prepared by the application, stop sending anti timeouts
1311 u2f_message_set_autoreply_wait_user_presence(&G_io_u2f, false0);
1312
1313 // continue processing currently received command until completely received.
1314 while(!u2f_message_repliable(&G_io_u2f)) {
1315
1316 io_seproxyhal_general_status();
1317 do {
1318 io_seproxyhal_spi_recvio_seph_recv(G_io_seproxyhal_spi_buffer, sizeof(G_io_seproxyhal_spi_buffer), 0);
1319 // check for reply timeout
1320 if (G_io_app.ms >= timeout_ms) {
1321 THROW(EXCEPTION_IO_RESET)os_longjmp(0x5);
1322 }
1323 // avoid a general status to be replied
1324 io_seproxyhal_handle_event();
1325 } while (io_seproxyhal_spi_is_status_sentio_seph_is_status_sent());
1326 }
1327#ifdef U2F_PROXY_MAGIC
1328
1329 // user presence + counter + rapdu + sw must fit the apdu buffer
1330 if (1U+ 4U+ tx_len +2U > sizeof(G_io_apdu_buffer)) {
1331 THROW(INVALID_PARAMETER)os_longjmp(0x2);
1332 }
1333
1334 // u2F tunnel needs the status words to be included in the signature response BLOB, do it now.
1335 // always return 9000 in the signature to avoid error @ transport level in u2f layers.
1336 G_io_apdu_buffer[tx_len] = 0x90; //G_io_apdu_buffer[tx_len-2];
1337 G_io_apdu_buffer[tx_len+1] = 0x00; //G_io_apdu_buffer[tx_len-1];
1338 tx_len += 2;
1339 memmove(G_io_apdu_buffer + APDU_OFF_DATA5, G_io_apdu_buffer, tx_len);
1340 // zeroize user presence and counter
1341 memset(G_io_apdu_buffer, 0, APDU_OFF_DATA5);
1342 u2f_message_reply(&G_io_u2f, U2F_CMD_MSG, G_io_apdu_buffer, tx_len+5);
1343
1344#else // U2F_PROXY_MAGIC
1345 u2f_message_reply(&G_io_u2f, U2F_CMD_MSG, G_io_apdu_buffer, tx_len);
1346#endif // U2F_PROXY_MAGIC
1347 goto break_send;
1348#endif // HAVE_IO_U2F
1349 }
1350 continue;
1351
1352 break_send:
1353
1354 // wait end of reply transmission
1355 // TODO: add timeout here to avoid spending too much time when host has disconnected
1356 while (G_io_app.apdu_state != APDU_IDLE) {
1357 io_seproxyhal_general_status();
1358 do {
1359 io_seproxyhal_spi_recvio_seph_recv(G_io_seproxyhal_spi_buffer, sizeof(G_io_seproxyhal_spi_buffer), 0);
1360 // check for reply timeout (when asynch reply (over hid or u2f for example))
1361 // this case shall be covered by usb_ep_timeout but is not, investigate that
1362 if (G_io_app.ms >= timeout_ms) {
1363 THROW(EXCEPTION_IO_RESET)os_longjmp(0x5);
1364 }
1365 // avoid a general status to be replied
1366 io_seproxyhal_handle_event();
1367 } while (io_seproxyhal_spi_is_status_sentio_seph_is_status_sent());
1368 }
1369 // reset apdu state
1370 G_io_app.apdu_state = APDU_IDLE;
1371 G_io_app.apdu_media = IO_APDU_MEDIA_NONE;
1372
1373 G_io_app.apdu_length = 0;
1374
1375 // continue sending commands, don't issue status yet
1376 if (channel & IO_RETURN_AFTER_TX0x20) {
1377 return 0;
1378 }
1379 // acknowledge the write request (general status OK) and no more command to follow (wait until another APDU container is received to continue unwrapping)
1380 io_seproxyhal_general_status();
1381 break;
1382 }
1383
1384 // perform reset after io exchange
1385 if (channel & IO_RESET_AFTER_REPLIED0x80) {
1386 // The error cast is retrocompatible with the previous value.
1387 os_sched_exit((bolos_task_status_t)EXCEPTION_IO_RESET0x5);
1388 //reset();
1389 }
1390 }
1391
1392 if (!(channel&IO_ASYNCH_REPLY0x10)) {
1393
1394 // already received the data of the apdu when received the whole apdu
1395 if ((channel & (CHANNEL_APDU0|IO_RECEIVE_DATA0x40)) == (CHANNEL_APDU0|IO_RECEIVE_DATA0x40)) {
1396 // return apdu data - header
1397 return G_io_app.apdu_length-5;
1398 }
1399
1400 // reply has ended, proceed to next apdu reception (reset status only after asynch reply)
1401 G_io_app.apdu_state = APDU_IDLE;
1402 G_io_app.apdu_media = IO_APDU_MEDIA_NONE;
1403 }
1404
1405 // reset the received apdu length
1406 G_io_app.apdu_length = 0;
1407
1408 // ensure ready to receive an event (after an apdu processing with asynch flag, it may occur if the channel is not correctly managed)
1409
1410 // until a new whole CAPDU is received
1411 for (;;) {
1412 io_seproxyhal_general_status();
1413 // wait until a SPI packet is available
1414 // NOTE: on ST31, dual wait ISO & RF (ISO instead of SPI)
1415 rx_len = io_seproxyhal_spi_recvio_seph_recv(G_io_seproxyhal_spi_buffer, sizeof(G_io_seproxyhal_spi_buffer), 0);
1416
1417 // can't process split TLV, continue
1418 if (rx_len < 3 || rx_len != U2(G_io_seproxyhal_spi_buffer[1],G_io_seproxyhal_spi_buffer[2])((((G_io_seproxyhal_spi_buffer[1])&0xFFu) << 8) | (
(G_io_seproxyhal_spi_buffer[2])&0xFFu))
+3U) {
1419 LOG("invalid TLV format\n");
1420 G_io_app.apdu_state = APDU_IDLE;
1421 G_io_app.apdu_length = 0;
1422 continue;
1423 }
1424
1425 io_seproxyhal_handle_event();
1426
1427 // An apdu has been received asynchroneously.
1428 if (G_io_app.apdu_state != APDU_IDLE && G_io_app.apdu_length > 0) {
1429#if !defined(HAVE_BOLOS_NO_DEFAULT_APDU)
1430 // If a default command is received and processed within this call,
1431 // then we send the answer.
1432 if (io_process_default_apdus(&channel, &tx_len) == BOLOS_TRUE0xaa) {
1433 goto reply_apdu;
1434 }
1435#endif // ! HAVE_BOLOS_NO_DEFAULT_APDU
1436
1437 return G_io_app.apdu_length;
1438 }
1439 }
1440 break;
1441
1442 default:
1443 return io_exchange_al(channel, tx_len);
1444 }
1445}
1446
1447unsigned int os_io_seph_recv_and_process(unsigned int dont_process_ux_events) {
1448 // send general status before receiving next event
1449 io_seproxyhal_general_status();
1450
1451 io_seproxyhal_spi_recvio_seph_recv(G_io_seproxyhal_spi_buffer, sizeof(G_io_seproxyhal_spi_buffer), 0);
1452
1453 switch (G_io_seproxyhal_spi_buffer[0]) {
1454 case SEPROXYHAL_TAG_FINGER_EVENT0x0C:
1455 case SEPROXYHAL_TAG_BUTTON_PUSH_EVENT0x05:
1456 case SEPROXYHAL_TAG_TICKER_EVENT0x0E:
1457 case SEPROXYHAL_TAG_DISPLAY_PROCESSED_EVENT0x0D:
1458 case SEPROXYHAL_TAG_STATUS_EVENT0x15:
1459 // perform UX event on these ones, don't process as an IO event
1460 if (dont_process_ux_events) {
1461 return 0;
1462 }
1463 __attribute__((fallthrough));
1464
1465 default:
1466 // if malformed, then a stall is likely to occur
1467 if (io_seproxyhal_handle_event()) {
1468 return 1;
1469 }
1470 }
1471 return 0;
1472}
1473
1474#if !defined(APP_UX)
1475unsigned int os_ux_blocking(bolos_ux_params_t* params) {
1476 unsigned int ret;
1477
1478 // until a real status is returned
1479 os_ux(params);
1480 ret = os_sched_last_status(TASK_BOLOS_UX);
1481 while(ret == BOLOS_UX_IGNORE0x97
1482 || ret == BOLOS_UX_CONTINUE0) {
1483 // if the IO task is not running, then need to pump events manually
1484 if (os_sched_is_running(TASK_SUBTASKS_START) != BOLOS_TRUE0xaa) {
1485 // send general status before receiving next event
1486 io_seproxyhal_general_status();
1487 io_seproxyhal_spi_recvio_seph_recv(G_io_seproxyhal_spi_buffer, sizeof(G_io_seproxyhal_spi_buffer), 0);
1488 io_event(0);
1489 }
1490 else
1491 {
1492 // wait until UX takes some process time and update it's status
1493 os_sched_yield(BOLOS_UX_OK0xAA);
1494 }
1495 // only retrieve the current UX state
1496 ret = os_sched_last_status(TASK_BOLOS_UX);
1497 }
1498
1499 return ret;
1500}
1501#endif // !defined(APP_UX)
1502
1503#ifdef HAVE_PRINTF
1504void mcu_usb_prints(const char* str, unsigned int charcount) {
1505 unsigned char buf[4];
1506#ifdef TARGET_NANOS
1507 buf[0] = SEPROXYHAL_TAG_PRINTF_STATUS0x66;
1508#else
1509 buf[0] = SEPROXYHAL_TAG_PRINTF0x5F;
1510#endif
1511 buf[1] = charcount >> 8;
1512 buf[2] = charcount;
1513 io_seproxyhal_spi_sendio_seph_send(buf, 3);
1514 io_seproxyhal_spi_sendio_seph_send((const uint8_t *) str, charcount);
1515}
1516#endif // HAVE_PRINTF
1517
1518void io_seproxyhal_io_heartbeat(void) {
1519 io_seproxyhal_general_status();
1520 do {
1521 io_seproxyhal_spi_recvio_seph_recv(G_io_seproxyhal_spi_buffer, sizeof(G_io_seproxyhal_spi_buffer), 0);
1522 // avoid a general status to be replied
1523 if(G_io_seproxyhal_spi_buffer[0] != SEPROXYHAL_TAG_TICKER_EVENT0x0E) {
1524 io_seproxyhal_handle_event();
1525 }
1526 } while (io_seproxyhal_spi_is_status_sentio_seph_is_status_sent());
1527}
1528#endif // OS_IO_SEPROXYHAL
diff --git a/app/output-scan-build/2022-05-16-071232-98-1/scanview.css b/app/output-scan-build/2022-05-16-071232-98-1/scanview.css deleted file mode 100644 index cf8a5a6a..00000000 --- a/app/output-scan-build/2022-05-16-071232-98-1/scanview.css +++ /dev/null @@ -1,62 +0,0 @@ -body { color:#000000; background-color:#ffffff } -body { font-family: Helvetica, sans-serif; font-size:9pt } -h1 { font-size: 14pt; } -h2 { font-size: 12pt; } -table { font-size:9pt } -table { border-spacing: 0px; border: 1px solid black } -th, table thead { - background-color:#eee; color:#666666; - font-weight: bold; cursor: default; - text-align:center; - font-weight: bold; font-family: Verdana; - white-space:nowrap; -} -.W { font-size:0px } -th, td { padding:5px; padding-left:8px; text-align:left } -td.SUMM_DESC { padding-left:12px } -td.DESC { white-space:pre } -td.Q { text-align:right } -td { text-align:left } -tbody.scrollContent { overflow:auto } - -table.form_group { - background-color: #ccc; - border: 1px solid #333; - padding: 2px; -} - -table.form_inner_group { - background-color: #ccc; - border: 1px solid #333; - padding: 0px; -} - -table.form { - background-color: #999; - border: 1px solid #333; - padding: 2px; -} - -td.form_label { - text-align: right; - vertical-align: top; -} -/* For one line entires */ -td.form_clabel { - text-align: right; - vertical-align: center; -} -td.form_value { - text-align: left; - vertical-align: top; -} -td.form_submit { - text-align: right; - vertical-align: top; -} - -h1.SubmitFail { - color: #f00; -} -h1.SubmitOk { -} diff --git a/app/output-scan-build/2022-05-16-071232-98-1/sorttable.js b/app/output-scan-build/2022-05-16-071232-98-1/sorttable.js deleted file mode 100644 index 32faa078..00000000 --- a/app/output-scan-build/2022-05-16-071232-98-1/sorttable.js +++ /dev/null @@ -1,492 +0,0 @@ -/* - SortTable - version 2 - 7th April 2007 - Stuart Langridge, http://www.kryogenix.org/code/browser/sorttable/ - - Instructions: - Download this file - Add to your HTML - Add class="sortable" to any table you'd like to make sortable - Click on the headers to sort - - Thanks to many, many people for contributions and suggestions. - Licenced as X11: http://www.kryogenix.org/code/browser/licence.html - This basically means: do what you want with it. -*/ - - -var stIsIE = /*@cc_on!@*/false; - -sorttable = { - init: function() { - // quit if this function has already been called - if (arguments.callee.done) return; - // flag this function so we don't do the same thing twice - arguments.callee.done = true; - // kill the timer - if (_timer) clearInterval(_timer); - - if (!document.createElement || !document.getElementsByTagName) return; - - sorttable.DATE_RE = /^(\d\d?)[\/\.-](\d\d?)[\/\.-]((\d\d)?\d\d)$/; - - forEach(document.getElementsByTagName('table'), function(table) { - if (table.className.search(/\bsortable\b/) != -1) { - sorttable.makeSortable(table); - } - }); - - }, - - makeSortable: function(table) { - if (table.getElementsByTagName('thead').length == 0) { - // table doesn't have a tHead. Since it should have, create one and - // put the first table row in it. - the = document.createElement('thead'); - the.appendChild(table.rows[0]); - table.insertBefore(the,table.firstChild); - } - // Safari doesn't support table.tHead, sigh - if (table.tHead == null) table.tHead = table.getElementsByTagName('thead')[0]; - - if (table.tHead.rows.length != 1) return; // can't cope with two header rows - - // Sorttable v1 put rows with a class of "sortbottom" at the bottom (as - // "total" rows, for example). This is B&R, since what you're supposed - // to do is put them in a tfoot. So, if there are sortbottom rows, - // for backward compatibility, move them to tfoot (creating it if needed). - sortbottomrows = []; - for (var i=0; i5' : ' ▴'; - this.appendChild(sortrevind); - return; - } - if (this.className.search(/\bsorttable_sorted_reverse\b/) != -1) { - // if we're already sorted by this column in reverse, just - // re-reverse the table, which is quicker - sorttable.reverse(this.sorttable_tbody); - this.className = this.className.replace('sorttable_sorted_reverse', - 'sorttable_sorted'); - this.removeChild(document.getElementById('sorttable_sortrevind')); - sortfwdind = document.createElement('span'); - sortfwdind.id = "sorttable_sortfwdind"; - sortfwdind.innerHTML = stIsIE ? ' 6' : ' ▾'; - this.appendChild(sortfwdind); - return; - } - - // remove sorttable_sorted classes - theadrow = this.parentNode; - forEach(theadrow.childNodes, function(cell) { - if (cell.nodeType == 1) { // an element - cell.className = cell.className.replace('sorttable_sorted_reverse',''); - cell.className = cell.className.replace('sorttable_sorted',''); - } - }); - sortfwdind = document.getElementById('sorttable_sortfwdind'); - if (sortfwdind) { sortfwdind.parentNode.removeChild(sortfwdind); } - sortrevind = document.getElementById('sorttable_sortrevind'); - if (sortrevind) { sortrevind.parentNode.removeChild(sortrevind); } - - this.className += ' sorttable_sorted'; - sortfwdind = document.createElement('span'); - sortfwdind.id = "sorttable_sortfwdind"; - sortfwdind.innerHTML = stIsIE ? ' 6' : ' ▾'; - this.appendChild(sortfwdind); - - // build an array to sort. This is a Schwartzian transform thing, - // i.e., we "decorate" each row with the actual sort key, - // sort based on the sort keys, and then put the rows back in order - // which is a lot faster because you only do getInnerText once per row - row_array = []; - col = this.sorttable_columnindex; - rows = this.sorttable_tbody.rows; - for (var j=0; j 12) { - // definitely dd/mm - return sorttable.sort_ddmm; - } else if (second > 12) { - return sorttable.sort_mmdd; - } else { - // looks like a date, but we can't tell which, so assume - // that it's dd/mm (English imperialism!) and keep looking - sortfn = sorttable.sort_ddmm; - } - } - } - } - return sortfn; - }, - - getInnerText: function(node) { - // gets the text we want to use for sorting for a cell. - // strips leading and trailing whitespace. - // this is *not* a generic getInnerText function; it's special to sorttable. - // for example, you can override the cell text with a customkey attribute. - // it also gets .value for fields. - - hasInputs = (typeof node.getElementsByTagName == 'function') && - node.getElementsByTagName('input').length; - - if (node.getAttribute("sorttable_customkey") != null) { - return node.getAttribute("sorttable_customkey"); - } - else if (typeof node.textContent != 'undefined' && !hasInputs) { - return node.textContent.replace(/^\s+|\s+$/g, ''); - } - else if (typeof node.innerText != 'undefined' && !hasInputs) { - return node.innerText.replace(/^\s+|\s+$/g, ''); - } - else if (typeof node.text != 'undefined' && !hasInputs) { - return node.text.replace(/^\s+|\s+$/g, ''); - } - else { - switch (node.nodeType) { - case 3: - if (node.nodeName.toLowerCase() == 'input') { - return node.value.replace(/^\s+|\s+$/g, ''); - } - case 4: - return node.nodeValue.replace(/^\s+|\s+$/g, ''); - break; - case 1: - case 11: - var innerText = ''; - for (var i = 0; i < node.childNodes.length; i++) { - innerText += sorttable.getInnerText(node.childNodes[i]); - } - return innerText.replace(/^\s+|\s+$/g, ''); - break; - default: - return ''; - } - } - }, - - reverse: function(tbody) { - // reverse the rows in a tbody - newrows = []; - for (var i=0; i=0; i--) { - tbody.appendChild(newrows[i]); - } - delete newrows; - }, - - /* sort functions - each sort function takes two parameters, a and b - you are comparing a[0] and b[0] */ - sort_numeric: function(a,b) { - aa = parseFloat(a[0].replace(/[^0-9.-]/g,'')); - if (isNaN(aa)) aa = 0; - bb = parseFloat(b[0].replace(/[^0-9.-]/g,'')); - if (isNaN(bb)) bb = 0; - return aa-bb; - }, - sort_alpha: function(a,b) { - if (a[0]==b[0]) return 0; - if (a[0] 0 ) { - var q = list[i]; list[i] = list[i+1]; list[i+1] = q; - swap = true; - } - } // for - t--; - - if (!swap) break; - - for(var i = t; i > b; --i) { - if ( comp_func(list[i], list[i-1]) < 0 ) { - var q = list[i]; list[i] = list[i-1]; list[i-1] = q; - swap = true; - } - } // for - b++; - - } // while(swap) - } -} - -/* ****************************************************************** - Supporting functions: bundled here to avoid depending on a library - ****************************************************************** */ - -// Dean Edwards/Matthias Miller/John Resig - -/* for Mozilla/Opera9 */ -if (document.addEventListener) { - document.addEventListener("DOMContentLoaded", sorttable.init, false); -} - -/* for Internet Explorer */ -/*@cc_on @*/ -/*@if (@_win32) - document.write("