Skip to content

Commit

Permalink
Makefile: Improve app _install_parameters generation
Browse files Browse the repository at this point in the history
This includes:
- Generation before build time and inclusion in the binary at build time
  whereas it was previously done only during sideloading.
  This allows:
  * to have a proper app size when using arm-none-eabi-size bin/app.elf,
    taking into account the size of the install_parameters
  * to have complete artifacts app.elf, app.hex, app.map, app.asm which
    can be used for debug
  * to have a proper Speculos emulation on install_parameters
    interactions.

- Parsing of APP_LOAD_PARAMS variable so that its differents fields can
  be used cleanly

- New symbols in the linker script to expose the start and the end of
  install_parameters, allowing to retrieve its size.

- A small change in src/pic.c to avoid application sha256 change in this
  commit. The change will be removed in the next commit.

This commit as been tested without modification on the application
sha256 (which includes install_parameters generated at build time or as
previously by ledgerblue.loadapp script) on numerous applications.
  • Loading branch information
Xavier Chapron committed Dec 1, 2023
1 parent 536c84d commit 34448c2
Show file tree
Hide file tree
Showing 12 changed files with 365 additions and 34 deletions.
126 changes: 126 additions & 0 deletions Makefile.app_params
Original file line number Diff line number Diff line change
@@ -0,0 +1,126 @@
#*******************************************************************************
# Ledger SDK
# (c) 2023 Ledger
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
#*******************************************************************************

# Command to print ICONNAME hexadecimal bitmap on stdout according to the
# hardware target.
ifneq ($(TARGET),nanos)
#inverse B&W for non Stax
ifneq ($(TARGET_NAME),TARGET_STAX)
ICONHEX_CMD=python3 $(BOLOS_SDK)/lib_nbgl/tools/icon2glyph.py --reverse --hexbitmaponly $(ICONNAME)
else
ICONHEX_CMD=python3 $(BOLOS_SDK)/lib_nbgl/tools/icon2glyph.py --hexbitmaponly $(ICONNAME)
endif
else
ICONHEX_CMD=python3 $(BOLOS_SDK)/icon3.py --hexbitmaponly $(ICONNAME)
endif


#########################################
# Parse APP_LOAD_PARAMS #
#########################################
# This is necessary when makefile.standard_app is not completely used.
# Correctly implemented apps should not set anything in APP_LOAD_PARAMS anymore
# Potential presents info are:
# --appFlags
# --curve
# --path
# --path_slip21
# --tlvraw
# --dep
# --nocrc
# Other info are considered an error and will be silently discarded.

ifneq ($(APP_LOAD_PARAMS),)
EXTRACTED_APP_FLAGS := $(shell python3 $(BOLOS_SDK)/extract_param.py --appFlags $(APP_LOAD_PARAMS))
APP_FLAGS_APP_LOAD_PARAMS += $(EXTRACTED_APP_FLAGS)

EXTRACTED_CURVE := $(shell python3 $(BOLOS_SDK)/extract_param.py --curve $(APP_LOAD_PARAMS))
CURVE_APP_LOAD_PARAMS += $(EXTRACTED_CURVE)

EXTRACTED_PATH := $(shell python3 $(BOLOS_SDK)/extract_param.py --path $(APP_LOAD_PARAMS))
PATH_APP_LOAD_PARAMS += $(EXTRACTED_PATH)

EXTRACTED_PATH_SLIP21 := $(shell python3 $(BOLOS_SDK)/extract_param.py --path_slip21 $(APP_LOAD_PARAMS))
PATH_SLIP21_APP_LOAD_PARAMS += $(EXTRACTED_PATH_SLIP21)

EXTRACTED_TLVRAW := $(shell python3 $(BOLOS_SDK)/extract_param.py --tlvraw $(APP_LOAD_PARAMS))
TLVRAW_APP_LOAD_PARAMS += $(EXTRACTED_TLVRAW)

EXTRACTED_DEP := $(shell python3 $(BOLOS_SDK)/extract_param.py --dep $(APP_LOAD_PARAMS))
DEP_APP_LOAD_PARAMS += $(EXTRACTED_DEP)

ifneq ($(findstring --nocrc,$(APP_LOAD_PARAMS)),)
ENABLE_NOCRC_APP_LOAD_PARAMS = 1
endif
endif


#########################################
# Generate install_params #
#########################################
# Compute params to call install_params.py
# Consider only one path_slip21 can be added, whereas LedgerBlue seems to
# support multiple, but has the path can hold a " " in it, it mess with the
# foreach, so we choose to restrict to only one path_slip21.
APP_INSTALL_PARAMS = --appName $(APPNAME)
APP_INSTALL_PARAMS += --appVersion $(APPVERSION)
APP_INSTALL_PARAMS += `ICONHEX=\`$(ICONHEX_CMD) 2>/dev/null\` ; [ ! -z "$$ICONHEX" ] && echo "--icon $$ICONHEX"`
APP_INSTALL_PARAMS += $(foreach curve, $(CURVE_APP_LOAD_PARAMS), --curve $(curve))
APP_INSTALL_PARAMS += $(foreach path, $(PATH_APP_LOAD_PARAMS), --path $(path))
ifneq ($(PATH_SLIP21_APP_LOAD_PARAMS),)
APP_INSTALL_PARAMS += --path_slip21 $(PATH_SLIP21_APP_LOAD_PARAMS)
endif
APP_INSTALL_PARAMS += $(foreach tlvraw, $(TLVRAW_APP_LOAD_PARAMS), --tlvraw $(tlvraw))
APP_INSTALL_PARAMS += $(foreach dep, $(DEP_APP_LOAD_PARAMS), --dep $(dep))

# Compute install_params tlv binary blob then expose it via a define to
# src/app_metadata.c so that it is inserted in the binary at link time
APP_INSTALL_PARAMS_DATA := $(shell python3 $(BOLOS_SDK)/install_params.py $(APP_INSTALL_PARAMS))
DEFINES += APP_INSTALL_PARAMS_DATA=$(APP_INSTALL_PARAMS_DATA)

#########################################
# Generate APP_LOAD_PARAMS #
#########################################
# Rewrite APP_LOAD_PARAMS with params needed for generating the sideloading
# APDUs.
# This variable is then used in some Makefiles target as Ledgerblue.loadapp
# script parameters.
APP_LOAD_PARAMS = --targetId $(TARGET_ID)
APP_LOAD_PARAMS += --targetVersion="$(TARGET_VERSION)"
APP_LOAD_PARAMS += --apiLevel $(API_LEVEL)
APP_LOAD_PARAMS += --fileName bin/app.hex
APP_LOAD_PARAMS += --appName $(APPNAME)
ifneq ($(APP_FLAGS_APP_LOAD_PARAMS),)
APP_LOAD_PARAMS += --appFlags $(APP_FLAGS_APP_LOAD_PARAMS)
endif
APP_LOAD_PARAMS += --delete
APP_LOAD_PARAMS += --tlv
APP_LOAD_PARAMS += --dataSize $$((0x`cat debug/app.map | grep _envram_data | tr -s ' ' | cut -f2 -d' ' |cut -f2 -d'x' ` - 0x`cat debug/app.map | grep _nvram_data | tr -s ' ' | cut -f2 -d' ' | cut -f2 -d'x'`))
APP_LOAD_PARAMS += --installparamsSize $$((0x`cat debug/app.map | grep _einstall_parameters | tr -s ' ' | cut -f2 -d' ' |cut -f2 -d'x'` - 0x`cat debug/app.map | grep _install_parameters | tr -s ' ' | cut -f2 -d' ' |cut -f2 -d'x'`))

ifeq ($(ENABLE_NOCRC_APP_LOAD_PARAMS), 1)
APP_LOAD_PARAMS += --nocrc
endif

COMMON_DELETE_PARAMS = --targetId $(TARGET_ID) --appName $(APPNAME)

# Extra load parameters for loadApp script
ifneq ($(SCP_PRIVKEY),)
PARAM_SCP += --rootPrivateKey $(SCP_PRIVKEY)
APP_LOAD_PARAMS += $(PARAM_SCP)
COMMON_DELETE_PARAMS += $(PARAM_SCP)
endif
20 changes: 0 additions & 20 deletions Makefile.defines
Original file line number Diff line number Diff line change
Expand Up @@ -60,26 +60,6 @@ DEFINES += API_LEVEL=$(API_LEVEL)
APP_METADATA_LIST := TARGET TARGET_NAME APPVERSION SDK_NAME SDK_VERSION SDK_HASH
DEFINES += $(foreach item,$(APP_METADATA_LIST), $(item)=\"$($(item))\")

# extra load parameters for loadApp script
ifneq ($(SCP_PRIVKEY),)
PARAM_SCP+=--rootPrivateKey $(SCP_PRIVKEY)
endif

# Command to print ICONNAME hexadecimal bitmap on stdout
# according to the hardware target.
ifneq ($(TARGET),nanos)
#inverse B&W for non Stax
ifneq ($(TARGET_NAME),TARGET_STAX)
ICONHEX_CMD=python3 $(BOLOS_SDK)/lib_nbgl/tools/icon2glyph.py --reverse --hexbitmaponly $(ICONNAME)
else
ICONHEX_CMD=python3 $(BOLOS_SDK)/lib_nbgl/tools/icon2glyph.py --hexbitmaponly $(ICONNAME)
endif
else
ICONHEX_CMD=python3 $(BOLOS_SDK)/icon3.py --hexbitmaponly $(ICONNAME)
endif

COMMON_LOAD_PARAMS=--tlv --targetId $(TARGET_ID) --targetVersion="$(TARGET_VERSION)" --apiLevel $(API_LEVEL) --delete --fileName bin/app.hex --appName $(APPNAME) --appVersion $(APPVERSION) --dataSize $$((0x`cat debug/app.map |grep _envram_data | tr -s ' ' | cut -f2 -d' '|cut -f2 -d'x'` - 0x`cat debug/app.map |grep _nvram_data | tr -s ' ' | cut -f2 -d' '|cut -f2 -d'x'`)) `ICONHEX=\`$(ICONHEX_CMD) 2>/dev/null\` ; [ ! -z "$$ICONHEX" ] && echo "--icon $$ICONHEX"` $(PARAM_SCP)
COMMON_DELETE_PARAMS=--targetId $(TARGET_ID) --appName $(APPNAME) $(PARAM_SCP)

BUILD_DIR := build
TARGET_BUILD_DIR := $(BUILD_DIR)/$(TARGET)
Expand Down
4 changes: 4 additions & 0 deletions Makefile.rules_generic
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,10 @@
# limitations under the License.
#*******************************************************************************

# Include Makefile.app_params here so that it is:
# - included on all apps Makefile, without changing them
# - included after apps Makefile changes on APP_LOAD_PARAMS
include $(BOLOS_SDK)/Makefile.app_params

# consider every intermediate target as final to avoid deleting intermediate files
.SECONDARY:
Expand Down
14 changes: 3 additions & 11 deletions Makefile.standard_app
Original file line number Diff line number Diff line change
Expand Up @@ -165,22 +165,14 @@ ifeq ($(HAVE_APPLICATION_FLAG_LIBRARY), 1)
STANDARD_APP_FLAGS := $(shell echo $$(($(STANDARD_APP_FLAGS) + 0x800)))
endif

APP_FLAGS = $(shell printf '0x%x' $$(( $(STANDARD_APP_FLAGS) + $(CUSTOM_APP_FLAGS) )) )

APP_LOAD_PARAMS += --appFlags $(APP_FLAGS)

APP_LOAD_PARAMS += $(foreach curve, $(CURVE_APP_LOAD_PARAMS), --curve $(curve))

APP_LOAD_PARAMS += $(foreach path, $(PATH_APP_LOAD_PARAMS), --path $(path))

APP_LOAD_PARAMS += $(COMMON_LOAD_PARAMS)

# Pending review flag
ifeq ($(ENABLE_PENDING_REVIEW_SCREEN), 1)
APP_LOAD_PARAMS += --tlvraw 9F:01
TLVRAW_APP_LOAD_PARAMS += 9F:01
DEFINES += HAVE_PENDING_REVIEW_SCREEN
endif

APP_FLAGS_APP_LOAD_PARAMS = $(shell printf '0x%x' $$(( $(STANDARD_APP_FLAGS) + $(CUSTOM_APP_FLAGS) )) )

#####################################################################
# COMPILER SETTINGS #
#####################################################################
Expand Down
20 changes: 20 additions & 0 deletions extract_param.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
"""
Helper to extract APP_LOAD_PARAMS parameters values.
It takes as a first parameter the parameter name to be search and output the
corresponding values from the rest of the script parameters.
"""

from sys import argv

if __name__ == '__main__':

assert len(argv) > 2
searching = argv[1]

res = []
args = argv[2:]

for i, arg in enumerate(args):
if arg == searching and len(args) > i:
res.append(repr(args[i + 1]))
print(" ".join(res))
Loading

0 comments on commit 34448c2

Please sign in to comment.