tychovrahe/T3W1/devkit1_with_ble_crypto3
tychovrahe 11 months ago
parent 121de394e9
commit 3a9ffef074

2
core/.gitignore vendored

@ -11,3 +11,5 @@ mypy_report
/CMakeLists.txt
/cmake-build-debug/
tools/gdb_scripts/*.log
/embed/ble_bootloader/jlink.jdebug.user
/embed/ble_firmware/jlink.jdebug.user

@ -5,6 +5,8 @@ MAKE = make -j $(JOBS)
SCONS = scons -Q -j $(JOBS)
BUILD_DIR = build
BLE_BOOTLOADER_BUILD_DIR = $(BUILD_DIR)/ble_bootloader
BLE_FIRMWARE_BUILD_DIR = $(BUILD_DIR)/ble_firmware
BOARDLOADER_BUILD_DIR = $(BUILD_DIR)/boardloader
BOOTLOADER_BUILD_DIR = $(BUILD_DIR)/bootloader
BOOTLOADER_CI_BUILD_DIR = $(BUILD_DIR)/bootloader_ci
@ -172,6 +174,13 @@ build: build_boardloader build_bootloader build_firmware build_prodtest build_un
build_embed: build_boardloader build_bootloader build_firmware # build boardloader, bootloader, firmware
build_ble_bootloader: ## build ble_bootloader
$(SCONS) CFLAGS="$(CFLAGS)" PRODUCTION="$(PRODUCTION)" TREZOR_MODEL="$(TREZOR_MODEL)" CMAKELISTS="$(CMAKELISTS)" $(BLE_BOOTLOADER_BUILD_DIR)/ble_bootloader.bin
build_ble_firmware: ## build ble_firmware
$(SCONS) CFLAGS="$(CFLAGS)" PRODUCTION="$(PRODUCTION)" TREZOR_MODEL="$(TREZOR_MODEL)" CMAKELISTS="$(CMAKELISTS)" $(BLE_FIRMWARE_BUILD_DIR)/ble_firmware.bin
build_boardloader: ## build boardloader
$(SCONS) CFLAGS="$(CFLAGS)" PRODUCTION="$(PRODUCTION)" TREZOR_MODEL="$(TREZOR_MODEL)" \
CMAKELISTS="$(CMAKELISTS)" $(BOARDLOADER_BUILD_DIR)/boardloader.bin
@ -226,9 +235,16 @@ build_cross: ## build mpy-cross port
## clean commands:
clean: clean_boardloader clean_bootloader clean_bootloader_emu clean_bootloader_ci clean_prodtest clean_reflash clean_firmware clean_unix clean_cross ## clean all
clean: clean_ble_bootloader clean_ble_firmware clean_boardloader clean_bootloader clean_bootloader_emu clean_bootloader_ci clean_prodtest clean_reflash clean_firmware clean_unix clean_cross ## clean all
rm -f ".sconsign.dblite"
clean_ble_bootloader: ## clean ble_bootloader build
rm -rf $(BLE_BOOTLOADER_BUILD_DIR)
clean_ble_firmware: ## clean ble_bootloader build
rm -rf $(BLE_FIRMWARE_BUILD_DIR)
clean_boardloader: ## clean boardloader build
rm -rf $(BOARDLOADER_BUILD_DIR)
@ -260,6 +276,24 @@ clean_cross: ## clean mpy-cross build
flash: flash_boardloader flash_bootloader flash_firmware ## flash everything using OpenOCD
flash_ble: flash_ble_bootloader flash_softdevice flash_ble_firmware
flash_ble_bootloader:
@echo Flashing: $(BLE_BOOTLOADER_BUILD_DIR)/ble_bootloader.hex
nrfjprog -f nrf52 --program $(BLE_BOOTLOADER_BUILD_DIR)/ble_bootloader.hex --sectorerase
flash_ble_firmware:
@echo Flashing: $(BLE_FIRMWARE_BUILD_DIR)/ble_firmware_merged.hex
nrfjprog -f nrf52 --program $(BLE_FIRMWARE_BUILD_DIR)/ble_firmware_merged.hex --sectorerase
flash_ble_bl_settings:
@echo Flashing: $(BLE_BOOTLOADER_BUILD_DIR)/settings.hex
nrfjprog -f nrf52 --program $(BLE_BOOTLOADER_BUILD_DIR)/settings.hex --sectorerase
flash_softdevice:
@echo Flashing: s140_nrf52_7.2.0_softdevice.hex
nrfjprog -f nrf52 --program embed/sdk/nrf52/components/softdevice/s140/hex/s140_nrf52_7.2.0_softdevice.hex --sectorerase
flash_boardloader: $(BOARDLOADER_BUILD_DIR)/boardloader.bin ## flash boardloader using OpenOCD
$(OPENOCD) -c "init; reset halt; flash write_image erase $< $(BOARDLOADER_START); exit"
@ -284,6 +318,9 @@ flash_combine: $(PRODTEST_BUILD_DIR)/combined.bin ## flash combined using OpenOC
flash_erase: ## erase all sectors in flash bank 0
$(OPENOCD) -c "init; reset halt; flash info 0; flash erase_sector 0 0 last; flash erase_check 0; exit"
flash_erase_ble:
nrfjprog -f nrf52 --eraseall
flash_read_storage: ## read storage sectors from flash
$(OPENOCD) -c "init; flash read_bank 0 storage1.data 0x10000 65536; flash read_bank 0 storage2.data 0x110000 65536; exit"
@ -312,6 +349,10 @@ openocd: ## start openocd which connects to the device
openocd_reset: ## cause a system reset using OpenOCD
$(OPENOCD) -c "init; reset; exit"
# nrfjprog debug commands:
nrfjprog_reset:
nrfjprog -f nrf52 --reset
GDB = arm-none-eabi-gdb --nx -ex 'set remotetimeout unlimited' -ex 'set confirm off' -ex 'target remote 127.0.0.1:3333' -ex 'monitor reset halt'
gdb_boardloader: $(BOARDLOADER_BUILD_DIR)/boardloader.elf ## start remote gdb session to openocd with boardloader symbols

@ -0,0 +1,349 @@
# pylint: disable=E0602
import os
import tools
TREZOR_MODEL = ARGUMENTS.get('TREZOR_MODEL', 'T')
CMAKELISTS = int(ARGUMENTS.get('CMAKELISTS', 0))
if TREZOR_MODEL in ('1', ):
# skip boardloader build
env = Environment()
def build_ble_bootloader(target,source,env):
print(f'BLE BOOTLOADER: nothing to build for Model {TREZOR_MODEL}')
program_bin = env.Command(
target='ble_bootloader.bin',
source=None,
action=build_ble_bootloader
)
Return()
CCFLAGS_MOD = ''
CPPPATH_MOD = []
CPPDEFINES_MOD = []
SOURCE_MOD = []
CCFLAGS_MOD += '-Wno-sequence-point '
if int(ARGUMENTS.get('PRODUCTION', 0)) == 0:
# Build for monitor debug mode and RTT.
DEBUG = True
else:
DEBUG = False
# C flags common to all targets
CPPDEFINES_MOD += [
'CONFIG_GPIO_AS_PINRESET',
'FLOAT_ABI_HARD',
'NRF52833_XXAA',
('NRF_DFU_SETTINGS_VERSION','2'),
'MBR_PRESENT',
'SVC_INTERFACE_CALL_AS_NORMAL_FUNCTION',
('__HEAP_SIZE','0'),
'__STARTUP_CLEAR_BSS',
('__START', 'main'),
('uECC_ENABLE_VLI_API', '0'),
('uECC_OPTIMIZATION_LEVEL', '3'),
('uECC_SQUARE_FUNC', '0'),
('uECC_SUPPORT_COMPRESSED_POINT', '0'),
('uECC_VLI_NATIVE_LITTLE_ENDIAN', '1'),
'ED25519_NO_PRECOMP',
]
CPPPATH_MOD += [
]
CPPDEFINES_MOD += [
]
SOURCE_MOD += [
]
CPPPATH_MOD += [
'embed/sdk/nrf52/modules/nrfx/drivers/include',
'embed/sdk/nrf52/components/libraries/memobj',
'embed/sdk/nrf52/components/libraries/crc32',
'embed/sdk/nrf52/components/libraries/experimental_section_vars',
'embed/sdk/nrf52/components/libraries/mem_manager',
'embed/sdk/nrf52/components/libraries/fstorage',
'embed/sdk/nrf52/components/libraries/util',
'embed/sdk/nrf52/modules/nrfx',
'embed/sdk/nrf52/external/nrf_oberon/include',
'embed/sdk/nrf52/components/libraries/atomic',
'embed/sdk/nrf52/integration/nrfx',
'embed/sdk/nrf52/components/libraries/crypto/backend/cc310_bl',
'embed/sdk/nrf52/components/drivers_nrf/nrf_soc_nosd',
'embed/sdk/nrf52/components/libraries/log/src',
'embed/sdk/nrf52/components/libraries/bootloader/serial_dfu',
'embed/sdk/nrf52/external/segger_rtt',
'embed/sdk/nrf52/components/libraries/delay',
'embed/sdk/nrf52/integration/nrfx/legacy',
'embed/sdk/nrf52/modules/nrfx/hal',
'embed/sdk/nrf52/components/libraries/log',
'embed/sdk/nrf52/components/libraries/strerror',
'embed/sdk/nrf52/components/libraries/bootloader',
'embed/sdk/nrf52/components/softdevice/mbr/headers',
'embed/sdk/nrf52/components/libraries/scheduler',
'embed/sdk/nrf52/components/libraries/slip',
'embed/sdk/nrf52/external/fprintf',
'embed/sdk/nrf52/components/toolchain/cmsis/include',
'embed/sdk/nrf52/components/libraries/balloc',
'embed/sdk/nrf52/components/libraries/stack_info',
'embed/sdk/nrf52/modules/nrfx/mdk',
'embed/sdk/nrf52/components/libraries/queue',
'embed/sdk/nrf52/components/libraries/mutex',
'embed/sdk/nrf52/components/libraries/ringbuf',
'embed/trezorhal/boards',
'embed/lib',
'vendor/trezor-crypto',
'vendor/nanopb',
]
SOURCE_MOD += [
]
SOURCE_NRFHAL_AS = [
'embed/sdk/nrf52/modules/nrfx/mdk/gcc_startup_nrf52833.S',
]
SOURCE_NRFHAL = [
'embed/sdk/nrf52/components/libraries/log/src/nrf_log_frontend.c',
'embed/sdk/nrf52/components/libraries/log/src/nrf_log_str_formatter.c',
'embed/sdk/nrf52/modules/nrfx/mdk/system_nrf52833.c',
'embed/sdk/nrf52/components/libraries/util/app_error_weak.c',
'embed/sdk/nrf52/components/libraries/scheduler/app_scheduler.c',
'embed/sdk/nrf52/components/libraries/util/app_util_platform.c',
'embed/sdk/nrf52/components/libraries/crc32/crc32.c',
'embed/sdk/nrf52/components/libraries/mem_manager/mem_manager.c',
'embed/sdk/nrf52/components/libraries/util/nrf_assert.c',
'embed/sdk/nrf52/components/libraries/atomic/nrf_atomic.c',
'embed/sdk/nrf52/components/libraries/balloc/nrf_balloc.c',
'embed/sdk/nrf52/external/fprintf/nrf_fprintf.c',
'embed/sdk/nrf52/external/fprintf/nrf_fprintf_format.c',
'embed/sdk/nrf52/components/libraries/fstorage/nrf_fstorage.c',
'embed/sdk/nrf52/components/libraries/fstorage/nrf_fstorage_nvmc.c',
'embed/sdk/nrf52/components/libraries/memobj/nrf_memobj.c',
'embed/sdk/nrf52/components/libraries/queue/nrf_queue.c',
'embed/sdk/nrf52/components/libraries/ringbuf/nrf_ringbuf.c',
'embed/sdk/nrf52/components/libraries/strerror/nrf_strerror.c',
'embed/sdk/nrf52/components/libraries/slip/slip.c',
'embed/sdk/nrf52/integration/nrfx/legacy/nrf_drv_uart.c',
'embed/sdk/nrf52/components/drivers_nrf/nrf_soc_nosd/nrf_nvic.c',
'embed/sdk/nrf52/modules/nrfx/hal/nrf_nvmc.c',
'embed/sdk/nrf52/components/drivers_nrf/nrf_soc_nosd/nrf_soc.c',
'embed/sdk/nrf52/modules/nrfx/soc/nrfx_atomic.c',
'embed/sdk/nrf52/modules/nrfx/drivers/src/prs/nrfx_prs.c',
'embed/sdk/nrf52/modules/nrfx/drivers/src/nrfx_uart.c',
'embed/sdk/nrf52/modules/nrfx/drivers/src/nrfx_uarte.c',
'embed/sdk/nrf52/components/libraries/bootloader/nrf_bootloader_app_start.c',
'embed/sdk/nrf52/components/libraries/bootloader/nrf_bootloader_app_start_final.c',
'embed/sdk/nrf52/components/libraries/bootloader/nrf_bootloader_dfu_timers.c',
'embed/sdk/nrf52/components/libraries/bootloader/nrf_bootloader_fw_activation.c',
'embed/sdk/nrf52/components/libraries/bootloader/nrf_bootloader_info.c',
'embed/sdk/nrf52/components/libraries/bootloader/nrf_bootloader_wdt.c',
'embed/sdk/nrf52/components/libraries/bootloader/serial_dfu/nrf_dfu_serial.c',
]
SOURCE_BLE_BOOTLOADER = [
'embed/ble_bootloader/main.c',
'embed/ble_bootloader/dfu_public_key.c',
# originally embed/sdk/nrf52/components/libraries/bootloader/serial_dfu/nrf_dfu_serial_uart.c',
'embed/ble_bootloader/nrf_dfu_serial_uart.c',
'embed/ble_bootloader/nrf_bootloader.c',
# ejected from embed/sdk/nrf52/components/libraries/bootloader/dfu
'embed/ble_bootloader/dfu/nrf_dfu_validation.c',
'embed/ble_bootloader/dfu/dfu-cc.pb.c',
'embed/ble_bootloader/dfu/nrf_dfu.c',
'embed/ble_bootloader/dfu/nrf_dfu_flash.c',
'embed/ble_bootloader/dfu/nrf_dfu_handling_error.c',
'embed/ble_bootloader/dfu/nrf_dfu_mbr.c',
'embed/ble_bootloader/dfu/nrf_dfu_req_handler.c',
'embed/ble_bootloader/dfu/nrf_dfu_settings.c',
'embed/ble_bootloader/dfu/nrf_dfu_transport.c',
'embed/ble_bootloader/dfu/nrf_dfu_utils.c',
'embed/ble_bootloader/dfu/nrf_dfu_ver_validation.c',
'vendor/trezor-crypto/blake2s.c',
'vendor/trezor-crypto/ed25519-donna/curve25519-donna-32bit.c',
'vendor/trezor-crypto/ed25519-donna/curve25519-donna-helpers.c',
'vendor/trezor-crypto/ed25519-donna/ed25519.c',
'vendor/trezor-crypto/ed25519-donna/ed25519-donna-32bit-tables.c',
'vendor/trezor-crypto/ed25519-donna/ed25519-donna-impl-base.c',
'vendor/trezor-crypto/ed25519-donna/modm-donna-32bit.c',
'vendor/trezor-crypto/memzero.c',
'vendor/trezor-crypto/sha2.c',
'vendor/nanopb/pb_common.c',
'vendor/nanopb/pb_decode.c',
'vendor/nanopb/pb_encode.c',
]
if DEBUG:
CPPDEFINES_MOD += [
'DEBUG',
'DEBUG_NRF',
'NRF_DFU_DEBUG_VERSION',
'MMD'
]
SOURCE_BLE_BOOTLOADER += [
'embed/segger/SEGGER_MMD/JLINK_MONITOR.c',
'embed/segger/SEGGER_MMD/JLINK_MONITOR_ISR_SES.S'
]
SOURCE_NRFHAL += [
'embed/sdk/nrf52/components/libraries/log/src/nrf_log_backend_rtt.c',
'embed/sdk/nrf52/components/libraries/log/src/nrf_log_backend_serial.c',
'embed/sdk/nrf52/components/libraries/log/src/nrf_log_backend_uart.c',
'embed/sdk/nrf52/components/libraries/log/src/nrf_log_default_backends.c',
'embed/sdk/nrf52/external/segger_rtt/SEGGER_RTT.c',
'embed/sdk/nrf52/external/segger_rtt/SEGGER_RTT_Syscalls_GCC.c',
'embed/sdk/nrf52/external/segger_rtt/SEGGER_RTT_printf.c',
]
CPPPATH_MOD += [
'embed/segger/SEGGER_MMD'
]
env = Environment(ENV=os.environ, CFLAGS='%s -DPRODUCTION=%s' % (ARGUMENTS.get('CFLAGS', ''), ARGUMENTS.get('PRODUCTION', '0')))
env.Replace(
CP='cp',
AS='arm-none-eabi-as',
AR='arm-none-eabi-ar',
CC='arm-none-eabi-gcc',
LINK='arm-none-eabi-gcc',
SIZE='arm-none-eabi-size',
STRIP='arm-none-eabi-strip',
OBJCOPY='arm-none-eabi-objcopy',
PYTHON='python',
MAKECMAKELISTS='$PYTHON tools/make_cmakelists.py', )
env.Replace(
TREZOR_MODEL=TREZOR_MODEL, )
CPU_ASFLAGS = '-mthumb -mabi=aapcs -mcpu=cortex-m4 -mfloat-abi=hard -mfpu=fpv4-sp-d16'
CPU_CCFLAGS = '-mthumb -mabi=aapcs -mcpu=cortex-m4 -mfloat-abi=hard -mfpu=fpv4-sp-d16 '
env.Replace(
COPT=env.get('ENV').get('OPTIMIZE', '-Os'),
CCFLAGS='$COPT '
'-g3 '
'-nostdlib '
'-std=gnu11 -Wall -Werror -Wdouble-promotion -Wpointer-arith -Wno-missing-braces -Wno-unused-function '
'-fdata-sections -ffunction-sections '
'-fno-strict-aliasing '
'-fno-builtin '
'-fshort-enums '
+ CPU_CCFLAGS + CCFLAGS_MOD,
LINKFLAGS='-Lembed/sdk/nrf52/modules/nrfx/mdk -T embed/ble_bootloader/memory.ld -Wl,--gc-sections --specs=nano.specs -Wl,-Map=build/ble_bootloader/ble_bootloader.map -Wl,--warn-common -Wl,--print-memory-usage',
CPPPATH=[
'embed/ble_bootloader',
'embed/ble_bootloader/dfu',
'embed/sdk/nrf52',
] + CPPPATH_MOD,
CPPDEFINES=[
'BLE_BOOTLOADER',
'TREZOR_MODEL_'+TREZOR_MODEL,
] + CPPDEFINES_MOD,
ASFLAGS=CPU_ASFLAGS,
ASPPFLAGS='$CFLAGS $CCFLAGS', )
#
# Program objects
#
obj_program = []
obj_program += env.Object(source=SOURCE_BLE_BOOTLOADER)
obj_program += env.Object(source=SOURCE_NRFHAL_AS, COPT='-O0')
obj_program += env.Object(source=SOURCE_NRFHAL)
obj_program += env.Object(source=SOURCE_MOD)
env.Replace(
ALLSOURCES=SOURCE_NRFHAL_AS + SOURCE_MOD + SOURCE_BLE_BOOTLOADER + SOURCE_NRFHAL,
ALLDEFS=tools.get_defs_for_cmake(env['CPPDEFINES']))
cmake_gen = env.Command(
target='CMakeLists.txt',
source='',
action='$MAKECMAKELISTS --sources $ALLSOURCES --dirs $CPPPATH --defs $ALLDEFS',
)
LIB_FILES = [
]
program_elf = env.Command(
target='ble_bootloader.elf',
source=obj_program,
action=
'$LINK -o $TARGET $CCFLAGS $CFLAGS $LINKFLAGS $SOURCES ' + ' '.join(LIB_FILES) + ' -lc -lnosys -lm',
)
BINARY_NAME = f"build/ble_bootloader/ble_bootloader-{tools.get_model_identifier(TREZOR_MODEL)}"
BINARY_NAME += "-" + tools.get_version('embed/ble_bootloader/version.h')
BINARY_NAME += "-" + tools.get_git_revision_short_hash()
BINARY_NAME += "-dirty" if tools.get_git_modified() else ""
BINARY_NAME += ".bin"
if CMAKELISTS != 0:
env.Depends(program_elf, cmake_gen)
program_hex = env.Command(
target='ble_bootloader.hex',
source=program_elf,
action='$OBJCOPY -O ihex $SOURCE $TARGET',
)
program_bin = env.Command(
target='ble_bootloader.bin',
source=program_elf,
action=[
'$OBJCOPY -O binary $SOURCE $TARGET',
'$CP $TARGET ' + BINARY_NAME,
],
)
bootloader_pkg = env.Command(
target='ble_bootloader.zip',
source=program_hex,
action=[
f'python ../../pc-nrfutil/nordicsemi/ pkg generate --hw-version 52 --sd-req=0x100 --key-file ./embed/ble_bootloader/priv.pem $TARGET --bootloader $SOURCE --bootloader-version {tools.get_version_int("embed/ble_bootloader/version.h")}'
],
)
program_settings = env.Command(
target='settings.hex',
source=None,
action='$CP ./embed/ble_bootloader/settings.hex $TARGET',
)
env.Depends(program_bin, program_hex)
env.Depends(program_bin, bootloader_pkg)
env.Depends(program_bin, program_settings)

@ -0,0 +1,508 @@
# pylint: disable=E0602
import os
import tools
TREZOR_MODEL = ARGUMENTS.get('TREZOR_MODEL', 'T')
CMAKELISTS = int(ARGUMENTS.get('CMAKELISTS', 0))
if TREZOR_MODEL in ('1', ):
# skip boardloader build
env = Environment()
def build_ble_firmware(target,source,env):
print(f'BLE FIRMWARE: nothing to build for Model {TREZOR_MODEL}')
program_bin = env.Command(
target='ble_firmware.bin',
source=None,
action=build_ble_firmware
)
Return()
CCFLAGS_MOD = ''
CPPPATH_MOD = []
CPPDEFINES_MOD = []
SOURCE_MOD = []
CCFLAGS_MOD += '-Wno-sequence-point '
if int(ARGUMENTS.get('PRODUCTION', 0)) == 0:
# Build for monitor debug mode.
MMD = True
else:
MMD = False
# C flags common to all targets
CPPDEFINES_MOD += [
'CONFIG_GPIO_AS_PINRESET',
'FLOAT_ABI_HARD',
'NRF52833_XXAA',
'SOFTDEVICE_PRESENT',
('NRF_SD_BLE_API_VERSION', '7'),
'APP_TIMER_V2',
'APP_TIMER_V2_RTC1_ENABLED',
'S140',
('__HEAP_SIZE','8192'),
('__STACK_SIZE','8192'),
'__STARTUP_CLEAR_BSS',
('__START', 'main'),
('uECC_ENABLE_VLI_API', '0'),
('uECC_OPTIMIZATION_LEVEL', '3'),
('uECC_SQUARE_FUNC', '0'),
('uECC_SUPPORT_COMPRESSED_POINT', '0'),
('uECC_VLI_NATIVE_LITTLE_ENDIAN', '1'),
]
CPPPATH_MOD += [
]
CPPDEFINES_MOD += [
]
SOURCE_MOD += [
]
CPPPATH_MOD += [
'embed/sdk/nrf52/components/nfc/ndef/generic/message',
'embed/sdk/nrf52/components/nfc/t2t_lib',
'embed/sdk/nrf52/components/nfc/t4t_parser/hl_detection_procedure',
'embed/sdk/nrf52/components/ble/ble_services/ble_ancs_c',
'embed/sdk/nrf52/components/ble/ble_services/ble_ias_c',
'embed/sdk/nrf52/components/libraries/pwm',
'embed/sdk/nrf52/components/libraries/usbd/class/cdc/acm',
'embed/sdk/nrf52/components/libraries/usbd/class/hid/generic',
'embed/sdk/nrf52/components/libraries/usbd/class/msc',
'embed/sdk/nrf52/components/libraries/usbd/class/hid',
'embed/sdk/nrf52/modules/nrfx/hal',
'embed/sdk/nrf52/components/nfc/ndef/conn_hand_parser/le_oob_rec_parser',
'embed/sdk/nrf52/components/libraries/log',
'embed/sdk/nrf52/components/ble/ble_services/ble_gls',
'embed/sdk/nrf52/components/libraries/fstorage',
'embed/sdk/nrf52/components/nfc/ndef/text',
'embed/sdk/nrf52/components/libraries/mutex',
'embed/sdk/nrf52/components/libraries/gfx',
'embed/sdk/nrf52/components/libraries/bootloader/ble_dfu',
'embed/sdk/nrf52/components/nfc/ndef/connection_handover/common',
'embed/sdk/nrf52/components/libraries/fifo',
'embed/sdk/nrf52/components/nfc/ndef/generic/record',
'embed/sdk/nrf52/components/nfc/t4t_parser/cc_file',
'embed/sdk/nrf52/components/ble/ble_advertising',
'embed/sdk/nrf52/external/utf_converter',
'embed/sdk/nrf52/components/ble/ble_services/ble_bas_c',
'embed/sdk/nrf52/modules/nrfx/drivers/include',
'embed/sdk/nrf52/components/libraries/experimental_task_manager',
'embed/sdk/nrf52/components/ble/ble_services/ble_hrs_c',
'embed/sdk/nrf52/components/softdevice/s140/headers/nrf52',
'embed/sdk/nrf52/components/nfc/ndef/connection_handover/le_oob_rec',
'embed/sdk/nrf52/components/libraries/queue',
'embed/sdk/nrf52/components/libraries/pwr_mgmt',
'embed/sdk/nrf52/components/ble/ble_dtm',
'embed/sdk/nrf52/components/toolchain/cmsis/include',
'embed/sdk/nrf52/components/ble/ble_services/ble_rscs_c',
'embed/sdk/nrf52/components/ble/common',
'embed/sdk/nrf52/components/ble/ble_services/ble_lls',
'embed/sdk/nrf52/components/nfc/platform',
'embed/sdk/nrf52/components/nfc/ndef/connection_handover/ac_rec',
'embed/sdk/nrf52/components/ble/ble_services/ble_bas',
'embed/sdk/nrf52/components/libraries/mpu',
'embed/sdk/nrf52/components/libraries/experimental_section_vars',
'embed/sdk/nrf52/components/ble/ble_services/ble_ans_c',
'embed/sdk/nrf52/components/libraries/slip',
'embed/sdk/nrf52/components/libraries/delay',
'embed/sdk/nrf52/components/libraries/csense_drv',
'embed/sdk/nrf52/components/libraries/memobj',
'embed/sdk/nrf52/components/ble/ble_services/ble_nus_c',
'embed/sdk/nrf52/components/softdevice/common',
'embed/sdk/nrf52/components/ble/ble_services/ble_ias',
'embed/sdk/nrf52/components/libraries/usbd/class/hid/mouse',
'embed/sdk/nrf52/components/libraries/low_power_pwm',
'embed/sdk/nrf52/components/nfc/ndef/conn_hand_parser/ble_oob_advdata_parser',
'embed/sdk/nrf52/components/ble/ble_services/ble_dfu',
'embed/sdk/nrf52/external/fprintf',
'embed/sdk/nrf52/components/libraries/svc',
'embed/sdk/nrf52/components/libraries/atomic',
'embed/sdk/nrf52/components',
'embed/sdk/nrf52/components/libraries/scheduler',
'embed/sdk/nrf52/components/libraries/cli',
'embed/sdk/nrf52/components/ble/ble_services/ble_lbs',
'embed/sdk/nrf52/components/ble/ble_services/ble_hts',
'embed/sdk/nrf52/components/ble/ble_services/ble_cts_c',
'embed/sdk/nrf52/components/libraries/crc16',
'embed/sdk/nrf52/components/nfc/t4t_parser/apdu',
'embed/sdk/nrf52/components/libraries/util',
'embed/sdk/nrf52/components/libraries/usbd/class/cdc',
'embed/sdk/nrf52/components/libraries/csense',
'embed/sdk/nrf52/components/libraries/balloc',
'embed/sdk/nrf52/components/libraries/ecc',
'embed/sdk/nrf52/components/libraries/hardfault',
'embed/sdk/nrf52/components/ble/ble_services/ble_cscs',
'embed/sdk/nrf52/components/libraries/uart',
'embed/sdk/nrf52/components/libraries/hci',
'embed/sdk/nrf52/components/libraries/usbd/class/hid/kbd',
'embed/sdk/nrf52/components/libraries/timer',
'embed/sdk/nrf52/components/libraries/queue',
'embed/sdk/nrf52/components/softdevice/s140/headers',
'embed/sdk/nrf52/integration/nrfx',
'embed/sdk/nrf52/components/nfc/t4t_parser/tlv',
'embed/sdk/nrf52/components/libraries/sortlist',
'embed/sdk/nrf52/components/libraries/spi_mngr',
'embed/sdk/nrf52/components/libraries/led_softblink',
'embed/sdk/nrf52/components/nfc/ndef/conn_hand_parser',
'embed/sdk/nrf52/components/libraries/sdcard',
'embed/sdk/nrf52/components/nfc/ndef/parser/record',
'embed/sdk/nrf52/modules/nrfx/mdk',
'embed/sdk/nrf52/components/ble/ble_link_ctx_manager',
'embed/sdk/nrf52/components/ble/ble_services/ble_nus',
'embed/sdk/nrf52/components/libraries/twi_mngr',
'embed/sdk/nrf52/components/ble/ble_services/ble_hids',
'embed/sdk/nrf52/components/libraries/strerror',
'embed/sdk/nrf52/components/libraries/crc32',
'embed/sdk/nrf52/components/nfc/ndef/connection_handover/ble_oob_advdata',
'embed/sdk/nrf52/components/nfc/t2t_parser',
'embed/sdk/nrf52/components/nfc/ndef/connection_handover/ble_pair_msg',
'embed/sdk/nrf52/components/libraries/usbd/class/audio',
'embed/sdk/nrf52/components/nfc/t4t_lib',
'embed/sdk/nrf52/components/ble/peer_manager',
'embed/sdk/nrf52/components/libraries/mem_manager',
'embed/sdk/nrf52/components/libraries/ringbuf',
'embed/sdk/nrf52/components/ble/ble_services/ble_tps',
'embed/sdk/nrf52/components/nfc/ndef/parser/message',
'embed/sdk/nrf52/components/ble/ble_services/ble_dis',
'embed/sdk/nrf52/components/nfc/ndef/uri',
'embed/sdk/nrf52/components/ble/nrf_ble_gatt',
'embed/sdk/nrf52/components/ble/nrf_ble_qwr',
'embed/sdk/nrf52/components/libraries/gpiote',
'embed/sdk/nrf52/components/libraries/button',
'embed/sdk/nrf52/modules/nrfx',
'embed/sdk/nrf52/components/libraries/twi_sensor',
'embed/sdk/nrf52/integration/nrfx/legacy',
'embed/sdk/nrf52/components/libraries/usbd',
'embed/sdk/nrf52/components/nfc/ndef/connection_handover/ep_oob_rec',
'embed/sdk/nrf52/external/segger_rtt',
'embed/sdk/nrf52/components/libraries/atomic_fifo',
'embed/sdk/nrf52/components/ble/ble_services/ble_lbs_c',
'embed/sdk/nrf52/components/nfc/ndef/connection_handover/ble_pair_lib',
'embed/sdk/nrf52/components/libraries/crypto',
'embed/sdk/nrf52/components/libraries/crypto/backend/cc310',
'embed/sdk/nrf52/components/libraries/crypto/backend/cc310_bl',
'embed/sdk/nrf52/components/libraries/crypto/backend/micro_ecc',
'embed/sdk/nrf52/components/libraries/crypto/backend/mbedtls',
'embed/sdk/nrf52/components/libraries/crypto/backend/oberon',
'embed/sdk/nrf52/components/libraries/crypto/backend/optiga',
'embed/sdk/nrf52/components/libraries/crypto/backend/nrf_sw',
'embed/sdk/nrf52/components/libraries/crypto/backend/nrf_hw',
'embed/sdk/nrf52/components/libraries/crypto/backend/cifra',
'embed/sdk/nrf52/components/ble/ble_racp',
'embed/sdk/nrf52/components/libraries/fds',
'embed/sdk/nrf52/components/nfc/ndef/launchapp',
'embed/sdk/nrf52/components/libraries/atomic_flags',
'embed/sdk/nrf52/components/ble/ble_services/ble_hrs',
'embed/sdk/nrf52/components/ble/ble_services/ble_rscs',
'embed/sdk/nrf52/components/nfc/ndef/connection_handover/hs_rec',
'embed/sdk/nrf52/components/nfc/ndef/conn_hand_parser/ac_rec_parser',
'embed/sdk/nrf52/components/libraries/stack_guard',
'embed/sdk/nrf52/components/libraries/stack_info',
'embed/sdk/nrf52/components/libraries/log/src',
'embed/sdk/nrf52/external/mbedtls/include',
'embed',
'embed/trezorhal/boards',
]
SOURCE_MOD += [
]
SOURCE_NRFHAL_AS = [
'embed/sdk/nrf52/modules/nrfx/mdk/gcc_startup_nrf52833.S',
]
SOURCE_NRFHAL = [
'embed/sdk/nrf52/components/libraries/log/src/nrf_log_frontend.c',
'embed/sdk/nrf52/components/libraries/log/src/nrf_log_str_formatter.c',
'embed/sdk/nrf52/components/libraries/button/app_button.c',
'embed/sdk/nrf52/components/libraries/util/app_error.c',
'embed/sdk/nrf52/components/libraries/util/app_error_handler_gcc.c',
'embed/sdk/nrf52/components/libraries/util/app_error_weak.c',
'embed/sdk/nrf52/components/libraries/fifo/app_fifo.c',
'embed/sdk/nrf52/components/libraries/scheduler/app_scheduler.c',
'embed/sdk/nrf52/components/libraries/timer/app_timer2.c',
'embed/sdk/nrf52/components/libraries/uart/app_uart_fifo.c',
'embed/sdk/nrf52/components/libraries/util/app_util_platform.c',
'embed/sdk/nrf52/components/libraries/timer/drv_rtc.c',
'embed/sdk/nrf52/components/libraries/hardfault/hardfault_implementation.c',
'embed/sdk/nrf52/components/libraries/util/nrf_assert.c',
'embed/sdk/nrf52/components/libraries/atomic_fifo/nrf_atfifo.c',
'embed/sdk/nrf52/components/libraries/atomic_flags/nrf_atflags.c',
'embed/sdk/nrf52/components/libraries/atomic/nrf_atomic.c',
'embed/sdk/nrf52/components/libraries/balloc/nrf_balloc.c',
'embed/sdk/nrf52/external/fprintf/nrf_fprintf.c',
'embed/sdk/nrf52/external/fprintf/nrf_fprintf_format.c',
'embed/sdk/nrf52/components/libraries/memobj/nrf_memobj.c',
'embed/sdk/nrf52/components/libraries/pwr_mgmt/nrf_pwr_mgmt.c',
'embed/sdk/nrf52/components/libraries/ringbuf/nrf_ringbuf.c',
'embed/sdk/nrf52/components/libraries/experimental_section_vars/nrf_section_iter.c',
'embed/sdk/nrf52/components/libraries/sortlist/nrf_sortlist.c',
'embed/sdk/nrf52/components/libraries/strerror/nrf_strerror.c',
'embed/sdk/nrf52/components/libraries/uart/retarget.c',
'embed/sdk/nrf52/components/libraries/queue/nrf_queue.c',
'embed/sdk/nrf52/modules/nrfx/mdk/system_nrf52833.c',
'embed/sdk/nrf52/integration/nrfx/legacy/nrf_drv_clock.c',
'embed/sdk/nrf52/integration/nrfx/legacy/nrf_drv_uart.c',
'embed/sdk/nrf52/integration/nrfx/legacy/nrf_drv_spi.c',
'embed/sdk/nrf52/integration/nrfx/legacy/nrf_drv_rng.c',
'embed/sdk/nrf52/modules/nrfx/soc/nrfx_atomic.c',
'embed/sdk/nrf52/modules/nrfx/drivers/src/nrfx_clock.c',
'embed/sdk/nrf52/modules/nrfx/drivers/src/nrfx_gpiote.c',
'embed/sdk/nrf52/modules/nrfx/drivers/src/prs/nrfx_prs.c',
'embed/sdk/nrf52/modules/nrfx/drivers/src/nrfx_uart.c',
'embed/sdk/nrf52/modules/nrfx/drivers/src/nrfx_uarte.c',
'embed/sdk/nrf52/modules/nrfx/drivers/src/nrfx_rng.c',
'embed/sdk/nrf52/modules/nrfx/drivers/src/nrfx_spi.c',
'embed/sdk/nrf52/modules/nrfx/drivers/src/nrfx_spim.c',
'embed/sdk/nrf52/components/ble/common/ble_advdata.c',
'embed/sdk/nrf52/components/ble/ble_advertising/ble_advertising.c',
'embed/sdk/nrf52/components/ble/common/ble_conn_params.c',
'embed/sdk/nrf52/components/ble/common/ble_conn_state.c',
'embed/sdk/nrf52/components/ble/ble_link_ctx_manager/ble_link_ctx_manager.c',
'embed/sdk/nrf52/components/ble/common/ble_srv_common.c',
'embed/sdk/nrf52/components/ble/nrf_ble_gatt/nrf_ble_gatt.c',
'embed/sdk/nrf52/components/ble/nrf_ble_qwr/nrf_ble_qwr.c',
'embed/sdk/nrf52/external/utf_converter/utf.c',
'embed/sdk/nrf52/components/softdevice/common/nrf_sdh.c',
'embed/sdk/nrf52/components/softdevice/common/nrf_sdh_ble.c',
'embed/sdk/nrf52/components/softdevice/common/nrf_sdh_soc.c',
'embed/sdk/nrf52/components/ble/peer_manager/gatt_cache_manager.c',
'embed/sdk/nrf52/components/ble/peer_manager/gatts_cache_manager.c',
'embed/sdk/nrf52/components/ble/peer_manager/id_manager.c',
'embed/sdk/nrf52/components/ble/peer_manager/peer_data_storage.c',
'embed/sdk/nrf52/components/ble/peer_manager/peer_database.c',
'embed/sdk/nrf52/components/ble/peer_manager/peer_id.c',
'embed/sdk/nrf52/components/ble/peer_manager/peer_manager.c',
'embed/sdk/nrf52/components/ble/peer_manager/peer_manager_handler.c',
'embed/sdk/nrf52/components/ble/peer_manager/pm_buffer.c',
'embed/sdk/nrf52/components/ble/peer_manager/nrf_ble_lesc.c',
'embed/sdk/nrf52/components/libraries/fds/fds.c',
'embed/sdk/nrf52/components/ble/peer_manager/security_manager.c',
'embed/sdk/nrf52/components/ble/peer_manager/security_dispatcher.c',
'embed/sdk/nrf52/components/libraries/fstorage/nrf_fstorage.c',
'embed/sdk/nrf52/components/libraries/fstorage/nrf_fstorage_sd.c',
'embed/sdk/nrf52/components/ble/ble_services/ble_dis/ble_dis.c',
'embed/sdk/nrf52/components/libraries/crypto/backend/micro_ecc/micro_ecc_backend_ecc.c',
'embed/sdk/nrf52/components/libraries/crypto/backend/micro_ecc/micro_ecc_backend_ecdh.c',
'embed/sdk/nrf52/components/libraries/crypto/backend/micro_ecc/micro_ecc_backend_ecdsa.c',
'embed/sdk/nrf52/components/libraries/crypto/backend/nrf_hw/nrf_hw_backend_rng_mbedtls.c',
'embed/sdk/nrf52/components/libraries/crypto/nrf_crypto_ecc.c',
'embed/sdk/nrf52/components/libraries/crypto/nrf_crypto_ecdsa.c',
'embed/sdk/nrf52/components/libraries/crypto/nrf_crypto_ecdh.c',
'embed/sdk/nrf52/components/libraries/crypto/nrf_crypto_hash.c',
'embed/sdk/nrf52/components/libraries/crypto/nrf_crypto_init.c',
'embed/sdk/nrf52/components/libraries/crypto/nrf_crypto_shared.c',
'embed/sdk/nrf52/components/libraries/crypto/nrf_crypto_rng.c',
'embed/sdk/nrf52/external/mbedtls/library/ctr_drbg.c',
'embed/sdk/nrf52/external/mbedtls/library/aes.c',
'embed/sdk/nrf52/external/mbedtls/library/platform.c',
'embed/sdk/nrf52/external/mbedtls/library/platform_util.c',
]
SOURCE_NANOPB = [
'vendor/nanopb/pb_common.c',
'vendor/nanopb/pb_decode.c',
'vendor/nanopb/pb_encode.c',
]
SOURCE_BLE_FIRMWARE = [
'embed/ble_firmware/main.c',
'embed/ble_firmware/ble_nus.c',
'embed/ble_firmware/int_comm.c',
'embed/ble_firmware/dis.c',
'embed/ble_firmware/pm.c',
'embed/ble_firmware/power.c',
'embed/ble_firmware/advertising.c',
'embed/ble_firmware/connection.c',
'embed/ble_firmware/uecc/uECC.c',
'embed/bootloader/protob/messages.pb.c',
'embed/lib/protob_helpers.c',
]
if MMD:
CPPDEFINES_MOD += [
'DEBUG',
'DEBUG_NRF',
'MMD'
]
SOURCE_BLE_FIRMWARE += [
'embed/segger/SEGGER_MMD/JLINK_MONITOR.c',
'embed/segger/SEGGER_MMD/JLINK_MONITOR_ISR_SES.S'
]
SOURCE_NRFHAL += [
'embed/sdk/nrf52/components/libraries/log/src/nrf_log_backend_rtt.c',
'embed/sdk/nrf52/components/libraries/log/src/nrf_log_backend_serial.c',
'embed/sdk/nrf52/components/libraries/log/src/nrf_log_backend_uart.c',
'embed/sdk/nrf52/components/libraries/log/src/nrf_log_default_backends.c',
'embed/sdk/nrf52/external/segger_rtt/SEGGER_RTT.c',
'embed/sdk/nrf52/external/segger_rtt/SEGGER_RTT_Syscalls_GCC.c',
'embed/sdk/nrf52/external/segger_rtt/SEGGER_RTT_printf.c',
]
CPPPATH_MOD += [
'embed/segger/SEGGER_MMD'
]
env = Environment(ENV=os.environ, CFLAGS='%s -DPRODUCTION=%s' % (ARGUMENTS.get('CFLAGS', ''), ARGUMENTS.get('PRODUCTION', '0')))
env.Replace(
CP='cp',
AS='arm-none-eabi-as',
AR='arm-none-eabi-ar',
CC='arm-none-eabi-gcc',
LINK='arm-none-eabi-gcc',
SIZE='arm-none-eabi-size',
STRIP='arm-none-eabi-strip',
OBJCOPY='arm-none-eabi-objcopy',
PYTHON='python',
MAKECMAKELISTS='$PYTHON tools/make_cmakelists.py', )
env.Replace(
TREZOR_MODEL=TREZOR_MODEL, )
CPU_ASFLAGS = '-mthumb -mabi=aapcs -mcpu=cortex-m4 -mfloat-abi=hard -mfpu=fpv4-sp-d16'
CPU_CCFLAGS = '-mthumb -mabi=aapcs -mcpu=cortex-m4 -mfloat-abi=hard -mfpu=fpv4-sp-d16 '
env.Replace(
COPT=env.get('ENV').get('OPTIMIZE', '-Os'),
CCFLAGS='$COPT '
'-g3 '
'-std=gnu11 -Wall -Werror -Wdouble-promotion -Wpointer-arith -Wno-missing-braces -Wno-unused-function '
'-fdata-sections -ffunction-sections '
'-fno-strict-aliasing '
'-fno-builtin '
'-fshort-enums '
+ CPU_CCFLAGS + CCFLAGS_MOD,
LINKFLAGS='-Lembed/sdk/nrf52/modules/nrfx/mdk -T embed/ble_firmware/memory.ld -Wl,--gc-sections --specs=nano.specs -Wl,-Map=build/ble_firmware/ble_firmware.map -Wl,--warn-common -Wl,--print-memory-usage',
CPPPATH=[
'embed/ble_firmware',
'embed/bootloader/protob',
'embed/ble_bootloader/dfu',
'embed/sdk/nrf52',
'embed/lib',
'vendor/nanopb',
'embed/ble_firmware/uecc',
] + CPPPATH_MOD,
CPPDEFINES=[
'BLE_FIRMWARE',
'TREZOR_MODEL_'+TREZOR_MODEL,
] + CPPDEFINES_MOD,
ASFLAGS=CPU_ASFLAGS,
ASPPFLAGS='$CFLAGS $CCFLAGS', )
#
# Program objects
#
obj_program = []
obj_program += env.Object(source=SOURCE_BLE_FIRMWARE)
obj_program += env.Object(source=SOURCE_NRFHAL_AS, COPT='-O0')
obj_program += env.Object(source=SOURCE_NRFHAL)
obj_program += env.Object(source=SOURCE_NANOPB)
obj_program += env.Object(source=SOURCE_MOD)
env.Replace(
ALLSOURCES=SOURCE_NRFHAL_AS + SOURCE_MOD + SOURCE_BLE_FIRMWARE + SOURCE_NRFHAL,
ALLDEFS=tools.get_defs_for_cmake(env['CPPDEFINES']))
cmake_gen = env.Command(
target='CMakeLists.txt',
source='',
action='$MAKECMAKELISTS --sources $ALLSOURCES --dirs $CPPPATH --defs $ALLDEFS',
)
LIB_FILES = [
]
program_elf = env.Command(
target='ble_firmware.elf',
source=obj_program,
action=
'$LINK -o $TARGET $CCFLAGS $CFLAGS $LINKFLAGS $SOURCES ' + ' '.join(LIB_FILES) + ' -lc -lnosys -lm',
)
BINARY_NAME = f"build/ble_firmware/ble_firmware-{tools.get_model_identifier(TREZOR_MODEL)}"
BINARY_NAME += "-" + tools.get_version('embed/ble_firmware/version.h')
BINARY_NAME += "-" + tools.get_git_revision_short_hash()
BINARY_NAME += "-dirty" if tools.get_git_modified() else ""
BINARY_NAME += ".bin"
if CMAKELISTS != 0:
env.Depends(program_elf, cmake_gen)
program_hex = env.Command(
target='ble_firmware.hex',
source=program_elf,
action='$OBJCOPY -O ihex $SOURCE $TARGET',
)
program_pkg = env.Command(
target='ble_firmware.zip',
source=program_hex,
action=[
f'python ../../pc-nrfutil/nordicsemi/ pkg generate --hw-version 52 --sd-req=0x100 --application $SOURCE --key-file ./embed/ble_bootloader/priv.pem $TARGET --application-version-string {tools.get_version("embed/ble_firmware/version.h")}'
],
)
softdevice_pkg = env.Command(
target='ble_softdevice.zip',
source=None,
action=[
f'python ../../pc-nrfutil/nordicsemi/ pkg generate --hw-version 52 --sd-req=0x100 --key-file ./embed/ble_bootloader/priv.pem $TARGET --sd-id=0x100 --softdevice ./embed/sdk/nrf52/components/softdevice/s140/hex/s140_nrf52_7.2.0_softdevice.hex'
],
)
settings = env.Command(
target='settings.hex',
source=program_hex,
action=f'python ../../pc-nrfutil/nordicsemi/ settings generate --family NRF52 --application $SOURCE --application-version-string {tools.get_version("embed/ble_firmware/version.h")} --bootloader-version {tools.get_version_int("embed/ble_bootloader/version.h")} --softdevice ./embed/sdk/nrf52/components/softdevice/s140/hex/s140_nrf52_7.2.0_softdevice.hex --key-file ./embed/ble_bootloader/priv.pem $TARGET',
)
program_merge = env.Command(
target='ble_firmware_merged.hex',
source=[program_hex, settings],
action='mergehex -m $SOURCES -o $TARGET',
)
program_bin = env.Command(
target='ble_firmware.bin',
source=program_elf,
action=[
'$OBJCOPY -O binary $SOURCE $TARGET',
'$CP $TARGET ' + BINARY_NAME,
],
)
env.Depends(program_bin, program_hex)
env.Depends(program_pkg, program_hex)
env.Depends(settings, program_hex)
env.Depends(program_bin, program_pkg)
env.Depends(program_bin, softdevice_pkg)
env.Depends(program_merge, settings)
env.Depends(program_merge, program_hex)
env.Depends(program_bin, program_merge)

@ -1,5 +1,7 @@
# pylint: disable=E0602
SConscript('SConscript.ble_bootloader', variant_dir='build/ble_bootloader', duplicate=False)
SConscript('SConscript.ble_firmware', variant_dir='build/ble_firmware', duplicate=False)
SConscript('SConscript.boardloader', variant_dir='build/boardloader', duplicate=False)
SConscript('SConscript.bootloader', variant_dir='build/bootloader', duplicate=False)
SConscript('SConscript.bootloader_ci', variant_dir='build/bootloader_ci', duplicate=False)

@ -0,0 +1,5 @@
dfu.Hash.hash max_size:32
dfu.SignedCommand.signature max_size:64
dfu.InitCommand.sd_req max_count:16
dfu.InitCommand.boot_validation max_count:3
dfu.BootValidation.bytes max_size:64

@ -0,0 +1,30 @@
/* Automatically generated nanopb constant definitions */
/* Generated by nanopb-0.4.5 */
#include "dfu-cc.pb.h"
#if PB_PROTO_HEADER_VERSION != 40
#error Regenerate this file with the current version of nanopb generator.
#endif
PB_BIND(dfu_Hash, dfu_Hash, AUTO)
PB_BIND(dfu_BootValidation, dfu_BootValidation, AUTO)
PB_BIND(dfu_InitCommand, dfu_InitCommand, 2)
PB_BIND(dfu_Command, dfu_Command, 2)
PB_BIND(dfu_SignedCommand, dfu_SignedCommand, 2)
PB_BIND(dfu_Packet, dfu_Packet, 2)

@ -0,0 +1,228 @@
/* Automatically generated nanopb header */
/* Generated by nanopb-0.4.5 */
#ifndef PB_DFU_DFU_CC_PB_H_INCLUDED
#define PB_DFU_DFU_CC_PB_H_INCLUDED
#include <pb.h>
#if PB_PROTO_HEADER_VERSION != 40
#error Regenerate this file with the current version of nanopb generator.
#endif
/* Enum definitions */
typedef enum _dfu_FwType {
dfu_FwType_APPLICATION = 0,
dfu_FwType_SOFTDEVICE = 1,
dfu_FwType_BOOTLOADER = 2,
dfu_FwType_SOFTDEVICE_BOOTLOADER = 3,
dfu_FwType_EXTERNAL_APPLICATION = 4
} dfu_FwType;
typedef enum _dfu_HashType {
dfu_HashType_NO_HASH = 0,
dfu_HashType_CRC = 1,
dfu_HashType_SHA128 = 2,
dfu_HashType_SHA256 = 3,
dfu_HashType_SHA512 = 4
} dfu_HashType;
typedef enum _dfu_OpCode {
dfu_OpCode_INIT = 1
} dfu_OpCode;
/* Struct definitions */
typedef PB_BYTES_ARRAY_T(64) dfu_BootValidation_bytes_t;
typedef struct _dfu_BootValidation {
uint32_t sigmask;
dfu_BootValidation_bytes_t bytes;
} dfu_BootValidation;
typedef PB_BYTES_ARRAY_T(32) dfu_Hash_hash_t;
typedef struct _dfu_Hash {
dfu_HashType hash_type;
dfu_Hash_hash_t hash;
} dfu_Hash;
/* Commands data */
typedef struct _dfu_InitCommand {
bool has_fw_version;
uint32_t fw_version;
bool has_hw_version;
uint32_t hw_version;
pb_size_t sd_req_count;
uint32_t sd_req[16];
bool has_type;
dfu_FwType type;
bool has_sd_size;
uint32_t sd_size;
bool has_bl_size;
uint32_t bl_size;
bool has_app_size;
uint32_t app_size;
bool has_hash;
dfu_Hash hash;
bool has_is_debug;
bool is_debug;
pb_size_t boot_validation_count;
dfu_BootValidation boot_validation[3];
} dfu_InitCommand;
/* Command type */
typedef struct _dfu_Command {
bool has_op_code;
dfu_OpCode op_code;
bool has_init;
dfu_InitCommand init;
} dfu_Command;
typedef PB_BYTES_ARRAY_T(64) dfu_SignedCommand_signature_t;
typedef struct _dfu_SignedCommand {
dfu_Command command;
uint32_t sigmask;
dfu_SignedCommand_signature_t signature;
} dfu_SignedCommand;
/* Parent packet type */
typedef struct _dfu_Packet {
bool has_command;
dfu_Command command;
bool has_signed_command;
dfu_SignedCommand signed_command;
} dfu_Packet;
/* Helper constants for enums */
#define _dfu_FwType_MIN dfu_FwType_APPLICATION
#define _dfu_FwType_MAX dfu_FwType_EXTERNAL_APPLICATION
#define _dfu_FwType_ARRAYSIZE ((dfu_FwType)(dfu_FwType_EXTERNAL_APPLICATION+1))
#define _dfu_HashType_MIN dfu_HashType_NO_HASH
#define _dfu_HashType_MAX dfu_HashType_SHA512
#define _dfu_HashType_ARRAYSIZE ((dfu_HashType)(dfu_HashType_SHA512+1))
#define _dfu_OpCode_MIN dfu_OpCode_INIT
#define _dfu_OpCode_MAX dfu_OpCode_INIT
#define _dfu_OpCode_ARRAYSIZE ((dfu_OpCode)(dfu_OpCode_INIT+1))
#ifdef __cplusplus
extern "C" {
#endif
/* Initializer values for message structs */
#define dfu_Hash_init_default {_dfu_HashType_MIN, {0, {0}}}
#define dfu_BootValidation_init_default {0, {0, {0}}}
#define dfu_InitCommand_init_default {false, 0, false, 0, 0, {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, false, _dfu_FwType_MIN, false, 0, false, 0, false, 0, false, dfu_Hash_init_default, false, false, 0, {dfu_BootValidation_init_default, dfu_BootValidation_init_default, dfu_BootValidation_init_default}}
#define dfu_Command_init_default {false, _dfu_OpCode_MIN, false, dfu_InitCommand_init_default}
#define dfu_SignedCommand_init_default {dfu_Command_init_default, 0, {0, {0}}}
#define dfu_Packet_init_default {false, dfu_Command_init_default, false, dfu_SignedCommand_init_default}
#define dfu_Hash_init_zero {_dfu_HashType_MIN, {0, {0}}}
#define dfu_BootValidation_init_zero {0, {0, {0}}}
#define dfu_InitCommand_init_zero {false, 0, false, 0, 0, {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, false, _dfu_FwType_MIN, false, 0, false, 0, false, 0, false, dfu_Hash_init_zero, false, 0, 0, {dfu_BootValidation_init_zero, dfu_BootValidation_init_zero, dfu_BootValidation_init_zero}}
#define dfu_Command_init_zero {false, _dfu_OpCode_MIN, false, dfu_InitCommand_init_zero}
#define dfu_SignedCommand_init_zero {dfu_Command_init_zero, 0, {0, {0}}}
#define dfu_Packet_init_zero {false, dfu_Command_init_zero, false, dfu_SignedCommand_init_zero}
/* Field tags (for use in manual encoding/decoding) */
#define dfu_BootValidation_sigmask_tag 1
#define dfu_BootValidation_bytes_tag 2
#define dfu_Hash_hash_type_tag 1
#define dfu_Hash_hash_tag 2
#define dfu_InitCommand_fw_version_tag 1
#define dfu_InitCommand_hw_version_tag 2
#define dfu_InitCommand_sd_req_tag 3
#define dfu_InitCommand_type_tag 4
#define dfu_InitCommand_sd_size_tag 5
#define dfu_InitCommand_bl_size_tag 6
#define dfu_InitCommand_app_size_tag 7
#define dfu_InitCommand_hash_tag 8
#define dfu_InitCommand_is_debug_tag 9
#define dfu_InitCommand_boot_validation_tag 10
#define dfu_Command_op_code_tag 1
#define dfu_Command_init_tag 2
#define dfu_SignedCommand_command_tag 1
#define dfu_SignedCommand_sigmask_tag 2
#define dfu_SignedCommand_signature_tag 3
#define dfu_Packet_command_tag 1
#define dfu_Packet_signed_command_tag 2
/* Struct field encoding specification for nanopb */
#define dfu_Hash_FIELDLIST(X, a) \
X(a, STATIC, REQUIRED, UENUM, hash_type, 1) \
X(a, STATIC, REQUIRED, BYTES, hash, 2)
#define dfu_Hash_CALLBACK NULL
#define dfu_Hash_DEFAULT NULL
#define dfu_BootValidation_FIELDLIST(X, a) \
X(a, STATIC, REQUIRED, UINT32, sigmask, 1) \
X(a, STATIC, REQUIRED, BYTES, bytes, 2)
#define dfu_BootValidation_CALLBACK NULL
#define dfu_BootValidation_DEFAULT NULL
#define dfu_InitCommand_FIELDLIST(X, a) \
X(a, STATIC, OPTIONAL, UINT32, fw_version, 1) \
X(a, STATIC, OPTIONAL, UINT32, hw_version, 2) \
X(a, STATIC, REPEATED, UINT32, sd_req, 3) \
X(a, STATIC, OPTIONAL, UENUM, type, 4) \
X(a, STATIC, OPTIONAL, UINT32, sd_size, 5) \
X(a, STATIC, OPTIONAL, UINT32, bl_size, 6) \
X(a, STATIC, OPTIONAL, UINT32, app_size, 7) \
X(a, STATIC, OPTIONAL, MESSAGE, hash, 8) \
X(a, STATIC, OPTIONAL, BOOL, is_debug, 9) \
X(a, STATIC, REPEATED, MESSAGE, boot_validation, 10)
#define dfu_InitCommand_CALLBACK NULL
#define dfu_InitCommand_DEFAULT (const pb_byte_t*)"\x48\x00\x00"
#define dfu_InitCommand_hash_MSGTYPE dfu_Hash
#define dfu_InitCommand_boot_validation_MSGTYPE dfu_BootValidation
#define dfu_Command_FIELDLIST(X, a) \
X(a, STATIC, OPTIONAL, UENUM, op_code, 1) \
X(a, STATIC, OPTIONAL, MESSAGE, init, 2)
#define dfu_Command_CALLBACK NULL
#define dfu_Command_DEFAULT (const pb_byte_t*)"\x08\x01\x00"
#define dfu_Command_init_MSGTYPE dfu_InitCommand
#define dfu_SignedCommand_FIELDLIST(X, a) \
X(a, STATIC, REQUIRED, MESSAGE, command, 1) \
X(a, STATIC, REQUIRED, UINT32, sigmask, 2) \
X(a, STATIC, REQUIRED, BYTES, signature, 3)
#define dfu_SignedCommand_CALLBACK NULL
#define dfu_SignedCommand_DEFAULT NULL
#define dfu_SignedCommand_command_MSGTYPE dfu_Command
#define dfu_Packet_FIELDLIST(X, a) \
X(a, STATIC, OPTIONAL, MESSAGE, command, 1) \
X(a, STATIC, OPTIONAL, MESSAGE, signed_command, 2)
#define dfu_Packet_CALLBACK NULL
#define dfu_Packet_DEFAULT NULL
#define dfu_Packet_command_MSGTYPE dfu_Command
#define dfu_Packet_signed_command_MSGTYPE dfu_SignedCommand
extern const pb_msgdesc_t dfu_Hash_msg;
extern const pb_msgdesc_t dfu_BootValidation_msg;
extern const pb_msgdesc_t dfu_InitCommand_msg;
extern const pb_msgdesc_t dfu_Command_msg;
extern const pb_msgdesc_t dfu_SignedCommand_msg;
extern const pb_msgdesc_t dfu_Packet_msg;
/* Defines for backwards compatibility with code written before nanopb-0.4.0 */
#define dfu_Hash_fields &dfu_Hash_msg
#define dfu_BootValidation_fields &dfu_BootValidation_msg
#define dfu_InitCommand_fields &dfu_InitCommand_msg
#define dfu_Command_fields &dfu_Command_msg
#define dfu_SignedCommand_fields &dfu_SignedCommand_msg
#define dfu_Packet_fields &dfu_Packet_msg
/* Maximum encoded size of messages (where known) */
#define dfu_BootValidation_size 72
#define dfu_Command_size 395
#define dfu_Hash_size 36
#define dfu_InitCommand_size 390
#define dfu_Packet_size 871
#define dfu_SignedCommand_size 470
#ifdef __cplusplus
} /* extern "C" */
#endif
#endif

@ -0,0 +1,69 @@
package dfu;
// Version 0.1
enum FwType {
APPLICATION = 0;
SOFTDEVICE = 1;
BOOTLOADER = 2;
SOFTDEVICE_BOOTLOADER = 3;
EXTERNAL_APPLICATION = 4;
}
enum HashType {
NO_HASH = 0;
CRC = 1;
SHA128 = 2;
SHA256 = 3;
SHA512 = 4;
}
enum OpCode {
INIT = 1;
}
message Hash {
required HashType hash_type = 1;
required bytes hash = 2;
}
message BootValidation {
required uint32 sigmask = 1;
required bytes bytes = 2;
}
// Commands data
message InitCommand {
optional uint32 fw_version = 1;
optional uint32 hw_version = 2;
repeated uint32 sd_req = 3 [packed = true];
optional FwType type = 4;
optional uint32 sd_size = 5;
optional uint32 bl_size = 6;
optional uint32 app_size = 7;
optional Hash hash = 8;
optional bool is_debug = 9 [default = false];
repeated BootValidation boot_validation = 10;
}
// Command type
message Command {
optional OpCode op_code = 1;
optional InitCommand init = 2;
}
message SignedCommand {
required Command command = 1;
required uint32 sigmask = 2;
required bytes signature = 3;
}
// Parent packet type
message Packet {
optional Command command = 1;
optional SignedCommand signed_command = 2;
}

@ -0,0 +1,98 @@
/**
* Copyright (c) 2016 - 2021, Nordic Semiconductor ASA
*
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without modification,
* are permitted provided that the following conditions are met:
*
* 1. Redistributions of source code must retain the above copyright notice, this
* list of conditions and the following disclaimer.
*
* 2. Redistributions in binary form, except as embedded into a Nordic
* Semiconductor ASA integrated circuit in a product or a software update for
* such product, must reproduce the above copyright notice, this list of
* conditions and the following disclaimer in the documentation and/or other
* materials provided with the distribution.
*
* 3. Neither the name of Nordic Semiconductor ASA nor the names of its
* contributors may be used to endorse or promote products derived from this
* software without specific prior written permission.
*
* 4. This software, with or without modification, must only be used with a
* Nordic Semiconductor ASA integrated circuit.
*
* 5. Any software provided in binary form under this license must not be reverse
* engineered, decompiled, modified and/or disassembled.
*
* THIS SOFTWARE IS PROVIDED BY NORDIC SEMICONDUCTOR ASA "AS IS" AND ANY EXPRESS
* OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
* OF MERCHANTABILITY, NONINFRINGEMENT, AND FITNESS FOR A PARTICULAR PURPOSE ARE
* DISCLAIMED. IN NO EVENT SHALL NORDIC SEMICONDUCTOR ASA OR CONTRIBUTORS BE
* LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE
* GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
* OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*
*/
#include "nrf_dfu.h"
#include "nrf_dfu_utils.h"
#include "nrf_dfu_transport.h"
#include "nrf_dfu_req_handler.h"
#include "nrf_log.h"
static nrf_dfu_observer_t m_user_observer; //<! Observer callback set by the user.
/**
* @brief This function calls the user's observer (@ref m_observer) after it is done handling the event.
*/
static void dfu_observer(nrf_dfu_evt_type_t event)
{
switch (event)
{
case NRF_DFU_EVT_DFU_COMPLETED:
case NRF_DFU_EVT_DFU_ABORTED:
#ifndef NRF_DFU_NO_TRANSPORT
UNUSED_RETURN_VALUE(nrf_dfu_transports_close(NULL));
#endif
break;
default:
break;
}
/* Call user's observer if present. */
if (m_user_observer)
{
m_user_observer(event);
}
}
uint32_t nrf_dfu_init(nrf_dfu_observer_t observer)
{
uint32_t ret_val;
m_user_observer = observer;
NRF_LOG_INFO("Entering DFU mode.");
dfu_observer(NRF_DFU_EVT_DFU_INITIALIZED);
// Initializing transports
ret_val = nrf_dfu_transports_init(dfu_observer);
if (ret_val != NRF_SUCCESS)
{
NRF_LOG_ERROR("Could not initalize DFU transport: 0x%08x", ret_val);
return ret_val;
}
ret_val = nrf_dfu_req_handler_init(dfu_observer);
return ret_val;
}

@ -0,0 +1,85 @@
/**
* Copyright (c) 2016 - 2021, Nordic Semiconductor ASA
*
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without modification,
* are permitted provided that the following conditions are met:
*
* 1. Redistributions of source code must retain the above copyright notice, this
* list of conditions and the following disclaimer.
*
* 2. Redistributions in binary form, except as embedded into a Nordic
* Semiconductor ASA integrated circuit in a product or a software update for
* such product, must reproduce the above copyright notice, this list of
* conditions and the following disclaimer in the documentation and/or other
* materials provided with the distribution.
*
* 3. Neither the name of Nordic Semiconductor ASA nor the names of its
* contributors may be used to endorse or promote products derived from this
* software without specific prior written permission.
*
* 4. This software, with or without modification, must only be used with a
* Nordic Semiconductor ASA integrated circuit.
*
* 5. Any software provided in binary form under this license must not be reverse
* engineered, decompiled, modified and/or disassembled.
*
* THIS SOFTWARE IS PROVIDED BY NORDIC SEMICONDUCTOR ASA "AS IS" AND ANY EXPRESS
* OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
* OF MERCHANTABILITY, NONINFRINGEMENT, AND FITNESS FOR A PARTICULAR PURPOSE ARE
* DISCLAIMED. IN NO EVENT SHALL NORDIC SEMICONDUCTOR ASA OR CONTRIBUTORS BE
* LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE
* GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
* OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*
*/
/**@file
*
* @defgroup nrf_dfu DFU modules
* @{
* @ingroup nrf_bootloader
* @brief Modules providing Device Firmware Update (DFU) functionality.
*
* The DFU module, in combination with the @ref nrf_bootloader module,
* can be used to implement a bootloader that supports Device Firmware Updates.
*/
#ifndef NRF_DFU_H__
#define NRF_DFU_H__
#include <stdint.h>
#include <stdbool.h>
#include "nrf_dfu_types.h"
#include "nrf_dfu_req_handler.h"
#ifdef __cplusplus
extern "C" {
#endif
#define NRF_DFU_SCHED_EVENT_DATA_SIZE (sizeof(nrf_dfu_request_t))
/** @brief Function for initializing a DFU operation.
*
* This function initializes a DFU operation and any transports that are registered
* in the system.
*
* @param[in] observer Callback function for receiving DFU notifications.
*
* @retval NRF_SUCCESS If the DFU operation was successfully initialized.
*/
uint32_t nrf_dfu_init(nrf_dfu_observer_t observer);
#ifdef __cplusplus
}
#endif
#endif // NRF_DFU_H__
/** @} */

@ -0,0 +1,167 @@
/**
* Copyright (c) 2016 - 2021, Nordic Semiconductor ASA
*
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without modification,
* are permitted provided that the following conditions are met:
*
* 1. Redistributions of source code must retain the above copyright notice, this
* list of conditions and the following disclaimer.
*
* 2. Redistributions in binary form, except as embedded into a Nordic
* Semiconductor ASA integrated circuit in a product or a software update for
* such product, must reproduce the above copyright notice, this list of
* conditions and the following disclaimer in the documentation and/or other
* materials provided with the distribution.
*
* 3. Neither the name of Nordic Semiconductor ASA nor the names of its
* contributors may be used to endorse or promote products derived from this
* software without specific prior written permission.
*
* 4. This software, with or without modification, must only be used with a
* Nordic Semiconductor ASA integrated circuit.
*
* 5. Any software provided in binary form under this license must not be reverse
* engineered, decompiled, modified and/or disassembled.
*
* THIS SOFTWARE IS PROVIDED BY NORDIC SEMICONDUCTOR ASA "AS IS" AND ANY EXPRESS
* OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
* OF MERCHANTABILITY, NONINFRINGEMENT, AND FITNESS FOR A PARTICULAR PURPOSE ARE
* DISCLAIMED. IN NO EVENT SHALL NORDIC SEMICONDUCTOR ASA OR CONTRIBUTORS BE
* LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE
* GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
* OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*
*/
#include "nrf_dfu_flash.h"
#include "nrf_dfu_types.h"
#include "nrf_fstorage.h"
#include "nrf_fstorage_sd.h"
#include "nrf_fstorage_nvmc.h"
#define NRF_LOG_MODULE_NAME nrf_dfu_flash
#include "nrf_log.h"
NRF_LOG_MODULE_REGISTER();
void dfu_fstorage_evt_handler(nrf_fstorage_evt_t * p_evt);
NRF_FSTORAGE_DEF(nrf_fstorage_t m_fs) =
{
.evt_handler = dfu_fstorage_evt_handler,
.start_addr = MBR_SIZE,
.end_addr = BOOTLOADER_SETTINGS_ADDRESS + BOOTLOADER_SETTINGS_PAGE_SIZE
};
static uint32_t m_flash_operations_pending;
void dfu_fstorage_evt_handler(nrf_fstorage_evt_t * p_evt)
{
if (NRF_LOG_ENABLED && (m_flash_operations_pending > 0))
{
m_flash_operations_pending--;
}
if (p_evt->result == NRF_SUCCESS)
{
NRF_LOG_DEBUG("Flash %s success: addr=%p, pending %d",
(p_evt->id == NRF_FSTORAGE_EVT_WRITE_RESULT) ? "write" : "erase",
p_evt->addr, m_flash_operations_pending);
}
else
{
NRF_LOG_DEBUG("Flash %s failed (0x%x): addr=%p, len=0x%x bytes, pending %d",
(p_evt->id == NRF_FSTORAGE_EVT_WRITE_RESULT) ? "write" : "erase",
p_evt->result, p_evt->addr, p_evt->len, m_flash_operations_pending);
}
if (p_evt->p_param)
{
//lint -save -e611 (Suspicious cast)
((nrf_dfu_flash_callback_t)(p_evt->p_param))((void*)p_evt->p_src);
//lint -restore
}
}
ret_code_t nrf_dfu_flash_init(bool sd_irq_initialized)
{
nrf_fstorage_api_t * p_api_impl;
/* Setup the desired API implementation. */
#if defined(BLE_STACK_SUPPORT_REQD) || defined(ANT_STACK_SUPPORT_REQD)
if (sd_irq_initialized)
{
NRF_LOG_DEBUG("Initializing nrf_fstorage_sd backend.");
p_api_impl = &nrf_fstorage_sd;
}
else
#endif
{
NRF_LOG_DEBUG("Initializing nrf_fstorage_nvmc backend.");
p_api_impl = &nrf_fstorage_nvmc;
}
return nrf_fstorage_init(&m_fs, p_api_impl, NULL);
}
ret_code_t nrf_dfu_flash_store(uint32_t dest,
void const * p_src,
uint32_t len,
nrf_dfu_flash_callback_t callback)
{
ret_code_t rc;
NRF_LOG_DEBUG("nrf_fstorage_write(addr=%p, src=%p, len=%d bytes), queue usage: %d",
dest, p_src, len, m_flash_operations_pending);
//lint -save -e611 (Suspicious cast)
rc = nrf_fstorage_write(&m_fs, dest, p_src, len, (void *)callback);
//lint -restore
if ((NRF_LOG_ENABLED) && (rc == NRF_SUCCESS))
{
m_flash_operations_pending++;
}
else
{
NRF_LOG_WARNING("nrf_fstorage_write() failed with error 0x%x.", rc);
}
return rc;
}
ret_code_t nrf_dfu_flash_erase(uint32_t page_addr,
uint32_t num_pages,
nrf_dfu_flash_callback_t callback)
{
ret_code_t rc;
NRF_LOG_DEBUG("nrf_fstorage_erase(addr=0x%p, len=%d pages), queue usage: %d",
page_addr, num_pages, m_flash_operations_pending);
//lint -save -e611 (Suspicious cast)
rc = nrf_fstorage_erase(&m_fs, page_addr, num_pages, (void *)callback);
//lint -restore
if ((NRF_LOG_ENABLED) && (rc == NRF_SUCCESS))
{
m_flash_operations_pending++;
}
else
{
NRF_LOG_WARNING("nrf_fstorage_erase() failed with error 0x%x.", rc);
}
return rc;
}

@ -0,0 +1,132 @@
/**
* Copyright (c) 2016 - 2021, Nordic Semiconductor ASA
*
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without modification,
* are permitted provided that the following conditions are met:
*
* 1. Redistributions of source code must retain the above copyright notice, this
* list of conditions and the following disclaimer.
*
* 2. Redistributions in binary form, except as embedded into a Nordic
* Semiconductor ASA integrated circuit in a product or a software update for
* such product, must reproduce the above copyright notice, this list of
* conditions and the following disclaimer in the documentation and/or other
* materials provided with the distribution.
*
* 3. Neither the name of Nordic Semiconductor ASA nor the names of its
* contributors may be used to endorse or promote products derived from this
* software without specific prior written permission.
*
* 4. This software, with or without modification, must only be used with a
* Nordic Semiconductor ASA integrated circuit.
*
* 5. Any software provided in binary form under this license must not be reverse
* engineered, decompiled, modified and/or disassembled.
*
* THIS SOFTWARE IS PROVIDED BY NORDIC SEMICONDUCTOR ASA "AS IS" AND ANY EXPRESS
* OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
* OF MERCHANTABILITY, NONINFRINGEMENT, AND FITNESS FOR A PARTICULAR PURPOSE ARE
* DISCLAIMED. IN NO EVENT SHALL NORDIC SEMICONDUCTOR ASA OR CONTRIBUTORS BE
* LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE
* GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
* OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*
*/
/**@file
*
* @defgroup sdk_nrf_dfu_flash Flash operations
* @{
* @ingroup nrf_dfu
*/
#ifndef NRF_DFU_FLASH_H__
#define NRF_DFU_FLASH_H__
#include <stdint.h>
#include <stdbool.h>
#include "sdk_errors.h"
#ifdef __cplusplus
extern "C" {
#endif
/**@brief nrf_fstorage event handler function for DFU fstorage operations.
*
* This function will be called after a flash operation has completed.
*/
typedef void (*nrf_dfu_flash_callback_t)(void * p_buf);
/**@brief Function for initializing the flash module.
*
* Depending on whether or not the SoftDevice is present and its IRQ have been initialized,
* this function initializes the correct @ref nrf_fstorage backend.
*
* @param[in] sd_irq_initialized Whether or not the SoftDevice IRQ have been initialized.
*
* @retval NRF_SUCCESS If the operation was successful.
*/
ret_code_t nrf_dfu_flash_init(bool sd_irq_initialized);
/**@brief Function for storing data to flash.
*
* This functions is asynchronous when the SoftDevice is enabled and synchronous when
* the SoftDevice is not present or disabled. In both cases, if a callback function is provided,
* it will be called when the operation has completed.
*
* @note The content of @p p_src should be kept in memory until the operation has completed.
*
* @param[in] dest The address where the data should be stored.
* @param[in] p_src Pointer to the address where the data should be copied from.
* This address can be in flash or RAM.
* @param[in] len The number of bytes to be copied from @p p_src to @p dest.
* @param[in] callback Callback function.
*
* @retval NRF_SUCCESS If the operation was successful.
* @retval NRF_ERROR_INVALID_STATE If nrf_dfu_flash is not initialized.
* @retval NRF_ERROR_INVALID_ADDR If @p p_src or @p dest is not word-aligned.
* @retval NRF_ERROR_INVALID_LENGTH If @p len is zero.
* @retval NRF_ERROR_NULL If @p p_src is NULL.
* @retval NRF_ERROR_NO_MEM If nrf_fstorage is out of memory.
*/
ret_code_t nrf_dfu_flash_store(uint32_t dest,
void const * p_src,
uint32_t len,
nrf_dfu_flash_callback_t callback);
/**@brief Function for erasing data from flash.
*
* This functions is asynchronous when the SoftDevice is enabled and synchronous when
* the SoftDevice is not present or disabled. In both cases, if a callback function is provided,
* it will be called when the operation has completed.
*
* @param[in] page_addr The address of the first flash page to be deleted.
* @param[in] num_pages The number of flash pages to be deleted.
* @param[in] callback Callback function.
*
* @retval NRF_SUCCESS If the operation was successful.
* @retval NRF_ERROR_INVALID_STATE If nrf_dfu_flash is not initialized.
* @retval NRF_ERROR_INVALID_ADDR If @p page_addr is not aligned to a page boundary or the
* operation would go beyond the flash memory boundaries.
* @retval NRF_ERROR_INVALID_LENGTH If @p num_pages is zero.
* @retval NRF_ERROR_NULL If @p page_addr is NULL.
* @retval NRF_ERROR_NO_MEM If the queue of nrf_fstorage is full.
*/
ret_code_t nrf_dfu_flash_erase(uint32_t page_addr, uint32_t num_pages, nrf_dfu_flash_callback_t callback);
#ifdef __cplusplus
}
#endif
#endif // NRF_DFU_FLASH_H__
/** @} */

@ -0,0 +1,61 @@
/**
* Copyright (c) 2017 - 2021, Nordic Semiconductor ASA
*
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without modification,
* are permitted provided that the following conditions are met:
*
* 1. Redistributions of source code must retain the above copyright notice, this
* list of conditions and the following disclaimer.
*
* 2. Redistributions in binary form, except as embedded into a Nordic
* Semiconductor ASA integrated circuit in a product or a software update for
* such product, must reproduce the above copyright notice, this list of
* conditions and the following disclaimer in the documentation and/or other
* materials provided with the distribution.
*
* 3. Neither the name of Nordic Semiconductor ASA nor the names of its
* contributors may be used to endorse or promote products derived from this
* software without specific prior written permission.
*
* 4. This software, with or without modification, must only be used with a
* Nordic Semiconductor ASA integrated circuit.
*
* 5. Any software provided in binary form under this license must not be reverse
* engineered, decompiled, modified and/or disassembled.
*
* THIS SOFTWARE IS PROVIDED BY NORDIC SEMICONDUCTOR ASA "AS IS" AND ANY EXPRESS
* OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
* OF MERCHANTABILITY, NONINFRINGEMENT, AND FITNESS FOR A PARTICULAR PURPOSE ARE
* DISCLAIMED. IN NO EVENT SHALL NORDIC SEMICONDUCTOR ASA OR CONTRIBUTORS BE
* LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE
* GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
* OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*
*/
#include "nrf_dfu_handling_error.h"
#include "nrf_log.h"
#include "nrf_dfu_req_handler.h"
static nrf_dfu_ext_error_code_t m_last_error = NRF_DFU_EXT_ERROR_NO_ERROR;
nrf_dfu_result_t ext_error_set(nrf_dfu_ext_error_code_t error_code)
{
m_last_error = error_code;
return NRF_DFU_RES_CODE_EXT_ERROR;
}
nrf_dfu_ext_error_code_t ext_error_get()
{
nrf_dfu_ext_error_code_t last_error = m_last_error;
m_last_error = NRF_DFU_EXT_ERROR_NO_ERROR;
return last_error;
}

@ -0,0 +1,125 @@
/**
* Copyright (c) 2017 - 2021, Nordic Semiconductor ASA
*
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without modification,
* are permitted provided that the following conditions are met:
*
* 1. Redistributions of source code must retain the above copyright notice, this
* list of conditions and the following disclaimer.
*
* 2. Redistributions in binary form, except as embedded into a Nordic
* Semiconductor ASA integrated circuit in a product or a software update for
* such product, must reproduce the above copyright notice, this list of
* conditions and the following disclaimer in the documentation and/or other
* materials provided with the distribution.
*
* 3. Neither the name of Nordic Semiconductor ASA nor the names of its
* contributors may be used to endorse or promote products derived from this
* software without specific prior written permission.
*
* 4. This software, with or without modification, must only be used with a
* Nordic Semiconductor ASA integrated circuit.
*
* 5. Any software provided in binary form under this license must not be reverse
* engineered, decompiled, modified and/or disassembled.
*
* THIS SOFTWARE IS PROVIDED BY NORDIC SEMICONDUCTOR ASA "AS IS" AND ANY EXPRESS
* OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
* OF MERCHANTABILITY, NONINFRINGEMENT, AND FITNESS FOR A PARTICULAR PURPOSE ARE
* DISCLAIMED. IN NO EVENT SHALL NORDIC SEMICONDUCTOR ASA OR CONTRIBUTORS BE
* LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE
* GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
* OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*
*/
/**@file
*
* @defgroup nrf_dfu_rescodes DFU result codes
* @{
* @ingroup sdk_nrf_dfu_transport
* @brief When the DFU controller sends requests to the DFU bootloader on
* the DFU target, the DFU bootloader answers with any of these result codes.
*/
#ifndef DFU_HANDLING_ERROR_H__
#define DFU_HANDLING_ERROR_H__
#include "nrf_dfu_types.h"
#include "nrf_dfu_req_handler.h"
#ifdef __cplusplus
extern "C" {
#endif
/**@brief DFU request extended result codes.
*
* @details When an event returns @ref NRF_DFU_RES_CODE_EXT_ERROR, it also stores an extended error code.
* The transport layer can then send the extended error code together with the error code to give
* the controller additional information about the cause of the error.
*/
typedef enum
{
NRF_DFU_EXT_ERROR_NO_ERROR = 0x00, /**< No extended error code has been set. This error indicates an implementation problem. */
NRF_DFU_EXT_ERROR_INVALID_ERROR_CODE = 0x01, /**< Invalid error code. This error code should never be used outside of development. */
NRF_DFU_EXT_ERROR_WRONG_COMMAND_FORMAT = 0x02, /**< The format of the command was incorrect. This error code is not used in the
current implementation, because @ref NRF_DFU_RES_CODE_OP_CODE_NOT_SUPPORTED
and @ref NRF_DFU_RES_CODE_INVALID_PARAMETER cover all
possible format errors. */
NRF_DFU_EXT_ERROR_UNKNOWN_COMMAND = 0x03, /**< The command was successfully parsed, but it is not supported or unknown. */
NRF_DFU_EXT_ERROR_INIT_COMMAND_INVALID = 0x04, /**< The init command is invalid. The init packet either has
an invalid update type or it is missing required fields for the update type
(for example, the init packet for a SoftDevice update is missing the SoftDevice size field). */
NRF_DFU_EXT_ERROR_FW_VERSION_FAILURE = 0x05, /**< The firmware version is too low. For an application or SoftDevice, the version must be greater than
or equal to the current version. For a bootloader, it must be greater than the current version.
to the current version. This requirement prevents downgrade attacks.*/
NRF_DFU_EXT_ERROR_HW_VERSION_FAILURE = 0x06, /**< The hardware version of the device does not match the required
hardware version for the update. */
NRF_DFU_EXT_ERROR_SD_VERSION_FAILURE = 0x07, /**< The array of supported SoftDevices for the update does not contain
the FWID of the current SoftDevice or the first FWID is '0' on a
bootloader which requires the SoftDevice to be present. */
NRF_DFU_EXT_ERROR_SIGNATURE_MISSING = 0x08, /**< The init packet does not contain a signature. This error code is not used in the
current implementation, because init packets without a signature
are regarded as invalid. */
NRF_DFU_EXT_ERROR_WRONG_HASH_TYPE = 0x09, /**< The hash type that is specified by the init packet is not supported by the DFU bootloader. */
NRF_DFU_EXT_ERROR_HASH_FAILED = 0x0A, /**< The hash of the firmware image cannot be calculated. */
NRF_DFU_EXT_ERROR_WRONG_SIGNATURE_TYPE = 0x0B, /**< The type of the signature is unknown or not supported by the DFU bootloader. */
NRF_DFU_EXT_ERROR_VERIFICATION_FAILED = 0x0C, /**< The hash of the received firmware image does not match the hash in the init packet. */
NRF_DFU_EXT_ERROR_INSUFFICIENT_SPACE = 0x0D, /**< The available space on the device is insufficient to hold the firmware. */
} nrf_dfu_ext_error_code_t;
/**@brief Function for setting an extended error code that can be retrieved later.
*
* @details When an extended error occurs in the DFU process, this function can be used to store the error.
*
* @param error_code The error code to store.
*
* @retval NRF_DFU_RES_CODE_EXT_ERROR
*/
nrf_dfu_result_t ext_error_set(nrf_dfu_ext_error_code_t error_code);
/**@brief Function for getting the most recent extended error code.
*
* @details This function is used by the transport layer to fetch the most recent extended error code.
*
* @return The most recent error code. If the function is called again before a new error occurs, @ref NRF_DFU_EXT_ERROR_NO_ERROR is returned.
*/
nrf_dfu_ext_error_code_t ext_error_get( void );
#ifdef __cplusplus
}
#endif
#endif // DFU_HANDLING_ERROR_H__
/** @} */

@ -0,0 +1,105 @@
/**
* Copyright (c) 2016 - 2021, Nordic Semiconductor ASA
*
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without modification,
* are permitted provided that the following conditions are met:
*
* 1. Redistributions of source code must retain the above copyright notice, this
* list of conditions and the following disclaimer.
*
* 2. Redistributions in binary form, except as embedded into a Nordic
* Semiconductor ASA integrated circuit in a product or a software update for
* such product, must reproduce the above copyright notice, this list of
* conditions and the following disclaimer in the documentation and/or other
* materials provided with the distribution.
*
* 3. Neither the name of Nordic Semiconductor ASA nor the names of its
* contributors may be used to endorse or promote products derived from this
* software without specific prior written permission.
*
* 4. This software, with or without modification, must only be used with a
* Nordic Semiconductor ASA integrated circuit.
*
* 5. Any software provided in binary form under this license must not be reverse
* engineered, decompiled, modified and/or disassembled.
*
* THIS SOFTWARE IS PROVIDED BY NORDIC SEMICONDUCTOR ASA "AS IS" AND ANY EXPRESS
* OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
* OF MERCHANTABILITY, NONINFRINGEMENT, AND FITNESS FOR A PARTICULAR PURPOSE ARE
* DISCLAIMED. IN NO EVENT SHALL NORDIC SEMICONDUCTOR ASA OR CONTRIBUTORS BE
* LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE
* GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
* OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*
*/
#include "nrf_dfu_mbr.h"
#include "nrf_mbr.h"
#include "nrf_dfu_types.h"
#include "nrf_log.h"
#include "nrf_bootloader_info.h"
#define MBR_IRQ_FORWARD_ADDRESS_ADDRESS (0x20000000) //!< The address of the variable that decides where the MBR forwards interrupts
uint32_t nrf_dfu_mbr_copy_bl(uint32_t * p_src, uint32_t len)
{
uint32_t ret_val;
uint32_t const len_words = len / sizeof(uint32_t);
sd_mbr_command_t command =
{
.command = SD_MBR_COMMAND_COPY_BL,
.params.copy_bl.bl_src = p_src,
.params.copy_bl.bl_len = len_words
};
ret_val = sd_mbr_command(&command);
return ret_val;
}
uint32_t nrf_dfu_mbr_init_sd(void)
{
uint32_t ret_val;
sd_mbr_command_t command =
{
.command = SD_MBR_COMMAND_INIT_SD
};
ret_val = sd_mbr_command(&command);
return ret_val;
}
uint32_t nrf_dfu_mbr_irq_forward_address_set(void)
{
uint32_t ret_val = NRF_ERROR_INVALID_PARAM;
uint32_t address = MBR_SIZE;
#if !defined(BLE_STACK_SUPPORT_REQD) && !defined(ANT_STACK_SUPPORT_REQD)
sd_mbr_command_t command =
{
.command = SD_MBR_COMMAND_IRQ_FORWARD_ADDRESS_SET,
.params.irq_forward_address_set.address = address,
};
ret_val = sd_mbr_command(&command);
#endif
if (ret_val == NRF_ERROR_INVALID_PARAM)
{
// Manually set the forward address if this MBR doesn't have the command.
*(uint32_t *)(MBR_IRQ_FORWARD_ADDRESS_ADDRESS) = address;
ret_val = NRF_SUCCESS;
}
return ret_val;
}

@ -0,0 +1,90 @@
/**
* Copyright (c) 2016 - 2021, Nordic Semiconductor ASA
*
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without modification,
* are permitted provided that the following conditions are met:
*
* 1. Redistributions of source code must retain the above copyright notice, this
* list of conditions and the following disclaimer.
*
* 2. Redistributions in binary form, except as embedded into a Nordic
* Semiconductor ASA integrated circuit in a product or a software update for
* such product, must reproduce the above copyright notice, this list of
* conditions and the following disclaimer in the documentation and/or other
* materials provided with the distribution.
*
* 3. Neither the name of Nordic Semiconductor ASA nor the names of its
* contributors may be used to endorse or promote products derived from this
* software without specific prior written permission.
*
* 4. This software, with or without modification, must only be used with a
* Nordic Semiconductor ASA integrated circuit.
*
* 5. Any software provided in binary form under this license must not be reverse
* engineered, decompiled, modified and/or disassembled.
*
* THIS SOFTWARE IS PROVIDED BY NORDIC SEMICONDUCTOR ASA "AS IS" AND ANY EXPRESS
* OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
* OF MERCHANTABILITY, NONINFRINGEMENT, AND FITNESS FOR A PARTICULAR PURPOSE ARE
* DISCLAIMED. IN NO EVENT SHALL NORDIC SEMICONDUCTOR ASA OR CONTRIBUTORS BE
* LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE
* GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
* OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*
*/
/**@file
*
* @defgroup sdk_nrf_dfu_mbr MBR functions
* @{
* @ingroup nrf_dfu
*/
#ifndef NRF_DFU_MBR_H__
#define NRF_DFU_MBR_H__
#include <stdint.h>
#ifdef __cplusplus
extern "C" {
#endif
/** @brief Function for copying the bootloader using an MBR command.
*
* @param[in] p_src Source address of the bootloader data to copy.
* @param[in] len Length of the data to copy in bytes.
*
* @return This function will return only if the command request could not be run.
* See @ref sd_mbr_command_copy_bl_t for possible return values.
*/
uint32_t nrf_dfu_mbr_copy_bl(uint32_t * p_src, uint32_t len);
/** @brief Function for initializing the SoftDevice using an MBR command.
*
* @retval NRF_SUCCESS If the SoftDevice was initialized successfully.
* Any other return value indicates that the SoftDevice
* could not be initialized.
*/
uint32_t nrf_dfu_mbr_init_sd(void);
/** @brief Function for setting the address of the IRQ table to the app's using an MBR command.
*
* @retval NRF_SUCCESS If the address of the new irq table was set. Any other
* return value indicates that the address could not be set.
*/
uint32_t nrf_dfu_mbr_irq_forward_address_set(void);
#ifdef __cplusplus
}
#endif
#endif // NRF_DFU_MBR_H__
/** @} */

@ -0,0 +1,864 @@
/**
* Copyright (c) 2016 - 2021, Nordic Semiconductor ASA
*
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without modification,
* are permitted provided that the following conditions are met:
*
* 1. Redistributions of source code must retain the above copyright notice, this
* list of conditions and the following disclaimer.
*
* 2. Redistributions in binary form, except as embedded into a Nordic
* Semiconductor ASA integrated circuit in a product or a software update for
* such product, must reproduce the above copyright notice, this list of
* conditions and the following disclaimer in the documentation and/or other
* materials provided with the distribution.
*
* 3. Neither the name of Nordic Semiconductor ASA nor the names of its
* contributors may be used to endorse or promote products derived from this
* software without specific prior written permission.
*
* 4. This software, with or without modification, must only be used with a
* Nordic Semiconductor ASA integrated circuit.
*
* 5. Any software provided in binary form under this license must not be reverse
* engineered, decompiled, modified and/or disassembled.
*
* THIS SOFTWARE IS PROVIDED BY NORDIC SEMICONDUCTOR ASA "AS IS" AND ANY EXPRESS
* OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
* OF MERCHANTABILITY, NONINFRINGEMENT, AND FITNESS FOR A PARTICULAR PURPOSE ARE
* DISCLAIMED. IN NO EVENT SHALL NORDIC SEMICONDUCTOR ASA OR CONTRIBUTORS BE
* LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE
* GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
* OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*
*/
#include <stdint.h>
#include <stdbool.h>
#include "sdk_config.h"
#include "nrf_dfu.h"
#include "nrf_dfu_types.h"
#include "nrf_dfu_req_handler.h"
#include "nrf_dfu_handling_error.h"
#include "nrf_dfu_settings.h"
#include "nrf_dfu_utils.h"
#include "nrf_dfu_flash.h"
#include "nrf_fstorage.h"
#include "nrf_bootloader_info.h"
#include "app_util.h"
#include "pb.h"
#include "pb_common.h"
#include "pb_decode.h"
#include "dfu-cc.pb.h"
#include "crc32.h"
#include "app_scheduler.h"
#include "sdk_macros.h"
#include "nrf_assert.h"
#include "nrf_dfu_validation.h"
#define NRF_LOG_MODULE_NAME nrf_dfu_req_handler
#include "nrf_log.h"
NRF_LOG_MODULE_REGISTER();
#define NRF_DFU_PROTOCOL_VERSION (0x01)
#ifndef NRF_DFU_PROTOCOL_REDUCED
#define NRF_DFU_PROTOCOL_REDUCED 0
#endif
STATIC_ASSERT(dfu_SignedCommand_size <= INIT_COMMAND_MAX_SIZE);
static uint32_t m_firmware_start_addr; /**< Start address of the current firmware image. */
static uint32_t m_firmware_size_req; /**< The size of the entire firmware image. Defined by the init command. */
static nrf_dfu_observer_t m_observer;
static void on_dfu_complete(nrf_fstorage_evt_t * p_evt)
{
UNUSED_PARAMETER(p_evt);
NRF_LOG_DEBUG("All flash operations have completed. DFU completed.");
m_observer(NRF_DFU_EVT_DFU_COMPLETED);
}
static nrf_dfu_result_t ext_err_code_handle(nrf_dfu_result_t ret_val)
{
if (ret_val < NRF_DFU_RES_CODE_EXT_ERROR)
{
return ret_val;
}
else
{
nrf_dfu_ext_error_code_t ext_err =
(nrf_dfu_ext_error_code_t)((uint8_t)ret_val - (uint8_t)NRF_DFU_RES_CODE_EXT_ERROR);
return ext_error_set(ext_err);
}
}
#if !NRF_DFU_PROTOCOL_REDUCED
static void on_protocol_version_request(nrf_dfu_request_t const * p_req, nrf_dfu_response_t * p_res)
{
UNUSED_PARAMETER(p_req);
NRF_LOG_DEBUG("Handle NRF_DFU_OP_PROTOCOL_VERSION");
if (NRF_DFU_PROTOCOL_VERSION_MSG)
{
p_res->protocol.version = NRF_DFU_PROTOCOL_VERSION;
}
else
{
NRF_LOG_DEBUG("NRF_DFU_OP_PROTOCOL_VERSION disabled.");
p_res->result = NRF_DFU_RES_CODE_OP_CODE_NOT_SUPPORTED;
}
}
static void on_hw_version_request(nrf_dfu_request_t const * p_req, nrf_dfu_response_t * p_res)
{
NRF_LOG_DEBUG("Handle NRF_DFU_OP_HARDWARE_VERSION");
p_res->hardware.part = NRF_FICR->INFO.PART;
p_res->hardware.variant = NRF_FICR->INFO.VARIANT;
/* FICR values are in Kilobytes, we report them in bytes. */
p_res->hardware.memory.ram_size = NRF_FICR->INFO.RAM * 1024;
p_res->hardware.memory.rom_size = NRF_FICR->INFO.FLASH * 1024;
p_res->hardware.memory.rom_page_size = NRF_FICR->CODEPAGESIZE;
}
static void on_fw_version_request(nrf_dfu_request_t const * p_req, nrf_dfu_response_t * p_res)
{
NRF_LOG_DEBUG("Handle NRF_DFU_OP_FIRMWARE_VERSION");
NRF_LOG_DEBUG("Firmware image requested: %d", p_req->firmware.image_number);
if (NRF_DFU_PROTOCOL_FW_VERSION_MSG)
{
uint8_t fw_count = 1;
if (SD_PRESENT)
{
fw_count++;
}
if (s_dfu_settings.bank_0.bank_code == NRF_DFU_BANK_VALID_APP)
{
fw_count++;
}
p_res->result = NRF_DFU_RES_CODE_SUCCESS;
if (p_req->firmware.image_number == 0)
{
/* Bootloader is always present and it is always image zero. */
p_res->firmware.type = NRF_DFU_FIRMWARE_TYPE_BOOTLOADER;
p_res->firmware.version = s_dfu_settings.bootloader_version;
p_res->firmware.addr = BOOTLOADER_START_ADDR;
p_res->firmware.len = BOOTLOADER_SIZE;
}
else if ((p_req->firmware.image_number == 1) && SD_PRESENT)
{
/* If a SoftDevice is present, it will be firmware image one. */
p_res->firmware.type = NRF_DFU_FIRMWARE_TYPE_SOFTDEVICE;
p_res->firmware.version = SD_VERSION_GET(MBR_SIZE);
p_res->firmware.addr = MBR_SIZE;
p_res->firmware.len = SD_SIZE_GET(MBR_SIZE);
}
else if ((p_req->firmware.image_number < fw_count))
{
/* Either there is no SoftDevice and the firmware image requested is one,
* or there is a SoftDevice and the firmware image requested is two.
*/
p_res->firmware.type = NRF_DFU_FIRMWARE_TYPE_APPLICATION;
p_res->firmware.version = s_dfu_settings.app_version;
p_res->firmware.addr = nrf_dfu_app_start_address();
p_res->firmware.len = s_dfu_settings.bank_0.image_size;
}
else
{
NRF_LOG_DEBUG("No such firmware image");
p_res->firmware.type = NRF_DFU_FIRMWARE_TYPE_UNKNOWN;
p_res->firmware.version = 0x00;
p_res->firmware.addr = 0x00;
p_res->firmware.len = 0x00;
}
}
else
{
NRF_LOG_DEBUG("NRF_DFU_OP_FIRMWARE_VERSION disabled.");
p_res->result = NRF_DFU_RES_CODE_OP_CODE_NOT_SUPPORTED;
p_res->firmware.type = NRF_DFU_FIRMWARE_TYPE_UNKNOWN;
}
}
static void on_ping_request(nrf_dfu_request_t * p_req, nrf_dfu_response_t * p_res)
{
NRF_LOG_DEBUG("Handle NRF_DFU_OP_PING");
p_res->ping.id = p_req->ping.id;
}
static void on_mtu_get_request(nrf_dfu_request_t * p_req, nrf_dfu_response_t * p_res)
{
NRF_LOG_DEBUG("Handle NRF_DFU_OP_MTU_GET");
p_res->mtu.size = p_req->mtu.size;
}
#endif // !NRF_DFU_PROTOCOL_REDUCED
static void on_prn_set_request(nrf_dfu_request_t * p_req, nrf_dfu_response_t * p_res)
{
UNUSED_PARAMETER(p_req);
UNUSED_PARAMETER(p_res);
NRF_LOG_DEBUG("Handle NRF_DFU_OP_RECEIPT_NOTIF_SET");
}
static void on_abort_request(nrf_dfu_request_t * p_req, nrf_dfu_response_t * p_res)
{
UNUSED_PARAMETER(p_req);
UNUSED_PARAMETER(p_res);
NRF_LOG_DEBUG("Handle NRF_DFU_OP_ABORT");
m_observer(NRF_DFU_EVT_DFU_ABORTED);
}
/* Set offset and CRC fields in the response for a 'command' message. */
static void cmd_response_offset_and_crc_set(nrf_dfu_response_t * const p_res)
{
ASSERT(p_res);
/* Copy the CRC and offset of the init packet. */
p_res->crc.offset = s_dfu_settings.progress.command_offset;
p_res->crc.crc = s_dfu_settings.progress.command_crc;
}
static void on_cmd_obj_select_request(nrf_dfu_request_t const * p_req, nrf_dfu_response_t * p_res)
{
UNUSED_PARAMETER(p_req);
NRF_LOG_DEBUG("Handle NRF_DFU_OP_OBJECT_SELECT (command)");
p_res->select.max_size = INIT_COMMAND_MAX_SIZE;
cmd_response_offset_and_crc_set(p_res);
}
static void on_cmd_obj_create_request(nrf_dfu_request_t * p_req, nrf_dfu_response_t * p_res)
{
ASSERT(p_req);
ASSERT(p_res);
NRF_LOG_DEBUG("Handle NRF_DFU_OP_OBJECT_CREATE (command)");
m_observer(NRF_DFU_EVT_DFU_STARTED);
nrf_dfu_result_t ret_val = nrf_dfu_validation_init_cmd_create(p_req->create.object_size);
p_res->result = ext_err_code_handle(ret_val);
}
static void on_cmd_obj_write_request(nrf_dfu_request_t * p_req, nrf_dfu_response_t * p_res)
{
ASSERT(p_req);
ASSERT(p_req->write.p_data);
ASSERT(p_req->write.len);
ASSERT(p_res);
NRF_LOG_DEBUG("Handle NRF_DFU_OP_OBJECT_WRITE (command)");
nrf_dfu_result_t ret_val;
ret_val = nrf_dfu_validation_init_cmd_append(p_req->write.p_data, p_req->write.len);
p_res->result = ext_err_code_handle(ret_val);
/* Update response. This is only used when the PRN is triggered and the 'write' message
* is answered with a CRC message and these field are copied into the response. */
cmd_response_offset_and_crc_set(p_res);
/* If a callback to free the request payload buffer was provided, invoke it now. */
if (p_req->callback.write)
{
p_req->callback.write((void*)p_req->write.p_data);
}
}
static void on_cmd_obj_execute_request(nrf_dfu_request_t const * p_req, nrf_dfu_response_t * p_res)
{
ASSERT(p_req);
ASSERT(p_res);
NRF_LOG_DEBUG("Handle NRF_DFU_OP_OBJECT_EXECUTE (command)");
nrf_dfu_result_t ret_val;
ret_val = nrf_dfu_validation_init_cmd_execute(&m_firmware_start_addr, &m_firmware_size_req);
p_res->result = ext_err_code_handle(ret_val);
if (p_res->result == NRF_DFU_RES_CODE_SUCCESS)
{
if (nrf_dfu_settings_write_and_backup(NULL) == NRF_SUCCESS)
{
/* Setting DFU to initialized */
NRF_LOG_DEBUG("Writing valid init command to flash.");
}
else
{
p_res->result = NRF_DFU_RES_CODE_OPERATION_FAILED;
}
}
}
static void on_cmd_obj_crc_request(nrf_dfu_request_t const * p_req, nrf_dfu_response_t * p_res)
{
UNUSED_PARAMETER(p_req);
NRF_LOG_DEBUG("Handle NRF_DFU_OP_CRC_GET (command)");
cmd_response_offset_and_crc_set(p_res);
}
/** @brief Function handling command requests from the transport layer.
*
* @param p_req[in] Pointer to the structure holding the DFU request.
* @param p_res[out] Pointer to the structure holding the DFU response.
*
* @retval NRF_SUCCESS If the command request was executed successfully.
* Any other error code indicates that the data request
* could not be handled.
*/
static void nrf_dfu_command_req(nrf_dfu_request_t * p_req, nrf_dfu_response_t * p_res)
{
ASSERT(p_req);
ASSERT(p_res);
switch (p_req->request)
{
case NRF_DFU_OP_OBJECT_CREATE:
{
on_cmd_obj_create_request(p_req, p_res);
} break;
case NRF_DFU_OP_CRC_GET:
{
on_cmd_obj_crc_request(p_req, p_res);
} break;
case NRF_DFU_OP_OBJECT_WRITE:
{
on_cmd_obj_write_request(p_req, p_res);
} break;
case NRF_DFU_OP_OBJECT_EXECUTE:
{
on_cmd_obj_execute_request(p_req, p_res);
} break;
case NRF_DFU_OP_OBJECT_SELECT:
{
on_cmd_obj_select_request(p_req, p_res);
} break;
default:
{
ASSERT(false);
} break;
}
}
static void on_data_obj_select_request(nrf_dfu_request_t * p_req, nrf_dfu_response_t * p_res)
{
NRF_LOG_DEBUG("Handle NRF_DFU_OP_OBJECT_SELECT (data)");
p_res->select.crc = s_dfu_settings.progress.firmware_image_crc;
p_res->select.offset = s_dfu_settings.progress.firmware_image_offset;
p_res->select.max_size = DATA_OBJECT_MAX_SIZE;
NRF_LOG_DEBUG("crc = 0x%x, offset = 0x%x, max_size = 0x%x",
p_res->select.crc,
p_res->select.offset,
p_res->select.max_size);
}
static void on_data_obj_create_request(nrf_dfu_request_t * p_req, nrf_dfu_response_t * p_res)
{
NRF_LOG_DEBUG("Handle NRF_DFU_OP_OBJECT_CREATE (data)");
if (!nrf_dfu_validation_init_cmd_present())
{
/* Can't accept data because DFU isn't initialized by init command. */
NRF_LOG_ERROR("Cannot create data object without valid init command");
p_res->result = NRF_DFU_RES_CODE_OPERATION_NOT_PERMITTED;
return;
}
if (p_req->create.object_size == 0)
{
NRF_LOG_ERROR("Object size cannot be 0.")
p_res->result = NRF_DFU_RES_CODE_INVALID_PARAMETER;
return;
}
if ( ((p_req->create.object_size & (CODE_PAGE_SIZE - 1)) != 0)
&& (s_dfu_settings.progress.firmware_image_offset_last + p_req->create.object_size != m_firmware_size_req))
{
NRF_LOG_ERROR("Object size must be page aligned");
p_res->result = NRF_DFU_RES_CODE_INVALID_PARAMETER;
return;
}
if (p_req->create.object_size > DATA_OBJECT_MAX_SIZE)
{
/* It is impossible to handle the command because the size is too large */
NRF_LOG_ERROR("Invalid size for object (too large)");
p_res->result = NRF_DFU_RES_CODE_INSUFFICIENT_RESOURCES;
return;
}
if ((s_dfu_settings.progress.firmware_image_offset_last + p_req->create.object_size) >
m_firmware_size_req)
{
NRF_LOG_ERROR("Creating the object with size 0x%08x would overflow firmware size. "
"Offset is 0x%08x and firmware size is 0x%08x.",
p_req->create.object_size,
s_dfu_settings.progress.firmware_image_offset_last,
m_firmware_size_req);
p_res->result = NRF_DFU_RES_CODE_OPERATION_NOT_PERMITTED;
return;
}
s_dfu_settings.progress.data_object_size = p_req->create.object_size;
s_dfu_settings.progress.firmware_image_crc = s_dfu_settings.progress.firmware_image_crc_last;
s_dfu_settings.progress.firmware_image_offset = s_dfu_settings.progress.firmware_image_offset_last;
s_dfu_settings.write_offset = s_dfu_settings.progress.firmware_image_offset_last;
/* Erase the page we're at. */
if (nrf_dfu_flash_erase((m_firmware_start_addr + s_dfu_settings.progress.firmware_image_offset),
CEIL_DIV(p_req->create.object_size, CODE_PAGE_SIZE), NULL) != NRF_SUCCESS)
{
NRF_LOG_ERROR("Erase operation failed");
p_res->result = NRF_DFU_RES_CODE_INVALID_OBJECT;
return;
}
NRF_LOG_DEBUG("Creating object with size: %d. Offset: 0x%08x, CRC: 0x%08x",
s_dfu_settings.progress.data_object_size,
s_dfu_settings.progress.firmware_image_offset,
s_dfu_settings.progress.firmware_image_crc);
}
static void on_data_obj_write_request(nrf_dfu_request_t * p_req, nrf_dfu_response_t * p_res)
{
NRF_LOG_DEBUG("Handle NRF_DFU_OP_OBJECT_WRITE (data)");
if (!nrf_dfu_validation_init_cmd_present())
{
/* Can't accept data because DFU isn't initialized by init command. */
p_res->result = NRF_DFU_RES_CODE_OPERATION_NOT_PERMITTED;
return;
}
uint32_t const data_object_offset = s_dfu_settings.progress.firmware_image_offset -
s_dfu_settings.progress.firmware_image_offset_last;
if ((p_req->write.len + data_object_offset) > s_dfu_settings.progress.data_object_size)
{
/* Can't accept data because too much data has been received. */
NRF_LOG_ERROR("Write request too long");
p_res->result = NRF_DFU_RES_CODE_INVALID_PARAMETER;
return;
}
uint32_t const write_addr = m_firmware_start_addr + s_dfu_settings.write_offset;
/* CRC must be calculated before handing off the data to fstorage because the data is
* freed on write completion.
*/
uint32_t const next_crc =
crc32_compute(p_req->write.p_data, p_req->write.len, &s_dfu_settings.progress.firmware_image_crc);
ASSERT(p_req->callback.write);
ret_code_t ret =
nrf_dfu_flash_store(write_addr, p_req->write.p_data, p_req->write.len, p_req->callback.write);
if (ret != NRF_SUCCESS)
{
/* When nrf_dfu_flash_store() fails because there is no space in the queue,
* stop processing the request so that the peer can detect a CRC error
* and retransmit this object. Remember to manually free the buffer !
*/
p_req->callback.write((void*)p_req->write.p_data);
return;
}
/* Update the CRC of the firmware image. */
s_dfu_settings.write_offset += p_req->write.len;
s_dfu_settings.progress.firmware_image_offset += p_req->write.len;
s_dfu_settings.progress.firmware_image_crc = next_crc;
/* This is only used when the PRN is triggered and the 'write' message
* is answered with a CRC message and these field are copied into the response.
*/
p_res->write.crc = s_dfu_settings.progress.firmware_image_crc;
p_res->write.offset = s_dfu_settings.progress.firmware_image_offset;
}
static void on_data_obj_crc_request(nrf_dfu_request_t * p_req, nrf_dfu_response_t * p_res)
{
NRF_LOG_DEBUG("Handle NRF_DFU_OP_CRC_GET (data)");
NRF_LOG_DEBUG("Offset:%d, CRC:0x%08x",
s_dfu_settings.progress.firmware_image_offset,
s_dfu_settings.progress.firmware_image_crc);
p_res->crc.crc = s_dfu_settings.progress.firmware_image_crc;
p_res->crc.offset = s_dfu_settings.progress.firmware_image_offset;
}
static void on_data_obj_execute_request_sched(void * p_evt, uint16_t event_length)
{
UNUSED_PARAMETER(event_length);
ret_code_t ret;
nrf_dfu_request_t * p_req = (nrf_dfu_request_t *)(p_evt);
/* Wait for all buffers to be written in flash. */
if (nrf_fstorage_is_busy(NULL))
{
ret = app_sched_event_put(p_req, sizeof(nrf_dfu_request_t), on_data_obj_execute_request_sched);
if (ret != NRF_SUCCESS)
{
NRF_LOG_ERROR("Failed to schedule object execute: 0x%x.", ret);
}
return;
}
nrf_dfu_response_t res =
{
.request = NRF_DFU_OP_OBJECT_EXECUTE,
};
if (s_dfu_settings.progress.firmware_image_offset == m_firmware_size_req)
{
NRF_LOG_DEBUG("Whole firmware image received. Postvalidating.");
#if NRF_DFU_IN_APP
res.result = nrf_dfu_validation_post_data_execute(m_firmware_start_addr, m_firmware_size_req);
#else
res.result = nrf_dfu_validation_activation_prepare(m_firmware_start_addr, m_firmware_size_req);
#endif
res.result = ext_err_code_handle(res.result);
/* Provide response to transport */
p_req->callback.response(&res, p_req->p_context);
ret = nrf_dfu_settings_write_and_backup((nrf_dfu_flash_callback_t)on_dfu_complete);
UNUSED_RETURN_VALUE(ret);
}
else
{
res.result = NRF_DFU_RES_CODE_SUCCESS;
/* Provide response to transport */
p_req->callback.response(&res, p_req->p_context);
if (NRF_DFU_SAVE_PROGRESS_IN_FLASH)
{
/* Allowing skipping settings backup to save time and flash wear. */
ret = nrf_dfu_settings_write_and_backup(NULL);
UNUSED_RETURN_VALUE(ret);
}
}
NRF_LOG_DEBUG("Request handling complete. Result: 0x%x", res.result);
}
static bool on_data_obj_execute_request(nrf_dfu_request_t * p_req, nrf_dfu_response_t * p_res)
{
NRF_LOG_DEBUG("Handle NRF_DFU_OP_OBJECT_EXECUTE (data)");
uint32_t const data_object_size = s_dfu_settings.progress.firmware_image_offset -
s_dfu_settings.progress.firmware_image_offset_last;
if (s_dfu_settings.progress.data_object_size != data_object_size)
{
/* The size of the written object was not as expected. */
NRF_LOG_ERROR("Invalid data. expected: %d, got: %d",
s_dfu_settings.progress.data_object_size,
data_object_size);
p_res->result = NRF_DFU_RES_CODE_OPERATION_NOT_PERMITTED;
return true;
}
/* Update the offset and crc values for the last object written. */
s_dfu_settings.progress.data_object_size = 0;
s_dfu_settings.progress.firmware_image_crc_last = s_dfu_settings.progress.firmware_image_crc;
s_dfu_settings.progress.firmware_image_offset_last = s_dfu_settings.progress.firmware_image_offset;
on_data_obj_execute_request_sched(p_req, 0);
m_observer(NRF_DFU_EVT_OBJECT_RECEIVED);
return false;
}
static bool nrf_dfu_data_req(nrf_dfu_request_t * p_req, nrf_dfu_response_t * p_res)
{
ASSERT(p_req);
ASSERT(p_res);
bool response_ready = true;
switch (p_req->request)
{
case NRF_DFU_OP_OBJECT_CREATE:
{
on_data_obj_create_request(p_req, p_res);
} break;
case NRF_DFU_OP_OBJECT_WRITE:
{
on_data_obj_write_request(p_req, p_res);
} break;
case NRF_DFU_OP_CRC_GET:
{
on_data_obj_crc_request(p_req, p_res);
} break;
case NRF_DFU_OP_OBJECT_EXECUTE:
{
response_ready = on_data_obj_execute_request(p_req, p_res);
} break;
case NRF_DFU_OP_OBJECT_SELECT:
{
on_data_obj_select_request(p_req, p_res);
} break;
default:
{
ASSERT(false);
} break;
}
return response_ready;
}
/**@brief Function for handling requests to manipulate data or command objects.
*
* @param[in] p_req Request.
* @param[out] p_res Response.
*
* @return Whether response is ready to be sent.
*/
static bool nrf_dfu_obj_op(nrf_dfu_request_t * p_req, nrf_dfu_response_t * p_res)
{
/* Keep track of the current object type since write and execute requests don't contain it. */
static nrf_dfu_obj_type_t current_object = NRF_DFU_OBJ_TYPE_COMMAND;
if ( (p_req->request == NRF_DFU_OP_OBJECT_SELECT)
|| (p_req->request == NRF_DFU_OP_OBJECT_CREATE))
{
STATIC_ASSERT(offsetof(nrf_dfu_request_select_t, object_type) ==
offsetof(nrf_dfu_request_create_t, object_type),
"Wrong object_type offset!");
current_object = (nrf_dfu_obj_type_t)(p_req->select.object_type);
}
bool response_ready = true;
switch (current_object)
{
case NRF_DFU_OBJ_TYPE_COMMAND:
nrf_dfu_command_req(p_req, p_res);
break;
case NRF_DFU_OBJ_TYPE_DATA:
response_ready = nrf_dfu_data_req(p_req, p_res);
break;
default:
/* The select request had an invalid object type. */
NRF_LOG_ERROR("Invalid object type in request.");
current_object = NRF_DFU_OBJ_TYPE_INVALID;
p_res->result = NRF_DFU_RES_CODE_INVALID_OBJECT;
break;
}
return response_ready;
}
static void nrf_dfu_req_handler_req_process(nrf_dfu_request_t * p_req)
{
ASSERT(p_req->callback.response);
bool response_ready = true;
/* The request handlers assume these values to be set. */
nrf_dfu_response_t response =
{
.request = p_req->request,
.result = NRF_DFU_RES_CODE_SUCCESS,
};
switch (p_req->request)
{
#if !NRF_DFU_PROTOCOL_REDUCED
case NRF_DFU_OP_PROTOCOL_VERSION:
{
on_protocol_version_request(p_req, &response);
} break;
case NRF_DFU_OP_HARDWARE_VERSION:
{
on_hw_version_request(p_req, &response);
} break;
case NRF_DFU_OP_FIRMWARE_VERSION:
{
on_fw_version_request(p_req, &response);
} break;
case NRF_DFU_OP_PING:
{
on_ping_request(p_req, &response);
} break;
case NRF_DFU_OP_MTU_GET:
{
on_mtu_get_request(p_req, &response);
} break;
#endif
case NRF_DFU_OP_RECEIPT_NOTIF_SET:
{
on_prn_set_request(p_req, &response);
} break;
case NRF_DFU_OP_ABORT:
{
on_abort_request(p_req, &response);
} break;
case NRF_DFU_OP_OBJECT_CREATE:
/* Restart the inactivity timer on CREATE messages. */
/* Fallthrough. */
case NRF_DFU_OP_OBJECT_SELECT:
case NRF_DFU_OP_OBJECT_WRITE:
case NRF_DFU_OP_OBJECT_EXECUTE:
case NRF_DFU_OP_CRC_GET:
{
response_ready = nrf_dfu_obj_op(p_req, &response);
} break;
default:
NRF_LOG_INFO("Invalid opcode received: 0x%x.", p_req->request);
response.result = NRF_DFU_RES_CODE_OP_CODE_NOT_SUPPORTED;
break;
}
if (response_ready)
{
NRF_LOG_DEBUG("Request handling complete. Result: 0x%x", response.result);
p_req->callback.response(&response, p_req->p_context);
if (response.result != NRF_DFU_RES_CODE_SUCCESS)
{
m_observer(NRF_DFU_EVT_DFU_FAILED);
}
}
}
static void nrf_dfu_req_handler_req(void * p_evt, uint16_t event_length)
{
nrf_dfu_request_t * p_req = (nrf_dfu_request_t *)(p_evt);
nrf_dfu_req_handler_req_process(p_req);
}
ret_code_t nrf_dfu_req_handler_on_req(nrf_dfu_request_t * p_req)
{
ret_code_t ret;
if (p_req->callback.response == NULL)
{
return NRF_ERROR_INVALID_PARAM;
}
ret = app_sched_event_put(p_req, sizeof(nrf_dfu_request_t), nrf_dfu_req_handler_req);
if (ret != NRF_SUCCESS)
{
NRF_LOG_WARNING("Scheduler ran out of space!");
}
return ret;
}
ret_code_t nrf_dfu_req_handler_init(nrf_dfu_observer_t observer)
{
ret_code_t ret_val;
nrf_dfu_result_t result;
if (observer == NULL)
{
return NRF_ERROR_INVALID_PARAM;
}
#if defined(BLE_STACK_SUPPORT_REQD) || defined(ANT_STACK_SUPPORT_REQD)
ret_val = nrf_dfu_flash_init(true);
#else
ret_val = nrf_dfu_flash_init(false);
#endif
if (ret_val != NRF_SUCCESS)
{
return ret_val;
}
nrf_dfu_validation_init();
if (nrf_dfu_validation_init_cmd_present())
{
/* Execute a previously received init packed. Subsequent executes will have no effect. */
result = nrf_dfu_validation_init_cmd_execute(&m_firmware_start_addr, &m_firmware_size_req);
if (result != NRF_DFU_RES_CODE_SUCCESS)
{
/* Init packet in flash is not valid! */
return NRF_ERROR_INTERNAL;
}
}
m_observer = observer;
/* Initialize extended error handling with "No error" as the most recent error. */
result = ext_error_set(NRF_DFU_EXT_ERROR_NO_ERROR);
UNUSED_RETURN_VALUE(result);
return NRF_SUCCESS;
}

@ -0,0 +1,346 @@
/**
* Copyright (c) 2016 - 2021, Nordic Semiconductor ASA
*
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without modification,
* are permitted provided that the following conditions are met:
*
* 1. Redistributions of source code must retain the above copyright notice, this
* list of conditions and the following disclaimer.
*
* 2. Redistributions in binary form, except as embedded into a Nordic
* Semiconductor ASA integrated circuit in a product or a software update for
* such product, must reproduce the above copyright notice, this list of
* conditions and the following disclaimer in the documentation and/or other
* materials provided with the distribution.
*
* 3. Neither the name of Nordic Semiconductor ASA nor the names of its
* contributors may be used to endorse or promote products derived from this
* software without specific prior written permission.
*
* 4. This software, with or without modification, must only be used with a
* Nordic Semiconductor ASA integrated circuit.
*
* 5. Any software provided in binary form under this license must not be reverse
* engineered, decompiled, modified and/or disassembled.
*
* THIS SOFTWARE IS PROVIDED BY NORDIC SEMICONDUCTOR ASA "AS IS" AND ANY EXPRESS
* OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
* OF MERCHANTABILITY, NONINFRINGEMENT, AND FITNESS FOR A PARTICULAR PURPOSE ARE
* DISCLAIMED. IN NO EVENT SHALL NORDIC SEMICONDUCTOR ASA OR CONTRIBUTORS BE
* LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE
* GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
* OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*
*/
/**@file
*
* @defgroup sdk_nrf_dfu_req_handler Request handling
* @{
* @ingroup nrf_dfu
*/
#ifndef NRF_DFU_REQ_HANDLER_H__
#define NRF_DFU_REQ_HANDLER_H__
#include <stdint.h>
#include <stdbool.h>
#include "app_util_platform.h"
#include "nrf_dfu_flash.h"
#include "nrf_dfu_types.h"
#ifdef __cplusplus
extern "C"
{
#endif
ANON_UNIONS_ENABLE;
/**
* @brief DFU object types.
*/
typedef enum
{
NRF_DFU_OBJ_TYPE_INVALID, //!< Invalid object type.
NRF_DFU_OBJ_TYPE_COMMAND, //!< Command object.
NRF_DFU_OBJ_TYPE_DATA, //!< Data object.
} nrf_dfu_obj_type_t;
/**
* @brief DFU protocol operation.
*/
typedef enum
{
NRF_DFU_OP_PROTOCOL_VERSION = 0x00, //!< Retrieve protocol version.
NRF_DFU_OP_OBJECT_CREATE = 0x01, //!< Create selected object.
NRF_DFU_OP_RECEIPT_NOTIF_SET = 0x02, //!< Set receipt notification.
NRF_DFU_OP_CRC_GET = 0x03, //!< Request CRC of selected object.
NRF_DFU_OP_OBJECT_EXECUTE = 0x04, //!< Execute selected object.
NRF_DFU_OP_OBJECT_SELECT = 0x06, //!< Select object.
NRF_DFU_OP_MTU_GET = 0x07, //!< Retrieve MTU size.
NRF_DFU_OP_OBJECT_WRITE = 0x08, //!< Write selected object.
NRF_DFU_OP_PING = 0x09, //!< Ping.
NRF_DFU_OP_HARDWARE_VERSION = 0x0A, //!< Retrieve hardware version.
NRF_DFU_OP_FIRMWARE_VERSION = 0x0B, //!< Retrieve firmware version.
NRF_DFU_OP_ABORT = 0x0C, //!< Abort the DFU procedure.
NRF_DFU_OP_RESPONSE = 0x60, //!< Response.
NRF_DFU_OP_INVALID = 0xFF,
} nrf_dfu_op_t;
/**
* @brief DFU operation result code.
*/
typedef enum
{
NRF_DFU_RES_CODE_INVALID = 0x00, //!< Invalid opcode.
NRF_DFU_RES_CODE_SUCCESS = 0x01, //!< Operation successful.
NRF_DFU_RES_CODE_OP_CODE_NOT_SUPPORTED = 0x02, //!< Opcode not supported.
NRF_DFU_RES_CODE_INVALID_PARAMETER = 0x03, //!< Missing or invalid parameter value.
NRF_DFU_RES_CODE_INSUFFICIENT_RESOURCES = 0x04, //!< Not enough memory for the data object.
NRF_DFU_RES_CODE_INVALID_OBJECT = 0x05, //!< Data object does not match the firmware and hardware requirements, the signature is wrong, or parsing the command failed.
NRF_DFU_RES_CODE_UNSUPPORTED_TYPE = 0x07, //!< Not a valid object type for a Create request.
NRF_DFU_RES_CODE_OPERATION_NOT_PERMITTED = 0x08, //!< The state of the DFU process does not allow this operation.
NRF_DFU_RES_CODE_OPERATION_FAILED = 0x0A, //!< Operation failed.
NRF_DFU_RES_CODE_EXT_ERROR = 0x0B, //!< Extended error. The next byte of the response contains the error code of the extended error (see @ref nrf_dfu_ext_error_code_t.
NRF_DFU_ERROR_INVALID_SIGNATURE = 0x0C, //!< The provided signature is wrong.
} nrf_dfu_result_t;
typedef enum
{
NRF_DFU_FIRMWARE_TYPE_SOFTDEVICE = 0x00,
NRF_DFU_FIRMWARE_TYPE_APPLICATION = 0x01,
NRF_DFU_FIRMWARE_TYPE_BOOTLOADER = 0x02,
NRF_DFU_FIRMWARE_TYPE_UNKNOWN = 0xFF,
} nrf_dfu_firmware_type_t;
/**
* @brief @ref NRF_DFU_OP_PROTOCOL_VERSION response details.
*/
typedef struct
{
uint8_t version; //!< Protocol version.
} nrf_dfu_response_protocol_t;
/**
* @brief @ref NRF_DFU_OP_HARDWARE_VERSION response details.
*/
typedef struct
{
uint32_t part; //!< Hardware part, from FICR register.
uint32_t variant; //!< Hardware variant, from FICR register.
struct
{
uint32_t rom_size; //!< ROM size, in bytes.
uint32_t ram_size; //!< RAM size, in bytes.
uint32_t rom_page_size; //!< ROM flash page size, in bytes.
} memory;
} nrf_dfu_response_hardware_t;
/**
* @brief @ref NRF_DFU_OP_FIRMWARE_VERSION response details.
*/
typedef struct
{
nrf_dfu_firmware_type_t type; //!< Firmware type.
uint32_t version; //!< Firmware version.
uint32_t addr; //!< Firmware address in flash.
uint32_t len; //!< Firmware length in bytes.
} nrf_dfu_response_firmware_t;
/**
* @brief @ref NRF_DFU_OP_OBJECT_SELECT response details.
*/
typedef struct
{
uint32_t offset; //!< Current offset.
uint32_t crc; //!< Current CRC.
uint32_t max_size; //!< Maximum size of selected object.
} nrf_dfu_response_select_t;
/**
* @brief @ref NRF_DFU_OP_OBJECT_CREATE response details.
*/
typedef struct
{
uint32_t offset; //!< Current offset
uint32_t crc; //!< Current CRC.
} nrf_dfu_response_create_t;
/**
* @brief @ref NRF_DFU_OP_OBJECT_WRITE response details.
*/
typedef struct
{
uint32_t offset; //!< Used only when packet receipt notification is used.
uint32_t crc; //!< Used only when packet receipt notification is used.
} nrf_dfu_response_write_t;
/**
* @brief @ref NRF_DFU_OP_CRC_GET response details.
*/
typedef struct
{
uint32_t offset; //!< Current offset.
uint32_t crc; //!< Current CRC.
} nrf_dfu_response_crc_t;
/**
* @brief @ref NRF_DFU_OP_PING response details.
*/
typedef struct
{
uint8_t id; //!< The received ID which is echoed back.
} nrf_dfu_response_ping_t;
/**
* @brief @ref NRF_DFU_OP_MTU_GET response details.
*/
typedef struct
{
uint16_t size; //!< The MTU size as specified by the local transport.
} nrf_dfu_response_mtu_t;
/**
* @brief DFU response message.
*/
typedef struct
{
nrf_dfu_op_t request; //!< Requested operation.
nrf_dfu_result_t result; //!< Result of the operation.
union
{
nrf_dfu_response_protocol_t protocol; //!< Protocol version response.
nrf_dfu_response_hardware_t hardware; //!< Hardware version response.
nrf_dfu_response_firmware_t firmware; //!< Firmware version response.
nrf_dfu_response_select_t select; //!< Select object response..
nrf_dfu_response_create_t create; //!< Create object response..
nrf_dfu_response_write_t write; //!< Write object response.
nrf_dfu_response_crc_t crc; //!< CRC response.
nrf_dfu_response_ping_t ping; //!< Ping response.
nrf_dfu_response_mtu_t mtu; //!< MTU response.
};
} nrf_dfu_response_t;
/**
* @brief @ref NRF_DFU_OP_FIRMWARE_VERSION request details.
*/
typedef struct
{
uint8_t image_number; //!< Index of the firmware.
} nrf_dfu_request_firmware_t;
/**
* @brief @ref NRF_DFU_OP_OBJECT_SELECT request details.
*/
typedef struct
{
uint32_t object_type; //!< Object type. See @ref nrf_dfu_obj_type_t.
} nrf_dfu_request_select_t;
/**
* @brief @ref NRF_DFU_OP_OBJECT_CREATE request details.
*/
typedef struct
{
uint32_t object_type; //!< Object type. See @ref nrf_dfu_obj_type_t.
uint32_t object_size; //!< Object size in bytes.
} nrf_dfu_request_create_t;
/**
* @brief @ref NRF_DFU_OP_OBJECT_WRITE request details.
*/
typedef struct
{
uint8_t const * p_data; //!< Data.
uint16_t len; //!< Length of data in @ref nrf_dfu_request_write_t::p_data.
} nrf_dfu_request_write_t;
/**
* @brief @ref NRF_DFU_OP_PING request details.
*/
typedef struct
{
uint8_t id; //!< Ping ID that will be returned in response.
} nrf_dfu_request_ping_t;
/**
* @brief @ref NRF_DFU_OP_MTU_GET request details.
*/
typedef struct
{
uint16_t size; //!< Transport MTU size in bytes.
} nrf_dfu_request_mtu_t;
/**
* @brief @ref NRF_DFU_OP_RECEIPT_NOTIF_SET request details.
*/
typedef struct
{
uint32_t target; //!< Target PRN.
} nrf_dfu_request_prn_t;
typedef void (*nrf_dfu_response_callback_t)(nrf_dfu_response_t * p_res, void * p_context);
/**
*@brief DFU request.
*/
typedef struct
{
nrf_dfu_op_t request; //!< Requested operation.
void * p_context;
struct
{
nrf_dfu_response_callback_t response; //!< Callback to call to send the response.
nrf_dfu_flash_callback_t write;
} callback;
union
{
nrf_dfu_request_firmware_t firmware; //!< Firmware version request.
nrf_dfu_request_select_t select; //!< Select object request.
nrf_dfu_request_create_t create; //!< Create object request.
nrf_dfu_request_write_t write; //!< Write object request.
nrf_dfu_request_ping_t ping; //!< Ping.
nrf_dfu_request_mtu_t mtu; //!< MTU size request.
nrf_dfu_request_prn_t prn; //!< Set receipt notification request.
};
} nrf_dfu_request_t;
/**@brief Function for initializing the request handling module.
*
* @param observer Callback function for receiving notifications.
*
* @retval NRF_SUCCESS If the operation was successful.
* @retval NRF_ERROR_INTERNAL If the init packet in flash is not valid.
* @retval NRF_ERROR_INVALID_PARAM If observer is not provided.
*/
ret_code_t nrf_dfu_req_handler_init(nrf_dfu_observer_t observer);
/**@brief Function for scheduling processing of a DFU request.
*
* Requests are processed asynchronously by the scheduler.
*
* @param[in] p_req Request to be handled. The response callback must be non-null.
*
* @retval NRF_SUCCESS If the command request was executed successfully.
* @retval NRF_ERROR_NO_MEM If the scheduler ran out of memory.
* @retval NRF_ERROR_INVALID_PARAM If the response callback is NULL.
*/
ret_code_t nrf_dfu_req_handler_on_req(nrf_dfu_request_t * p_req);
ANON_UNIONS_DISABLE;
#ifdef __cplusplus
}
#endif
#endif // NRF_DFU_REQ_HANDLER_H__
/** @} */

@ -0,0 +1,423 @@
/**
* Copyright (c) 2016 - 2021, Nordic Semiconductor ASA
*
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without modification,
* are permitted provided that the following conditions are met:
*
* 1. Redistributions of source code must retain the above copyright notice, this
* list of conditions and the following disclaimer.
*
* 2. Redistributions in binary form, except as embedded into a Nordic
* Semiconductor ASA integrated circuit in a product or a software update for
* such product, must reproduce the above copyright notice, this list of
* conditions and the following disclaimer in the documentation and/or other
* materials provided with the distribution.
*
* 3. Neither the name of Nordic Semiconductor ASA nor the names of its
* contributors may be used to endorse or promote products derived from this
* software without specific prior written permission.
*
* 4. This software, with or without modification, must only be used with a
* Nordic Semiconductor ASA integrated circuit.
*
* 5. Any software provided in binary form under this license must not be reverse
* engineered, decompiled, modified and/or disassembled.
*
* THIS SOFTWARE IS PROVIDED BY NORDIC SEMICONDUCTOR ASA "AS IS" AND ANY EXPRESS
* OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
* OF MERCHANTABILITY, NONINFRINGEMENT, AND FITNESS FOR A PARTICULAR PURPOSE ARE
* DISCLAIMED. IN NO EVENT SHALL NORDIC SEMICONDUCTOR ASA OR CONTRIBUTORS BE
* LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE
* GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
* OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*
*/
#include "nrf_dfu_settings.h"
#include <stddef.h>
#include <string.h>
#include "nrf_dfu_flash.h"
#include "nrf_soc.h"
#include "crc32.h"
#include "nrf_nvmc.h"
#include "sdk_config.h"
#define DFU_SETTINGS_VERSION_OFFSET (offsetof(nrf_dfu_settings_t, settings_version)) //<! Offset in the settings struct where the settings version is located.
#define DFU_SETTINGS_INIT_COMMAND_OFFSET (offsetof(nrf_dfu_settings_t, init_command)) //<! Offset in the settings struct where the InitCommand is located.
#define DFU_SETTINGS_BOOT_VALIDATION_OFFSET (offsetof(nrf_dfu_settings_t, boot_validation_crc)) //<! Offset in the settings struct where the boot validation info is located.
#define DFU_SETTINGS_BOOT_VALIDATION_SIZE ((3 * sizeof(boot_validation_t)) + 4)
#define DFU_SETTINGS_BOND_DATA_OFFSET_V1 (offsetof(nrf_dfu_settings_t, init_command) + INIT_COMMAND_MAX_SIZE_v1) //<! Offset in the settings struct where the bond data was located in settings version 1.
#define DFU_SETTINGS_ADV_NAME_OFFSET_V1 (offsetof(nrf_dfu_settings_t, init_command) + INIT_COMMAND_MAX_SIZE_v1 + NRF_DFU_PEER_DATA_LEN) //<! Offset in the settings struct where the bond data was located in settings version 1.
#define NRF_LOG_MODULE_NAME nrf_dfu_settings
#include "nrf_log.h"
NRF_LOG_MODULE_REGISTER();
/**@brief This variable reserves a page in flash for bootloader settings
* to ensure the linker doesn't place any code or variables at this location.
*/
#if defined (__CC_ARM )
uint8_t m_dfu_settings_buffer[BOOTLOADER_SETTINGS_PAGE_SIZE]
__attribute__((at(BOOTLOADER_SETTINGS_ADDRESS)))
__attribute__((used));
#elif defined ( __GNUC__ ) || defined ( __SES_ARM )
uint8_t m_dfu_settings_buffer[BOOTLOADER_SETTINGS_PAGE_SIZE]
__attribute__((section(".bootloader_settings_page")))
__attribute__((used));
#elif defined ( __ICCARM__ )
__no_init __root uint8_t m_dfu_settings_buffer[BOOTLOADER_SETTINGS_PAGE_SIZE]
@ BOOTLOADER_SETTINGS_ADDRESS;
#else
#error Not a valid compiler/linker for m_dfu_settings placement.
#endif // Compiler specific
#if defined(NRF52_SERIES)
/**@brief This variable reserves a page in flash for MBR parameters
* to ensure the linker doesn't place any code or variables at this location.
*/
#if defined ( __CC_ARM )
uint8_t m_mbr_params_page[NRF_MBR_PARAMS_PAGE_SIZE]
__attribute__((at(NRF_MBR_PARAMS_PAGE_ADDRESS)))
__attribute__((used));
#elif defined ( __GNUC__ ) || defined ( __SES_ARM )
uint8_t m_mbr_params_page[NRF_MBR_PARAMS_PAGE_SIZE]
__attribute__((section(".mbr_params_page")))
__attribute__((used));
#elif defined ( __ICCARM__ )
__no_init uint8_t m_mbr_params_page[NRF_MBR_PARAMS_PAGE_SIZE]
@ NRF_MBR_PARAMS_PAGE_ADDRESS;
#else
#error Not a valid compiler/linker for m_mbr_params_page placement.
#endif // Compiler specific
uint8_t * mp_dfu_settings_backup_buffer = &m_mbr_params_page[0];
#ifndef NRF_DFU_IN_APP
#define NRF_DFU_IN_APP 0
#endif
#define UICR_PARAM_PAGE_ADDR 0x10001018
#if !defined(BL_SETTINGS_ACCESS_ONLY) && !NRF_DFU_IN_APP
/**@brief This variable has the linker write the MBR parameters page address to the
* UICR register. This value will be written in the HEX file and thus to the
* UICR when the bootloader is flashed into the chip.
*/
#if defined ( __CC_ARM )
uint32_t const m_uicr_mbr_params_page_address
__attribute__((at(UICR_PARAM_PAGE_ADDR))) = NRF_MBR_PARAMS_PAGE_ADDRESS;
#elif defined ( __GNUC__ ) || defined ( __SES_ARM )
uint32_t const m_uicr_mbr_params_page_address
__attribute__ ((section(".uicr_mbr_params_page")))
__attribute__ ((used)) = NRF_MBR_PARAMS_PAGE_ADDRESS;
#elif defined ( __ICCARM__ )
__root uint32_t const m_uicr_mbr_params_page_address
@ UICR_PARAM_PAGE_ADDR = NRF_MBR_PARAMS_PAGE_ADDRESS;
#else
#error Not a valid compiler/linker for m_mbr_params_page placement.
#endif // Compiler specific
#endif // #ifndef BL_SETTINGS_ACCESS_ONLY
#endif // #if defined( NRF52_SERIES )
nrf_dfu_settings_t s_dfu_settings;
static uint32_t settings_crc_get(nrf_dfu_settings_t const * p_settings)
{
ASSERT(offsetof(nrf_dfu_settings_t, crc) == 0);
// The crc is calculated from the s_dfu_settings struct, except the crc itself, the init command, bond data, and boot validation.
return crc32_compute((uint8_t*)(p_settings) + 4, DFU_SETTINGS_INIT_COMMAND_OFFSET - 4, NULL);
}
static bool crc_ok(nrf_dfu_settings_t const * p_settings)
{
if (p_settings->crc != 0xFFFFFFFF)
{
// CRC is set. Content must be valid
uint32_t crc = settings_crc_get(p_settings);
if (crc == p_settings->crc)
{
return true;
}
}
return false;
}
static uint32_t boot_validation_crc(nrf_dfu_settings_t const * p_settings)
{
return crc32_compute((const uint8_t *)&p_settings->boot_validation_softdevice,
DFU_SETTINGS_BOOT_VALIDATION_SIZE - 4,
NULL);
}
static bool boot_validation_crc_ok(nrf_dfu_settings_t const * p_settings)
{
return (boot_validation_crc(p_settings) == p_settings->boot_validation_crc);
}
static bool settings_crc_ok(void)
{
nrf_dfu_settings_t const * p_settings = (nrf_dfu_settings_t const *)m_dfu_settings_buffer;
return crc_ok(p_settings);
}
static bool settings_backup_crc_ok(void)
{
nrf_dfu_settings_t const * p_settings = (nrf_dfu_settings_t const *)mp_dfu_settings_backup_buffer;
return crc_ok(p_settings) && ((p_settings->settings_version == 1) || boot_validation_crc_ok(p_settings));
}
#define REGION_COPY_BY_MEMBER(start_member, end_member, p_dst_addr) \
memcpy(p_dst_addr + offsetof(nrf_dfu_settings_t, start_member), \
mp_dfu_settings_backup_buffer + offsetof(nrf_dfu_settings_t, start_member), \
offsetof(nrf_dfu_settings_t, end_member) - offsetof(nrf_dfu_settings_t, start_member))
static void settings_forbidden_parts_copy_from_backup(uint8_t * p_dst_addr)
{
#if NRF_DFU_IN_APP || NRF_BL_DFU_ALLOW_UPDATE_FROM_APP
REGION_COPY_BY_MEMBER(settings_version, bank_current, p_dst_addr);
REGION_COPY_BY_MEMBER(bank_0, write_offset, p_dst_addr);
REGION_COPY_BY_MEMBER(sd_size, progress, p_dst_addr);
REGION_COPY_BY_MEMBER(boot_validation_crc, peer_data, p_dst_addr);
#else
REGION_COPY_BY_MEMBER(settings_version, enter_buttonless_dfu, p_dst_addr);
REGION_COPY_BY_MEMBER(init_command, peer_data, p_dst_addr);
#endif
}
void nrf_dfu_settings_reinit(void)
{
bool settings_valid = settings_crc_ok();
bool settings_backup_valid = settings_backup_crc_ok();
if (settings_valid)
{
NRF_LOG_DEBUG("Using settings page.");
memcpy(&s_dfu_settings, m_dfu_settings_buffer, sizeof(nrf_dfu_settings_t));
if (settings_backup_valid)
{
NRF_LOG_DEBUG("Copying forbidden parts from backup page.");
settings_forbidden_parts_copy_from_backup((uint8_t *)&s_dfu_settings);
}
}
else if (settings_backup_valid)
{
NRF_LOG_INFO("Restoring settings from backup since the settings page contents are "
"invalid (CRC error).");
memcpy(&s_dfu_settings,
mp_dfu_settings_backup_buffer,
sizeof(nrf_dfu_settings_t));
}
else
{
NRF_LOG_WARNING("Resetting bootloader settings since neither the settings page nor the "
"backup are valid (CRC error).");
memset(&s_dfu_settings, 0x00, sizeof(nrf_dfu_settings_t));
s_dfu_settings.settings_version = NRF_DFU_SETTINGS_VERSION;
}
if (NRF_DFU_SETTINGS_COMPATIBILITY_MODE && !NRF_DFU_IN_APP && (s_dfu_settings.settings_version == 1))
{
NRF_LOG_WARNING("Resetting bootloader settings since neither the settings page is old.");
memset(&s_dfu_settings, 0x00, sizeof(nrf_dfu_settings_t));
s_dfu_settings.settings_version = NRF_DFU_SETTINGS_VERSION;
}
return;
}
ret_code_t nrf_dfu_settings_init(bool sd_irq_initialized)
{
NRF_LOG_DEBUG("Calling nrf_dfu_settings_init()...");
ret_code_t err_code = nrf_dfu_flash_init(sd_irq_initialized);
if (err_code != NRF_SUCCESS)
{
NRF_LOG_ERROR("nrf_dfu_flash_init() failed with error: %x", err_code);
return NRF_ERROR_INTERNAL;
}
nrf_dfu_settings_reinit();
err_code = nrf_dfu_settings_write_and_backup(NULL);
if (err_code != NRF_SUCCESS)
{
NRF_LOG_ERROR("nrf_dfu_settings_write_and_backup() failed with error: %x", err_code);
return NRF_ERROR_INTERNAL;
}
return NRF_SUCCESS;
}
static bool settings_forbidden_parts_equal_to_backup(uint8_t * p_compare_addr)
{
nrf_dfu_settings_t temp_settings;
memcpy(&temp_settings, p_compare_addr, sizeof(nrf_dfu_settings_t));
settings_forbidden_parts_copy_from_backup((uint8_t *)&temp_settings);
return memcmp(&temp_settings, p_compare_addr, sizeof(nrf_dfu_settings_t)) == 0;
}
static ret_code_t settings_write(void * p_dst,
void const * p_src,
nrf_dfu_flash_callback_t callback,
nrf_dfu_settings_t * p_dfu_settings_buffer)
{
ret_code_t err_code;
if (memcmp(p_dst, p_src, sizeof(nrf_dfu_settings_t)) == 0)
{
NRF_LOG_DEBUG("Destination settings are identical to source, write not needed. Skipping.");
if (callback != NULL)
{
callback(NULL);
}
return NRF_SUCCESS;
}
if (NRF_DFU_IN_APP && !settings_forbidden_parts_equal_to_backup((uint8_t *)&s_dfu_settings))
{
NRF_LOG_WARNING("Settings write aborted since it tries writing to forbidden settings.");
return NRF_ERROR_FORBIDDEN;
}
NRF_LOG_DEBUG("Writing settings...");
NRF_LOG_DEBUG("Erasing old settings at: 0x%08x", p_dst);
// Not setting the callback function because ERASE is required before STORE
// Only report completion on successful STORE.
err_code = nrf_dfu_flash_erase((uint32_t)p_dst, 1, NULL);
if (err_code != NRF_SUCCESS)
{
NRF_LOG_ERROR("Could not erase the settings page!");
return NRF_ERROR_INTERNAL;
}
ASSERT(p_dfu_settings_buffer != NULL);
memcpy(p_dfu_settings_buffer, p_src, sizeof(nrf_dfu_settings_t));
err_code = nrf_dfu_flash_store((uint32_t)p_dst,
p_dfu_settings_buffer,
sizeof(nrf_dfu_settings_t),
callback);
if (err_code != NRF_SUCCESS)
{
NRF_LOG_ERROR("Could not write the DFU settings page!");
return NRF_ERROR_INTERNAL;
}
return NRF_SUCCESS;
}
ret_code_t nrf_dfu_settings_write(nrf_dfu_flash_callback_t callback)
{
static nrf_dfu_settings_t dfu_settings_buffer;
s_dfu_settings.crc = settings_crc_get(&s_dfu_settings);
s_dfu_settings.boot_validation_crc = boot_validation_crc(&s_dfu_settings);
return settings_write(m_dfu_settings_buffer,
&s_dfu_settings,
callback,
&dfu_settings_buffer);
}
void settings_backup(nrf_dfu_flash_callback_t callback, void * p_src)
{
#if NRF_DFU_IN_APP
NRF_LOG_INFO("Settings backup not available from app.");
#else
static nrf_dfu_settings_t dfu_settings_buffer;
NRF_LOG_INFO("Backing up settings page to address 0x%x.", mp_dfu_settings_backup_buffer);
ASSERT(crc_ok(p_src));
ret_code_t err_code = settings_write(mp_dfu_settings_backup_buffer,
p_src,
callback,
&dfu_settings_buffer);
if (err_code != NRF_SUCCESS)
{
NRF_LOG_ERROR("Could not perform backup of bootloader settings! Error: 0x%x", err_code);
}
#endif
}
void nrf_dfu_settings_backup(nrf_dfu_flash_callback_t callback)
{
settings_backup(callback, m_dfu_settings_buffer);
}
ret_code_t nrf_dfu_settings_write_and_backup(nrf_dfu_flash_callback_t callback)
{
#if NRF_DFU_IN_APP
ret_code_t err_code = nrf_dfu_settings_write(callback);
#else
ret_code_t err_code = nrf_dfu_settings_write(NULL);
if (err_code == NRF_SUCCESS)
{
settings_backup(callback, &s_dfu_settings);
}
#endif
return err_code;
}
__WEAK ret_code_t nrf_dfu_settings_additional_erase(void)
{
NRF_LOG_WARNING("No additional data erased");
return NRF_SUCCESS;
}
void nrf_dfu_settings_progress_reset(void)
{
memset(s_dfu_settings.init_command, 0xFF, INIT_COMMAND_MAX_SIZE); // Remove the last init command
memset(&s_dfu_settings.progress, 0, sizeof(dfu_progress_t));
s_dfu_settings.write_offset = 0;
}

@ -0,0 +1,212 @@
/**
* Copyright (c) 2016 - 2021, Nordic Semiconductor ASA
*
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without modification,
* are permitted provided that the following conditions are met:
*
* 1. Redistributions of source code must retain the above copyright notice, this
* list of conditions and the following disclaimer.
*
* 2. Redistributions in binary form, except as embedded into a Nordic
* Semiconductor ASA integrated circuit in a product or a software update for
* such product, must reproduce the above copyright notice, this list of
* conditions and the following disclaimer in the documentation and/or other
* materials provided with the distribution.
*
* 3. Neither the name of Nordic Semiconductor ASA nor the names of its
* contributors may be used to endorse or promote products derived from this
* software without specific prior written permission.
*
* 4. This software, with or without modification, must only be used with a
* Nordic Semiconductor ASA integrated circuit.
*
* 5. Any software provided in binary form under this license must not be reverse
* engineered, decompiled, modified and/or disassembled.
*
* THIS SOFTWARE IS PROVIDED BY NORDIC SEMICONDUCTOR ASA "AS IS" AND ANY EXPRESS
* OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
* OF MERCHANTABILITY, NONINFRINGEMENT, AND FITNESS FOR A PARTICULAR PURPOSE ARE
* DISCLAIMED. IN NO EVENT SHALL NORDIC SEMICONDUCTOR ASA OR CONTRIBUTORS BE
* LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE
* GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
* OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*
*/
/**@file
*
* @defgroup nrf_dfu_settings DFU settings
* @{
* @ingroup nrf_dfu
*/
#ifndef NRF_DFU_SETTINGS_H__
#define NRF_DFU_SETTINGS_H__
#include <stdint.h>
#include "nrf_dfu_types.h"
#include "nrf_dfu_flash.h"
#include "sdk_config.h"
#include "sdk_errors.h"
#ifdef __cplusplus
extern "C" {
#endif
/**@brief Global settings.
*
* @note Using this variable is not thread-safe.
*
*/
extern nrf_dfu_settings_t s_dfu_settings;
/**@brief Function for writing DFU settings to flash.
*
* @param[in] callback Pointer to a function that is called after completing the write operation.
*
* @retval NRF_SUCCESS If the write process was successfully initiated.
* @retval NRF_ERROR_INTERNAL If a flash error occurred.
*/
ret_code_t nrf_dfu_settings_write(nrf_dfu_flash_callback_t callback);
/**@brief Function for backing up the settings.
*
* This function copies the contents of the settings page (in flash) to a separate page (in flash).
* During @ref nrf_dfu_settings_init, the backup is restored if the original is invalid.
*
* @param[in] callback Pointer to a function that is called after completing the write operation.
*/
void nrf_dfu_settings_backup(nrf_dfu_flash_callback_t callback);
/**@brief Function for writing DFU settings to flash and to backup.
*
* This function first calls @ref nrf_dfu_settings_write and then @ref nrf_dfu_settings_backup.
*
* @param[in] callback Pointer to a function that is called after completing the write and backup operation.
*
* @retval NRF_SUCCESS If the write process was successfully initiated.
* @retval NRF_ERROR_INTERNAL If a flash error occurred during the first write.
*/
ret_code_t nrf_dfu_settings_write_and_backup(nrf_dfu_flash_callback_t callback);
/**@brief Function for initializing the DFU settings structure.
*
* Initializes the RAM structure from the flash contents.
* This function is called as part of @ref nrf_dfu_settings_init.
*
* @retval NRF_SUCCESS If the initialization was successful.
* @retval NRF_ERROR_INTERNAL If a flash error occurred.
*/
void nrf_dfu_settings_reinit(void);
/**@brief Function for initializing the DFU settings module.
*
* @retval NRF_SUCCESS If the initialization was successful.
* @retval NRF_ERROR_INTERNAL If a flash error occurred.
*/
ret_code_t nrf_dfu_settings_init(bool sd_irq_initialized);
#if defined(NRF_DFU_TRANSPORT_BLE) && NRF_DFU_TRANSPORT_BLE
/** @brief Function for storing peer data received through an SVCI call in DFU settings.
*
* @note The content of the type can be verified by a CRC value stored inside the struct
* If the CRC value is 0xFFFFFFFF, it means that no data is set.
*
* @note The storage operation is an asynchronous progress. Success will be notified
* through system events raised by the SoftDevice.
*
* @param[in] p_data Peer data to be stored in flash.
*
* @retval NRF_SUCCESS Asynchronous operation was successfully started.
* @retval NRF_ERROR_NULL p_data was NULL.
* @retval Any other error code reported by SoftDevice API calls.
*/
ret_code_t nrf_dfu_settings_peer_data_write(nrf_dfu_peer_data_t * p_data);
/** @brief Function for copying peer data from DFU settings to RAM.
*
* @param[in,out] p_data Structure to copy peer data to.
*
* @retval NRF_SUCCESS Peer data was successfully copied.
* @retval NRF_ERROR_NULL p_data was NULL.
*/
ret_code_t nrf_dfu_settings_peer_data_copy(nrf_dfu_peer_data_t * p_data);
/** @brief Function for validating peer data in DFU settings.
*
* @retval True if peer data is validated by CRC, false if not.
*/
bool nrf_dfu_settings_peer_data_is_valid(void);
/** @brief Function for storing an advertisement name received through an SVCI call in DFU settings.
*
* @note The content of the type is verifyable by a CRC-value stored inside the struct.
*
* @note The storage operation is an asynchronous progress. Success will be notified
* through system events raised by the SoftDevice.
*
* @param[in] p_adv_name Structure holding information about the new advertisement name.
*
* @retval NRF_SUCCESS Asynchronous operation was successfully started.
* @retval NRF_ERROR_NULL p_adv_name was NULL.
* @retval Any other error code reported by SoftDevice API calls.
*/
ret_code_t nrf_dfu_settings_adv_name_write(nrf_dfu_adv_name_t * p_adv_name);
/** @brief Function for copying the advertisement name from DFU settings to RAM.
*
* @param[in,out] p_adv_name Structure to copy the new advertisement name to.
*
* @retval NRF_SUCCESS Advertisement name was successfully copied.
* @retval NRF_ERROR_NULL p_adv_name was NULL.
*/
ret_code_t nrf_dfu_settings_adv_name_copy(nrf_dfu_adv_name_t * p_adv_name);
/** @brief Function for validating advertisement data in DFU settings.
*
* @retval True if advertisement name is validated by CRC, false if not.
*/
bool nrf_dfu_settings_adv_name_is_valid(void);
#endif // NRF_DFU_TRANSPORT_BLE
/** @brief Function for erasing additional data in DFU settings.
*
* @note Erasing additional data in DFU settings is only possible
* if nrf_dfu_flash is initialized to not use SoftDevice calls.
*
* @retval NRF_SUCCESS Additional data was successfully erased.
* @retval Any other error code reported by nrf_dfu_flash
*/
ret_code_t nrf_dfu_settings_additional_erase(void);
/** @brief Function for resetting both init command and DFU transfer progress inside settings structure.
*
* @note This function does not perform flash operation.
* In order to save the reset state, please use @ref nrf_dfu_settings_write function.
*/
void nrf_dfu_settings_progress_reset(void);
#ifdef __cplusplus
}
#endif
#endif // NRF_DFU_SETTINGS_H__
/**@} */

@ -0,0 +1,185 @@
/**
* Copyright (c) 2017 - 2021, Nordic Semiconductor ASA
*
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without modification,
* are permitted provided that the following conditions are met:
*
* 1. Redistributions of source code must retain the above copyright notice, this
* list of conditions and the following disclaimer.
*
* 2. Redistributions in binary form, except as embedded into a Nordic
* Semiconductor ASA integrated circuit in a product or a software update for
* such product, must reproduce the above copyright notice, this list of
* conditions and the following disclaimer in the documentation and/or other
* materials provided with the distribution.
*
* 3. Neither the name of Nordic Semiconductor ASA nor the names of its
* contributors may be used to endorse or promote products derived from this
* software without specific prior written permission.
*
* 4. This software, with or without modification, must only be used with a
* Nordic Semiconductor ASA integrated circuit.
*
* 5. Any software provided in binary form under this license must not be reverse
* engineered, decompiled, modified and/or disassembled.
*
* THIS SOFTWARE IS PROVIDED BY NORDIC SEMICONDUCTOR ASA "AS IS" AND ANY EXPRESS
* OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
* OF MERCHANTABILITY, NONINFRINGEMENT, AND FITNESS FOR A PARTICULAR PURPOSE ARE
* DISCLAIMED. IN NO EVENT SHALL NORDIC SEMICONDUCTOR ASA OR CONTRIBUTORS BE
* LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE
* GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
* OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*
*/
#include <stddef.h>
#include <string.h>
#include "app_error.h"
#include "sdk_macros.h"
#include "nrf_dfu_settings.h"
#include "nrf_nvmc.h"
#include "crc32.h"
#define NRF_LOG_MODULE_NAME nrf_dfu_settings_svci
#include "nrf_log.h"
NRF_LOG_MODULE_REGISTER();
#define DFU_SETTINGS_PEER_DATA_OFFSET offsetof(nrf_dfu_settings_t, peer_data) //<! Offset in the settings struct where the additional peer data is located.
#define DFU_SETTINGS_ADV_NAME_OFFSET offsetof(nrf_dfu_settings_t, adv_name) //<! Offset in the settings struct where the additional advertisement name is located.
extern nrf_dfu_settings_t s_dfu_settings;
extern uint8_t m_dfu_settings_buffer[CODE_PAGE_SIZE];
#if defined(NRF_DFU_BLE_REQUIRES_BONDS) && (NRF_DFU_BLE_REQUIRES_BONDS == 1)
ret_code_t nrf_dfu_settings_peer_data_write(nrf_dfu_peer_data_t * p_data)
{
uint32_t ret_val;
uint32_t * p_peer_data_settings =
(uint32_t*) &m_dfu_settings_buffer[DFU_SETTINGS_PEER_DATA_OFFSET];
uint32_t crc = (uint32_t)*p_peer_data_settings;
VERIFY_PARAM_NOT_NULL(p_data);
if (crc != 0xFFFFFFFF)
{
// Already written to, must be cleared out
// Reset required.
return NRF_ERROR_INVALID_STATE;
}
// Calculate the CRC for the structure excluding the CRC value itself.
p_data->crc = crc32_compute((uint8_t*)p_data + 4, sizeof(nrf_dfu_peer_data_t) - 4, NULL);
// Using SoftDevice call since this function cannot use static memory.
ret_val = sd_flash_write(p_peer_data_settings,
(uint32_t*)p_data,
sizeof(nrf_dfu_peer_data_t)/4);
return ret_val;
}
ret_code_t nrf_dfu_settings_peer_data_copy(nrf_dfu_peer_data_t * p_data)
{
VERIFY_PARAM_NOT_NULL(p_data);
memcpy(p_data, &m_dfu_settings_buffer[DFU_SETTINGS_PEER_DATA_OFFSET], sizeof(nrf_dfu_peer_data_t));
return NRF_SUCCESS;
}
bool nrf_dfu_settings_peer_data_is_valid(void)
{
nrf_dfu_peer_data_t * p_peer_data =
(nrf_dfu_peer_data_t*) &m_dfu_settings_buffer[DFU_SETTINGS_PEER_DATA_OFFSET];
// Calculate the CRC for the structure excluding the CRC value itself.
uint32_t crc = crc32_compute((uint8_t*)p_peer_data + 4, sizeof(nrf_dfu_peer_data_t) - 4, NULL);
return (p_peer_data->crc == crc);
}
#else // not NRF_DFU_BLE_REQUIRES_BONDS
ret_code_t nrf_dfu_settings_adv_name_write(nrf_dfu_adv_name_t * p_adv_name)
{
uint32_t ret_val;
uint32_t * p_adv_name_settings =
(uint32_t*) &m_dfu_settings_buffer[DFU_SETTINGS_ADV_NAME_OFFSET];
uint32_t crc = (uint32_t)*p_adv_name_settings;
VERIFY_PARAM_NOT_NULL(p_adv_name);
if (crc != 0xFFFFFFFF)
{
// Already written to, must be cleared out.
// Reset required
return NRF_ERROR_INVALID_STATE;
}
// Calculate the CRC for the structure excluding the CRC value itself.
p_adv_name->crc = crc32_compute((uint8_t *)p_adv_name + 4, sizeof(nrf_dfu_adv_name_t) - 4, NULL);
// Using SoftDevice call since this function cannot use static memory.
ret_val = sd_flash_write(p_adv_name_settings,
(uint32_t*) p_adv_name,
sizeof(nrf_dfu_adv_name_t)/4);
return ret_val;
}
ret_code_t nrf_dfu_settings_adv_name_copy(nrf_dfu_adv_name_t * p_adv_name)
{
VERIFY_PARAM_NOT_NULL(p_adv_name);
memcpy(p_adv_name, &m_dfu_settings_buffer[DFU_SETTINGS_ADV_NAME_OFFSET], sizeof(nrf_dfu_adv_name_t));
return NRF_SUCCESS;
}
bool nrf_dfu_settings_adv_name_is_valid(void)
{
nrf_dfu_adv_name_t * p_adv_name =
(nrf_dfu_adv_name_t*)&m_dfu_settings_buffer[DFU_SETTINGS_ADV_NAME_OFFSET];
// Calculate the CRC for the structure excluding the CRC value itself.
uint32_t crc = crc32_compute((uint8_t*)p_adv_name + 4, sizeof(nrf_dfu_adv_name_t) - 4, NULL);
return (p_adv_name->crc == crc);
}
#endif
//lint -save -e(14)
ret_code_t nrf_dfu_settings_additional_erase(void)
{
ret_code_t ret_code = NRF_SUCCESS;
// Check CRC for both types.
if ( (s_dfu_settings.peer_data.crc != 0xFFFFFFFF)
|| (s_dfu_settings.adv_name.crc != 0xFFFFFFFF))
{
NRF_LOG_DEBUG("Erasing settings page additional data.");
// Erasing and resetting the settings page without the peer data/adv data
nrf_nvmc_page_erase(BOOTLOADER_SETTINGS_ADDRESS);
nrf_nvmc_write_words(BOOTLOADER_SETTINGS_ADDRESS, (uint32_t const *)&s_dfu_settings, DFU_SETTINGS_PEER_DATA_OFFSET / 4);
}
return ret_code;
}
//lint -restore

@ -0,0 +1,87 @@
/**
* Copyright (c) 2016 - 2021, Nordic Semiconductor ASA
*
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without modification,
* are permitted provided that the following conditions are met:
*
* 1. Redistributions of source code must retain the above copyright notice, this
* list of conditions and the following disclaimer.
*
* 2. Redistributions in binary form, except as embedded into a Nordic
* Semiconductor ASA integrated circuit in a product or a software update for
* such product, must reproduce the above copyright notice, this list of
* conditions and the following disclaimer in the documentation and/or other
* materials provided with the distribution.
*
* 3. Neither the name of Nordic Semiconductor ASA nor the names of its
* contributors may be used to endorse or promote products derived from this
* software without specific prior written permission.
*
* 4. This software, with or without modification, must only be used with a
* Nordic Semiconductor ASA integrated circuit.
*
* 5. Any software provided in binary form under this license must not be reverse
* engineered, decompiled, modified and/or disassembled.
*
* THIS SOFTWARE IS PROVIDED BY NORDIC SEMICONDUCTOR ASA "AS IS" AND ANY EXPRESS
* OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
* OF MERCHANTABILITY, NONINFRINGEMENT, AND FITNESS FOR A PARTICULAR PURPOSE ARE
* DISCLAIMED. IN NO EVENT SHALL NORDIC SEMICONDUCTOR ASA OR CONTRIBUTORS BE
* LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE
* GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
* OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*
*/
#include <stdint.h>
#include <stdbool.h>
#include "nrf_log.h"
#include "nrf_sdm.h"
#include "app_util.h"
#define APP_START_ADDR CODE_START
uint32_t nrf_dfu_svci_vector_table_set(void)
{
uint32_t err_code;
uint32_t bootloader_addr = BOOTLOADER_ADDRESS;
if (bootloader_addr != 0xFFFFFFFF)
{
NRF_LOG_INFO("Setting vector table to bootloader: 0x%08x", bootloader_addr);
err_code = sd_softdevice_vector_table_base_set(bootloader_addr);
if (err_code != NRF_SUCCESS)
{
NRF_LOG_ERROR("Failed running sd_softdevice_vector_table_base_set");
return err_code;
}
return NRF_SUCCESS;
}
NRF_LOG_ERROR("No bootloader was found");
return NRF_ERROR_NO_MEM;
}
uint32_t nrf_dfu_svci_vector_table_unset(void)
{
uint32_t err_code;
NRF_LOG_INFO("Setting vector table to main app: 0x%08x", APP_START_ADDR);
err_code = sd_softdevice_vector_table_base_set(APP_START_ADDR);
if (err_code != NRF_SUCCESS)
{
NRF_LOG_ERROR("Failed running sd_softdevice_vector_table_base_set");
return err_code;
}
return NRF_SUCCESS;
}

@ -0,0 +1,212 @@
/**
* Copyright (c) 2016 - 2021, Nordic Semiconductor ASA
*
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without modification,
* are permitted provided that the following conditions are met:
*
* 1. Redistributions of source code must retain the above copyright notice, this
* list of conditions and the following disclaimer.
*
* 2. Redistributions in binary form, except as embedded into a Nordic
* Semiconductor ASA integrated circuit in a product or a software update for
* such product, must reproduce the above copyright notice, this list of
* conditions and the following disclaimer in the documentation and/or other
* materials provided with the distribution.
*
* 3. Neither the name of Nordic Semiconductor ASA nor the names of its
* contributors may be used to endorse or promote products derived from this
* software without specific prior written permission.
*
* 4. This software, with or without modification, must only be used with a
* Nordic Semiconductor ASA integrated circuit.
*
* 5. Any software provided in binary form under this license must not be reverse
* engineered, decompiled, modified and/or disassembled.
*
* THIS SOFTWARE IS PROVIDED BY NORDIC SEMICONDUCTOR ASA "AS IS" AND ANY EXPRESS
* OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
* OF MERCHANTABILITY, NONINFRINGEMENT, AND FITNESS FOR A PARTICULAR PURPOSE ARE
* DISCLAIMED. IN NO EVENT SHALL NORDIC SEMICONDUCTOR ASA OR CONTRIBUTORS BE
* LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE
* GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
* OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*
*/
#include <string.h>
#include "nrf_svci_async_handler.h"
#include "app_error.h"
#include "nrf_nvmc.h"
#include "nrf_dfu_types.h"
#include "nrf_dfu_ble_svci_bond_sharing.h"
#include "nrf_log.h"
#include "nrf_dfu_settings.h"
#include "sdk_config.h"
#if (NRF_DFU_TRANSPORT_BLE && NRF_DFU_BLE_REQUIRES_BONDS)
NRF_SVCI_ASYNC_HANDLER_CREATE(NRF_DFU_SVCI_SET_PEER_DATA,
nrf_dfu_set_peer_data, nrf_dfu_peer_data_t, nrf_dfu_peer_data_state_t);
static uint32_t nrf_dfu_set_peer_data_handler(nrf_dfu_set_peer_data_svci_async_t * p_async)
{
VERIFY_PARAM_NOT_NULL(p_async);
p_async->async_func = nrf_dfu_set_peer_data_on_call;
p_async->sys_evt_handler = nrf_dfu_set_peer_data_on_sys_evt;
p_async->state = DFU_PEER_DATA_STATE_INITIALIZED;
return NRF_SUCCESS;
}
static uint32_t nrf_dfu_set_peer_data_on_call(nrf_dfu_peer_data_t * p_data,
nrf_dfu_peer_data_state_t * p_state)
{
uint32_t ret_val = NRF_ERROR_BUSY;
VERIFY_PARAM_NOT_NULL(p_state);
switch (*p_state)
{
case DFU_PEER_DATA_STATE_INVALID:
return NRF_ERROR_INVALID_STATE;
case DFU_PEER_DATA_STATE_INITIALIZED:
ret_val = nrf_dfu_settings_peer_data_write(p_data);
if (ret_val == NRF_SUCCESS)
{
*p_state = DFU_PEER_DATA_STATE_WRITE_REQUESTED;
}
break;
case DFU_PEER_DATA_STATE_WRITE_REQUESTED:
return NRF_ERROR_BUSY;
case DFU_PEER_DATA_STATE_WRITE_FINISHED:
return NRF_ERROR_INVALID_STATE;
case DFU_PEER_DATA_STATE_WRITE_FAILED:
return NRF_ERROR_INVALID_STATE;
}
return ret_val;
}
static uint32_t nrf_dfu_set_peer_data_on_sys_evt(uint32_t sys_event, nrf_dfu_peer_data_state_t * p_state)
{
uint32_t ret_val = NRF_ERROR_INVALID_STATE;
VERIFY_PARAM_NOT_NULL(p_state);
if (*p_state == DFU_PEER_DATA_STATE_WRITE_REQUESTED)
{
switch (sys_event)
{
case NRF_EVT_FLASH_OPERATION_ERROR:
return NRF_ERROR_BUSY;
case NRF_EVT_FLASH_OPERATION_SUCCESS:
ret_val = NRF_SUCCESS;
(*p_state) = DFU_PEER_DATA_STATE_WRITE_FINISHED;
break;
default:
// Event not intended for us
break;
}
}
return ret_val;
}
#elif (NRF_DFU_TRANSPORT_BLE && !NRF_DFU_BLE_REQUIRES_BONDS)
NRF_SVCI_ASYNC_HANDLER_CREATE(NRF_DFU_SVCI_SET_ADV_NAME,
nrf_dfu_set_adv_name, nrf_dfu_adv_name_t, nrf_dfu_set_adv_name_state_t);
static uint32_t nrf_dfu_set_adv_name_handler(nrf_dfu_set_adv_name_svci_async_t * p_async)
{
VERIFY_PARAM_NOT_NULL(p_async);
p_async->async_func = nrf_dfu_set_adv_name_on_call;
p_async->sys_evt_handler = nrf_dfu_set_adv_name_on_sys_evt;
p_async->state = DFU_ADV_NAME_STATE_INITIALIZED;
return NRF_SUCCESS;
}
static uint32_t nrf_dfu_set_adv_name_on_call(nrf_dfu_adv_name_t * p_adv_name,
nrf_dfu_set_adv_name_state_t * p_state)
{
uint32_t ret_val = NRF_ERROR_BUSY;
VERIFY_PARAM_NOT_NULL(p_state);
switch (*p_state)
{
case DFU_ADV_NAME_STATE_INVALID:
return NRF_ERROR_INVALID_STATE;
case DFU_ADV_NAME_STATE_INITIALIZED:
ret_val = nrf_dfu_settings_adv_name_write(p_adv_name);
if (ret_val == NRF_SUCCESS)
{
*p_state = DFU_ADV_NAME_STATE_WRITE_REQUESTED;
}
break;
case DFU_ADV_NAME_STATE_WRITE_REQUESTED:
return NRF_ERROR_BUSY;
case DFU_ADV_NAME_STATE_WRITE_FINISHED:
return NRF_ERROR_INVALID_STATE;
case DFU_ADV_NAME_STATE_WRITE_FAILED:
return NRF_ERROR_INVALID_STATE;
}
return ret_val;
}
static uint32_t nrf_dfu_set_adv_name_on_sys_evt(uint32_t sys_event, nrf_dfu_set_adv_name_state_t * p_state)
{
uint32_t ret_val = NRF_ERROR_INVALID_STATE;
VERIFY_PARAM_NOT_NULL(p_state);
if (*p_state == DFU_ADV_NAME_STATE_WRITE_REQUESTED)
{
switch (sys_event)
{
case NRF_EVT_FLASH_OPERATION_ERROR:
return NRF_ERROR_BUSY;
case NRF_EVT_FLASH_OPERATION_SUCCESS:
ret_val = NRF_SUCCESS;
(*p_state) = DFU_ADV_NAME_STATE_WRITE_FINISHED;
break;
default:
// Event not intended for us
break;
}
}
return ret_val;
}
#endif // NRF_DFU_TRANSPORT_BLE && !NRF_DFU_BLE_REQUIRES_BONDS

@ -0,0 +1,91 @@
/**
* Copyright (c) 2016 - 2021, Nordic Semiconductor ASA
*
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without modification,
* are permitted provided that the following conditions are met:
*
* 1. Redistributions of source code must retain the above copyright notice, this
* list of conditions and the following disclaimer.
*
* 2. Redistributions in binary form, except as embedded into a Nordic
* Semiconductor ASA integrated circuit in a product or a software update for
* such product, must reproduce the above copyright notice, this list of
* conditions and the following disclaimer in the documentation and/or other
* materials provided with the distribution.
*
* 3. Neither the name of Nordic Semiconductor ASA nor the names of its
* contributors may be used to endorse or promote products derived from this
* software without specific prior written permission.
*
* 4. This software, with or without modification, must only be used with a
* Nordic Semiconductor ASA integrated circuit.
*
* 5. Any software provided in binary form under this license must not be reverse
* engineered, decompiled, modified and/or disassembled.
*
* THIS SOFTWARE IS PROVIDED BY NORDIC SEMICONDUCTOR ASA "AS IS" AND ANY EXPRESS
* OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
* OF MERCHANTABILITY, NONINFRINGEMENT, AND FITNESS FOR A PARTICULAR PURPOSE ARE
* DISCLAIMED. IN NO EVENT SHALL NORDIC SEMICONDUCTOR ASA OR CONTRIBUTORS BE
* LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE
* GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
* OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*
*/
#include "nrf_dfu_transport.h"
#include "nrf_log.h"
#define DFU_TRANS_SECTION_ITEM_GET(i) NRF_SECTION_ITEM_GET(dfu_trans, nrf_dfu_transport_t, (i))
#define DFU_TRANS_SECTION_ITEM_COUNT NRF_SECTION_ITEM_COUNT(dfu_trans, nrf_dfu_transport_t)
NRF_SECTION_DEF(dfu_trans, const nrf_dfu_transport_t);
uint32_t nrf_dfu_transports_init(nrf_dfu_observer_t observer)
{
uint32_t const num_transports = DFU_TRANS_SECTION_ITEM_COUNT;
uint32_t ret_val = NRF_SUCCESS;
NRF_LOG_DEBUG("Initializing transports (found: %d)", num_transports);
for (uint32_t i = 0; i < num_transports; i++)
{
nrf_dfu_transport_t * const trans = DFU_TRANS_SECTION_ITEM_GET(i);
ret_val = trans->init_func(observer);
if (ret_val != NRF_SUCCESS)
{
NRF_LOG_DEBUG("Failed to initialize transport %d, error %d", i, ret_val);
break;
}
}
return ret_val;
}
uint32_t nrf_dfu_transports_close(nrf_dfu_transport_t const * p_exception)
{
uint32_t const num_transports = DFU_TRANS_SECTION_ITEM_COUNT;
uint32_t ret_val = NRF_SUCCESS;
NRF_LOG_DEBUG("Shutting down transports (found: %d)", num_transports);
for (uint32_t i = 0; i < num_transports; i++)
{
nrf_dfu_transport_t * const trans = DFU_TRANS_SECTION_ITEM_GET(i);
ret_val = trans->close_func(p_exception);
if (ret_val != NRF_SUCCESS)
{
NRF_LOG_DEBUG("Failed to shutdown transport %d, error %d", i, ret_val);
break;
}
}
return ret_val;
}

@ -0,0 +1,134 @@
/**
* Copyright (c) 2016 - 2021, Nordic Semiconductor ASA
*
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without modification,
* are permitted provided that the following conditions are met:
*
* 1. Redistributions of source code must retain the above copyright notice, this
* list of conditions and the following disclaimer.
*
* 2. Redistributions in binary form, except as embedded into a Nordic
* Semiconductor ASA integrated circuit in a product or a software update for
* such product, must reproduce the above copyright notice, this list of
* conditions and the following disclaimer in the documentation and/or other
* materials provided with the distribution.
*
* 3. Neither the name of Nordic Semiconductor ASA nor the names of its
* contributors may be used to endorse or promote products derived from this
* software without specific prior written permission.
*
* 4. This software, with or without modification, must only be used with a
* Nordic Semiconductor ASA integrated circuit.
*
* 5. Any software provided in binary form under this license must not be reverse
* engineered, decompiled, modified and/or disassembled.
*
* THIS SOFTWARE IS PROVIDED BY NORDIC SEMICONDUCTOR ASA "AS IS" AND ANY EXPRESS
* OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
* OF MERCHANTABILITY, NONINFRINGEMENT, AND FITNESS FOR A PARTICULAR PURPOSE ARE
* DISCLAIMED. IN NO EVENT SHALL NORDIC SEMICONDUCTOR ASA OR CONTRIBUTORS BE
* LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE
* GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
* OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*
*/
/**@file
*
* @defgroup sdk_nrf_dfu_transport DFU transport
* @{
* @ingroup nrf_dfu
* @brief Generic Device Firmware Update (DFU) transport interface.
*
* @details The DFU transport module defines a generic interface that must
* be implemented for each transport layer.
*/
#ifndef NRF_DFU_TRANSPORT_H__
#define NRF_DFU_TRANSPORT_H__
#include <stdint.h>
#include "nrf_section.h"
#include "nrf_dfu_types.h"
#ifdef __cplusplus
extern "C" {
#endif
/** @brief Forward declaration of nrf_dfu_transport_t */
typedef struct nrf_dfu_transport_s nrf_dfu_transport_t;
/** @brief Function type for initializing a DFU transport.
*
* @details This function initializes a DFU transport. The implementation
* of the function must initialize DFU mode and stay in service
* until either the device is reset or the DFU operation is finalized.
* When the DFU transport receives requests, it should call @ref nrf_dfu_req_handler_on_req for handling the requests.
*
* @param observer Callback function for receiving DFU transport notifications.
*
* @retval NRF_SUCCESS If initialization was successful for the transport. Any other return code indicates that the DFU transport could not be initialized.
*/
typedef uint32_t (*nrf_dfu_init_fn_t)(nrf_dfu_observer_t observer);
/** @brief Function type for closing down a DFU transport.
*
* @details This function closes down a DFU transport in a gentle way.
*
* @param[in] p_exception If exception matches current transport closing should be omitted.
*
* @retval NRF_SUCCESS If closing was successful for the transport. Any other return code indicates that the DFU transport could not be closed closed down.
*/
typedef uint32_t (*nrf_dfu_close_fn_t)(nrf_dfu_transport_t const * p_exception);
/** @brief DFU transport registration.
*
* @details Every DFU transport must provide a registration of the initialization function.
*/
struct nrf_dfu_transport_s
{
nrf_dfu_init_fn_t init_func; /**< Registration of the init function to run to initialize a DFU transport. */
nrf_dfu_close_fn_t close_func; /**< Registration of the close function to close down a DFU transport. */
};
/** @brief Function for initializing all the registered DFU transports.
*
* @retval NRF_SUCCESS If all DFU transport were initialized successfully.
* Any other error code indicates that at least one DFU
* transport could not be initialized.
*/
uint32_t nrf_dfu_transports_init(nrf_dfu_observer_t observer);
/** @brief Function for closing down all (with optional exception) the registered DFU transports.
*
* @param[in] p_exception Transport which should not be closed. NULL if all transports should be closed.
* @retval NRF_SUCCESS If all DFU transport were closed down successfully.
* Any other error code indicates that at least one DFU
* transport could not be closed down.
*/
uint32_t nrf_dfu_transports_close(nrf_dfu_transport_t const * p_exception);
/** @brief Macro for registering a DFU transport by using section variables.
*
* @details This macro places a variable in a section named "dfu_trans", which
* is initialized by @ref nrf_dfu_transports_init.
*/
#define DFU_TRANSPORT_REGISTER(trans_var) NRF_SECTION_ITEM_REGISTER(dfu_trans, trans_var)
#ifdef __cplusplus
}
#endif
#endif // NRF_DFU_TRANSPORT_H__
/** @} */

@ -0,0 +1,244 @@
/**
* Copyright (c) 2017 - 2021, Nordic Semiconductor ASA
*
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without modification,
* are permitted provided that the following conditions are met:
*
* 1. Redistributions of source code must retain the above copyright notice, this
* list of conditions and the following disclaimer.
*
* 2. Redistributions in binary form, except as embedded into a Nordic
* Semiconductor ASA integrated circuit in a product or a software update for
* such product, must reproduce the above copyright notice, this list of
* conditions and the following disclaimer in the documentation and/or other
* materials provided with the distribution.
*
* 3. Neither the name of Nordic Semiconductor ASA nor the names of its
* contributors may be used to endorse or promote products derived from this
* software without specific prior written permission.
*
* 4. This software, with or without modification, must only be used with a
* Nordic Semiconductor ASA integrated circuit.
*
* 5. Any software provided in binary form under this license must not be reverse
* engineered, decompiled, modified and/or disassembled.
*
* THIS SOFTWARE IS PROVIDED BY NORDIC SEMICONDUCTOR ASA "AS IS" AND ANY EXPRESS
* OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
* OF MERCHANTABILITY, NONINFRINGEMENT, AND FITNESS FOR A PARTICULAR PURPOSE ARE
* DISCLAIMED. IN NO EVENT SHALL NORDIC SEMICONDUCTOR ASA OR CONTRIBUTORS BE
* LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE
* GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
* OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*
*/
#include "nrf_dfu_trigger_usb.h"
#include "app_usbd.h"
#include "app_usbd_nrf_dfu_trigger.h"
#include "nrf_drv_clock.h"
#include "nrf_log_ctrl.h"
#include "nrf_gpio.h"
#include "boards.h"
#include "app_util.h"
#include "app_usbd_serial_num.h"
#define NRF_LOG_MODULE_NAME nrf_dfu_trigger_usb
#include "nrf_log.h"
NRF_LOG_MODULE_REGISTER();
#ifndef BSP_SELF_PINRESET_PIN
#error "This module is intended to be used with boards that have the GP pin shortened with the RESET pin."
#endif
/**
* @brief Enable power USB detection.
*
* Configure if the example supports USB port connection.
*/
#ifndef USBD_POWER_DETECTION
#define USBD_POWER_DETECTION true
#endif
#define DFU_FLASH_PAGE_SIZE (NRF_FICR->CODEPAGESIZE)
#define DFU_FLASH_PAGE_COUNT (NRF_FICR->CODESIZE)
// Semantic versioning string.
#define VERSION_STRING STRINGIFY(APP_VERSION_MAJOR) "." STRINGIFY(APP_VERSION_MINOR) "." STRINGIFY(APP_VERSION_PATCH) APP_VERSION_PRERELEASE APP_VERSION_METADATA
static uint8_t m_version_string[] = APP_NAME " " VERSION_STRING; ///< Human-readable version string.
static app_usbd_nrf_dfu_trigger_nordic_info_t m_dfu_info; ///< Struct with various information about the current firmware.
static void dfu_trigger_evt_handler(app_usbd_class_inst_t const * p_inst,
app_usbd_nrf_dfu_trigger_user_event_t event)
{
UNUSED_PARAMETER(p_inst);
switch (event)
{
case APP_USBD_NRF_DFU_TRIGGER_USER_EVT_DETACH:
NRF_LOG_INFO("DFU Detach request received. Triggering a pin reset.");
NRF_LOG_FINAL_FLUSH();
nrf_gpio_cfg_output(BSP_SELF_PINRESET_PIN);
nrf_gpio_pin_clear(BSP_SELF_PINRESET_PIN);
break;
default:
break;
}
}
APP_USBD_NRF_DFU_TRIGGER_GLOBAL_DEF(m_app_dfu,
NRF_DFU_TRIGGER_USB_INTERFACE_NUM,
&m_dfu_info,
m_version_string,
dfu_trigger_evt_handler);
static void usbd_user_evt_handler(app_usbd_event_type_t event)
{
switch (event)
{
case APP_USBD_EVT_DRV_SUSPEND:
break;
case APP_USBD_EVT_DRV_RESUME:
break;
case APP_USBD_EVT_STARTED:
break;
case APP_USBD_EVT_STOPPED:
app_usbd_disable();
break;
case APP_USBD_EVT_POWER_DETECTED:
NRF_LOG_INFO("USB power detected");
if (!nrf_drv_usbd_is_enabled())
{
app_usbd_enable();
}
break;
case APP_USBD_EVT_POWER_REMOVED:
NRF_LOG_INFO("USB power removed");
app_usbd_stop();
break;
case APP_USBD_EVT_POWER_READY:
NRF_LOG_INFO("USB ready");
app_usbd_start();
break;
default:
break;
}
}
static void strings_create(void)
{
uint8_t prev_char = 'a'; // Arbitrary valid char, not '-'.
// Remove characters that are not supported in semantic version strings.
for (size_t i = strlen(APP_NAME) + 1; i < strlen((char*)m_version_string); i++)
{
if (((m_version_string[i] >= 'a') && (m_version_string[i] <= 'z'))
|| ((m_version_string[i] >= 'A') && (m_version_string[i] <= 'Z'))
|| ((m_version_string[i] >= '0') && (m_version_string[i] <= '9'))
|| (m_version_string[i] == '+')
|| (m_version_string[i] == '.')
|| (m_version_string[i] == '-'))
{
// Valid semantic version character.
}
else if (prev_char == '-')
{
m_version_string[i] = '0';
}
else
{
m_version_string[i] = '-';
}
prev_char = m_version_string[i];
}
#if !NRF_DFU_TRIGGER_USB_USB_SHARED
app_usbd_serial_num_generate();
#endif
}
#if !(APP_USBD_CONFIG_EVENT_QUEUE_ENABLE)
static void usbd_evt_handler(app_usbd_internal_evt_t const * const p_event)
{
app_usbd_event_execute(p_event);
}
#endif
ret_code_t nrf_dfu_trigger_usb_init(void)
{
ret_code_t ret;
static bool initialized = false;
if (initialized)
{
return NRF_SUCCESS;
}
m_dfu_info.wAddress = CODE_START;
m_dfu_info.wFirmwareSize = CODE_SIZE;
m_dfu_info.wVersionMajor = APP_VERSION_MAJOR;
m_dfu_info.wVersionMinor = APP_VERSION_MINOR;
m_dfu_info.wFirmwareID = APP_ID;
m_dfu_info.wFlashPageSize = DFU_FLASH_PAGE_SIZE;
m_dfu_info.wFlashSize = m_dfu_info.wFlashPageSize * DFU_FLASH_PAGE_COUNT;
strings_create();
if (!NRF_DFU_TRIGGER_USB_USB_SHARED)
{
static const app_usbd_config_t usbd_config = {
#if !(APP_USBD_CONFIG_EVENT_QUEUE_ENABLE)
.ev_handler = usbd_evt_handler,
#endif
.ev_state_proc = usbd_user_evt_handler
};
ret = nrf_drv_clock_init();
if ((ret != NRF_SUCCESS) && (ret != NRF_ERROR_MODULE_ALREADY_INITIALIZED))
{
return ret;
}
ret = app_usbd_init(&usbd_config);
if (ret != NRF_SUCCESS)
{
return ret;
}
}
app_usbd_class_inst_t const * class_dfu = app_usbd_nrf_dfu_trigger_class_inst_get(&m_app_dfu);
ret = app_usbd_class_append(class_dfu);
if (!NRF_DFU_TRIGGER_USB_USB_SHARED)
{
if (USBD_POWER_DETECTION)
{
ret = app_usbd_power_events_enable();
APP_ERROR_CHECK(ret);
}
else
{
NRF_LOG_INFO("No USB power detection enabled\r\nStarting USB now");
app_usbd_enable();
app_usbd_start();
}
}
if (ret == NRF_SUCCESS)
{
initialized = true;
}
return ret;
}

@ -0,0 +1,74 @@
/**
* Copyright (c) 2017 - 2021, Nordic Semiconductor ASA
*
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without modification,
* are permitted provided that the following conditions are met:
*
* 1. Redistributions of source code must retain the above copyright notice, this
* list of conditions and the following disclaimer.
*
* 2. Redistributions in binary form, except as embedded into a Nordic
* Semiconductor ASA integrated circuit in a product or a software update for
* such product, must reproduce the above copyright notice, this list of
* conditions and the following disclaimer in the documentation and/or other
* materials provided with the distribution.
*
* 3. Neither the name of Nordic Semiconductor ASA nor the names of its
* contributors may be used to endorse or promote products derived from this
* software without specific prior written permission.
*
* 4. This software, with or without modification, must only be used with a
* Nordic Semiconductor ASA integrated circuit.
*
* 5. Any software provided in binary form under this license must not be reverse
* engineered, decompiled, modified and/or disassembled.
*
* THIS SOFTWARE IS PROVIDED BY NORDIC SEMICONDUCTOR ASA "AS IS" AND ANY EXPRESS
* OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
* OF MERCHANTABILITY, NONINFRINGEMENT, AND FITNESS FOR A PARTICULAR PURPOSE ARE
* DISCLAIMED. IN NO EVENT SHALL NORDIC SEMICONDUCTOR ASA OR CONTRIBUTORS BE
* LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE
* GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
* OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*
*/
#ifndef NRF_DFU_TRIGGER_USB_H
#define NRF_DFU_TRIGGER_USB_H
#include "sdk_errors.h"
/**
* @defgroup nrf_dfu_trigger_usb USB DFU trigger library
* @ingroup app_common
*
* @brief @tagAPI52840 USB DFU trigger library is used to enter the bootloader and read the firmware version.
*
* @details See @ref lib_dfu_trigger_usb for additional documentation.
* @{
*/
/**
* @brief Function for initializing the USB DFU trigger library.
*
* @note If the USB is also used for other purposes, then this function must be called after USB is
* initialized but before it is enabled. In this case, the configuration flag @ref
* NRF_DFU_TRIGGER_USB_USB_SHARED must be set to 1.
*
* @note Calling this again after the first success has no effect and returns @ref NRF_SUCCESS.
*
* @note If @ref APP_USBD_CONFIG_EVENT_QUEUE_ENABLE is on (1), USB events must be handled manually.
* See @ref app_usbd_event_queue_process.
*
* @retval NRF_SUCCESS On successful initialization.
* @return An error code on failure, for example if called at a wrong time.
*/
ret_code_t nrf_dfu_trigger_usb_init(void);
/** @} */
#endif //NRF_DFU_TRIGGER_USB_H

@ -0,0 +1,342 @@
/**
* Copyright (c) 2016 - 2021, Nordic Semiconductor ASA
*
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without modification,
* are permitted provided that the following conditions are met:
*
* 1. Redistributions of source code must retain the above copyright notice, this
* list of conditions and the following disclaimer.
*
* 2. Redistributions in binary form, except as embedded into a Nordic
* Semiconductor ASA integrated circuit in a product or a software update for
* such product, must reproduce the above copyright notice, this list of
* conditions and the following disclaimer in the documentation and/or other
* materials provided with the distribution.
*
* 3. Neither the name of Nordic Semiconductor ASA nor the names of its
* contributors may be used to endorse or promote products derived from this
* software without specific prior written permission.
*
* 4. This software, with or without modification, must only be used with a
* Nordic Semiconductor ASA integrated circuit.
*
* 5. Any software provided in binary form under this license must not be reverse
* engineered, decompiled, modified and/or disassembled.
*
* THIS SOFTWARE IS PROVIDED BY NORDIC SEMICONDUCTOR ASA "AS IS" AND ANY EXPRESS
* OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
* OF MERCHANTABILITY, NONINFRINGEMENT, AND FITNESS FOR A PARTICULAR PURPOSE ARE
* DISCLAIMED. IN NO EVENT SHALL NORDIC SEMICONDUCTOR ASA OR CONTRIBUTORS BE
* LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE
* GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
* OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*
*/
/**@file
*
* @defgroup sdk_nrf_dfu_types DFU types
* @{
* @ingroup nrf_dfu
*/
#ifndef NRF_DFU_TYPES_H__
#define NRF_DFU_TYPES_H__
#include <stdint.h>
#include <stddef.h>
#include "sdk_common.h"
#include "nrf.h"
#include "nrf_mbr.h"
#include "app_util_platform.h"
#include "sdk_config.h"
#if defined(NRF_DFU_TRANSPORT_BLE) && NRF_DFU_TRANSPORT_BLE
#include "ble_gap.h"
#define SYSTEM_SERVICE_ATT_SIZE 8 /**< Size of the system service attribute length including CRC-16 at the end. */
#endif
#ifdef __cplusplus
extern "C" {
#endif
#define INIT_COMMAND_MAX_SIZE 512 /**< Maximum size of the init command stored in dfu_settings. */
#define INIT_COMMAND_MAX_SIZE_v1 256 /**< Maximum size of the init command in settings version 1. */
/** @brief Size of a flash page. This value is used for calculating the size of the reserved
* flash space in the bootloader region.
*/
#if defined(NRF51)
#define CODE_PAGE_SIZE (PAGE_SIZE_IN_WORDS * sizeof(uint32_t))
#elif defined(NRF52_SERIES)
#define CODE_PAGE_SIZE (MBR_PAGE_SIZE_IN_WORDS * sizeof(uint32_t))
#else
#error "Architecture not set."
#endif
/** @brief Maximum size of a data object.*/
#if defined(NRF51)
#define DATA_OBJECT_MAX_SIZE (CODE_PAGE_SIZE * 4)
#elif defined(NRF52_SERIES) || defined (__SDK_DOXYGEN__)
#define DATA_OBJECT_MAX_SIZE (CODE_PAGE_SIZE)
#else
#error "Architecture not set."
#endif
/** @brief Page location of the bootloader settings address.
*/
#if defined (NRF51)
#define BOOTLOADER_SETTINGS_ADDRESS (0x0003FC00UL)
#elif defined( NRF52810_XXAA )
#define BOOTLOADER_SETTINGS_ADDRESS (0x0002F000UL)
#elif defined( NRF52811_XXAA )
#define BOOTLOADER_SETTINGS_ADDRESS (0x0002F000UL)
#elif defined( NRF52820_XXAA )
#define BOOTLOADER_SETTINGS_ADDRESS (0x0003F000UL)
#elif defined( NRF52832_XXAA )
#define BOOTLOADER_SETTINGS_ADDRESS (0x0007F000UL)
#elif defined( NRF52833_XXAA )
#define BOOTLOADER_SETTINGS_ADDRESS (0x0007F000UL)
#elif defined(NRF52840_XXAA)
#define BOOTLOADER_SETTINGS_ADDRESS (0x000FF000UL)
#else
#error No valid target set for BOOTLOADER_SETTINGS_ADDRESS.
#endif
#define BOOTLOADER_SETTINGS_PAGE_SIZE (CODE_PAGE_SIZE)
#define NRF_MBR_PARAMS_PAGE_SIZE (CODE_PAGE_SIZE)
/** @brief Page location of the MBR parameters page address.
*/
#if defined(NRF52840_XXAA) || defined(NRF52840_XXAA_ENGA)
#define NRF_MBR_PARAMS_PAGE_ADDRESS (0x000FE000UL)
#elif defined(NRF52832_XXAA)
#define NRF_MBR_PARAMS_PAGE_ADDRESS (0x0007E000UL)
#elif defined(NRF52833_XXAA)
#define NRF_MBR_PARAMS_PAGE_ADDRESS (0x0007E000UL)
#elif defined(NRF52810_XXAA)
#define NRF_MBR_PARAMS_PAGE_ADDRESS (0x0002E000UL)
#elif defined(NRF52811_XXAA)
#define NRF_MBR_PARAMS_PAGE_ADDRESS (0x0002E000UL)
#elif defined(NRF52820_XXAA)
#define NRF_MBR_PARAMS_PAGE_ADDRESS (0x0003E000UL)
#endif
#define BOOTLOADER_SETTINGS_BACKUP_ADDRESS NRF_MBR_PARAMS_PAGE_ADDRESS
#ifndef NRF_DFU_APP_DATA_AREA_SIZE
#define NRF_DFU_APP_DATA_AREA_SIZE (CODE_PAGE_SIZE * 3)
#endif
STATIC_ASSERT((NRF_DFU_APP_DATA_AREA_SIZE % CODE_PAGE_SIZE) == 0, "NRF_DFU_APP_DATA_AREA_SIZE must be a multiple of the flash page size.");
#define DFU_APP_DATA_RESERVED NRF_DFU_APP_DATA_AREA_SIZE // For backward compatibility with 15.0.0.
/** @brief Total size of the region between the SoftDevice and the bootloader.
*/
#define DFU_REGION_END(bootloader_start_addr) ((bootloader_start_addr) - (NRF_DFU_APP_DATA_AREA_SIZE))
#if defined(BLE_STACK_SUPPORT_REQD) || defined(ANT_STACK_SUPPORT_REQD)
#define DFU_REGION_START (nrf_dfu_bank0_start_addr())
#else
#define DFU_REGION_START (MBR_SIZE)
#endif
#define DFU_REGION_TOTAL_SIZE ((DFU_REGION_END) - (DFU_REGION_START))
#define NRF_DFU_CURRENT_BANK_0 0x00
#define NRF_DFU_CURRENT_BANK_1 0x01
#define NRF_DFU_BANK_LAYOUT_DUAL 0x00
#define NRF_DFU_BANK_LAYOUT_SINGLE 0x01
/** @brief DFU bank state codes.
*
* @details The DFU bank state indicates the content of a bank:
* A valid image of a certain type or an invalid image.
*/
#define NRF_DFU_BANK_INVALID 0x00 /**< Invalid image. */
#define NRF_DFU_BANK_VALID_APP 0x01 /**< Valid application. */
#define NRF_DFU_BANK_VALID_SD 0xA5 /**< Valid SoftDevice. */
#define NRF_DFU_BANK_VALID_BL 0xAA /**< Valid bootloader. */
#define NRF_DFU_BANK_VALID_SD_BL 0xAC /**< Valid SoftDevice and bootloader. */
#define NRF_DFU_BANK_VALID_EXT_APP 0xB1 /**< Valid application designated for a remote node. */
/** @brief Description of a single bank. */
#pragma pack(4)
typedef struct
{
uint32_t image_size; /**< Size of the image in the bank. */
uint32_t image_crc; /**< CRC of the image. If set to 0, the CRC is ignored. */
uint32_t bank_code; /**< Identifier code for the bank. */
} nrf_dfu_bank_t;
/**@brief DFU progress.
*
* Be aware of the difference between objects and firmware images. A firmware image consists of multiple objects, each of a maximum size @ref DATA_OBJECT_MAX_SIZE.
*
* @note The union inside this struct is cleared when CREATE_OBJECT of command type is executed, and when there is a valid post-validation.
* In DFU activation (after reset) the @ref dfu_progress_t::update_start_address will be used in case of a SD/SD+BL update.
*/
ANON_UNIONS_ENABLE;
typedef struct
{
uint32_t command_size; /**< The size of the current init command stored in the DFU settings. */
uint32_t command_offset; /**< The offset of the currently received init command data. The offset will increase as the init command is received. */
uint32_t command_crc; /**< The calculated CRC of the init command (calculated after the transfer is completed). */
uint32_t data_object_size; /**< The size of the last object created. Note that this size is not the size of the whole firmware image.*/
union
{
struct
{
uint32_t firmware_image_crc; /**< CRC value of the current firmware (continuously calculated as data is received). */
uint32_t firmware_image_crc_last; /**< The CRC of the last executed object. */
uint32_t firmware_image_offset; /**< The offset of the current firmware image being transferred. Note that this offset is the offset in the entire firmware image and not only the current object. */
uint32_t firmware_image_offset_last;/**< The offset of the last executed object from the start of the firmware image. */
};
struct
{
uint32_t update_start_address; /**< Value indicating the start address of the new firmware (before copy). It's always used, but it's most important for an SD/SD+BL update where the SD changes size or if the DFU process had a power loss when updating a SD with changed size. */
};
};
} dfu_progress_t;
ANON_UNIONS_DISABLE;
/** @brief Event types in the bootloader and DFU process. */
typedef enum
{
NRF_DFU_EVT_DFU_INITIALIZED, /**< Starting DFU. */
NRF_DFU_EVT_TRANSPORT_ACTIVATED, /**< Transport activated (e.g. BLE connected, USB plugged in). */
NRF_DFU_EVT_TRANSPORT_DEACTIVATED, /**< Transport deactivated (e.g. BLE disconnected, USB plugged out). */
NRF_DFU_EVT_DFU_STARTED, /**< DFU process started. */
NRF_DFU_EVT_OBJECT_RECEIVED, /**< A DFU data object has been received. */
NRF_DFU_EVT_DFU_FAILED, /**< DFU process has failed, been interrupted, or hung. */
NRF_DFU_EVT_DFU_COMPLETED, /**< DFU process completed. */
NRF_DFU_EVT_DFU_ABORTED, /**< DFU process aborted. */
} nrf_dfu_evt_type_t;
/**
* @brief Function for notifying DFU state.
*/
typedef void (*nrf_dfu_observer_t)(nrf_dfu_evt_type_t notification);
#define NRF_DFU_PEER_DATA_LEN 64 /**< The length in bytes of nrf_dfu_peer_data_t expected by tools manipulating the settings page. Do not change without changing the settings page version. */
#define NRF_DFU_ADV_NAME_LEN 28 /**< The length in bytes of nrf_dfu_adv_name_t expected by tools manipulating the settings page. Do not change without changing the settings page version. */
#if defined(NRF_DFU_TRANSPORT_BLE) && NRF_DFU_TRANSPORT_BLE
typedef struct
{
uint32_t crc; /**< CRC of the rest of the parameters in this struct. */
ble_gap_id_key_t ble_id; /**< BLE GAP identity key of the device that initiated the DFU process. */
ble_gap_enc_key_t enc_key; /**< Encryption key structure containing encrypted diversifier and LTK for reestablishing the bond. */
uint8_t sys_serv_attr[SYSTEM_SERVICE_ATT_SIZE]; /**< System service attributes for restoring of Service Changed Indication setting in DFU mode. */
} nrf_dfu_peer_data_t;
typedef enum
{
DFU_PEER_DATA_STATE_INVALID = 0,
DFU_PEER_DATA_STATE_INITIALIZED = 1,
DFU_PEER_DATA_STATE_WRITE_REQUESTED = 2,
DFU_PEER_DATA_STATE_WRITE_FINISHED = 3,
DFU_PEER_DATA_STATE_WRITE_FAILED = 4,
} nrf_dfu_peer_data_state_t;
typedef struct
{
uint32_t crc; /**< CRC of the rest of the parameters in this struct. Calculated by the bootloader. */
uint8_t name[20]; /**< New advertisement name to set. */
uint32_t len; /**< Length of the advertisement name. */
} nrf_dfu_adv_name_t;
typedef enum
{
DFU_ADV_NAME_STATE_INVALID = 0,
DFU_ADV_NAME_STATE_INITIALIZED = 1,
DFU_ADV_NAME_STATE_WRITE_REQUESTED = 2,
DFU_ADV_NAME_STATE_WRITE_FINISHED = 3,
DFU_ADV_NAME_STATE_WRITE_FAILED = 4,
} nrf_dfu_set_adv_name_state_t;
#else
typedef struct
{
uint8_t dummy_data[NRF_DFU_PEER_DATA_LEN];
} nrf_dfu_peer_data_t;
typedef struct
{
uint8_t dummy_data[NRF_DFU_ADV_NAME_LEN];
} nrf_dfu_adv_name_t;
#endif // NRF_DFU_TRANSPORT_BLE
STATIC_ASSERT(sizeof(nrf_dfu_peer_data_t) == NRF_DFU_PEER_DATA_LEN, "nrf_dfu_peer_data_t has unexpected length. This can cause incompatibility with tools.");
STATIC_ASSERT(sizeof(nrf_dfu_adv_name_t) == NRF_DFU_ADV_NAME_LEN, "nrf_dfu_adv_name_t has unexpected length. This can cause incompatibility with tools.");
#define SETTINGS_RESERVED_AREA_SIZE 16 /**< The number of words in the reserved area of the DFU settings. */
#define SETTINGS_BOOT_VALIDATION_SIZE 64 /**< The number of bytes reserved for boot_validation value. */
typedef enum
{
NO_VALIDATION,
VALIDATE_CRC,
VALIDATE_SHA256,
VALIDATE_ECDSA_P256_SHA256,
} boot_validation_type_t;
typedef struct
{
uint32_t sigmask;
uint8_t bytes[SETTINGS_BOOT_VALIDATION_SIZE];
} boot_validation_t;
/**@brief DFU settings for application and bank data.
*/
typedef struct
{
uint32_t crc; /**< CRC for the stored DFU settings, not including the CRC itself. If 0xFFFFFFF, the CRC has never been calculated. */
uint32_t settings_version; /**< Version of the current DFU settings struct layout. */
uint32_t app_version; /**< Version of the last stored application. */
uint32_t bootloader_version; /**< Version of the last stored bootloader. */
uint32_t bank_layout; /**< Bank layout: single bank or dual bank. This value can change. */
uint32_t bank_current; /**< The bank that is currently used. */
nrf_dfu_bank_t bank_0; /**< Bank 0. */
nrf_dfu_bank_t bank_1; /**< Bank 1. */
uint32_t write_offset; /**< Write offset for the current operation. */
uint32_t sd_size; /**< Size of the SoftDevice. */
dfu_progress_t progress; /**< Current DFU progress. */
uint32_t enter_buttonless_dfu;
uint8_t init_command[INIT_COMMAND_MAX_SIZE]; /**< Buffer for storing the init command. */
uint32_t boot_validation_crc;
boot_validation_t boot_validation_softdevice;
boot_validation_t boot_validation_app;
boot_validation_t boot_validation_bootloader;
nrf_dfu_peer_data_t peer_data; /**< Not included in calculated CRC. */
nrf_dfu_adv_name_t adv_name; /**< Not included in calculated CRC. */
} nrf_dfu_settings_t;
#pragma pack() // revert pack settings
#ifdef __cplusplus
}
#endif
#endif // NRF_DFU_TYPES_H__
/** @} */

@ -0,0 +1,220 @@
/**
* Copyright (c) 2016 - 2021, Nordic Semiconductor ASA
*
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without modification,
* are permitted provided that the following conditions are met:
*
* 1. Redistributions of source code must retain the above copyright notice, this
* list of conditions and the following disclaimer.
*
* 2. Redistributions in binary form, except as embedded into a Nordic
* Semiconductor ASA integrated circuit in a product or a software update for
* such product, must reproduce the above copyright notice, this list of
* conditions and the following disclaimer in the documentation and/or other
* materials provided with the distribution.
*
* 3. Neither the name of Nordic Semiconductor ASA nor the names of its
* contributors may be used to endorse or promote products derived from this
* software without specific prior written permission.
*
* 4. This software, with or without modification, must only be used with a
* Nordic Semiconductor ASA integrated circuit.
*
* 5. Any software provided in binary form under this license must not be reverse
* engineered, decompiled, modified and/or disassembled.
*
* THIS SOFTWARE IS PROVIDED BY NORDIC SEMICONDUCTOR ASA "AS IS" AND ANY EXPRESS
* OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
* OF MERCHANTABILITY, NONINFRINGEMENT, AND FITNESS FOR A PARTICULAR PURPOSE ARE
* DISCLAIMED. IN NO EVENT SHALL NORDIC SEMICONDUCTOR ASA OR CONTRIBUTORS BE
* LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE
* GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
* OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*
*/
#include "nrf_dfu_utils.h"
#include "nrf_dfu_settings.h"
#include "nrf_bootloader_info.h"
#include "crc32.h"
#include "nrf_log.h"
#include "nrf_dfu_validation.h"
void nrf_dfu_bank_invalidate(nrf_dfu_bank_t * const p_bank)
{
// Set the bank-code to invalid, and reset size/CRC
memset(p_bank, 0, sizeof(nrf_dfu_bank_t));
// Reset write pointer after completed operation
s_dfu_settings.write_offset = 0;
}
#if !defined(BLE_STACK_SUPPORT_REQD) && !defined(ANT_STACK_SUPPORT_REQD)
void nrf_dfu_softdevice_invalidate(void)
{
static const uint32_t all_zero = 0UL;
if (SD_PRESENT && !NRF_DFU_IN_APP)
{
ret_code_t err_code = nrf_dfu_flash_store(SD_MAGIC_NUMBER_ABS_OFFSET_GET(MBR_SIZE), &all_zero, 4, NULL);
if (err_code != NRF_SUCCESS)
{
NRF_LOG_ERROR("Could not invalidate SoftDevice.")
}
else
{
// If there is an app it must be invalidated since its start address can no longer be resolved.
if (s_dfu_settings.bank_0.bank_code == NRF_DFU_BANK_VALID_APP)
{
s_dfu_settings.bank_0.bank_code = NRF_DFU_BANK_INVALID;
}
// Since the start of bank 0 has now implicitly been moved to the start
// of the invalidated SoftDevice, its image size must be increased by the
// same amount so the start of bank 1 will be correctly calculated.
s_dfu_settings.bank_0.image_size += SD_SIZE_GET(MBR_SIZE) - MBR_SIZE;
}
}
}
#endif
uint32_t nrf_dfu_bank0_start_addr(void)
{
if (SD_PRESENT)
{
return ALIGN_TO_PAGE(SD_SIZE_GET(MBR_SIZE));
}
else
{
return MBR_SIZE;
}
}
uint32_t nrf_dfu_bank1_start_addr(void)
{
uint32_t bank0_addr = nrf_dfu_bank0_start_addr();
return ALIGN_TO_PAGE(bank0_addr + s_dfu_settings.bank_0.image_size);
}
uint32_t nrf_dfu_app_start_address(void)
{
return nrf_dfu_bank0_start_addr();
}
uint32_t nrf_dfu_softdevice_start_address(void)
{
return MBR_SIZE;
}
uint32_t nrf_dfu_cache_prepare(const uint32_t required_size, bool single_bank, bool keep_app, bool keep_softdevice)
{
ret_code_t err_code;
bool cache_too_small;
enum
{
INITIAL_DELETE_APP = 0,
APP_DELETED_DELETE_SOFTDEVICE = 1,
SOFTDEVICE_DELETED = 2
} pass;
NRF_LOG_DEBUG("Enter nrf_dfu_cache_prepare()");
NRF_LOG_DEBUG("required_size: 0x%x.", required_size);
NRF_LOG_DEBUG("single_bank: %s.", single_bank ? "true" : "false");
NRF_LOG_DEBUG("keep_app: %s.", keep_app ? "true" : "false");
NRF_LOG_DEBUG("keep_softdevice: %s.", keep_softdevice ? "true" : "false");
NRF_LOG_DEBUG("SD_PRESENT: %s.", SD_PRESENT ? "true" : "false");
NRF_LOG_DEBUG("Bank contents:");
NRF_LOG_DEBUG("Bank 0 code: 0x%02x: Size: 0x%x", s_dfu_settings.bank_0.bank_code, s_dfu_settings.bank_0.image_size);
NRF_LOG_DEBUG("Bank 1 code: 0x%02x: Size: 0x%x", s_dfu_settings.bank_1.bank_code, s_dfu_settings.bank_1.image_size);
// Pass 0 deletes the app if necessary or requested, and if so, proceeds to pass 1.
// Pass 1 deletes the SoftDevice if necessary or requested, and if so, proceeds to pass 2.
// Pass 2 does a last size check.
for (pass = INITIAL_DELETE_APP; pass <= SOFTDEVICE_DELETED; pass++)
{
uint32_t cache_address;
const uint32_t bootloader_start_addr = BOOTLOADER_START_ADDR; // Assign to a variable to prevent warning in Keil 4.
bool keep_firmware = true;
bool delete_more;
switch (pass)
{
case INITIAL_DELETE_APP:
cache_address = nrf_dfu_bank1_start_addr();
// If there is no app, keep_app should be assumed false, so we can free up more space.
keep_firmware = keep_app && (s_dfu_settings.bank_0.bank_code == NRF_DFU_BANK_VALID_APP);
break;
case APP_DELETED_DELETE_SOFTDEVICE:
cache_address = nrf_dfu_bank0_start_addr();
// If there is no SoftDevice, keep_SoftDevice should be assumed true, because there is
// no point to continuing since the SoftDevice is the last firmware that can be deleted.
keep_firmware = keep_softdevice || !SD_PRESENT;
break;
case SOFTDEVICE_DELETED:
cache_address = nrf_dfu_softdevice_start_address();
break;
default:
ASSERT(false);
cache_address = 0;
break;
}
ASSERT(cache_address <= DFU_REGION_END(bootloader_start_addr));
cache_too_small = required_size > (DFU_REGION_END(bootloader_start_addr) - cache_address);
delete_more = cache_too_small || single_bank; // Delete app or SoftDevice only if we need more room, or if single bank is requested.
NRF_LOG_DEBUG("pass: %d.", pass);
NRF_LOG_DEBUG("cache_address: 0x%x.", cache_address);
NRF_LOG_DEBUG("cache_too_small: %s.", cache_too_small ? "true" : "false");
NRF_LOG_DEBUG("keep_firmware: %s.", keep_firmware ? "true" : "false");
NRF_LOG_DEBUG("delete_more: %s.", delete_more ? "true" : "false");
if (!delete_more || keep_firmware || (pass >= SOFTDEVICE_DELETED))
{
// Stop, done.
break;
}
}
if (cache_too_small)
{
NRF_LOG_WARNING("Aborting. Cannot fit new firmware on device");
err_code = NRF_ERROR_NO_MEM;
}
else
{
// Room was found. Make the necessary preparations for receiving update.
#if !defined(BLE_STACK_SUPPORT_REQD) && !defined(ANT_STACK_SUPPORT_REQD)
if (pass >= SOFTDEVICE_DELETED)
{
NRF_LOG_DEBUG("Invalidating SoftDevice.");
nrf_dfu_softdevice_invalidate();
}
#endif
if (pass >= APP_DELETED_DELETE_SOFTDEVICE)
{
NRF_LOG_DEBUG("Invalidating app.");
nrf_dfu_bank_invalidate(&s_dfu_settings.bank_0);
}
err_code = NRF_SUCCESS;
}
return err_code;
}

@ -0,0 +1,154 @@
/**
* Copyright (c) 2016 - 2021, Nordic Semiconductor ASA
*
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without modification,
* are permitted provided that the following conditions are met:
*
* 1. Redistributions of source code must retain the above copyright notice, this
* list of conditions and the following disclaimer.
*
* 2. Redistributions in binary form, except as embedded into a Nordic
* Semiconductor ASA integrated circuit in a product or a software update for
* such product, must reproduce the above copyright notice, this list of
* conditions and the following disclaimer in the documentation and/or other
* materials provided with the distribution.
*
* 3. Neither the name of Nordic Semiconductor ASA nor the names of its
* contributors may be used to endorse or promote products derived from this
* software without specific prior written permission.
*
* 4. This software, with or without modification, must only be used with a
* Nordic Semiconductor ASA integrated circuit.
*
* 5. Any software provided in binary form under this license must not be reverse
* engineered, decompiled, modified and/or disassembled.
*
* THIS SOFTWARE IS PROVIDED BY NORDIC SEMICONDUCTOR ASA "AS IS" AND ANY EXPRESS
* OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
* OF MERCHANTABILITY, NONINFRINGEMENT, AND FITNESS FOR A PARTICULAR PURPOSE ARE
* DISCLAIMED. IN NO EVENT SHALL NORDIC SEMICONDUCTOR ASA OR CONTRIBUTORS BE
* LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE
* GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
* OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*
*/
/**@file
*
* @defgroup sdk_nrf_dfu_utils DFU utilities
* @{
* @ingroup nrf_dfu
*/
#ifndef NRF_DFU_UTILS_H__
#define NRF_DFU_UTILS_H__
#include <stdint.h>
#include <stdbool.h>
#include "nrf_dfu_types.h"
#include "app_util.h"
#ifdef __cplusplus
extern "C"
{
#endif
/**
* Round up val to the next page boundary
*/
#define ALIGN_TO_PAGE(val) ALIGN_NUM((CODE_PAGE_SIZE), (val))
/** @brief Function for getting the start address of bank 0.
*
* @note Bank 0 starts after the SoftDevice if a SoftDevice is present.
*
* @return The start address of bank 0.
*/
uint32_t nrf_dfu_bank0_start_addr(void);
/** @brief Function for getting the start address of bank 1.
*
* @return The start address of bank 1.
*/
uint32_t nrf_dfu_bank1_start_addr(void);
/** @brief Function for getting the start address of the app.
*
* @return The start address of the bootable app.
*/
uint32_t nrf_dfu_app_start_address(void);
/** @brief Function for getting the start address of the SoftDevice.
*
* @return The start address of the SoftDevivce.
*/
uint32_t nrf_dfu_softdevice_start_address(void);
/** @brief Function for finding and preparing a place in flash in which to store a DFU update.
*
* @details This function checks the size requirements and selects a location for
* placing the cache of the DFU images.
* The function tries to find enough space after the existing firmwares. If there is not
* enough space, the present application is deleted. If there is still not enough space,
* the SoftDevice is deleted.
* If @p single_bank is true, the default behavior is to immediately delete the app and
* SoftDevice as necessary to place the new firmware at its intended location. If the
* intended location cannot be made available, or if the update is a bootloader update,
* the update will be a dual bank update, and nothing will be deleted by this function
* except when needed for size.
* If @p keep_app is true, the app is never deleted by this function. Likewise if @p
* keep_softdevice is true, the SoftDevice is never deleted by this function.
* If the new firmware cannot fit within the constraints, nothing is deleted and the
* function fails.
*
* @param[in] required_size Requirements for the size of the new image.
* @param[in] single_bank Whether to put the firmware directly where it's meant to go.
* @p keep_app and @p keep_softdevice take precedence over this.
* @param[in] keep_app True to ensure the app is not deleted by this function. This
* effectively enforces dual bank update.
* @param[out] keep_softdevice True to ensure the SoftDevice is not deleted by this function.
*
* @retval NRF_SUCCESS If a cache location was found for the DFU process.
* @retval NRF_ERROR_NO_MEM If there is not enough space available to receive the update.
* Nothing has been deleted.
*/
uint32_t nrf_dfu_cache_prepare(uint32_t required_size, bool single_bank, bool keep_app, bool keep_softdevice);
/**@brief Function for making sure a SoftDevice is not recognized as such anymore.
*
* @details It works by overwriting the magic number of the SoftDevice with 0s. The
* magic number is used throughout the bootloader to detect whether a SoftDevice
* is present.
*
* @warning This function should only be called when both banks are already invalid.
* because the (implicit) position of the banks will shift when the SoftDevice
* is invalidated.
*/
void nrf_dfu_softdevice_invalidate(void);
/**@brief Function for making sure a bank is not copied or booted.
*
* @details This also sets the size of the bank to 0.
*
* @param[in] p_bank Pointer to the bank to be invalidated.
*/
void nrf_dfu_bank_invalidate(nrf_dfu_bank_t * const p_bank);
#ifdef __cplusplus
}
#endif
#endif // NRF_DFU_UTILS_H__
/** @} */

@ -0,0 +1,986 @@
/**
* Copyright (c) 2017 - 2021, Nordic Semiconductor ASA
*
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without modification,
* are permitted provided that the following conditions are met:
*
* 1. Redistributions of source code must retain the above copyright notice, this
* list of conditions and the following disclaimer.
*
* 2. Redistributions in binary form, except as embedded into a Nordic
* Semiconductor ASA integrated circuit in a product or a software update for
* such product, must reproduce the above copyright notice, this list of
* conditions and the following disclaimer in the documentation and/or other
* materials provided with the distribution.
*
* 3. Neither the name of Nordic Semiconductor ASA nor the names of its
* contributors may be used to endorse or promote products derived from this
* software without specific prior written permission.
*
* 4. This software, with or without modification, must only be used with a
* Nordic Semiconductor ASA integrated circuit.
*
* 5. Any software provided in binary form under this license must not be reverse
* engineered, decompiled, modified and/or disassembled.
*
* THIS SOFTWARE IS PROVIDED BY NORDIC SEMICONDUCTOR ASA "AS IS" AND ANY EXPRESS
* OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
* OF MERCHANTABILITY, NONINFRINGEMENT, AND FITNESS FOR A PARTICULAR PURPOSE ARE
* DISCLAIMED. IN NO EVENT SHALL NORDIC SEMICONDUCTOR ASA OR CONTRIBUTORS BE
* LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE
* GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
* OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*
*/
#include <stdbool.h>
#include "nrf_dfu_types.h"
#include "nrf_dfu_settings.h"
#include "nrf_dfu_utils.h"
#include "nrf_dfu_flash.h"
#include "nrf_bootloader_info.h"
#include "pb.h"
#include "pb_common.h"
#include "pb_decode.h"
#include "dfu-cc.pb.h"
#include "crc32.h"
#include "nrf_assert.h"
#include "nrf_dfu_validation.h"
#include "nrf_dfu_ver_validation.h"
#include "nrf_strerror.h"
#include "blake2s.h"
#include "ed25519-donna/ed25519.h"
#include "secbool.h"
#define NRF_LOG_MODULE_NAME nrf_dfu_validation
#include "nrf_log.h"
#include "nrf_log_ctrl.h"
NRF_LOG_MODULE_REGISTER();
#ifndef DFU_REQUIRES_SOFTDEVICE
#if !defined(BLE_STACK_SUPPORT_REQD) && !defined(ANT_STACK_SUPPORT_REQD)
#define DFU_REQUIRES_SOFTDEVICE 0
#else
#define DFU_REQUIRES_SOFTDEVICE 1
#endif
#endif
#define EXT_ERR(err) (nrf_dfu_result_t)((uint32_t)NRF_DFU_RES_CODE_EXT_ERROR + (uint32_t)err)
/* Whether a complete init command has been received and prevalidated, but the firmware
* is not yet fully transferred. This value will also be correct after reset.
*/
static bool m_valid_init_cmd_present = false;
static dfu_Packet m_packet = dfu_Packet_init_default;
static uint8_t* m_init_packet_data_ptr = 0;
static uint32_t m_init_packet_data_len = 0;
static pb_istream_t m_pb_stream;
static dfu_InitCommand const * mp_init = NULL;
extern const uint8_t NRF_BOOTLOADER_KEY_M;
extern const uint8_t NRF_BOOTLOADER_KEY_N;
extern const uint8_t * const NRF_BOOTLOADER_KEYS[];
/** @brief Flag used by parser code to indicate that the init command has been found to be invalid.
*/
static bool m_init_packet_valid = false;
//
//static void pb_decoding_callback(pb_istream_t *str,
// uint32_t tag,
// pb_wire_type_t wire_type,
// void *iter)
//{
// pb_field_iter_t* p_iter = (pb_field_iter_t *) iter;
//
// // Match the beginning of the init command.
// if (p_iter->pos->ptr == &dfu_init_command_fields[0])
// {
// uint8_t * ptr = (uint8_t *)str->state;
// uint32_t size = str->bytes_left;
//
// if (m_init_packet_data_ptr != NULL || m_init_packet_data_len != 0)
// {
// m_init_packet_valid = false;
// return;
// }
//
// // Remove tag.
// while (*ptr & 0x80)
// {
// ptr++;
// size--;
// }
// ptr++;
// size--;
//
// // Store the info in init_packet_data.
// m_init_packet_data_ptr = ptr;
// m_init_packet_data_len = size;
// m_init_packet_valid = true;
//
// NRF_LOG_DEBUG("PB: Init packet data len: %d", size);
// }
//}
/** @brief Function for decoding byte stream into variable.
*
* @retval true If the stored init command was successfully decoded.
* @retval false If there was no stored init command, or the decoding failed.
*/
static bool stored_init_cmd_decode(void)
{
m_pb_stream = pb_istream_from_buffer(s_dfu_settings.init_command,
s_dfu_settings.progress.command_size);
dfu_InitCommand * p_init;
// Attach our callback to follow the field decoding.
//m_pb_stream.decoding_callback = pb_decoding_callback;
m_init_packet_valid = false;
m_init_packet_data_ptr = NULL;
m_init_packet_data_len = 0;
memset(&m_packet, 0, sizeof(m_packet));
if (!pb_decode(&m_pb_stream, dfu_Packet_fields, &m_packet))
{
NRF_LOG_ERROR("Handler: Invalid protocol buffer m_pb_stream");
return false;
}
if (m_packet.has_signed_command && m_packet.has_command)
{
NRF_LOG_ERROR("Handler: Invalid init command.");
return false;
}
if (m_packet.has_signed_command) {
//TODO: this is where signed init command is stored, but is it guaranteed to be there always?
// pb_decoding_callback was meant to find it, how to do that without nanopb modifications?
m_init_packet_data_ptr = &s_dfu_settings.init_command[11];
m_init_packet_data_len = s_dfu_settings.progress.command_size-(64+4+11); // signature, sigmask
m_init_packet_valid = true;
}
if (!m_init_packet_valid || (m_packet.has_signed_command && m_packet.has_command))
{
NRF_LOG_ERROR("Handler: Invalid init command.");
return false;
}
else if (m_packet.has_signed_command && m_packet.signed_command.command.has_init)
{
p_init = &m_packet.signed_command.command.init;
m_pb_stream = pb_istream_from_buffer(m_init_packet_data_ptr, m_init_packet_data_len);
memset(p_init, 0, sizeof(dfu_InitCommand));
if (!pb_decode(&m_pb_stream, dfu_InitCommand_fields, p_init))
{
NRF_LOG_ERROR("Handler: Invalid protocol buffer m_pb_stream (init command)");
return false;
}
}
else if (m_packet.has_command && m_packet.command.has_init)
{
p_init = &m_packet.command.init;
}
else
{
return false;
}
mp_init = p_init;
return true;
}
void nrf_dfu_validation_init(void)
{
// If the command is stored to flash, init command was valid.
if ((s_dfu_settings.progress.command_size != 0) &&
stored_init_cmd_decode())
{
m_valid_init_cmd_present = true;
}
else
{
m_valid_init_cmd_present = false;
}
}
nrf_dfu_result_t nrf_dfu_validation_init_cmd_create(uint32_t size)
{
nrf_dfu_result_t ret_val = NRF_DFU_RES_CODE_SUCCESS;
if (size == 0)
{
ret_val = NRF_DFU_RES_CODE_INVALID_PARAMETER;
}
else if (size > INIT_COMMAND_MAX_SIZE)
{
ret_val = NRF_DFU_RES_CODE_INSUFFICIENT_RESOURCES;
}
else
{
// Set DFU to uninitialized.
m_valid_init_cmd_present = false;
// Reset all progress.
nrf_dfu_settings_progress_reset();
// Set the init command size.
s_dfu_settings.progress.command_size = size;
}
return ret_val;
}
nrf_dfu_result_t nrf_dfu_validation_init_cmd_append(uint8_t const * p_data, uint32_t length)
{
nrf_dfu_result_t ret_val = NRF_DFU_RES_CODE_SUCCESS;
if ((length + s_dfu_settings.progress.command_offset) > s_dfu_settings.progress.command_size)
{
NRF_LOG_ERROR("Init command larger than expected.");
ret_val = NRF_DFU_RES_CODE_INVALID_PARAMETER;
}
else
{
// Copy the received data to RAM, update offset and calculate CRC.
memcpy(&s_dfu_settings.init_command[s_dfu_settings.progress.command_offset],
p_data,
length);
s_dfu_settings.progress.command_offset += length;
s_dfu_settings.progress.command_crc = crc32_compute(p_data,
length,
&s_dfu_settings.progress.command_crc);
}
return ret_val;
}
void nrf_dfu_validation_init_cmd_status_get(uint32_t * p_offset,
uint32_t * p_crc,
uint32_t * p_max_size)
{
*p_offset = s_dfu_settings.progress.command_offset;
*p_crc = s_dfu_settings.progress.command_crc;
*p_max_size = INIT_COMMAND_MAX_SIZE;
}
bool nrf_dfu_validation_init_cmd_present(void)
{
return m_valid_init_cmd_present;
}
// Function determines if init command signature is obligatory.
static bool signature_required(dfu_FwType fw_type_to_be_updated)
{
bool result = true;
// DFU_FW_TYPE_EXTERNAL_APPLICATION and bootloader updates always require
// signature check
if ((!DFU_REQUIRES_SOFTDEVICE && (fw_type_to_be_updated == dfu_FwType_SOFTDEVICE)) ||
(fw_type_to_be_updated == dfu_FwType_APPLICATION))
{
result = NRF_DFU_REQUIRE_SIGNED_APP_UPDATE;
}
return result;
}
static secbool compute_pubkey(uint8_t sig_m, uint8_t sig_n,
const uint8_t *const *pub, uint8_t sigmask,
ed25519_public_key res) {
if (0 == sig_m || 0 == sig_n) return secfalse;
if (sig_m > sig_n) return secfalse;
// discard bits higher than sig_n
sigmask &= ((1 << sig_n) - 1);
// remove if number of set bits in sigmask is not equal to sig_m
if (__builtin_popcount(sigmask) != sig_m) return secfalse;
ed25519_public_key keys[sig_m];
int j = 0;
for (int i = 0; i < sig_n; i++) {
if ((1 << i) & sigmask) {
memcpy(keys[j], pub[i], 32);
j++;
}
}
return sectrue * (0 == ed25519_cosi_combine_publickeys(res, keys, sig_m));
}
secbool check_trezor_sig(const uint8_t * digest,
size_t digest_len,
uint8_t key_m,
uint8_t key_n,
uint8_t sigmask,
const uint8_t *const *keys,
uint8_t * sig) {
// check header signature
ed25519_public_key pub;
if (sectrue != compute_pubkey(key_m, key_n, keys, sigmask, pub))
return secfalse;
return sectrue *
(0 == ed25519_sign_open(digest, digest_len, pub,
sig));
}
// Function to perform signature check if required.
static nrf_dfu_result_t nrf_dfu_validation_signature_check(uint32_t sigmask,
uint8_t const * p_signature,
uint32_t signature_len,
uint8_t const * p_data,
uint32_t data_len)
{
ret_code_t err_code = NRF_SUCCESS;
uint8_t hash_digest[BLAKE2S_DIGEST_LENGTH];
uint8_t signature[64];
NRF_LOG_INFO("Signature required. Checking signature.")
if (p_signature == NULL)
{
NRF_LOG_WARNING("No signature found.");
return EXT_ERR(NRF_DFU_EXT_ERROR_SIGNATURE_MISSING);
}
NRF_LOG_INFO("Calculating hash (len: %d)", data_len);
blake2s(p_data, data_len, hash_digest, BLAKE2S_DIGEST_LENGTH);
if (sizeof(signature) != signature_len)
{
return NRF_DFU_RES_CODE_OPERATION_FAILED;
}
// Prepare the signature received over the air.
memcpy(signature, p_signature, signature_len);
// Calculate the signature.
NRF_LOG_INFO("Verify signature");
if (sectrue != check_trezor_sig(hash_digest, BLAKE2S_DIGEST_LENGTH, NRF_BOOTLOADER_KEY_M, NRF_BOOTLOADER_KEY_N, sigmask, NRF_BOOTLOADER_KEYS, signature)){
NRF_LOG_ERROR("Signature failed");
err_code = NRF_DFU_ERROR_INVALID_SIGNATURE;
}
if (err_code != NRF_SUCCESS)
{
NRF_LOG_ERROR("Signature failed (err_code: 0x%x)", err_code);
NRF_LOG_DEBUG("Signature:");
NRF_LOG_HEXDUMP_DEBUG(signature, sizeof(signature));
NRF_LOG_DEBUG("Hash:");
NRF_LOG_HEXDUMP_DEBUG(hash_digest, BLAKE2S_DIGEST_LENGTH);
NRF_LOG_FLUSH();
return NRF_DFU_RES_CODE_INVALID_OBJECT;
}
NRF_LOG_INFO("Image verified");
return NRF_DFU_RES_CODE_SUCCESS;
}
// Function to calculate the total size of the firmware(s) in the update.
static nrf_dfu_result_t update_data_size_get(dfu_InitCommand const * p_init, uint32_t * p_size)
{
nrf_dfu_result_t ret_val = EXT_ERR(NRF_DFU_EXT_ERROR_INIT_COMMAND_INVALID);
uint32_t fw_sz = 0;
if ((p_init->type == dfu_FwType_APPLICATION ||
p_init->type == dfu_FwType_EXTERNAL_APPLICATION) &&
(p_init->has_app_size == true))
{
fw_sz = p_init->app_size;
}
else
{
if ((p_init->type & dfu_FwType_SOFTDEVICE) && (p_init->has_sd_size == true))
{
fw_sz = p_init->sd_size;
}
if ((p_init->type & dfu_FwType_BOOTLOADER) && (p_init->has_bl_size == true))
{
if (p_init->bl_size <= BOOTLOADER_SIZE)
{
fw_sz += p_init->bl_size;
}
else
{
NRF_LOG_ERROR("BL size (%d) over limit (%d)", p_init->bl_size, BOOTLOADER_SIZE);
fw_sz = 0;
ret_val = NRF_DFU_RES_CODE_INSUFFICIENT_RESOURCES;
}
}
}
if (fw_sz)
{
*p_size = fw_sz;
ret_val = NRF_DFU_RES_CODE_SUCCESS;
}
else
{
NRF_LOG_ERROR("Init packet does not contain valid firmware size");
}
return ret_val;
}
/**
* @brief Function to check if single bank update should be used.
*
* @param new_fw_type Firmware type.
*/
static bool use_single_bank(dfu_FwType new_fw_type)
{
bool result = false;
// DFU_FW_TYPE_EXTERNAL_APPLICATION never uses single bank
if (((new_fw_type == dfu_FwType_APPLICATION) ||
(new_fw_type == dfu_FwType_SOFTDEVICE)) &&
NRF_DFU_SINGLE_BANK_APP_UPDATES)
{
result = true;
}
return result;
}
// Function to determine whether the new firmware needs a SoftDevice to be present.
static bool update_requires_softdevice(dfu_InitCommand const * p_init)
{
return ((p_init->sd_req_count > 0) && (p_init->sd_req[0] != SD_REQ_APP_OVERWRITES_SD));
}
// Function to determine whether the SoftDevice can be removed during the update or not.
static bool keep_softdevice(dfu_InitCommand const * p_init)
{
UNUSED_PARAMETER(p_init); // It's unused when DFU_REQUIRES_SOFTDEVICE is true.
return DFU_REQUIRES_SOFTDEVICE || update_requires_softdevice(p_init);
}
/**@brief Function to determine where to temporarily store the incoming firmware.
* This also checks whether the update will fit, and deletes existing
* firmware to make room for the new firmware.
*
* @param[in] p_init Init command.
* @param[in] fw_size The size of the incoming firmware.
* @param[out] p_addr The address at which to initially store the firmware.
*
* @retval NRF_DFU_RES_CODE_SUCCESS If the size check passed and
* an address was found.
* @retval NRF_DFU_RES_CODE_INSUFFICIENT_RESOURCES If the size check failed.
*/
static nrf_dfu_result_t update_data_addr_get(dfu_InitCommand const * p_init,
uint32_t fw_size,
uint32_t * p_addr)
{
nrf_dfu_result_t ret_val = NRF_DFU_RES_CODE_SUCCESS;
ret_code_t err_code = nrf_dfu_cache_prepare(fw_size,
use_single_bank(p_init->type),
NRF_DFU_FORCE_DUAL_BANK_APP_UPDATES,
keep_softdevice(p_init));
if (err_code != NRF_SUCCESS)
{
NRF_LOG_ERROR("Can't find room for update");
ret_val = NRF_DFU_RES_CODE_INSUFFICIENT_RESOURCES;
}
else
{
*p_addr = nrf_dfu_bank1_start_addr();
NRF_LOG_DEBUG("Write address set to 0x%08x", *p_addr);
}
return ret_val;
}
nrf_dfu_result_t nrf_dfu_validation_prevalidate(void)
{
nrf_dfu_result_t ret_val = NRF_DFU_RES_CODE_SUCCESS;
dfu_Command const * p_command = &m_packet.command;
uint32_t sigmask = 0;
uint8_t const * p_signature = NULL;
uint32_t signature_len = 0;
if (m_packet.has_signed_command)
{
p_command = &m_packet.signed_command.command;
sigmask = m_packet.signed_command.sigmask;
p_signature = m_packet.signed_command.signature.bytes;
signature_len = m_packet.signed_command.signature.size;
}
// Validate signature.
if (signature_required(p_command->init.type))
{
ret_val = nrf_dfu_validation_signature_check(sigmask,
p_signature,
signature_len,
m_init_packet_data_ptr,
m_init_packet_data_len);
}
// Validate versions.
if (ret_val == NRF_DFU_RES_CODE_SUCCESS)
{
ret_val = nrf_dfu_ver_validation_check(&p_command->init);
}
if (ret_val != NRF_DFU_RES_CODE_SUCCESS)
{
NRF_LOG_WARNING("Prevalidation failed.");
NRF_LOG_DEBUG("Init command:");
NRF_LOG_HEXDUMP_DEBUG(m_init_packet_data_ptr, m_init_packet_data_len);
}
return ret_val;
}
nrf_dfu_result_t nrf_dfu_validation_init_cmd_execute(uint32_t * p_dst_data_addr,
uint32_t * p_data_len)
{
nrf_dfu_result_t ret_val = NRF_DFU_RES_CODE_SUCCESS;
if (s_dfu_settings.progress.command_offset != s_dfu_settings.progress.command_size)
{
// The object wasn't the right (requested) size.
NRF_LOG_ERROR("Execute with faulty offset");
ret_val = NRF_DFU_RES_CODE_OPERATION_NOT_PERMITTED;
}
else if (m_valid_init_cmd_present)
{
*p_dst_data_addr = nrf_dfu_bank1_start_addr();
ret_val = update_data_size_get(mp_init, p_data_len);
}
else if (stored_init_cmd_decode())
{
// Will only get here if init command was received since last reset.
// An init command should not be written to flash until after it's been checked here.
ret_val = nrf_dfu_validation_prevalidate();
*p_dst_data_addr = 0;
*p_data_len = 0;
// Get size of binary.
if (ret_val == NRF_DFU_RES_CODE_SUCCESS)
{
ret_val = update_data_size_get(mp_init, p_data_len);
}
// Get address where to flash the binary.
if (ret_val == NRF_DFU_RES_CODE_SUCCESS)
{
ret_val = update_data_addr_get(mp_init, *p_data_len, p_dst_data_addr);
}
// Set flag validating the init command.
if (ret_val == NRF_DFU_RES_CODE_SUCCESS)
{
m_valid_init_cmd_present = true;
}
else
{
nrf_dfu_settings_progress_reset();
}
}
else
{
NRF_LOG_ERROR("Failed to decode init packet");
ret_val = NRF_DFU_RES_CODE_INVALID_OBJECT;
}
return ret_val;
}
// Function to check the hash received in the init command against the received firmware.
// little_endian specifies the endianness of @p p_hash.
static bool nrf_dfu_validation_hash_ok(uint8_t const * p_hash, uint32_t src_addr, uint32_t data_len)
{
bool result = true;
uint8_t hash[BLAKE2S_DIGEST_LENGTH];
NRF_LOG_DEBUG("Hash verification. start address: 0x%x, size: 0x%x",
src_addr,
data_len);
blake2s( (uint8_t*)src_addr, data_len, hash, BLAKE2S_DIGEST_LENGTH);
if (memcmp(hash, p_hash, BLAKE2S_DIGEST_LENGTH) != 0)
{
NRF_LOG_WARNING("Hash verification failed.");
NRF_LOG_DEBUG("Expected FW hash:")
NRF_LOG_HEXDUMP_DEBUG(p_hash, BLAKE2S_DIGEST_LENGTH);
NRF_LOG_DEBUG("Actual FW hash:")
NRF_LOG_HEXDUMP_DEBUG(hash, BLAKE2S_DIGEST_LENGTH);
NRF_LOG_FLUSH();
result = false;
}
return result;
}
// Function to check the hash received in the init command against the received firmware.
bool fw_hash_ok(dfu_InitCommand const * p_init, uint32_t fw_start_addr, uint32_t fw_size)
{
ASSERT(p_init != NULL);
return nrf_dfu_validation_hash_ok((uint8_t *)p_init->hash.hash.bytes, fw_start_addr, fw_size);
}
// Function to check whether the update contains a SoftDevice and, if so, if it is of a different
// major version than the existing SoftDevice.
static bool is_major_softdevice_update(uint32_t new_sd_addr)
{
// True if there is no SD right now, but there is a new one coming. This counts as a major update.
bool result = !SD_PRESENT && (SD_MAGIC_NUMBER_GET(new_sd_addr) == SD_MAGIC_NUMBER);
if (SD_PRESENT && (SD_MAGIC_NUMBER_GET(new_sd_addr) == SD_MAGIC_NUMBER))
{
// Both SoftDevices are present.
uint32_t current_SD_major = SD_MAJOR_VERSION_EXTRACT(SD_VERSION_GET(MBR_SIZE));
uint32_t new_SD_major = SD_MAJOR_VERSION_EXTRACT(SD_VERSION_GET(new_sd_addr));
result = (current_SD_major != new_SD_major);
NRF_LOG_INFO("SoftDevice update is a %s version update. Current: %d. New: %d.",
result ? "major" : "minor",
current_SD_major,
new_SD_major);
}
return result;
}
/**@brief Validate the SoftDevice size and magic number in structure found at 0x2000 in received SoftDevice.
*
* @param[in] sd_start_addr Start address of received SoftDevice.
* @param[in] sd_size Size of received SoftDevice in bytes.
*/
static bool softdevice_info_ok(uint32_t sd_start_addr, uint32_t sd_size)
{
bool result = true;
if (SD_MAGIC_NUMBER_GET(sd_start_addr) != SD_MAGIC_NUMBER)
{
NRF_LOG_ERROR("The SoftDevice does not contain the magic number identifying it as a SoftDevice.");
result = false;
}
else if (SD_SIZE_GET(sd_start_addr) < ALIGN_TO_PAGE(sd_size + MBR_SIZE))
{
// The size in the info struct should be rounded up to a page boundary
// and be larger than the actual size + the size of the MBR.
NRF_LOG_ERROR("The SoftDevice size in the info struct is too small compared with the size reported in the init command.");
result = false;
}
else if (SD_PRESENT && (SD_ID_GET(MBR_SIZE) != SD_ID_GET(sd_start_addr)))
{
NRF_LOG_ERROR("The new SoftDevice is of a different family than the present SoftDevice. Compatibility cannot be guaranteed.");
result = false;
}
return result;
}
static bool boot_validation_extract(boot_validation_t * p_boot_validation,
dfu_InitCommand const * p_init,
uint32_t index,
uint32_t start_addr,
uint32_t data_len,
boot_validation_type_t default_type)
{
memset(p_boot_validation, 0, sizeof(boot_validation_t));
p_boot_validation->sigmask = (boot_validation_type_t)p_init->boot_validation[index].sigmask;
memcpy(p_boot_validation->bytes, p_init->boot_validation[index].bytes.bytes, p_init->boot_validation[index].bytes.size);
if (default_type == NO_VALIDATION) {
return true;
}
return nrf_dfu_validation_boot_validate(p_boot_validation, start_addr, data_len);
}
// The is_trusted argument specifies whether the function should have side effects.
static bool postvalidate_app(dfu_InitCommand const * p_init, uint32_t src_addr, uint32_t data_len, bool is_trusted)
{
boot_validation_t boot_validation;
ASSERT(p_init->type == dfu_FwType_APPLICATION);
if (!boot_validation_extract(&boot_validation, p_init, 0, src_addr, data_len, VALIDATE_ECDSA_P256_SHA256))
{
return false;
}
//#if !NRF_DFU_IN_APP
// else if (NRF_BL_APP_SIGNATURE_CHECK_REQUIRED &&
// (boot_validation.type != VALIDATE_ECDSA_P256_SHA256))
// {
// NRF_LOG_WARNING("The boot validation of the app must be a signature check.");
// return false;
// }
//#endif
if (!is_trusted)
{
return true;
}
memcpy(&s_dfu_settings.boot_validation_app, &boot_validation, sizeof(boot_validation));
s_dfu_settings.bank_1.bank_code = NRF_DFU_BANK_VALID_APP;
NRF_LOG_DEBUG("Invalidating old application in bank 0.");
s_dfu_settings.bank_0.bank_code = NRF_DFU_BANK_INVALID;
if (!DFU_REQUIRES_SOFTDEVICE && !update_requires_softdevice(p_init))
{
// App does not need SD, so it should be placed where SD is.
nrf_dfu_softdevice_invalidate();
}
if (!NRF_DFU_DEBUG ||
(NRF_DFU_DEBUG && (p_init->has_is_debug == false || p_init->is_debug == false)))
{
s_dfu_settings.app_version = p_init->fw_version;
}
return true;
}
// Function to check a received SoftDevice or Bootloader firmware, or both,
// before it is copied into place.
// The is_trusted argument specifies whether the function should have side effects.
static bool postvalidate_sd_bl(dfu_InitCommand const * p_init,
bool with_sd,
bool with_bl,
uint32_t start_addr,
uint32_t data_len,
bool is_trusted)
{
boot_validation_t boot_validation_sd = {NO_VALIDATION};
boot_validation_t boot_validation_bl = {NO_VALIDATION};
uint32_t bl_start = start_addr;
uint32_t bl_size = data_len;
ASSERT(with_sd || with_bl);
if (with_sd)
{
if (!softdevice_info_ok(start_addr, p_init->sd_size))
{
return false;
}
if (is_major_softdevice_update(start_addr))
{
NRF_LOG_WARNING("Invalidating app because it is incompatible with the SoftDevice.");
if (DFU_REQUIRES_SOFTDEVICE && !with_bl)
{
NRF_LOG_ERROR("Major SD update but no BL. Abort to avoid incapacitating the BL.");
return false;
}
}
if (!boot_validation_extract(&boot_validation_sd, p_init, 0, start_addr, p_init->sd_size, VALIDATE_ECDSA_P256_SHA256))
{
return false;
}
bl_start += p_init->sd_size;
bl_size -= p_init->sd_size;
}
if (with_bl)
{
boot_validation_extract(&boot_validation_bl, p_init, with_sd ? 1 : 0, bl_start, bl_size, NO_VALIDATION);
}
if (!is_trusted)
{
return true;
}
if (with_sd)
{
if (is_major_softdevice_update(start_addr))
{
// Invalidate app since it may not be compatible with new SD.
nrf_dfu_bank_invalidate(&s_dfu_settings.bank_0);
}
memcpy(&s_dfu_settings.boot_validation_softdevice, &boot_validation_sd, sizeof(boot_validation_sd));
// Mark the update as valid.
s_dfu_settings.bank_1.bank_code = with_bl ? NRF_DFU_BANK_VALID_SD_BL
: NRF_DFU_BANK_VALID_SD;
s_dfu_settings.sd_size = p_init->sd_size;
}
else
{
s_dfu_settings.bank_1.bank_code = NRF_DFU_BANK_VALID_BL;
}
if (with_bl)
{
memcpy(&s_dfu_settings.boot_validation_bootloader, &boot_validation_bl, sizeof(boot_validation_bl));
if (!NRF_DFU_DEBUG ||
(NRF_DFU_DEBUG && (p_init->has_is_debug == false || p_init->is_debug == false)))
{
// If the update contains a bootloader, update the version.
// Unless the update is a debug packet.
s_dfu_settings.bootloader_version = p_init->fw_version;
}
}
return true;
}
bool nrf_dfu_validation_boot_validate(boot_validation_t const * p_validation, uint32_t data_addr, uint32_t data_len)
{
uint8_t const * p_data = (uint8_t*) data_addr;
nrf_dfu_result_t res_code = nrf_dfu_validation_signature_check(
p_validation->sigmask,
p_validation->bytes,
64,
p_data,
data_len);
return (res_code == NRF_DFU_RES_CODE_SUCCESS);
}
nrf_dfu_result_t postvalidate(uint32_t data_addr, uint32_t data_len, bool is_trusted)
{
nrf_dfu_result_t ret_val = NRF_DFU_RES_CODE_SUCCESS;
dfu_InitCommand const * p_init = mp_init;
if (!fw_hash_ok(p_init, data_addr, data_len))
{
ret_val = EXT_ERR(NRF_DFU_EXT_ERROR_VERIFICATION_FAILED);
}
else
{
if (p_init->type == dfu_FwType_APPLICATION)
{
if (!postvalidate_app(p_init, data_addr, data_len, is_trusted))
{
ret_val = NRF_DFU_RES_CODE_INVALID_OBJECT;
}
}
#if NRF_DFU_SUPPORTS_EXTERNAL_APP
else if (p_init->type == DFU_FW_TYPE_EXTERNAL_APPLICATION)
{
if (!is_trusted)
{
// This function must be implemented externally
ret_val = nrf_dfu_validation_post_external_app_execute(p_init, is_trusted);
}
else
{
s_dfu_settings.bank_1.bank_code = NRF_DFU_BANK_VALID_EXT_APP;
}
}
#endif // NRF_DFU_SUPPORTS_EXTERNAL_APP
else
{
bool with_sd = p_init->type & dfu_FwType_SOFTDEVICE;
bool with_bl = p_init->type & dfu_FwType_BOOTLOADER;
if (!postvalidate_sd_bl(p_init, with_sd, with_bl, data_addr, data_len, is_trusted))
{
ret_val = NRF_DFU_RES_CODE_INVALID_OBJECT;
if (is_trusted && with_sd && !DFU_REQUIRES_SOFTDEVICE &&
(data_addr == nrf_dfu_softdevice_start_address()))
{
nrf_dfu_softdevice_invalidate();
}
}
}
}
if (!is_trusted)
{
if (ret_val == NRF_DFU_RES_CODE_SUCCESS)
{
s_dfu_settings.bank_current = NRF_DFU_CURRENT_BANK_1;
}
else
{
nrf_dfu_settings_progress_reset();
}
}
else
{
if (ret_val == NRF_DFU_RES_CODE_SUCCESS)
{
// Mark the update as complete and valid.
s_dfu_settings.bank_1.image_crc = crc32_compute((uint8_t *)data_addr, data_len, NULL);
s_dfu_settings.bank_1.image_size = data_len;
}
else
{
nrf_dfu_bank_invalidate(&s_dfu_settings.bank_1);
}
nrf_dfu_settings_progress_reset();
s_dfu_settings.progress.update_start_address = data_addr;
}
return ret_val;
}
nrf_dfu_result_t nrf_dfu_validation_post_data_execute(uint32_t data_addr, uint32_t data_len)
{
return postvalidate(data_addr, data_len, false);
}
nrf_dfu_result_t nrf_dfu_validation_activation_prepare(uint32_t data_addr, uint32_t data_len)
{
return postvalidate(data_addr, data_len, true);
}
bool nrf_dfu_validation_valid_external_app(void)
{
return s_dfu_settings.bank_1.bank_code == NRF_DFU_BANK_VALID_EXT_APP;
}

@ -0,0 +1,199 @@
/**
* Copyright (c) 2017 - 2021, Nordic Semiconductor ASA
*
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without modification,
* are permitted provided that the following conditions are met:
*
* 1. Redistributions of source code must retain the above copyright notice, this
* list of conditions and the following disclaimer.
*
* 2. Redistributions in binary form, except as embedded into a Nordic
* Semiconductor ASA integrated circuit in a product or a software update for
* such product, must reproduce the above copyright notice, this list of
* conditions and the following disclaimer in the documentation and/or other
* materials provided with the distribution.
*
* 3. Neither the name of Nordic Semiconductor ASA nor the names of its
* contributors may be used to endorse or promote products derived from this
* software without specific prior written permission.
*
* 4. This software, with or without modification, must only be used with a
* Nordic Semiconductor ASA integrated circuit.
*
* 5. Any software provided in binary form under this license must not be reverse
* engineered, decompiled, modified and/or disassembled.
*
* THIS SOFTWARE IS PROVIDED BY NORDIC SEMICONDUCTOR ASA "AS IS" AND ANY EXPRESS
* OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
* OF MERCHANTABILITY, NONINFRINGEMENT, AND FITNESS FOR A PARTICULAR PURPOSE ARE
* DISCLAIMED. IN NO EVENT SHALL NORDIC SEMICONDUCTOR ASA OR CONTRIBUTORS BE
* LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE
* GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
* OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*
*/
/**@file
*
* @defgroup nrf_dfu_validation Validation
* @{
* @ingroup nrf_dfu
*/
#ifndef __NRF_DFU_VALIDATION_H
#define __NRF_DFU_VALIDATION_H
#include "stdint.h"
#include "sdk_errors.h"
#include "dfu-cc.pb.h"
#include "nrf_dfu_handling_error.h"
/**
* @brief Function for module initialization.
*
* Function checks if there is a valid init packet in DFU settings written in flash.
*/
void nrf_dfu_validation_init(void);
/**
* @brief Function called on reception of init command creation request.
*
* @param[in] size Size of incoming init packet.
*
* @return Operation result. See @ref nrf_dfu_result_t
*/
nrf_dfu_result_t nrf_dfu_validation_init_cmd_create(uint32_t size);
/**
* @brief Function called on reception of fragment of init command.
*
* @param[in] p_data Init command fragment.
* @param[in] length Init command fragment size.
*
* @return Operation result. See @ref nrf_dfu_result_t
*/
nrf_dfu_result_t nrf_dfu_validation_init_cmd_append(uint8_t const * p_data, uint32_t length);
/**
* @brief Function for getting init command status.
*
* @param[out] p_offset Current offset.
* @param[out] p_crc Current CRC.
* @param[out] p_max_size Maximum size of init command.
*/
void nrf_dfu_validation_init_cmd_status_get(uint32_t * p_offset,
uint32_t * p_crc,
uint32_t * p_max_size);
/**
* @brief Function for inquiring whether a valid init command has been received.
*
* @return true if there is a valid init command. This can be true at boot time
* if the device was reset during a DFU operation.
*/
bool nrf_dfu_validation_init_cmd_present(void);
/**
* @brief Function for validating init command and retrieving the address and length of the firmware.
*
* If init command is successfully validated Bank 1 details are written to out parameters.
*
* Until @ref nrf_dfu_validation_init_cmd_create is called, this function can be called
* again after the first time without side effects to retrieve address and length.
*
* @param[out] p_dst_data_addr Start address of received data, if validation is successful.
* @param[out] p_data_len Expected length of received data, if validation is successful.
*
* @return Operation result. See @ref nrf_dfu_result_t
*/
nrf_dfu_result_t nrf_dfu_validation_init_cmd_execute(uint32_t * p_dst_data_addr,
uint32_t * p_data_len);
/**
* @brief Function for validating the init command.
*
* @return Operation result. See @ref nrf_dfu_result_t.
*/
nrf_dfu_result_t nrf_dfu_validation_prevalidate(void);
/**
* @brief Function for validating the firmware for booting.
*
* @param[in] p_validation Validation parameters.
* @param[in] data_addr Start address of the firmware.
* @param[in] data_len Length of the firmware.
*
* @return Whether the firmware is valid for booting.
*/
bool nrf_dfu_validation_boot_validate(boot_validation_t const * p_validation, uint32_t data_addr, uint32_t data_len);
/**
* @brief Function for postvalidating the update after all data is received.
*
* @param[in] data_addr Start address of the received data.
* @param[in] data_len Length of the received data.
*
* @return Operation result. See @ref nrf_dfu_result_t.
*/
nrf_dfu_result_t nrf_dfu_validation_post_data_execute(uint32_t data_addr, uint32_t data_len);
/**
* @brief Function for preparing the update for activation.
*
* This function is called after a reset, after all data is received. This function also runs
* @ref nrf_dfu_validation_post_data_execute internally. If this succeeds, the update is
* activated by the activation machinery in the bootloader the next time it runs.
*
* @note The caller must have permissions to edit the relevant entries in the settings.
*
* @param[in] data_addr Start address of the received data.
* @param[in] data_len Length of the received data.
*
* @return Operation result. See @ref nrf_dfu_result_t
*/
nrf_dfu_result_t nrf_dfu_validation_activation_prepare(uint32_t data_addr, uint32_t data_len);
/**
* @brief Function to execute on a validated external app.
*
* @details This function is called once all data is received with the parameter
* @p is_boot set to false. The function is called during bootup with the parameter
* set to true.
*
*
*
* @note This function requires that @ref NRF_DFU_SUPPORTS_EXTERNAL_APP is set to 1.
* It is up to the user to implement this function.
*
* @warning Parameter @p is_trusted must be used to ensure that no loss of security of process can happen.
* This parameter should only be set if the function is called after a root-of-trust
* reset on the device.
*
* Parameter @p is_trusted can be used for the following:
* - Ensuring that an external application is run only once (after root-of-trust).
* - Ensuring that a bank flag or any other flash access can only happen after root-of-trust.
* - Ensuring that the device reaches the correct state after a power failure on the device.
*
* @param[in] p_init Init command for the firmware upgrade.
* @param[in] is_trusted Must be set to true if this is called after root-of-trust boot.
* Must be set to false if this is called from DFU mode or background
* DFU operation.
*
* @return Operation result. see @ref nrf_dfu_result_t.
*/
nrf_dfu_result_t nrf_dfu_validation_post_external_app_execute(dfu_InitCommand const * p_init, bool is_trusted);
/**
* @brief Function to check if there is a valid external app in Bank 1.
*
* @returns True if valid external app, otherwise false.
*/
bool nrf_dfu_validation_valid_external_app(void);
#endif //__NRF_DFU_VALIDATION_H
/** @} */

@ -0,0 +1,311 @@
/**
* Copyright (c) 2017 - 2021, Nordic Semiconductor ASA
*
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without modification,
* are permitted provided that the following conditions are met:
*
* 1. Redistributions of source code must retain the above copyright notice, this
* list of conditions and the following disclaimer.
*
* 2. Redistributions in binary form, except as embedded into a Nordic
* Semiconductor ASA integrated circuit in a product or a software update for
* such product, must reproduce the above copyright notice, this list of
* conditions and the following disclaimer in the documentation and/or other
* materials provided with the distribution.
*
* 3. Neither the name of Nordic Semiconductor ASA nor the names of its
* contributors may be used to endorse or promote products derived from this
* software without specific prior written permission.
*
* 4. This software, with or without modification, must only be used with a
* Nordic Semiconductor ASA integrated circuit.
*
* 5. Any software provided in binary form under this license must not be reverse
* engineered, decompiled, modified and/or disassembled.
*
* THIS SOFTWARE IS PROVIDED BY NORDIC SEMICONDUCTOR ASA "AS IS" AND ANY EXPRESS
* OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
* OF MERCHANTABILITY, NONINFRINGEMENT, AND FITNESS FOR A PARTICULAR PURPOSE ARE
* DISCLAIMED. IN NO EVENT SHALL NORDIC SEMICONDUCTOR ASA OR CONTRIBUTORS BE
* LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE
* GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
* OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*
*/
#include <stdbool.h>
#include "nrf_dfu_types.h"
#include "nrf_dfu_settings.h"
#include "nrf_dfu_utils.h"
#include "nrf_bootloader_info.h"
#include "nrf_assert.h"
#include "dfu-cc.pb.h"
#include "nrf_dfu_ver_validation.h"
#define NRF_LOG_MODULE_NAME nrf_dfu_ver_validation
#include "nrf_log.h"
NRF_LOG_MODULE_REGISTER();
/** @brief Macro for reading the Firmware ID of a SoftDevice at a given base address.
*/
#ifndef _SD_FWID_GET
#define _SD_FWID_GET(baseaddr) SD_OFFSET_GET_UINT16(baseaddr, 0x0C)
#endif
#define EXT_ERR(err) (nrf_dfu_result_t)((uint32_t)NRF_DFU_RES_CODE_EXT_ERROR + (uint32_t)err)
static bool sd_req_check(uint32_t const * p_sd_req, uint8_t sd_req_cnt, bool accept_any)
{
bool result = false;
for (uint8_t i = 0; i < sd_req_cnt; i++)
{
if ((SD_PRESENT && (p_sd_req[i] == _SD_FWID_GET(MBR_SIZE))) ||
(accept_any && (p_sd_req[i] == SD_REQ_ANY_VERSION))
)
{
// Found a matching sd_req field. sd_req is ok.
result = true;
break;
}
}
return result;
}
static bool sd_req_ok(dfu_InitCommand const * p_init)
{
ASSERT(p_init != NULL);
bool result;
#if defined(BLE_STACK_SUPPORT_REQD) || defined(ANT_STACK_SUPPORT_REQD)
// The bootloader needs the SoftDevice, so disabling NRF_DFU_APP_DOWNGRADE_PREVENTION
// should not be applied to SoftDevice updates.
const bool prevent_downgrade = NRF_DFU_APP_DOWNGRADE_PREVENTION || (p_init->type == DFU_FW_TYPE_SOFTDEVICE);
#else
const bool prevent_downgrade = NRF_DFU_APP_DOWNGRADE_PREVENTION;
#endif
if (SD_PRESENT)
{
if (p_init->sd_req_count == 0)
{
result = false;
}
else if (p_init->sd_req[0] != SD_REQ_APP_OVERWRITES_SD)
{
result = sd_req_check(p_init->sd_req,
p_init->sd_req_count,
(p_init->type == dfu_FwType_EXTERNAL_APPLICATION));
}
else if (p_init->type == dfu_FwType_APPLICATION)
{
// The application wants to overwrite the SoftDevice.
if (prevent_downgrade && (p_init->sd_req_count > 1) && (p_init->sd_req[0] == SD_REQ_APP_OVERWRITES_SD))
{
// The application can overwrite the SD if sd_req[0] == 0 and table has the FWID of the current SD.
result = sd_req_check(p_init->sd_req, p_init->sd_req_count, false);
// Prevent BLE/ANT bootloaders from allowing applications overwriting the SoftDevice.
#if defined(BLE_STACK_SUPPORT_REQD) || defined(ANT_STACK_SUPPORT_REQD)
result = false;
#endif
}
else
{
result = true;
}
}
#if NRF_DFU_SUPPORTS_EXTERNAL_APP
else if(p_init->type == DFU_FW_TYPE_EXTERNAL_APPLICATION)
{
// Won't accept FW upgrade using external application to
// enforce replacing SoftDevice (SD_REQ_APP_OVERWRITES_SD)
result = false;
}
#endif // NRF_DFU_SUPPORTS_EXTERNAL_APP
else
{
// Don't allow SoftDevice updates which assume no SD is present already.
result = !prevent_downgrade || (p_init->type != dfu_FwType_SOFTDEVICE);
}
}
else
{
if (p_init->sd_req_count && (p_init->sd_req[0] != SD_REQ_APP_OVERWRITES_SD))
{
// Fail if there is no SD and the update requires SD. The special "any" FWID is valid
// for external apps only.
result = false;
#if NRF_DFU_SUPPORTS_EXTERNAL_APP
result = sd_req_check(p_init->sd_req,
p_init->sd_req_count,
(p_init->type == DFU_FW_TYPE_EXTERNAL_APPLICATION));
#endif // NRF_DFU_SUPPORTS_EXTERNAL_APP
}
else
{
// If there is no SD and update has SD it is accepted only if it has a fw_version.
result = !prevent_downgrade || p_init->has_fw_version;
}
}
return result;
}
static bool fw_hash_type_ok(dfu_InitCommand const * p_init)
{
ASSERT(p_init != NULL);
return (p_init->hash.hash_type == dfu_HashType_SHA256);
}
static bool fw_version_required(dfu_FwType new_fw_type)
{
bool result = true;
if (new_fw_type == dfu_FwType_SOFTDEVICE)
{
result = false; // fw_version is optional in SoftDevice updates. If present, it will be checked against the app version.
}
else if (new_fw_type == dfu_FwType_APPLICATION)
{
result = NRF_DFU_APP_DOWNGRADE_PREVENTION; // fw_version is configurable in app updates.
}
#if NRF_DFU_SUPPORTS_EXTERNAL_APP
#if !NRF_DFU_EXTERNAL_APP_VERSIONING
else if (new_fw_type == DFU_FW_TYPE_EXTERNAL_APPLICATION)
{
return false;
}
#endif //!NRF_DFU_EXTERNAL_APP_VERSIONING
#endif // NRF_DFU_SUPPORTS_EXTERNAL_APP
return result;
}
static bool fw_type_ok(dfu_InitCommand const * p_init)
{
ASSERT(p_init != NULL);
return ((p_init->has_type)
&& ( (p_init->type == dfu_FwType_APPLICATION)
|| (p_init->type == dfu_FwType_SOFTDEVICE)
|| (p_init->type == dfu_FwType_BOOTLOADER)
|| (p_init->type == dfu_FwType_SOFTDEVICE_BOOTLOADER)
#if NRF_DFU_SUPPORTS_EXTERNAL_APP
|| (p_init->type == DFU_FW_TYPE_EXTERNAL_APPLICATION)
#endif // NRF_DFU_SUPPORTS_EXTERNAL_APP
));
}
#ifndef NRF_DFU_APP_ACCEPT_SAME_VERSION
#define NRF_DFU_APP_ACCEPT_SAME_VERSION 1
#endif
// This function assumes p_init->has_fw_version.
static bool fw_version_ok(dfu_InitCommand const * p_init)
{
ASSERT(p_init != NULL);
ASSERT(p_init->has_fw_version);
if ((p_init->type == dfu_FwType_APPLICATION) ||
(p_init->type == dfu_FwType_SOFTDEVICE))
{
if (!NRF_DFU_APP_DOWNGRADE_PREVENTION)
{
return true;
}
else if ((p_init->fw_version > s_dfu_settings.app_version))
{
return true;
}
else if ((p_init->fw_version == s_dfu_settings.app_version))
{
return NRF_DFU_APP_ACCEPT_SAME_VERSION;
}
else
{
return false;
}
}
#if NRF_DFU_SUPPORTS_EXTERNAL_APP
#if NRF_DFU_EXTERNAL_APP_VERSIONING
else if (p_init->type == DFU_FW_TYPE_EXTERNAL_APPLICATION)
{
return (p_init->fw_version >= s_dfu_settings.app_version);
}
#else
else if(p_init->type == DFU_FW_TYPE_EXTERNAL_APPLICATION)
{
return true;
}
#endif // NRF_DFU_EXTERNAL_APP_VERSIONING
#endif // NRF_DFU_SUPPORTS_EXTERNAL_APP
else
{
return (p_init->fw_version > s_dfu_settings.bootloader_version);
}
}
nrf_dfu_result_t nrf_dfu_ver_validation_check(dfu_InitCommand const * p_init)
{
nrf_dfu_result_t ret_val = NRF_DFU_RES_CODE_SUCCESS;
if (!fw_type_ok(p_init))
{
NRF_LOG_ERROR("Invalid firmware type.");
ret_val = EXT_ERR(NRF_DFU_EXT_ERROR_INIT_COMMAND_INVALID);
}
else if (!fw_hash_type_ok(p_init))
{
NRF_LOG_ERROR("Invalid hash type.");
ret_val = EXT_ERR(NRF_DFU_EXT_ERROR_WRONG_HASH_TYPE);
}
else if (!NRF_DFU_DEBUG ||
(NRF_DFU_DEBUG && ((p_init->has_is_debug == false) || (p_init->is_debug == false))))
{
if (p_init->has_hw_version == false)
{
NRF_LOG_ERROR("No HW version.");
ret_val = EXT_ERR(NRF_DFU_EXT_ERROR_INIT_COMMAND_INVALID);
}
else if (p_init->hw_version != NRF_DFU_HW_VERSION)
{
NRF_LOG_WARNING("Faulty HW version.");
ret_val = EXT_ERR( NRF_DFU_EXT_ERROR_HW_VERSION_FAILURE);
}
else if (!sd_req_ok(p_init))
{
NRF_LOG_WARNING("SD req not met.");
ret_val = EXT_ERR(NRF_DFU_EXT_ERROR_SD_VERSION_FAILURE);
}
else if (p_init->has_fw_version)
{
if (!fw_version_ok(p_init))
{
NRF_LOG_WARNING("FW version too low.");
ret_val = EXT_ERR(NRF_DFU_EXT_ERROR_FW_VERSION_FAILURE);
}
}
else
{
if (fw_version_required(p_init->type))
{
NRF_LOG_ERROR("FW version missing.");
ret_val = EXT_ERR(NRF_DFU_EXT_ERROR_INIT_COMMAND_INVALID);
}
}
}
return ret_val;
}

@ -0,0 +1,64 @@
/**
* Copyright (c) 2017 - 2021, Nordic Semiconductor ASA
*
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without modification,
* are permitted provided that the following conditions are met:
*
* 1. Redistributions of source code must retain the above copyright notice, this
* list of conditions and the following disclaimer.
*
* 2. Redistributions in binary form, except as embedded into a Nordic
* Semiconductor ASA integrated circuit in a product or a software update for
* such product, must reproduce the above copyright notice, this list of
* conditions and the following disclaimer in the documentation and/or other
* materials provided with the distribution.
*
* 3. Neither the name of Nordic Semiconductor ASA nor the names of its
* contributors may be used to endorse or promote products derived from this
* software without specific prior written permission.
*
* 4. This software, with or without modification, must only be used with a
* Nordic Semiconductor ASA integrated circuit.
*
* 5. Any software provided in binary form under this license must not be reverse
* engineered, decompiled, modified and/or disassembled.
*
* THIS SOFTWARE IS PROVIDED BY NORDIC SEMICONDUCTOR ASA "AS IS" AND ANY EXPRESS
* OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
* OF MERCHANTABILITY, NONINFRINGEMENT, AND FITNESS FOR A PARTICULAR PURPOSE ARE
* DISCLAIMED. IN NO EVENT SHALL NORDIC SEMICONDUCTOR ASA OR CONTRIBUTORS BE
* LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE
* GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
* OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*
*/
#ifndef __NRF_DFU_VER_VALIDATION_H
#define __NRF_DFU_VER_VALIDATION_H
#include "stdint.h"
#include "sdk_errors.h"
#include "nrf_dfu_handling_error.h"
#include "dfu-cc.pb.h"
/** @brief SD_REQ field value which indicates that Softdevice can be overwritten by the application. */
#define SD_REQ_APP_OVERWRITES_SD 0
/** @brief SD_REQ_ANY_VERSION field value which indicates that any SoftDevice version is valid.
*
* @note This is used by external application in case SoftDevice version compatibility isn't needed.
*/
#define SD_REQ_ANY_VERSION (0xFFFE)
/**
* @brief Function for validating version of new firmware.
*
* @return NRF_DFU_RES_CODE_SUCCESS if successful or error code otherwise
*/
nrf_dfu_result_t nrf_dfu_ver_validation_check(dfu_InitCommand const * p_init);
#endif //__NRF_DFU_VER_VALIDATION_H

@ -0,0 +1,20 @@
/* This file was automatically generated by nrfutil on 2023-01-23 (YY-MM-DD) at
* 16:58:55 */
#include "compiler_abstraction.h"
#include "stdint.h"
/** @brief Public keys used to verify DFU images */
const uint8_t NRF_BOOTLOADER_KEY_M = 2;
const uint8_t NRF_BOOTLOADER_KEY_N = 3;
const uint8_t * const NRF_BOOTLOADER_KEYS[] = {
#if !PRODUCTION
(const uint8_t *)"\xdb\x99\x5f\xe2\x51\x69\xd1\x41\xca\xb9\xbb\xba\x92\xba\xa0\x1f\x9f\x2e\x1e\xce\x7d\xf4\xcb\x2a\xc0\x51\x90\xf3\x7f\xcc\x1f\x9d",
(const uint8_t *)"\x21\x52\xf8\xd1\x9b\x79\x1d\x24\x45\x32\x42\xe1\x5f\x2e\xab\x6c\xb7\xcf\xfa\x7b\x6a\x5e\xd3\x00\x97\x96\x0e\x06\x98\x81\xdb\x12",
(const uint8_t *)"\x22\xfc\x29\x77\x92\xf0\xb6\xff\xc0\xbf\xcf\xdb\x7e\xdb\x0c\x0a\xa1\x4e\x02\x5a\x36\x5e\xc0\xe3\x42\xe8\x6e\x38\x29\xcb\x74\xb6",
#else
MODEL_NRF_BOOTLOADER_KEYS
#endif
};

@ -0,0 +1,332 @@
/*********************************************************************
* (c) SEGGER Microcontroller GmbH *
* The Embedded Experts *
* www.segger.com *
**********************************************************************
File : /home/mbruna/CLionProjects/trezor-model_r/core/embed/ble_bootloader/jlink.jdebug
Created : 6 Feb 2023 15:54
Ozone Version : V3.28c
*/
/*********************************************************************
*
* OnProjectLoad
*
* Function description
* Project load routine. Required.
*
**********************************************************************
*/
void OnProjectLoad (void) {
//
// Dialog-generated settings
//
Project.AddPathSubstitute (".", "$(ProjectDir)");
Project.AddPathSubstitute (".", "$(ProjectDir)");
Project.SetDevice ("Cortex-M4");
Project.SetHostIF ("USB", "");
Project.SetTargetIF ("SWD");
Project.SetTIFSpeed ("20 MHz");
Project.AddSvdFile ("$(InstallDir)/Config/CPU/Cortex-M4F.svd");
//
// User settings
//
File.Open ("../../build/ble_bootloader/ble_bootloader.elf");
}
/*********************************************************************
*
* OnStartupComplete
*
* Function description
* Called when program execution has reached/passed
* the startup completion point. Optional.
*
**********************************************************************
*/
//void OnStartupComplete (void) {
//}
/*********************************************************************
*
* TargetReset
*
* Function description
* Replaces the default target device reset routine. Optional.
*
* Notes
* This example demonstrates the usage when
* debugging an application in RAM on a Cortex-M target device.
*
**********************************************************************
*/
//void TargetReset (void) {
//
// unsigned int SP;
// unsigned int PC;
// unsigned int VectorTableAddr;
//
// VectorTableAddr = Elf.GetBaseAddr();
// //
// // Set up initial stack pointer
// //
// if (VectorTableAddr != 0xFFFFFFFF) {
// SP = Target.ReadU32(VectorTableAddr);
// Target.SetReg("SP", SP);
// }
// //
// // Set up entry point PC
// //
// PC = Elf.GetEntryPointPC();
//
// if (PC != 0xFFFFFFFF) {
// Target.SetReg("PC", PC);
// } else if (VectorTableAddr != 0xFFFFFFFF) {
// PC = Target.ReadU32(VectorTableAddr + 4);
// Target.SetReg("PC", PC);
// } else {
// Util.Error("Project file error: failed to set entry point PC", 1);
// }
//}
/*********************************************************************
*
* BeforeTargetReset
*
* Function description
* Event handler routine. Optional.
*
**********************************************************************
*/
//void BeforeTargetReset (void) {
//}
/*********************************************************************
*
* AfterTargetReset
*
* Function description
* Event handler routine. Optional.
* The default implementation initializes SP and PC to reset values.
**
**********************************************************************
*/
void AfterTargetReset (void) {
_SetupTarget();
}
/*********************************************************************
*
* DebugStart
*
* Function description
* Replaces the default debug session startup routine. Optional.
*
**********************************************************************
*/
//void DebugStart (void) {
//}
/*********************************************************************
*
* TargetConnect
*
* Function description
* Replaces the default target IF connection routine. Optional.
*
**********************************************************************
*/
//void TargetConnect (void) {
//}
/*********************************************************************
*
* BeforeTargetConnect
*
* Function description
* Event handler routine. Optional.
*
**********************************************************************
*/
void BeforeTargetConnect (void) {
Project.SetJLinkScript("./MMDScript.JLinkScript");
}
/*********************************************************************
*
* AfterTargetConnect
*
* Function description
* Event handler routine. Optional.
*
**********************************************************************
*/
//void AfterTargetConnect (void) {
//}
/*********************************************************************
*
* TargetDownload
*
* Function description
* Replaces the default program download routine. Optional.
*
**********************************************************************
*/
//void TargetDownload (void) {
//}
/*********************************************************************
*
* BeforeTargetDownload
*
* Function description
* Event handler routine. Optional.
*
**********************************************************************
*/
//void BeforeTargetDownload (void) {
//}
/*********************************************************************
*
* AfterTargetDownload
*
* Function description
* Event handler routine. Optional.
* The default implementation initializes SP and PC to reset values.
*
**********************************************************************
*/
void AfterTargetDownload (void) {
_SetupTarget();
}
/*********************************************************************
*
* BeforeTargetDisconnect
*
* Function description
* Event handler routine. Optional.
*
**********************************************************************
*/
//void BeforeTargetDisconnect (void) {
//}
/*********************************************************************
*
* AfterTargetDisconnect
*
* Function description
* Event handler routine. Optional.
*
**********************************************************************
*/
//void AfterTargetDisconnect (void) {
//}
/*********************************************************************
*
* AfterTargetHalt
*
* Function description
* Event handler routine. Optional.
*
**********************************************************************
*/
//void AfterTargetHalt (void) {
//}
/*********************************************************************
*
* BeforeTargetResume
*
* Function description
* Event handler routine. Optional.
*
**********************************************************************
*/
//void BeforeTargetResume (void) {
//}
/*********************************************************************
*
* OnSnapshotLoad
*
* Function description
* Called upon loading a snapshot. Optional.
*
* Additional information
* This function is used to restore the target state in cases
* where values cannot simply be written to the target.
* Typical use: GPIO clock needs to be enabled, before
* GPIO is configured.
*
**********************************************************************
*/
//void OnSnapshotLoad (void) {
//}
/*********************************************************************
*
* OnSnapshotSave
*
* Function description
* Called upon saving a snapshot. Optional.
*
* Additional information
* This function is usually used to save values of the target
* state which can either not be trivially read,
* or need to be restored in a specific way or order.
* Typically use: Memory Mapped Registers,
* such as PLL and GPIO configuration.
*
**********************************************************************
*/
//void OnSnapshotSave (void) {
//}
/*********************************************************************
*
* OnError
*
* Function description
* Called when an error ocurred. Optional.
*
**********************************************************************
*/
//void OnError (void) {
//}
/*********************************************************************
*
* AfterProjectLoad
*
* Function description
* After Project load routine. Optional.
*
**********************************************************************
*/
//void AfterProjectLoad (void) {
//}
/*********************************************************************
*
* _SetupTarget
*
* Function description
* Setup the target.
* Called by AfterTargetReset() and AfterTargetDownload().
*
* Auto-generated function. May be overridden by Ozone.
*
**********************************************************************
*/
void _SetupTarget(void) {
//
// this function is intentionally empty because both inital PC and
// initial SP were chosen not to be set
//
}

@ -0,0 +1,169 @@
/**
* Copyright (c) 2016 - 2021, Nordic Semiconductor ASA
*
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
*
* 1. Redistributions of source code must retain the above copyright notice,
* this list of conditions and the following disclaimer.
*
* 2. Redistributions in binary form, except as embedded into a Nordic
* Semiconductor ASA integrated circuit in a product or a software update for
* such product, must reproduce the above copyright notice, this list of
* conditions and the following disclaimer in the documentation and/or other
* materials provided with the distribution.
*
* 3. Neither the name of Nordic Semiconductor ASA nor the names of its
* contributors may be used to endorse or promote products derived from this
* software without specific prior written permission.
*
* 4. This software, with or without modification, must only be used with a
* Nordic Semiconductor ASA integrated circuit.
*
* 5. Any software provided in binary form under this license must not be
* reverse engineered, decompiled, modified and/or disassembled.
*
* THIS SOFTWARE IS PROVIDED BY NORDIC SEMICONDUCTOR ASA "AS IS" AND ANY EXPRESS
* OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
* OF MERCHANTABILITY, NONINFRINGEMENT, AND FITNESS FOR A PARTICULAR PURPOSE ARE
* DISCLAIMED. IN NO EVENT SHALL NORDIC SEMICONDUCTOR ASA OR CONTRIBUTORS BE
* LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
* POSSIBILITY OF SUCH DAMAGE.
*
*/
/** @file
*
* @defgroup bootloader_secure_ble main.c
* @{
* @ingroup dfu_bootloader_api
* @brief Bootloader project main file for secure DFU.
*
*/
#include <stdint.h>
#include "app_error.h"
#include "app_error_weak.h"
#include "nrf_bootloader.h"
#include "nrf_bootloader_app_start.h"
#include "nrf_bootloader_dfu_timers.h"
#include "nrf_bootloader_info.h"
#include "nrf_delay.h"
#include "nrf_dfu.h"
#include "nrf_gpio.h"
#include "nrf_log.h"
#include "nrf_log_ctrl.h"
#include "nrf_log_default_backends.h"
#include "nrf_mbr.h"
#include "trezor_t3w1_d1_NRF.h"
static void on_error(void) {
NRF_LOG_FINAL_FLUSH();
#if NRF_MODULE_ENABLED(NRF_LOG_BACKEND_RTT)
// To allow the buffer to be flushed by the host.
nrf_delay_ms(100);
#endif
#ifdef NRF_DFU_DEBUG_VERSION
NRF_BREAKPOINT_COND;
#endif
NVIC_SystemReset();
}
void app_error_handler(uint32_t error_code, uint32_t line_num,
const uint8_t* p_file_name) {
NRF_LOG_ERROR("%s:%d, %d", p_file_name, line_num, error_code);
on_error();
}
void app_error_fault_handler(uint32_t id, uint32_t pc, uint32_t info) {
NRF_LOG_ERROR("Received a fault! id: 0x%08x, pc: 0x%08x, info: 0x%08x", id,
pc, info);
on_error();
}
void app_error_handler_bare(uint32_t error_code) {
NRF_LOG_ERROR("Received an error: 0x%08x!", error_code);
on_error();
}
/**
* @brief Function notifies certain events in DFU process.
*/
static void dfu_observer(nrf_dfu_evt_type_t evt_type) {
switch (evt_type) {
case NRF_DFU_EVT_DFU_FAILED:
case NRF_DFU_EVT_DFU_ABORTED:
case NRF_DFU_EVT_DFU_INITIALIZED:
// bsp_board_init(BSP_INIT_LEDS);
// bsp_board_led_on(BSP_BOARD_LED_0);
// bsp_board_led_on(BSP_BOARD_LED_1);
// bsp_board_led_off(BSP_BOARD_LED_2);
break;
case NRF_DFU_EVT_TRANSPORT_ACTIVATED:
// bsp_board_led_off(BSP_BOARD_LED_1);
// bsp_board_led_on(BSP_BOARD_LED_2);
break;
case NRF_DFU_EVT_DFU_STARTED:
break;
default:
break;
}
}
uint32_t nrf_dfu_init_user(void) {
// signalize DFU mode
nrf_gpio_pin_set(GPIO_1_PIN);
return NRF_SUCCESS;
}
/**@brief Function for application main entry. */
int main(void) {
NRF_APPROTECT->DISABLE = APPROTECT_DISABLE_DISABLE_SwDisable;
uint32_t ret_val;
// Apply priority for monitor mode interrupt
NVIC_SetPriority(DebugMonitor_IRQn, _PRIO_SD_LOW);
// Must happen before flash protection is applied, since it edits a protected
// page.
nrf_bootloader_mbr_addrs_populate();
// Protect MBR and bootloader code from being overwritten.
ret_val = nrf_bootloader_flash_protect(0, MBR_SIZE);
APP_ERROR_CHECK(ret_val);
ret_val =
nrf_bootloader_flash_protect(BOOTLOADER_START_ADDR, BOOTLOADER_SIZE);
APP_ERROR_CHECK(ret_val);
nrf_gpio_cfg_output(GPIO_1_PIN);
nrf_gpio_cfg_output(GPIO_2_PIN);
nrf_gpio_pin_clear(GPIO_1_PIN);
nrf_gpio_pin_clear(GPIO_2_PIN);
(void)NRF_LOG_INIT(nrf_bootloader_dfu_timer_counter_get);
NRF_LOG_DEFAULT_BACKENDS_INIT();
NRF_LOG_INFO("Inside main");
ret_val = nrf_bootloader_init(dfu_observer);
APP_ERROR_CHECK(ret_val);
NRF_LOG_FLUSH();
NRF_LOG_ERROR("After main, should never be reached.");
NRF_LOG_FLUSH();
APP_ERROR_CHECK_BOOL(false);
}
/**
* @}
*/

@ -0,0 +1,156 @@
/* Linker script to configure memory regions. */
SEARCH_DIR(.)
GROUP(-lgcc -lc -lnosys)
MEMORY
{
FLASH (rx) : ORIGIN = 0x70000, LENGTH = 0xe000
RAM (rwx) : ORIGIN = 0x20002ae8, LENGTH = 0x1d518
uicr_bootloader_start_address (r) : ORIGIN = 0x10001014, LENGTH = 0x4
bootloader_settings_page (r) : ORIGIN = 0x0007F000, LENGTH = 0x1000
uicr_mbr_params_page (r) : ORIGIN = 0x10001018, LENGTH = 0x4
mbr_params_page (r) : ORIGIN = 0x0007E000, LENGTH = 0x1000
}
SECTIONS
{
. = ALIGN(4);
.uicr_bootloader_start_address :
{
PROVIDE(__start_uicr_bootloader_start_address = .);
KEEP(*(SORT(.uicr_bootloader_start_address*)))
PROVIDE(__stop_uicr_bootloader_start_address = .);
} > uicr_bootloader_start_address
. = ALIGN(4);
.bootloader_settings_page(NOLOAD) :
{
PROVIDE(__start_bootloader_settings_page = .);
KEEP(*(SORT(.bootloader_settings_page*)))
PROVIDE(__stop_bootloader_settings_page = .);
} > bootloader_settings_page
. = ALIGN(4);
.uicr_mbr_params_page :
{
PROVIDE(__start_uicr_mbr_params_page = .);
KEEP(*(SORT(.uicr_mbr_params_page*)))
PROVIDE(__stop_uicr_mbr_params_page = .);
} > uicr_mbr_params_page
. = ALIGN(4);
.mbr_params_page(NOLOAD) :
{
PROVIDE(__start_mbr_params_page = .);
KEEP(*(SORT(.mbr_params_page*)))
PROVIDE(__stop_mbr_params_page = .);
} > mbr_params_page
}
SECTIONS
{
. = ALIGN(4);
.mem_section_dummy_ram :
{
}
.log_dynamic_data :
{
PROVIDE(__start_log_dynamic_data = .);
KEEP(*(SORT(.log_dynamic_data*)))
PROVIDE(__stop_log_dynamic_data = .);
} > RAM
.log_filter_data :
{
PROVIDE(__start_log_filter_data = .);
KEEP(*(SORT(.log_filter_data*)))
PROVIDE(__stop_log_filter_data = .);
} > RAM
.fs_data :
{
PROVIDE(__start_fs_data = .);
KEEP(*(.fs_data))
PROVIDE(__stop_fs_data = .);
} > RAM
} INSERT AFTER .data;
SECTIONS
{
.mem_section_dummy_rom :
{
}
.crypto_data :
{
PROVIDE(__start_crypto_data = .);
KEEP(*(SORT(.crypto_data*)))
PROVIDE(__stop_crypto_data = .);
} > FLASH
.nrf_queue :
{
PROVIDE(__start_nrf_queue = .);
KEEP(*(.nrf_queue))
PROVIDE(__stop_nrf_queue = .);
} > FLASH
.dfu_trans :
{
PROVIDE(__start_dfu_trans = .);
KEEP(*(SORT(.dfu_trans*)))
PROVIDE(__stop_dfu_trans = .);
} > FLASH
.svc_data :
{
PROVIDE(__start_svc_data = .);
KEEP(*(.svc_data))
PROVIDE(__stop_svc_data = .);
} > FLASH
.log_const_data :
{
PROVIDE(__start_log_const_data = .);
KEEP(*(SORT(.log_const_data*)))
PROVIDE(__stop_log_const_data = .);
} > FLASH
.nrf_balloc :
{
PROVIDE(__start_nrf_balloc = .);
KEEP(*(.nrf_balloc))
PROVIDE(__stop_nrf_balloc = .);
} > FLASH
.sdh_ble_observers :
{
PROVIDE(__start_sdh_ble_observers = .);
KEEP(*(SORT(.sdh_ble_observers*)))
PROVIDE(__stop_sdh_ble_observers = .);
} > FLASH
.log_backends :
{
PROVIDE(__start_log_backends = .);
KEEP(*(SORT(.log_backends*)))
PROVIDE(__stop_log_backends = .);
} > FLASH
.sdh_req_observers :
{
PROVIDE(__start_sdh_req_observers = .);
KEEP(*(SORT(.sdh_req_observers*)))
PROVIDE(__stop_sdh_req_observers = .);
} > FLASH
.sdh_state_observers :
{
PROVIDE(__start_sdh_state_observers = .);
KEEP(*(SORT(.sdh_state_observers*)))
PROVIDE(__stop_sdh_state_observers = .);
} > FLASH
.sdh_stack_observers :
{
PROVIDE(__start_sdh_stack_observers = .);
KEEP(*(SORT(.sdh_stack_observers*)))
PROVIDE(__stop_sdh_stack_observers = .);
} > FLASH
.sdh_soc_observers :
{
PROVIDE(__start_sdh_soc_observers = .);
KEEP(*(SORT(.sdh_soc_observers*)))
PROVIDE(__stop_sdh_soc_observers = .);
} > FLASH
} INSERT AFTER .text
INCLUDE "nrf_common.ld"

@ -0,0 +1,465 @@
/**
* Copyright (c) 2016 - 2021, Nordic Semiconductor ASA
*
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
*
* 1. Redistributions of source code must retain the above copyright notice,
* this list of conditions and the following disclaimer.
*
* 2. Redistributions in binary form, except as embedded into a Nordic
* Semiconductor ASA integrated circuit in a product or a software update for
* such product, must reproduce the above copyright notice, this list of
* conditions and the following disclaimer in the documentation and/or other
* materials provided with the distribution.
*
* 3. Neither the name of Nordic Semiconductor ASA nor the names of its
* contributors may be used to endorse or promote products derived from this
* software without specific prior written permission.
*
* 4. This software, with or without modification, must only be used with a
* Nordic Semiconductor ASA integrated circuit.
*
* 5. Any software provided in binary form under this license must not be
* reverse engineered, decompiled, modified and/or disassembled.
*
* THIS SOFTWARE IS PROVIDED BY NORDIC SEMICONDUCTOR ASA "AS IS" AND ANY EXPRESS
* OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
* OF MERCHANTABILITY, NONINFRINGEMENT, AND FITNESS FOR A PARTICULAR PURPOSE ARE
* DISCLAIMED. IN NO EVENT SHALL NORDIC SEMICONDUCTOR ASA OR CONTRIBUTORS BE
* LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
* POSSIBILITY OF SUCH DAMAGE.
*
*/
#include "nrf_bootloader.h"
#include "app_scheduler.h"
#include "compiler_abstraction.h"
#include "nordic_common.h"
#include "nrf.h"
#include "nrf_bootloader_app_start.h"
#include "nrf_bootloader_dfu_timers.h"
#include "nrf_bootloader_fw_activation.h"
#include "nrf_bootloader_info.h"
#include "nrf_bootloader_wdt.h"
#include "nrf_delay.h"
#include "nrf_dfu.h"
#include "nrf_dfu_settings.h"
#include "nrf_dfu_utils.h"
#include "nrf_dfu_validation.h"
#include "nrf_error.h"
#include "nrf_gpio.h"
#include "nrf_log.h"
#include "nrf_log_ctrl.h"
#include "nrf_power.h"
#include "sdk_config.h"
static nrf_dfu_observer_t
m_user_observer; //<! Observer callback set by the user.
static volatile bool m_flash_write_done;
#define SCHED_QUEUE_SIZE \
32 /**< Maximum number of events in the scheduler queue. */
#define SCHED_EVENT_DATA_SIZE \
NRF_DFU_SCHED_EVENT_DATA_SIZE /**< Maximum app_scheduler event size. */
#if !(defined(NRF_BL_DFU_ENTER_METHOD_BUTTON) && \
defined(NRF_BL_DFU_ENTER_METHOD_PINRESET) && \
defined(NRF_BL_DFU_ENTER_METHOD_GPREGRET) && \
defined(NRF_BL_DFU_ENTER_METHOD_BUTTONLESS) && \
defined(NRF_BL_RESET_DELAY_MS) && defined(NRF_BL_DEBUG_PORT_DISABLE))
#error Configuration file is missing flags. Update sdk_config.h.
#endif
STATIC_ASSERT((NRF_BL_DFU_INACTIVITY_TIMEOUT_MS >= 100) ||
(NRF_BL_DFU_INACTIVITY_TIMEOUT_MS == 0),
"NRF_BL_DFU_INACTIVITY_TIMEOUT_MS must be 100 ms or more, or 0 "
"to indicate that it is disabled.");
#if defined(NRF_LOG_BACKEND_FLASH_START_PAGE)
STATIC_ASSERT(NRF_LOG_BACKEND_FLASH_START_PAGE != 0,
"If nrf_log flash backend is used it cannot use space after code "
"because it would collide with settings page.");
#endif
/**@brief Weak implemenation of nrf_dfu_init
*
* @note This function will be overridden if nrf_dfu.c is
* compiled and linked with the project
*/
#if (__LINT__ != 1)
__WEAK uint32_t nrf_dfu_init(nrf_dfu_observer_t observer) {
NRF_LOG_DEBUG("in weak nrf_dfu_init");
return NRF_SUCCESS;
}
#endif
/**@brief Weak implementation of nrf_dfu_init
*
* @note This function must be overridden in application if
* user-specific initialization is needed.
*/
__WEAK uint32_t nrf_dfu_init_user(void) {
NRF_LOG_DEBUG("in weak nrf_dfu_init_user");
return NRF_SUCCESS;
}
static void flash_write_callback(void* p_context) {
UNUSED_PARAMETER(p_context);
m_flash_write_done = true;
}
static void do_reset(void* p_context) {
UNUSED_PARAMETER(p_context);
NRF_LOG_FINAL_FLUSH();
nrf_delay_ms(NRF_BL_RESET_DELAY_MS);
NVIC_SystemReset();
}
static void bootloader_reset(bool do_backup) {
NRF_LOG_DEBUG("Resetting bootloader.");
if (do_backup) {
m_flash_write_done = false;
nrf_dfu_settings_backup(do_reset);
} else {
do_reset(NULL);
}
}
static void inactivity_timeout(void) {
NRF_LOG_INFO("Inactivity timeout.");
bootloader_reset(true);
}
/**@brief Function for handling DFU events.
*/
static void dfu_observer(nrf_dfu_evt_type_t evt_type) {
switch (evt_type) {
case NRF_DFU_EVT_DFU_STARTED:
case NRF_DFU_EVT_OBJECT_RECEIVED:
nrf_bootloader_dfu_inactivity_timer_restart(
NRF_BOOTLOADER_MS_TO_TICKS(NRF_BL_DFU_INACTIVITY_TIMEOUT_MS),
inactivity_timeout);
break;
case NRF_DFU_EVT_DFU_COMPLETED:
case NRF_DFU_EVT_DFU_ABORTED:
bootloader_reset(true);
break;
case NRF_DFU_EVT_TRANSPORT_DEACTIVATED:
// Reset the internal state of the DFU settings to the last stored state.
nrf_dfu_settings_reinit();
break;
default:
break;
}
if (m_user_observer) {
m_user_observer(evt_type);
}
}
/**@brief Function for initializing the event scheduler.
*/
static void scheduler_init(void) {
APP_SCHED_INIT(SCHED_EVENT_DATA_SIZE, SCHED_QUEUE_SIZE);
}
/**@brief Suspend the CPU until an interrupt occurs.
*/
static void wait_for_event(void) {
#if defined(BLE_STACK_SUPPORT_REQD) || defined(ANT_STACK_SUPPORT_REQD)
(void)sd_app_evt_wait();
#else
// Wait for an event.
__WFE();
// Clear the internal event register.
__SEV();
__WFE();
#endif
}
/**@brief Continually sleep and process tasks whenever woken.
*/
static void loop_forever(void) {
while (true) {
// feed the watchdog if enabled.
nrf_bootloader_wdt_feed();
app_sched_execute();
if (!NRF_LOG_PROCESS()) {
wait_for_event();
}
}
}
#if NRF_BL_DFU_ENTER_METHOD_BUTTON
//#ifndef BUTTON_PULL
// #error NRF_BL_DFU_ENTER_METHOD_BUTTON is enabled but not buttons seem to
// be available on the board.
//#endif
/**@brief Function for initializing button used to enter DFU mode.
*/
static void dfu_enter_button_init(void) {
nrf_gpio_cfg_sense_input(NRF_BL_DFU_ENTER_METHOD_BUTTON_PIN,
NRF_GPIO_PIN_PULLUP, NRF_GPIO_PIN_SENSE_LOW);
}
#endif
static bool crc_on_valid_app_required(void) {
bool ret = true;
if (NRF_BL_APP_CRC_CHECK_SKIPPED_ON_SYSTEMOFF_RESET &&
(nrf_power_resetreas_get() & NRF_POWER_RESETREAS_OFF_MASK)) {
nrf_power_resetreas_clear(NRF_POWER_RESETREAS_OFF_MASK);
ret = false;
} else if (NRF_BL_APP_CRC_CHECK_SKIPPED_ON_GPREGRET2 &&
((nrf_power_gpregret2_get() & BOOTLOADER_DFU_SKIP_CRC_MASK) ==
BOOTLOADER_DFU_SKIP_CRC)) {
nrf_power_gpregret2_set(nrf_power_gpregret2_get() &
~BOOTLOADER_DFU_SKIP_CRC);
ret = false;
} else {
}
return ret;
}
static bool boot_validate(boot_validation_t const* p_validation,
uint32_t data_addr, uint32_t data_len) {
return nrf_dfu_validation_boot_validate(p_validation, data_addr, data_len);
}
/** @brief Function for checking if the main application is valid.
*
* @details This function checks if there is a valid application
* located at Bank 0.
*
* @param[in] do_crc Perform CRC check on application. Only CRC checks
can be skipped. For other boot validation types,
this parameter is ignored.
*
* @retval true If a valid application has been detected.
* @retval false If there is no valid application.
*/
static bool app_is_valid(bool do_crc) {
if (s_dfu_settings.bank_0.bank_code != NRF_DFU_BANK_VALID_APP) {
NRF_LOG_INFO("Boot validation failed. No valid app to boot.");
return false;
} else if (SD_PRESENT &&
!boot_validate(&s_dfu_settings.boot_validation_softdevice,
MBR_SIZE, s_dfu_settings.sd_size)) {
NRF_LOG_WARNING(
"Boot validation failed. SoftDevice is present but invalid.");
return false;
} else if (!boot_validate(&s_dfu_settings.boot_validation_app,
nrf_dfu_bank0_start_addr(),
s_dfu_settings.bank_0.image_size)) {
NRF_LOG_WARNING("Boot validation failed. App is invalid.");
return false;
}
// The bootloader itself is not checked, since a self-check of this kind gives
// little to no benefit compared to the cost incurred on each bootup.
NRF_LOG_DEBUG("App is valid");
return true;
}
/**@brief Function for clearing all DFU enter flags that
* preserve state during reset.
*
* @details This is used to make sure that each of these flags
* is checked only once after reset.
*/
static void dfu_enter_flags_clear(void) {
if (NRF_BL_DFU_ENTER_METHOD_PINRESET &&
(NRF_POWER->RESETREAS & POWER_RESETREAS_RESETPIN_Msk)) {
// Clear RESETPIN flag.
NRF_POWER->RESETREAS |= POWER_RESETREAS_RESETPIN_Msk;
}
if (NRF_BL_DFU_ENTER_METHOD_GPREGRET &&
((nrf_power_gpregret_get() & BOOTLOADER_DFU_START_MASK) ==
BOOTLOADER_DFU_START)) {
// Clear DFU mark in GPREGRET register.
nrf_power_gpregret_set(nrf_power_gpregret_get() & ~BOOTLOADER_DFU_START);
}
if (NRF_BL_DFU_ENTER_METHOD_BUTTONLESS &&
(s_dfu_settings.enter_buttonless_dfu == 1)) {
// Clear DFU flag in flash settings.
s_dfu_settings.enter_buttonless_dfu = 0;
APP_ERROR_CHECK(nrf_dfu_settings_write(NULL));
}
}
/**@brief Function for checking whether to enter DFU mode or not.
*/
static bool dfu_enter_check(void) {
if (!app_is_valid(crc_on_valid_app_required())) {
NRF_LOG_DEBUG("DFU mode because app is not valid.");
return true;
}
if (NRF_BL_DFU_ENTER_METHOD_BUTTON &&
(nrf_gpio_pin_read(NRF_BL_DFU_ENTER_METHOD_BUTTON_PIN) == 1)) {
NRF_LOG_DEBUG("DFU mode requested via button.");
return true;
}
if (NRF_BL_DFU_ENTER_METHOD_PINRESET &&
(NRF_POWER->RESETREAS & POWER_RESETREAS_RESETPIN_Msk)) {
NRF_LOG_DEBUG("DFU mode requested via pin-reset.");
return true;
}
if (NRF_BL_DFU_ENTER_METHOD_GPREGRET &&
((nrf_power_gpregret_get() & BOOTLOADER_DFU_START_MASK) ==
BOOTLOADER_DFU_START)) {
NRF_LOG_DEBUG("DFU mode requested via GPREGRET.");
return true;
}
if (NRF_BL_DFU_ENTER_METHOD_BUTTONLESS &&
(s_dfu_settings.enter_buttonless_dfu == 1)) {
NRF_LOG_DEBUG("DFU mode requested via bootloader settings.");
return true;
}
return false;
}
#if NRF_BL_DFU_ALLOW_UPDATE_FROM_APP
static void postvalidate(void) {
NRF_LOG_INFO("Postvalidating update after reset.");
nrf_dfu_validation_init();
if (nrf_dfu_validation_init_cmd_present()) {
uint32_t firmware_start_addr;
uint32_t firmware_size;
// Execute a previously received init packed. Subsequent executes will have
// no effect.
if (nrf_dfu_validation_init_cmd_execute(
&firmware_start_addr, &firmware_size) == NRF_DFU_RES_CODE_SUCCESS) {
if (nrf_dfu_validation_prevalidate() == NRF_DFU_RES_CODE_SUCCESS) {
if (nrf_dfu_validation_activation_prepare(firmware_start_addr,
firmware_size) ==
NRF_DFU_RES_CODE_SUCCESS) {
NRF_LOG_INFO("Postvalidation successful.");
}
}
}
}
s_dfu_settings.bank_current = NRF_DFU_CURRENT_BANK_0;
UNUSED_RETURN_VALUE(nrf_dfu_settings_write_and_backup(flash_write_callback));
}
#endif
ret_code_t nrf_bootloader_init(nrf_dfu_observer_t observer) {
NRF_LOG_DEBUG("In nrf_bootloader_init");
ret_code_t ret_val;
nrf_bootloader_fw_activation_result_t activation_result;
uint32_t initial_timeout;
bool dfu_enter = false;
m_user_observer = observer;
if (NRF_BL_DEBUG_PORT_DISABLE) {
nrf_bootloader_debug_port_disable();
}
#if NRF_BL_DFU_ENTER_METHOD_BUTTON
dfu_enter_button_init();
#endif
ret_val = nrf_dfu_settings_init(false);
if (ret_val != NRF_SUCCESS) {
return NRF_ERROR_INTERNAL;
}
#if NRF_BL_DFU_ALLOW_UPDATE_FROM_APP
// Postvalidate if DFU has signaled that update is ready.
if (s_dfu_settings.bank_current == NRF_DFU_CURRENT_BANK_1) {
postvalidate();
}
#endif
// Check if an update needs to be activated and activate it.
activation_result = nrf_bootloader_fw_activate();
switch (activation_result) {
case ACTIVATION_NONE:
initial_timeout =
NRF_BOOTLOADER_MS_TO_TICKS(NRF_BL_DFU_INACTIVITY_TIMEOUT_MS);
dfu_enter = dfu_enter_check();
break;
case ACTIVATION_SUCCESS_EXPECT_ADDITIONAL_UPDATE:
initial_timeout =
NRF_BOOTLOADER_MS_TO_TICKS(NRF_BL_DFU_CONTINUATION_TIMEOUT_MS);
dfu_enter = true;
break;
case ACTIVATION_SUCCESS:
bootloader_reset(true);
NRF_LOG_ERROR("Unreachable");
return NRF_ERROR_INTERNAL; // Should not reach this.
case ACTIVATION_ERROR:
default:
return NRF_ERROR_INTERNAL;
}
if (dfu_enter) {
nrf_bootloader_wdt_init();
scheduler_init();
dfu_enter_flags_clear();
// Call user-defined init function if implemented
ret_val = nrf_dfu_init_user();
if (ret_val != NRF_SUCCESS) {
return NRF_ERROR_INTERNAL;
}
nrf_bootloader_dfu_inactivity_timer_restart(initial_timeout,
inactivity_timeout);
ret_val = nrf_dfu_init(dfu_observer);
if (ret_val != NRF_SUCCESS) {
return NRF_ERROR_INTERNAL;
}
NRF_LOG_DEBUG("Enter main loop");
loop_forever(); // This function will never return.
NRF_LOG_ERROR("Unreachable");
} else {
// Erase additional data like peer data or advertisement name
ret_val = nrf_dfu_settings_additional_erase();
if (ret_val != NRF_SUCCESS) {
return NRF_ERROR_INTERNAL;
}
m_flash_write_done = false;
nrf_dfu_settings_backup(flash_write_callback);
ASSERT(m_flash_write_done);
nrf_bootloader_app_start();
NRF_LOG_ERROR("Unreachable");
}
// Should not be reached.
return NRF_ERROR_INTERNAL;
}

@ -0,0 +1,63 @@
/**
* Copyright (c) 2019 - 2021, Nordic Semiconductor ASA
*
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
*
* 1. Redistributions of source code must retain the above copyright notice,
* this list of conditions and the following disclaimer.
*
* 2. Redistributions in binary form, except as embedded into a Nordic
* Semiconductor ASA integrated circuit in a product or a software update for
* such product, must reproduce the above copyright notice, this list of
* conditions and the following disclaimer in the documentation and/or other
* materials provided with the distribution.
*
* 3. Neither the name of Nordic Semiconductor ASA nor the names of its
* contributors may be used to endorse or promote products derived from this
* software without specific prior written permission.
*
* 4. This software, with or without modification, must only be used with a
* Nordic Semiconductor ASA integrated circuit.
*
* 5. Any software provided in binary form under this license must not be
* reverse engineered, decompiled, modified and/or disassembled.
*
* THIS SOFTWARE IS PROVIDED BY NORDIC SEMICONDUCTOR ASA "AS IS" AND ANY EXPRESS
* OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
* OF MERCHANTABILITY, NONINFRINGEMENT, AND FITNESS FOR A PARTICULAR PURPOSE ARE
* DISCLAIMED. IN NO EVENT SHALL NORDIC SEMICONDUCTOR ASA OR CONTRIBUTORS BE
* LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
* POSSIBILITY OF SUCH DAMAGE.
*
*/
#ifndef NRF_CRYPTO_ALLOCATOR_H__
#define NRF_CRYPTO_ALLOCATOR_H__
#include "nrf_assert.h"
#ifdef __cplusplus
extern "C" {
#endif
/* Crypto library in bootloader case does not use dynamic allocation */
#define NRF_CRYPTO_ALLOC(size) \
NULL; \
ASSERT(0)
#define NRF_CRYPTO_ALLOC_ON_STACK(size) \
NULL; \
ASSERT(0)
#define NRF_CRYPTO_FREE(ptr) (void)ptr;
#ifdef __cplusplus
}
#endif
#endif /* NRF_CRYPTO_ALLOCATOR_H__ */

@ -0,0 +1,276 @@
// clang-format off
/**
* Copyright (c) 2016 - 2021, Nordic Semiconductor ASA
*
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without modification,
* are permitted provided that the following conditions are met:
*
* 1. Redistributions of source code must retain the above copyright notice, this
* list of conditions and the following disclaimer.
*
* 2. Redistributions in binary form, except as embedded into a Nordic
* Semiconductor ASA integrated circuit in a product or a software update for
* such product, must reproduce the above copyright notice, this list of
* conditions and the following disclaimer in the documentation and/or other
* materials provided with the distribution.
*
* 3. Neither the name of Nordic Semiconductor ASA nor the names of its
* contributors may be used to endorse or promote products derived from this
* software without specific prior written permission.
*
* 4. This software, with or without modification, must only be used with a
* Nordic Semiconductor ASA integrated circuit.
*
* 5. Any software provided in binary form under this license must not be reverse
* engineered, decompiled, modified and/or disassembled.
*
* THIS SOFTWARE IS PROVIDED BY NORDIC SEMICONDUCTOR ASA "AS IS" AND ANY EXPRESS
* OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
* OF MERCHANTABILITY, NONINFRINGEMENT, AND FITNESS FOR A PARTICULAR PURPOSE ARE
* DISCLAIMED. IN NO EVENT SHALL NORDIC SEMICONDUCTOR ASA OR CONTRIBUTORS BE
* LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE
* GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
* OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*
*/
#include "nrf_dfu_serial.h"
#include <string.h>
#include "trezor_t3w1_d1_NRF.h"
#include "nrf_gpio.h"
#include "nordic_common.h"
#include "app_util_platform.h"
#include "nrf_dfu_transport.h"
#include "nrf_dfu_req_handler.h"
#include "slip.h"
#include "nrf_balloc.h"
#include "nrf_drv_uart.h"
#define NRF_LOG_MODULE_NAME nrf_dfu_serial_uart
#include "nrf_log.h"
NRF_LOG_MODULE_REGISTER();
/**@file
*
* @defgroup nrf_dfu_serial_uart DFU Serial UART transport
* @ingroup nrf_dfu
* @brief Device Firmware Update (DFU) transport layer using UART.
*/
#define NRF_SERIAL_OPCODE_SIZE (sizeof(uint8_t))
#define NRF_UART_MAX_RESPONSE_SIZE_SLIP (2 * NRF_SERIAL_MAX_RESPONSE_SIZE + 1)
#define RX_BUF_SIZE (64) //to get 64bytes payload
#define OPCODE_OFFSET (sizeof(uint32_t) - NRF_SERIAL_OPCODE_SIZE)
#define DATA_OFFSET (OPCODE_OFFSET + NRF_SERIAL_OPCODE_SIZE)
#define UART_SLIP_MTU (2 * (RX_BUF_SIZE + 1) + 1)
#define BALLOC_BUF_SIZE ((CEIL_DIV((RX_BUF_SIZE+OPCODE_SIZE),sizeof(uint32_t))*sizeof(uint32_t)))
NRF_BALLOC_DEF(m_payload_pool, (UART_SLIP_MTU + 1), NRF_DFU_SERIAL_UART_RX_BUFFERS);
static nrf_drv_uart_t m_uart = NRF_DRV_UART_INSTANCE(0);
static uint8_t m_rx_byte;
static nrf_dfu_serial_t m_serial;
static slip_t m_slip;
static uint8_t m_rsp_buf[NRF_UART_MAX_RESPONSE_SIZE_SLIP];
static bool m_active;
static bool m_waiting_for_buffers = false;
static nrf_dfu_observer_t m_observer;
static uint32_t uart_dfu_transport_init(nrf_dfu_observer_t observer);
static uint32_t uart_dfu_transport_close(nrf_dfu_transport_t const * p_exception);
DFU_TRANSPORT_REGISTER(nrf_dfu_transport_t const uart_dfu_transport) =
{
.init_func = uart_dfu_transport_init,
.close_func = uart_dfu_transport_close,
};
static void payload_free(void * p_buf)
{
uint8_t * p_buf_root = (uint8_t *)p_buf - DATA_OFFSET; //pointer is shifted to point to data
nrf_balloc_free(&m_payload_pool, p_buf_root);
uint8_t utilization = m_payload_pool.p_stack_limit - m_payload_pool.p_cb->p_stack_pointer;
if (m_waiting_for_buffers && utilization < NRF_DFU_SERIAL_UART_RX_BUFFERS - 2) {
NRF_LOG_INFO("Buffer utilization: %d, resuming.", utilization);
nrf_gpio_pin_set(RTS_PIN_NUMBER);
nrf_gpio_cfg_output(RTS_PIN_NUMBER);
m_uart.uarte.p_reg->PSEL.RTS = RTS_PIN_NUMBER;
m_waiting_for_buffers = false;
}
}
static ret_code_t rsp_send(uint8_t const * p_data, uint32_t length)
{
uint32_t slip_len;
(void) slip_encode(m_rsp_buf, (uint8_t *)p_data, length, &slip_len);
return nrf_drv_uart_tx(&m_uart, m_rsp_buf, slip_len);
}
static __INLINE void on_rx_complete(nrf_dfu_serial_t * p_transport, uint8_t * p_data, uint8_t len)
{
ret_code_t ret_code = NRF_ERROR_TIMEOUT;
// Check if there is byte to process. Zero length transfer means that RXTO occured.
if (len)
{
ret_code = slip_decode_add_byte(&m_slip, p_data[0]);
}
(void) nrf_drv_uart_rx(&m_uart, &m_rx_byte, 1);
if (ret_code == NRF_SUCCESS)
{
nrf_dfu_serial_on_packet_received(p_transport,
(uint8_t const *)m_slip.p_buffer,
m_slip.current_index);
uint8_t * p_rx_buf = nrf_balloc_alloc(&m_payload_pool);
uint8_t utilization = m_payload_pool.p_stack_limit - m_payload_pool.p_cb->p_stack_pointer;
if (!m_waiting_for_buffers && utilization >= NRF_DFU_SERIAL_UART_RX_BUFFERS - 2) {
NRF_LOG_INFO("Buffer utilization: %d, waiting.", utilization);
m_uart.uarte.p_reg->PSEL.RTS = NRF_UART_PSEL_DISCONNECTED;
nrf_gpio_cfg_output(RTS_PIN_NUMBER);
nrf_gpio_pin_set(RTS_PIN_NUMBER);
m_waiting_for_buffers = true;
}
if (p_rx_buf == NULL)
{
NRF_LOG_ERROR("Failed to allocate buffer");
return;
}
NRF_LOG_INFO("Allocated buffer %x", p_rx_buf);
// reset the slip decoding
m_slip.p_buffer = &p_rx_buf[OPCODE_OFFSET];
m_slip.current_index = 0;
m_slip.state = SLIP_STATE_DECODING;
}
}
static void uart_event_handler(nrf_drv_uart_event_t * p_event, void * p_context)
{
switch (p_event->type)
{
case NRF_DRV_UART_EVT_RX_DONE:
on_rx_complete((nrf_dfu_serial_t*)p_context,
p_event->data.rxtx.p_data,
p_event->data.rxtx.bytes);
break;
case NRF_DRV_UART_EVT_ERROR:
APP_ERROR_HANDLER(p_event->data.error.error_mask);
break;
default:
// No action.
break;
}
}
static uint32_t uart_dfu_transport_init(nrf_dfu_observer_t observer)
{
uint32_t err_code = NRF_SUCCESS;
if (m_active)
{
return err_code;
}
NRF_LOG_DEBUG("serial_dfu_transport_init()");
m_observer = observer;
err_code = nrf_balloc_init(&m_payload_pool);
if (err_code != NRF_SUCCESS)
{
return err_code;
}
uint8_t * p_rx_buf = nrf_balloc_alloc(&m_payload_pool);
m_slip.p_buffer = &p_rx_buf[OPCODE_OFFSET];
m_slip.current_index = 0;
m_slip.buffer_len = UART_SLIP_MTU;
m_slip.state = SLIP_STATE_DECODING;
m_serial.rsp_func = rsp_send;
m_serial.payload_free_func = payload_free;
m_serial.mtu = UART_SLIP_MTU;
m_serial.p_rsp_buf = &m_rsp_buf[NRF_UART_MAX_RESPONSE_SIZE_SLIP -
NRF_SERIAL_MAX_RESPONSE_SIZE];
m_serial.p_low_level_transport = &uart_dfu_transport;
nrf_drv_uart_config_t uart_config = NRF_DRV_UART_DEFAULT_CONFIG;
uart_config.pseltxd = TX_PIN_NUMBER;
uart_config.pselrxd = RX_PIN_NUMBER;
uart_config.pselcts = CTS_PIN_NUMBER;
uart_config.pselrts = RTS_PIN_NUMBER;
uart_config.hwfc = NRF_UART_HWFC_ENABLED;
uart_config.p_context = &m_serial;
nrf_gpio_cfg(
RTS_PIN_NUMBER,
NRF_GPIO_PIN_DIR_OUTPUT,
NRF_GPIO_PIN_INPUT_DISCONNECT,
NRF_GPIO_PIN_NOPULL,
NRF_GPIO_PIN_S0S1,
NRF_GPIO_PIN_NOSENSE);
nrf_gpio_pin_write(RTS_PIN_NUMBER, 0);
err_code = nrf_drv_uart_init(&m_uart, &uart_config, uart_event_handler);
if (err_code != NRF_SUCCESS)
{
NRF_LOG_ERROR("Failed initializing uart");
return err_code;
}
err_code = nrf_drv_uart_rx(&m_uart, &m_rx_byte, 1);
if (err_code != NRF_SUCCESS)
{
NRF_LOG_ERROR("Failed initializing rx");
}
NRF_LOG_DEBUG("serial_dfu_transport_init() completed");
m_active = true;
if (m_observer)
{
m_observer(NRF_DFU_EVT_TRANSPORT_ACTIVATED);
}
return err_code;
}
static uint32_t uart_dfu_transport_close(nrf_dfu_transport_t const * p_exception)
{
if ((m_active == true) && (p_exception != &uart_dfu_transport))
{
nrf_drv_uart_uninit(&m_uart);
m_active = false;
}
return NRF_SUCCESS;
}

@ -0,0 +1,5 @@
-----BEGIN EC PRIVATE KEY-----
MHcCAQEEIOSMfopjR9WnpAjLnog4xJG5XRVi5MfXk7bGGuxLanCAoAoGCCqGSM49
AwEHoUQDQgAE9KQi8GEjC+sEphRRaW/GfnCfPJEaKY+oyAw/t0FUL37WzYQEfAos
6HnwYBqys9MYxWRJc0woWfaQGi5I+ptzrQ==
-----END EC PRIVATE KEY-----

File diff suppressed because it is too large Load Diff

@ -0,0 +1,104 @@
:020000040007F3
:10E000005021D2AF0200000000000000000000001C
:10E01000000000000000000080820100C0F8B7B4DA
:10E0200001000000000000000000000000000000EF
:10E030000000000034560200000000000000000054
:10E0400000000000000000000000000000000000D0
:10E0500000000000000000000000000000000000C0
:10E0600000000000000000000000000000000000B0
:10E0700000000000000000000000000000000000A0
:10E080000000000000000000000000000000000090
:10E090000000000000000000000000000000000080
:10E0A0000000000000000000000000000000000070
:10E0B0000000000000000000000000000000000060
:10E0C0000000000000000000000000000000000050
:10E0D0000000000000000000000000000000000040
:10E0E0000000000000000000000000000000000030
:10E0F0000000000000000000000000000000000020
:10E10000000000000000000000000000000000000F
:10E1100000000000000000000000000000000000FF
:10E1200000000000000000000000000000000000EF
:10E1300000000000000000000000000000000000DF
:10E1400000000000000000000000000000000000CF
:10E1500000000000000000000000000000000000BF
:10E1600000000000000000000000000000000000AF
:10E17000000000000000000000000000000000009F
:10E18000000000000000000000000000000000008F
:10E19000000000000000000000000000000000007F
:10E1A000000000000000000000000000000000006F
:10E1B000000000000000000000000000000000005F
:10E1C000000000000000000000000000000000004F
:10E1D000000000000000000000000000000000003F
:10E1E000000000000000000000000000000000002F
:10E1F000000000000000000000000000000000001F
:10E20000000000000000000000000000000000000E
:10E2100000000000000000000000000000000000FE
:10E2200000000000000000000000000000000000EE
:10E2300000000000000000000000000000000000DE
:10E2400000000000000000000000000000000000CE
:10E250000000000000000000000000008AEF67D40A
:10E26000039C5C1C98A20BBD8ABFB9C46939106BB2
:10E27000B47E723565915A51FAC818DE94DD6E8C01
:10E280002BD8C489343239712A38D616C1A9482C02
:10E29000CDA78E5E28F37D0E3AF147DF285C80170C
:10E2A00071035B9F4D32703D914A924FB5B9142076
:10E2B000EE2F84400F8681CD396EC8C55C811676FD
:10E2C000EC52E336EE8EF89DB5B57AAF4C54E69736
:10E2D000A3E5472CD695C51C2E4EB86E56EE19F503
:10E2E00051AE00000000000000000000000000002F
:10E2F000000000000000000000000000000000001E
:10E30000000000000000000000000000000000000D
:10E3100000000000000000000000000000000000FD
:04E32000000000FFFA
:10F000005021D2AF0200000000000000000000000C
:10F01000000000000000000080820100C0F8B7B4CA
:10F0200001000000000000000000000000000000DF
:10F030000000000034560200000000000000000044
:10F0400000000000000000000000000000000000C0
:10F0500000000000000000000000000000000000B0
:10F0600000000000000000000000000000000000A0
:10F070000000000000000000000000000000000090
:10F080000000000000000000000000000000000080
:10F090000000000000000000000000000000000070
:10F0A0000000000000000000000000000000000060
:10F0B0000000000000000000000000000000000050
:10F0C0000000000000000000000000000000000040
:10F0D0000000000000000000000000000000000030
:10F0E0000000000000000000000000000000000020
:10F0F0000000000000000000000000000000000010
:10F1000000000000000000000000000000000000FF
:10F1100000000000000000000000000000000000EF
:10F1200000000000000000000000000000000000DF
:10F1300000000000000000000000000000000000CF
:10F1400000000000000000000000000000000000BF
:10F1500000000000000000000000000000000000AF
:10F16000000000000000000000000000000000009F
:10F17000000000000000000000000000000000008F
:10F18000000000000000000000000000000000007F
:10F19000000000000000000000000000000000006F
:10F1A000000000000000000000000000000000005F
:10F1B000000000000000000000000000000000004F
:10F1C000000000000000000000000000000000003F
:10F1D000000000000000000000000000000000002F
:10F1E000000000000000000000000000000000001F
:10F1F000000000000000000000000000000000000F
:10F2000000000000000000000000000000000000FE
:10F2100000000000000000000000000000000000EE
:10F2200000000000000000000000000000000000DE
:10F2300000000000000000000000000000000000CE
:10F2400000000000000000000000000000000000BE
:10F250000000000000000000000000008AEF67D4FA
:10F26000039C5C1C98A20BBD8ABFB9C46939106BA2
:10F27000B47E723565915A51FAC818DE94DD6E8CF1
:10F280002BD8C489343239712A38D616C1A9482CF2
:10F29000CDA78E5E28F37D0E3AF147DF285C8017FC
:10F2A00071035B9F4D32703D914A924FB5B9142066
:10F2B000EE2F84400F8681CD396EC8C55C811676ED
:10F2C000EC52E336EE8EF89DB5B57AAF4C54E69726
:10F2D000A3E5472CD695C51C2E4EB86E56EE19F5F3
:10F2E00051AE00000000000000000000000000001F
:10F2F000000000000000000000000000000000000E
:10F3000000000000000000000000000000000000FD
:10F3100000000000000000000000000000000000ED
:04F32000000000FFEA
:00000001FF

@ -0,0 +1,4 @@
#define VERSION_MAJOR 0
#define VERSION_MINOR 0
#define VERSION_PATCH 0
#define VERSION_BUILD 0

@ -0,0 +1,203 @@
#include "ble_gap.h"
#include "advertising.h"
#include "ble_advdata.h"
#include "ble_advertising.h"
#include "ble_nus.h"
#include "connection.h"
#include "defs.h"
#include "int_comm.h"
#include "nrf_log.h"
#include "pm.h"
#include "power.h"
#define APP_ADV_INTERVAL \
64 /**< The advertising interval (in units of 0.625 ms. This value \
corresponds to 40 ms). */
#define APP_ADV_DURATION \
18000 /**< The advertising duration (180 seconds) in units of 10 \
milliseconds. */
#define NUS_SERVICE_UUID_TYPE \
BLE_UUID_TYPE_VENDOR_BEGIN /**< UUID type for the Nordic UART Service \
(vendor specific). */
static ble_uuid_t m_adv_uuids[] = /**< Universally unique service identifier. */
{{BLE_UUID_NUS_SERVICE, NUS_SERVICE_UUID_TYPE}};
BLE_ADVERTISING_DEF(m_advertising); /**< Advertising module instance. */
/**@brief Function for handling advertising events.
*
* @details This function will be called for advertising events which are passed
* to the application.
*
* @param[in] ble_adv_evt Advertising event.
*/
static void on_adv_evt(ble_adv_evt_t ble_adv_evt) {
uint32_t err_code;
switch (ble_adv_evt) {
case BLE_ADV_EVT_DIRECTED_HIGH_DUTY:
NRF_LOG_INFO("High Duty Directed advertising.");
send_status_event();
break;
case BLE_ADV_EVT_DIRECTED:
NRF_LOG_INFO("Directed advertising.");
send_status_event();
break;
case BLE_ADV_EVT_FAST:
NRF_LOG_INFO("Fast advertising.");
send_status_event();
break;
case BLE_ADV_EVT_SLOW:
NRF_LOG_INFO("Slow advertising.");
send_status_event();
break;
case BLE_ADV_EVT_FAST_WHITELIST:
NRF_LOG_INFO("Fast advertising with whitelist.");
send_status_event();
break;
case BLE_ADV_EVT_SLOW_WHITELIST:
NRF_LOG_INFO("Slow advertising with whitelist.");
send_status_event();
break;
case BLE_ADV_EVT_IDLE:
send_status_event();
// sleep_mode_enter();
break;
case BLE_ADV_EVT_WHITELIST_REQUEST: {
ble_gap_addr_t whitelist_addrs[BLE_GAP_WHITELIST_ADDR_MAX_COUNT];
ble_gap_irk_t whitelist_irks[BLE_GAP_WHITELIST_ADDR_MAX_COUNT];
uint32_t addr_cnt = BLE_GAP_WHITELIST_ADDR_MAX_COUNT;
uint32_t irk_cnt = BLE_GAP_WHITELIST_ADDR_MAX_COUNT;
err_code = pm_whitelist_get(whitelist_addrs, &addr_cnt, whitelist_irks,
&irk_cnt);
if (err_code != NRF_ERROR_NOT_FOUND) {
APP_ERROR_CHECK(err_code);
} else {
break;
}
NRF_LOG_DEBUG(
"pm_whitelist_get returns %d addr in whitelist and %d irk whitelist",
addr_cnt, irk_cnt);
// Set the correct identities list (no excluding peers with no Central
// Address Resolution).
identities_set(PM_PEER_ID_LIST_SKIP_NO_IRK);
// Apply the whitelist.
err_code = ble_advertising_whitelist_reply(
&m_advertising, whitelist_addrs, addr_cnt, whitelist_irks, irk_cnt);
APP_ERROR_CHECK(err_code);
} break; // BLE_ADV_EVT_WHITELIST_REQUEST
case BLE_ADV_EVT_PEER_ADDR_REQUEST: {
pm_peer_data_bonding_t peer_bonding_data;
// Only Give peer address if we have a handle to the bonded peer.
if (get_peer_id() != PM_PEER_ID_INVALID) {
err_code = pm_peer_data_bonding_load(get_peer_id(), &peer_bonding_data);
if (err_code != NRF_ERROR_NOT_FOUND) {
APP_ERROR_CHECK(err_code);
// Manipulate identities to exclude peers with no Central Address
// Resolution.
identities_set(PM_PEER_ID_LIST_SKIP_ALL);
ble_gap_addr_t *p_peer_addr =
&(peer_bonding_data.peer_ble_id.id_addr_info);
err_code =
ble_advertising_peer_addr_reply(&m_advertising, p_peer_addr);
APP_ERROR_CHECK(err_code);
}
}
} break; // BLE_ADV_EVT_PEER_ADDR_REQUEST
default:
break;
}
}
void advertising_init(void) {
uint32_t err_code;
uint8_t adv_flags;
ble_advertising_init_t init;
memset(&init, 0, sizeof(init));
adv_flags = BLE_GAP_ADV_FLAGS_LE_ONLY_GENERAL_DISC_MODE;
init.advdata.name_type = BLE_ADVDATA_FULL_NAME;
init.advdata.include_appearance = false;
init.advdata.flags = adv_flags;
init.advdata.uuids_complete.uuid_cnt = 0;
init.advdata.uuids_complete.p_uuids = NULL;
init.config.ble_adv_whitelist_enabled = true;
init.config.ble_adv_directed_high_duty_enabled = true;
init.config.ble_adv_directed_enabled = false;
init.config.ble_adv_directed_interval = 0;
init.config.ble_adv_directed_timeout = 0;
init.config.ble_adv_fast_enabled = true;
init.config.ble_adv_fast_interval = APP_ADV_INTERVAL;
init.config.ble_adv_fast_timeout = APP_ADV_DURATION;
init.evt_handler = on_adv_evt;
init.srdata.uuids_more_available.uuid_cnt =
sizeof(m_adv_uuids) / sizeof(m_adv_uuids[0]);
init.srdata.uuids_more_available.p_uuids = m_adv_uuids;
err_code = ble_advertising_init(&m_advertising, &init);
APP_ERROR_CHECK(err_code);
ble_advertising_conn_cfg_tag_set(&m_advertising, APP_BLE_CONN_CFG_TAG);
}
void advertising_start(bool whitelist) {
m_advertising.adv_modes_config.ble_adv_on_disconnect_disabled = false;
if (m_advertising.adv_mode_current != BLE_ADV_MODE_DIRECTED_HIGH_DUTY) {
if (m_advertising.adv_mode_current != BLE_ADV_MODE_FAST &&
get_connection_handle() == BLE_CONN_HANDLE_INVALID) {
whitelist_set(PM_PEER_ID_LIST_SKIP_NO_ID_ADDR);
ret_code_t ret = ble_advertising_start(&m_advertising, BLE_ADV_MODE_FAST);
APP_ERROR_CHECK(ret);
}
if (!whitelist) {
ret_code_t ret =
ble_advertising_restart_without_whitelist(&m_advertising);
APP_ERROR_CHECK(ret);
}
}
}
void advertising_stop(void) {
m_advertising.adv_modes_config.ble_adv_on_disconnect_disabled = true;
ret_code_t ret = ble_advertising_start(&m_advertising, BLE_ADV_MODE_IDLE);
APP_ERROR_CHECK(ret);
// ret =sd_ble_gap_disconnect(get_connection_handle(),
// BLE_HCI_REMOTE_USER_TERMINATED_CONNECTION); APP_ERROR_CHECK(ret);
}
void advertising_restart_without_whitelist(void) {
ret_code_t ret = ble_advertising_restart_without_whitelist(&m_advertising);
APP_ERROR_CHECK(ret);
}
bool is_advertising(void) {
return m_advertising.adv_mode_current != BLE_ADV_MODE_IDLE;
}
bool is_advertising_wl(void) { return m_advertising.whitelist_in_use; }

@ -0,0 +1,18 @@
#ifndef __ADVERTISING__
#define __ADVERTISING__
#include <stdbool.h>
void advertising_init(void);
void advertising_start(bool whitelist);
void advertising_stop(void);
void advertising_restart_without_whitelist(void);
bool is_advertising(void);
bool is_advertising_wl(void);
#endif

@ -0,0 +1,356 @@
// clang-format off
/**
* Copyright (c) 2012 - 2021, Nordic Semiconductor ASA
*
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without modification,
* are permitted provided that the following conditions are met:
*
* 1. Redistributions of source code must retain the above copyright notice, this
* list of conditions and the following disclaimer.
*
* 2. Redistributions in binary form, except as embedded into a Nordic
* Semiconductor ASA integrated circuit in a product or a software update for
* such product, must reproduce the above copyright notice, this list of
* conditions and the following disclaimer in the documentation and/or other
* materials provided with the distribution.
*
* 3. Neither the name of Nordic Semiconductor ASA nor the names of its
* contributors may be used to endorse or promote products derived from this
* software without specific prior written permission.
*
* 4. This software, with or without modification, must only be used with a
* Nordic Semiconductor ASA integrated circuit.
*
* 5. Any software provided in binary form under this license must not be reverse
* engineered, decompiled, modified and/or disassembled.
*
* THIS SOFTWARE IS PROVIDED BY NORDIC SEMICONDUCTOR ASA "AS IS" AND ANY EXPRESS
* OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
* OF MERCHANTABILITY, NONINFRINGEMENT, AND FITNESS FOR A PARTICULAR PURPOSE ARE
* DISCLAIMED. IN NO EVENT SHALL NORDIC SEMICONDUCTOR ASA OR CONTRIBUTORS BE
* LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE
* GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
* OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*
*/
#include "sdk_common.h"
#if NRF_MODULE_ENABLED(BLE_NUS)
#include "ble.h"
#include "ble_nus.h"
#include "ble_srv_common.h"
#define NRF_LOG_MODULE_NAME ble_nus
#if BLE_NUS_CONFIG_LOG_ENABLED
#define NRF_LOG_LEVEL BLE_NUS_CONFIG_LOG_LEVEL
#define NRF_LOG_INFO_COLOR BLE_NUS_CONFIG_INFO_COLOR
#define NRF_LOG_DEBUG_COLOR BLE_NUS_CONFIG_DEBUG_COLOR
#else // BLE_NUS_CONFIG_LOG_ENABLED
#define NRF_LOG_LEVEL 0
#endif // BLE_NUS_CONFIG_LOG_ENABLED
#include "nrf_log.h"
NRF_LOG_MODULE_REGISTER();
#define BLE_UUID_NUS_TX_CHARACTERISTIC 0x0003 /**< The UUID of the TX Characteristic. */
#define BLE_UUID_NUS_RX_CHARACTERISTIC 0x0002 /**< The UUID of the RX Characteristic. */
#define BLE_NUS_MAX_RX_CHAR_LEN BLE_NUS_MAX_DATA_LEN /**< Maximum length of the RX Characteristic (in bytes). */
#define BLE_NUS_MAX_TX_CHAR_LEN BLE_NUS_MAX_DATA_LEN /**< Maximum length of the TX Characteristic (in bytes). */
#define NUS_BASE_UUID {{0x9E, 0xCA, 0xDC, 0x24, 0x0E, 0xE5, 0xA9, 0xE0, 0x93, 0xF3, 0xA3, 0xB5, 0x00, 0x00, 0x40, 0x6E}} /**< Used vendor specific UUID. */
/**@brief Function for handling the @ref BLE_GAP_EVT_CONNECTED event from the SoftDevice.
*
* @param[in] p_nus Nordic UART Service structure.
* @param[in] p_ble_evt Pointer to the event received from BLE stack.
*/
static void on_connect(ble_nus_t * p_nus, ble_evt_t const * p_ble_evt)
{
ret_code_t err_code;
ble_nus_evt_t evt;
ble_gatts_value_t gatts_val;
uint8_t cccd_value[2];
ble_nus_client_context_t * p_client = NULL;
err_code = blcm_link_ctx_get(p_nus->p_link_ctx_storage,
p_ble_evt->evt.gap_evt.conn_handle,
(void *) &p_client);
if (err_code != NRF_SUCCESS)
{
NRF_LOG_ERROR("Link context for 0x%02X connection handle could not be fetched.",
p_ble_evt->evt.gap_evt.conn_handle);
}
/* Check the hosts CCCD value to inform of readiness to send data using the RX characteristic */
memset(&gatts_val, 0, sizeof(ble_gatts_value_t));
gatts_val.p_value = cccd_value;
gatts_val.len = sizeof(cccd_value);
gatts_val.offset = 0;
err_code = sd_ble_gatts_value_get(p_ble_evt->evt.gap_evt.conn_handle,
p_nus->tx_handles.cccd_handle,
&gatts_val);
if ((err_code == NRF_SUCCESS) &&
(p_nus->data_handler != NULL) &&
ble_srv_is_notification_enabled(gatts_val.p_value))
{
if (p_client != NULL)
{
p_client->is_notification_enabled = true;
}
memset(&evt, 0, sizeof(ble_nus_evt_t));
evt.type = BLE_NUS_EVT_COMM_STARTED;
evt.p_nus = p_nus;
evt.conn_handle = p_ble_evt->evt.gap_evt.conn_handle;
evt.p_link_ctx = p_client;
p_nus->data_handler(&evt);
}
}
/**@brief Function for handling the @ref BLE_GATTS_EVT_WRITE event from the SoftDevice.
*
* @param[in] p_nus Nordic UART Service structure.
* @param[in] p_ble_evt Pointer to the event received from BLE stack.
*/
static void on_write(ble_nus_t * p_nus, ble_evt_t const * p_ble_evt)
{
ret_code_t err_code;
ble_nus_evt_t evt;
ble_nus_client_context_t * p_client;
ble_gatts_evt_write_t const * p_evt_write = &p_ble_evt->evt.gatts_evt.params.write;
err_code = blcm_link_ctx_get(p_nus->p_link_ctx_storage,
p_ble_evt->evt.gatts_evt.conn_handle,
(void *) &p_client);
if (err_code != NRF_SUCCESS)
{
NRF_LOG_ERROR("Link context for 0x%02X connection handle could not be fetched.",
p_ble_evt->evt.gatts_evt.conn_handle);
}
memset(&evt, 0, sizeof(ble_nus_evt_t));
evt.p_nus = p_nus;
evt.conn_handle = p_ble_evt->evt.gatts_evt.conn_handle;
evt.p_link_ctx = p_client;
if ((p_evt_write->handle == p_nus->tx_handles.cccd_handle) &&
(p_evt_write->len == 2))
{
if (p_client != NULL)
{
if (ble_srv_is_notification_enabled(p_evt_write->data))
{
p_client->is_notification_enabled = true;
evt.type = BLE_NUS_EVT_COMM_STARTED;
}
else
{
p_client->is_notification_enabled = false;
evt.type = BLE_NUS_EVT_COMM_STOPPED;
}
if (p_nus->data_handler != NULL)
{
p_nus->data_handler(&evt);
}
}
}
else if ((p_evt_write->handle == p_nus->rx_handles.value_handle) &&
(p_nus->data_handler != NULL))
{
evt.type = BLE_NUS_EVT_RX_DATA;
evt.params.rx_data.p_data = p_evt_write->data;
evt.params.rx_data.length = p_evt_write->len;
p_nus->data_handler(&evt);
}
else
{
// Do Nothing. This event is not relevant for this service.
}
}
/**@brief Function for handling the @ref BLE_GATTS_EVT_HVN_TX_COMPLETE event from the SoftDevice.
*
* @param[in] p_nus Nordic UART Service structure.
* @param[in] p_ble_evt Pointer to the event received from BLE stack.
*/
static void on_hvx_tx_complete(ble_nus_t * p_nus, ble_evt_t const * p_ble_evt)
{
ret_code_t err_code;
ble_nus_evt_t evt;
ble_nus_client_context_t * p_client;
err_code = blcm_link_ctx_get(p_nus->p_link_ctx_storage,
p_ble_evt->evt.gatts_evt.conn_handle,
(void *) &p_client);
if (err_code != NRF_SUCCESS)
{
NRF_LOG_ERROR("Link context for 0x%02X connection handle could not be fetched.",
p_ble_evt->evt.gatts_evt.conn_handle);
return;
}
if ((p_client->is_notification_enabled) && (p_nus->data_handler != NULL))
{
memset(&evt, 0, sizeof(ble_nus_evt_t));
evt.type = BLE_NUS_EVT_TX_RDY;
evt.p_nus = p_nus;
evt.conn_handle = p_ble_evt->evt.gatts_evt.conn_handle;
evt.p_link_ctx = p_client;
p_nus->data_handler(&evt);
}
}
void ble_nus_on_ble_evt(ble_evt_t const * p_ble_evt, void * p_context)
{
if ((p_context == NULL) || (p_ble_evt == NULL))
{
return;
}
ble_nus_t * p_nus = (ble_nus_t *)p_context;
switch (p_ble_evt->header.evt_id)
{
case BLE_GAP_EVT_CONNECTED:
on_connect(p_nus, p_ble_evt);
break;
case BLE_GATTS_EVT_WRITE:
on_write(p_nus, p_ble_evt);
break;
case BLE_GATTS_EVT_HVN_TX_COMPLETE:
on_hvx_tx_complete(p_nus, p_ble_evt);
break;
default:
// No implementation needed.
break;
}
}
uint32_t ble_nus_init(ble_nus_t * p_nus, ble_nus_init_t const * p_nus_init)
{
ret_code_t err_code;
ble_uuid_t ble_uuid;
ble_uuid128_t nus_base_uuid = NUS_BASE_UUID;
ble_add_char_params_t add_char_params;
VERIFY_PARAM_NOT_NULL(p_nus);
VERIFY_PARAM_NOT_NULL(p_nus_init);
// Initialize the service structure.
p_nus->data_handler = p_nus_init->data_handler;
/**@snippet [Adding proprietary Service to the SoftDevice] */
// Add a custom base UUID.
err_code = sd_ble_uuid_vs_add(&nus_base_uuid, &p_nus->uuid_type);
VERIFY_SUCCESS(err_code);
ble_uuid.type = p_nus->uuid_type;
ble_uuid.uuid = BLE_UUID_NUS_SERVICE;
// Add the service.
err_code = sd_ble_gatts_service_add(BLE_GATTS_SRVC_TYPE_PRIMARY,
&ble_uuid,
&p_nus->service_handle);
/**@snippet [Adding proprietary Service to the SoftDevice] */
VERIFY_SUCCESS(err_code);
// Add the RX Characteristic.
memset(&add_char_params, 0, sizeof(add_char_params));
add_char_params.uuid = BLE_UUID_NUS_RX_CHARACTERISTIC;
add_char_params.uuid_type = p_nus->uuid_type;
add_char_params.max_len = BLE_NUS_MAX_RX_CHAR_LEN;
add_char_params.init_len = sizeof(uint8_t);
add_char_params.is_var_len = true;
add_char_params.char_props.write = 1;
add_char_params.char_props.write_wo_resp = 1;
add_char_params.read_access = SEC_MITM;
add_char_params.write_access = SEC_MITM;
err_code = characteristic_add(p_nus->service_handle, &add_char_params, &p_nus->rx_handles);
if (err_code != NRF_SUCCESS)
{
return err_code;
}
// Add the TX Characteristic.
/**@snippet [Adding proprietary characteristic to the SoftDevice] */
memset(&add_char_params, 0, sizeof(add_char_params));
add_char_params.uuid = BLE_UUID_NUS_TX_CHARACTERISTIC;
add_char_params.uuid_type = p_nus->uuid_type;
add_char_params.max_len = BLE_NUS_MAX_TX_CHAR_LEN;
add_char_params.init_len = sizeof(uint8_t);
add_char_params.is_var_len = true;
add_char_params.char_props.notify = 1;
add_char_params.read_access = SEC_MITM;
add_char_params.write_access = SEC_MITM;
add_char_params.cccd_write_access = SEC_MITM;
return characteristic_add(p_nus->service_handle, &add_char_params, &p_nus->tx_handles);
/**@snippet [Adding proprietary characteristic to the SoftDevice] */
}
uint32_t ble_nus_data_send(ble_nus_t * p_nus,
uint8_t * p_data,
uint16_t * p_length,
uint16_t conn_handle)
{
ret_code_t err_code;
ble_gatts_hvx_params_t hvx_params;
ble_nus_client_context_t * p_client;
VERIFY_PARAM_NOT_NULL(p_nus);
err_code = blcm_link_ctx_get(p_nus->p_link_ctx_storage, conn_handle, (void *) &p_client);
VERIFY_SUCCESS(err_code);
if ((conn_handle == BLE_CONN_HANDLE_INVALID) || (p_client == NULL))
{
return NRF_ERROR_NOT_FOUND;
}
if (!p_client->is_notification_enabled)
{
return NRF_ERROR_INVALID_STATE;
}
if (*p_length > BLE_NUS_MAX_DATA_LEN)
{
return NRF_ERROR_INVALID_PARAM;
}
memset(&hvx_params, 0, sizeof(hvx_params));
hvx_params.handle = p_nus->tx_handles.value_handle;
hvx_params.p_data = p_data;
hvx_params.p_len = p_length;
hvx_params.type = BLE_GATT_HVX_NOTIFICATION;
return sd_ble_gatts_hvx(conn_handle, &hvx_params);
}
#endif // NRF_MODULE_ENABLED(BLE_NUS)

@ -0,0 +1,17 @@
#include "ble_gap.h"
#include "connection.h"
static uint16_t m_conn_handle =
BLE_CONN_HANDLE_INVALID; /**< Handle of the current connection. */
void set_connection_handle(uint16_t val) { m_conn_handle = val; }
uint16_t get_connection_handle(void) { return m_conn_handle; }
void disconnect(void) {
if (m_conn_handle != BLE_CONN_HANDLE_INVALID) {
sd_ble_gap_disconnect(m_conn_handle,
BLE_HCI_REMOTE_USER_TERMINATED_CONNECTION);
}
}

@ -0,0 +1,11 @@
#ifndef BLE_CONNECTION_H__
#define BLE_CONNECTION_H__
#include <stdint.h>
void set_connection_handle(uint16_t val);
uint16_t get_connection_handle(void);
void disconnect(void);
#endif

@ -0,0 +1,3 @@
#define APP_BLE_CONN_CFG_TAG \
1 /**< A tag identifying the SoftDevice BLE configuration. */

@ -0,0 +1,23 @@
#include "dis.h"
#include <string.h>
#include "app_error.h"
#include "ble_dis.h"
#include "sdk_errors.h"
#define MANUFACTURER_NAME \
"SatoshiLabs" /**< Manufacturer. Will be passed to Device Information \
Service. */
void dis_init(void) {
ret_code_t err_code;
ble_dis_init_t dis_init_obj;
memset(&dis_init_obj, 0, sizeof(dis_init_obj));
ble_srv_ascii_to_utf8(&dis_init_obj.manufact_name_str, MANUFACTURER_NAME);
dis_init_obj.dis_char_rd_sec = SEC_JUST_WORKS;
err_code = ble_dis_init(&dis_init_obj);
APP_ERROR_CHECK(err_code);
}

@ -0,0 +1,6 @@
#ifndef __DIS__
#define __DIS__
void dis_init(void);
#endif

@ -0,0 +1,596 @@
#include "int_comm.h"
#include "advertising.h"
#include "app_error.h"
#include "app_timer.h"
#include "app_uart.h"
#include "ble/int_comm_defs.h"
#include "ble_advertising.h"
#include "ble_nus.h"
#include "connection.h"
#include "messages.pb.h"
#include "nrf_dfu_types.h"
#include "nrf_drv_spi.h"
#include "nrf_gpio.h"
#include "nrf_log.h"
#include "pm.h"
#include "protob_helpers.h"
#include "stdint.h"
#include "trezor_t3w1_d1_NRF.h"
#define SPI_INSTANCE 0 /**< SPI instance index. */
static uint8_t m_uart_rx_data[BLE_NUS_MAX_DATA_LEN];
static uint8_t m_spi_tx_data[BLE_PACKET_SIZE];
static volatile bool m_uart_rx_data_ready_internal = false;
static volatile bool m_internal_msg_ack = false;
BLE_NUS_DEF(m_nus,
NRF_SDH_BLE_TOTAL_LINK_COUNT); /**< BLE NUS service instance. */
static const nrf_drv_spi_t spi =
NRF_DRV_SPI_INSTANCE(SPI_INSTANCE); /**< SPI instance. */
static volatile bool spi_xfer_done = true; /**< Flag used to indicate that SPI
instance completed the transfer. */
#define CODE_PAGE_SIZE (MBR_PAGE_SIZE_IN_WORDS * sizeof(uint32_t))
#define BOOTLOADER_SETTINGS_PAGE_SIZE (CODE_PAGE_SIZE)
uint8_t m_dfu_settings_buffer[BOOTLOADER_SETTINGS_PAGE_SIZE]
__attribute__((section(".bootloader_settings_page"))) __attribute__((used));
APP_TIMER_DEF(m_backoff_timer); /**< Back off timer */
/**
* @brief SPI user event handler.
* @param event
*/
void spi_event_handler(nrf_drv_spi_evt_t const *p_event, void *p_context) {
spi_xfer_done = true;
NRF_LOG_INFO("Transfer completed.");
}
static void backoff_timer_evt_handler(void *p_context) {
*(uint32_t *)p_context = 1;
}
void int_comm_init(void) {
app_timer_create(&m_backoff_timer, APP_TIMER_MODE_SINGLE_SHOT,
backoff_timer_evt_handler);
nrf_drv_spi_config_t spi_config = NRF_DRV_SPI_DEFAULT_CONFIG;
spi_config.ss_pin = SPI_SS_PIN;
spi_config.miso_pin = SPI_MISO_PIN;
spi_config.mosi_pin = SPI_MOSI_PIN;
spi_config.sck_pin = SPI_SCK_PIN;
spi_config.frequency = NRF_DRV_SPI_FREQ_8M;
APP_ERROR_CHECK(nrf_drv_spi_init(&spi, &spi_config, spi_event_handler, NULL));
}
void nus_init() {
uint32_t err_code;
ble_nus_init_t nus_init;
memset(&nus_init, 0, sizeof(nus_init));
nus_init.data_handler = nus_data_handler;
err_code = ble_nus_init(&m_nus, &nus_init);
APP_ERROR_CHECK(err_code);
}
void send_byte(uint8_t byte) {
uint32_t err_code;
do {
err_code = app_uart_put(byte);
if ((err_code != NRF_SUCCESS) && (err_code != NRF_ERROR_BUSY)) {
NRF_LOG_ERROR("Failed receiving NUS message. Error 0x%x. ", err_code);
}
} while (err_code == NRF_ERROR_BUSY);
}
void send_packet(uint8_t message_type, const uint8_t *tx_data, uint16_t len) {
uint16_t total_len = len + OVERHEAD_SIZE;
send_byte(message_type);
send_byte((total_len >> 8) & 0xFF);
send_byte(total_len & 0xFF);
for (uint32_t i = 0; i < len; i++) {
send_byte(tx_data[i]);
}
send_byte(EOM);
}
bool write_resp(pb_ostream_t *stream, const pb_byte_t *buf, size_t count) {
write_state *state = (write_state *)(stream->state);
size_t written = 0;
// while we have data left
while (written < count) {
size_t remaining = count - written;
// if all remaining data fit into our packet
if (state->packet_pos + remaining <= USB_PACKET_SIZE) {
// append data from buf to state->buf
memcpy(state->buf + state->packet_pos, buf + written, remaining);
// advance position
state->packet_pos += remaining;
// and return
return true;
} else {
// append data that fits
memcpy(state->buf + state->packet_pos, buf + written,
USB_PACKET_SIZE - state->packet_pos);
written += USB_PACKET_SIZE - state->packet_pos;
uint32_t err_code;
// send packet
do {
uint16_t length = USB_PACKET_SIZE;
err_code = ble_nus_data_send(&m_nus, state->buf, &length,
get_connection_handle());
if ((err_code != NRF_ERROR_INVALID_STATE) &&
(err_code != NRF_ERROR_RESOURCES) &&
(err_code != NRF_ERROR_NOT_FOUND)) {
APP_ERROR_CHECK(err_code);
}
} while (err_code == NRF_ERROR_RESOURCES);
// prepare new packet
state->packet_index++;
memset(state->buf, 0, USB_PACKET_SIZE);
state->buf[0] = '?';
state->packet_pos = MSG_HEADER2_LEN;
}
}
return true;
};
void write_resp_flush(write_state *state) {
// if packet is not filled up completely
if (state->packet_pos < USB_PACKET_SIZE) {
// pad it with zeroes
memset(state->buf + state->packet_pos, 0,
USB_PACKET_SIZE - state->packet_pos);
}
// send packet
uint32_t err_code;
// send packet
do {
uint16_t length = USB_PACKET_SIZE;
err_code =
ble_nus_data_send(&m_nus, state->buf, &length, get_connection_handle());
if ((err_code != NRF_ERROR_INVALID_STATE) &&
(err_code != NRF_ERROR_RESOURCES) &&
(err_code != NRF_ERROR_NOT_FOUND)) {
APP_ERROR_CHECK(err_code);
}
} while (err_code == NRF_ERROR_RESOURCES);
}
bool write(pb_ostream_t *stream, const pb_byte_t *buf, size_t count) {
write_state *state = (write_state *)(stream->state);
size_t written = 0;
// while we have data left
while (written < count) {
size_t remaining = count - written;
// if all remaining data fit into our packet
if (state->packet_pos + remaining <= USB_PACKET_SIZE) {
// append data from buf to state->buf
memcpy(state->buf + state->packet_pos, buf + written, remaining);
// advance position
state->packet_pos += remaining;
// and return
return true;
} else {
// append data that fits
memcpy(state->buf + state->packet_pos, buf + written,
USB_PACKET_SIZE - state->packet_pos);
written += USB_PACKET_SIZE - state->packet_pos;
// send packet
send_packet(state->iface_num, state->buf, USB_PACKET_SIZE);
// prepare new packet
state->packet_index++;
memset(state->buf, 0, USB_PACKET_SIZE);
state->buf[0] = '?';
state->packet_pos = MSG_HEADER2_LEN;
}
}
return true;
};
void write_flush(write_state *state) {
// if packet is not filled up completely
if (state->packet_pos < USB_PACKET_SIZE) {
// pad it with zeroes
memset(state->buf + state->packet_pos, 0,
USB_PACKET_SIZE - state->packet_pos);
}
// send packet
send_packet(state->iface_num, state->buf, USB_PACKET_SIZE);
}
/* we don't use secbool/sectrue/secfalse here as it is a nanopb api */
static bool read(pb_istream_t *stream, uint8_t *buf, size_t count) {
read_state *state = (read_state *)(stream->state);
size_t read = 0;
// while we have data left
while (read < count) {
size_t remaining = count - read;
// if all remaining data fit into our packet
if (state->packet_pos + remaining <= state->packet_size) {
// append data from buf to state->buf
memcpy(buf + read, state->buf + state->packet_pos, remaining);
// advance position
state->packet_pos += remaining;
// and return
return true;
} else {
// append data that fits
memcpy(buf + read, state->buf + state->packet_pos,
state->packet_size - state->packet_pos);
read += state->packet_size - state->packet_pos;
// read next packet
while (!m_uart_rx_data_ready_internal)
;
m_uart_rx_data_ready_internal = false;
memcpy(state->buf, m_uart_rx_data, USB_PACKET_SIZE);
// prepare next packet
state->packet_index++;
state->packet_pos = MSG_HEADER2_LEN;
}
}
return true;
}
static void read_flush(read_state *state) { (void)state; }
#define MSG_SEND_NRF(msg) (MSG_SEND(msg, write, write_flush))
#define MSG_SEND_NRF_RESPONSE(msg) (MSG_SEND(msg, write_resp, write_resp_flush))
void process_command(uint8_t *data, uint16_t len) {
uint8_t cmd = data[0];
switch (cmd) {
case INTERNAL_CMD_SEND_STATE:
send_status_event();
break;
case INTERNAL_CMD_ADVERTISING_ON:
advertising_start(data[1] != 0);
send_status_event();
break;
case INTERNAL_CMD_ADVERTISING_OFF:
advertising_stop();
send_status_event();
break;
case INTERNAL_CMD_ERASE_BONDS:
delete_bonds();
send_success_event();
break;
case INTERNAL_CMD_DISCONNECT:
disconnect();
send_success_event();
case INTERNAL_CMD_ACK:
m_internal_msg_ack = true;
break;
default:
break;
}
}
secbool process_auth_key(uint8_t *data, uint32_t len, void *msg) {
recv_protob_msg(INTERNAL_MESSAGE, len, data, AuthKey_fields, msg, read,
read_flush, USB_PACKET_SIZE);
return sectrue;
}
secbool process_success(uint8_t *data, uint32_t len, void *msg) {
recv_protob_msg(INTERNAL_MESSAGE, len, data, Success_fields, msg, read,
read_flush, USB_PACKET_SIZE);
return sectrue;
}
void process_unexpected(uint8_t *data, uint32_t len) {}
void prepare_response_wait(void) {
m_internal_msg_ack = false;
m_uart_rx_data_ready_internal = 0;
memset(m_uart_rx_data, 0, sizeof(m_uart_rx_data));
}
secbool await_response(uint16_t expected,
secbool (*process)(uint8_t *data, uint32_t len,
void *msg),
void *msg_recv) {
uint32_t timeout = 0;
app_timer_start(m_backoff_timer, APP_TIMER_TICKS(1000), &timeout);
while (!m_internal_msg_ack) {
if (timeout != 0 || nrf_gpio_pin_read(GPIO_3_PIN) == 0) {
app_timer_stop(m_backoff_timer);
return secfalse;
}
}
app_timer_stop(m_backoff_timer);
while (!m_uart_rx_data_ready_internal) {
if (nrf_gpio_pin_read(GPIO_3_PIN) == 0) {
return secfalse;
}
}
m_uart_rx_data_ready_internal = false;
uint16_t id = 0;
uint32_t msg_size = 0;
msg_parse_header(m_uart_rx_data, &id, &msg_size);
if (id == expected) {
if (process != NULL) {
return process(m_uart_rx_data, msg_size, msg_recv);
}
return sectrue;
} else {
process_unexpected(m_uart_rx_data, msg_size);
}
return secfalse;
}
/**@brief Function for handling app_uart events.
*
* @details This function will receive a single character from the app_uart
* module and append it to a string. The string will be be sent over BLE when
* the last character received was a 'new line' '\n' (hex 0x0A) or if the string
* has reached the maximum data length.
*/
/**@snippet [Handling the data received over UART] */
void uart_event_handle(app_uart_evt_t *p_event) {
static uint8_t index = 0;
static uint8_t message_type = 0;
static uint16_t len = 0;
uint32_t err_code;
uint8_t rx_byte = 0;
switch (p_event->evt_type) {
case APP_UART_DATA_READY:
while (app_uart_get(&rx_byte) == NRF_SUCCESS) {
if (index == 0) {
if (rx_byte == INTERNAL_MESSAGE || rx_byte == INTERNAL_EVENT ||
rx_byte == EXTERNAL_MESSAGE) {
message_type = rx_byte;
index += 1;
continue;
} else {
// unknown message
continue;
}
}
if (index == 1) {
// len HI
len = rx_byte << 8;
index += 1;
continue;
}
if (index == 2) {
// len LO
len |= rx_byte;
index += 1;
if (len > sizeof(m_uart_rx_data) + OVERHEAD_SIZE) {
// message too long
index = 0;
continue;
}
continue;
}
if (index < (len - 1)) {
// command
m_uart_rx_data[index - COMM_HEADER_SIZE] = rx_byte;
index += 1;
continue;
}
if (index >= (len - 1)) {
if (rx_byte == EOM) {
if (message_type == EXTERNAL_MESSAGE) {
NRF_LOG_DEBUG("Ready to send data over BLE NUS");
NRF_LOG_HEXDUMP_DEBUG(m_uart_rx_data, index);
do {
uint16_t length = (uint16_t)len - OVERHEAD_SIZE;
err_code = ble_nus_data_send(&m_nus, m_uart_rx_data, &length,
get_connection_handle());
if ((err_code != NRF_ERROR_INVALID_STATE) &&
(err_code != NRF_ERROR_RESOURCES) &&
(err_code != NRF_ERROR_NOT_FOUND)) {
APP_ERROR_CHECK(err_code);
}
} while (err_code == NRF_ERROR_RESOURCES);
} else if (message_type == INTERNAL_MESSAGE) {
m_uart_rx_data_ready_internal = true;
} else if (message_type == INTERNAL_EVENT) {
process_command(m_uart_rx_data, len - OVERHEAD_SIZE);
}
}
index = 0;
}
}
break;
default:
break;
}
}
/**@snippet [Handling the data received over UART] */
/**@brief Function for handling the data from the Nordic UART Service.
*
* @details This function will process the data received from the Nordic UART
* BLE Service and forward it to Trezor
*
* @param[in] p_evt Nordic UART Service event.
*/
/**@snippet [Handling the data received over BLE] */
void nus_data_handler(ble_nus_evt_t *p_evt) {
if (!nrf_gpio_pin_read(GPIO_3_PIN)) {
// communication with trezor is disabled
uint8_t iface_num = 0;
MSG_SEND_INIT(Failure);
MSG_SEND_ASSIGN_VALUE(code, FailureType_Failure_ProcessError);
msg_send.has_message = true;
memset(msg_send.message, 0, sizeof(msg_send.message));
const char msg[] = "Device Locked or Busy";
strncpy(msg_send.message, msg, sizeof(msg_send.message) - 1);
MSG_SEND_NRF_RESPONSE(Failure);
return;
}
if (p_evt->type == BLE_NUS_EVT_RX_DATA) {
NRF_LOG_DEBUG("Received data from BLE NUS. Forwarding.");
NRF_LOG_HEXDUMP_DEBUG(p_evt->params.rx_data.p_data,
p_evt->params.rx_data.length);
if (p_evt->params.rx_data.length != BLE_PACKET_SIZE) {
return;
}
while (!spi_xfer_done)
;
spi_xfer_done = false;
memcpy(m_spi_tx_data, p_evt->params.rx_data.p_data, BLE_PACKET_SIZE);
nrf_drv_spi_transfer(&spi, m_spi_tx_data, BLE_PACKET_SIZE, NULL, 0);
}
}
/**@snippet [Handling the data received over BLE] */
void send_status_event(void) {
ble_version_t version = {0};
nrf_dfu_settings_t *settins = (nrf_dfu_settings_t *)m_dfu_settings_buffer;
sd_ble_version_get(&version);
event_status_msg_t msg = {0};
msg.msg_id = INTERNAL_EVENT_STATUS;
msg.connected = (get_connection_handle() != BLE_CONN_HANDLE_INVALID) ? 1 : 0;
msg.advertising = is_advertising() ? 1 : 0;
msg.advertising_whitelist = is_advertising_wl() ? 1 : 0;
msg.peer_count = pm_peer_count();
msg.sd_version_number = version.version_number;
msg.sd_company_id = version.company_id;
msg.sd_subversion_number = version.subversion_number;
msg.app_version = settins->app_version;
msg.bld_version = settins->bootloader_version;
send_packet(INTERNAL_EVENT, (uint8_t *)&msg, sizeof(msg));
}
void send_success_event(void) {
uint8_t tx_data[] = {
INTERNAL_EVENT_SUCCESS,
};
send_packet(INTERNAL_EVENT, tx_data, sizeof(tx_data));
}
uint16_t get_message_type(const uint8_t *rx_data) {
return (rx_data[3] << 8) | rx_data[4];
}
static bool read_authkey(pb_istream_t *stream, const pb_field_t *field,
void **arg) {
uint8_t *key_buffer = (uint8_t *)(*arg);
if (stream->bytes_left > BLE_GAP_PASSKEY_LEN) {
return false;
}
memset(key_buffer, 0, BLE_GAP_PASSKEY_LEN);
while (stream->bytes_left) {
// read data
if (!pb_read(stream, (pb_byte_t *)(key_buffer),
(stream->bytes_left > BLE_GAP_PASSKEY_LEN)
? BLE_GAP_PASSKEY_LEN
: stream->bytes_left)) {
return false;
}
}
return true;
}
static bool write_authkey(pb_ostream_t *stream, const pb_field_t *field,
void *const *arg) {
uint8_t *key = (uint8_t *)(*arg);
if (!pb_encode_tag_for_field(stream, field)) return false;
return pb_encode_string(stream, (uint8_t *)key, BLE_GAP_PASSKEY_LEN);
}
bool send_comparison_request(uint8_t *p_key, int8_t p_key_len) {
prepare_response_wait();
uint8_t iface_num = INTERNAL_MESSAGE;
MSG_SEND_INIT(ComparisonRequest);
MSG_SEND_CALLBACK(key, write_authkey, p_key);
MSG_SEND_NRF(ComparisonRequest);
MSG_RECV_INIT(Success);
secbool result = await_response(MessageType_MessageType_Success,
process_success, &msg_recv);
if (result != sectrue) {
return false;
}
return true;
}
bool send_auth_key_request(uint8_t *p_key, uint8_t p_key_len) {
prepare_response_wait();
uint8_t iface_num = INTERNAL_MESSAGE;
MSG_SEND_INIT(PairingRequest);
MSG_SEND_NRF(PairingRequest);
uint8_t buffer[BLE_GAP_PASSKEY_LEN];
MSG_RECV_INIT(AuthKey);
MSG_RECV_CALLBACK(key, read_authkey, buffer);
secbool result = await_response(MessageType_MessageType_AuthKey,
process_auth_key, &msg_recv);
if (result != sectrue) {
return false;
}
memcpy(p_key, buffer,
BLE_GAP_PASSKEY_LEN > p_key_len ? p_key_len : BLE_GAP_PASSKEY_LEN);
return true;
}
bool send_repair_request(void) {
prepare_response_wait();
uint8_t iface_num = INTERNAL_MESSAGE;
MSG_SEND_INIT(RepairRequest);
MSG_SEND_NRF(RepairRequest);
MSG_RECV_INIT(Success);
secbool result = await_response(MessageType_MessageType_Success,
process_success, &msg_recv);
return result == sectrue;
}

@ -0,0 +1,27 @@
#ifndef __INT_COMM__
#define __INT_COMM__
#include "app_uart.h"
#include "ble_nus.h"
#include "stdint.h"
void int_comm_init(void);
void nus_init(void);
void nus_data_handler(ble_nus_evt_t *p_evt);
void uart_event_handle(app_uart_evt_t *p_event);
void send_status_event(void);
void send_success_event(void);
bool send_comparison_request(uint8_t *p_key, int8_t p_key_len);
bool send_auth_key_request(uint8_t *p_key, uint8_t p_key_len);
bool send_repair_request(void);
void send_initialized(void);
#endif

@ -0,0 +1,332 @@
/*********************************************************************
* (c) SEGGER Microcontroller GmbH *
* The Embedded Experts *
* www.segger.com *
**********************************************************************
File : /home/mbruna/CLionProjects/trezor-model_r/core/embed/ble_firmware/jlink.jdebug
Created : 6 Feb 2023 15:54
Ozone Version : V3.28c
*/
/*********************************************************************
*
* OnProjectLoad
*
* Function description
* Project load routine. Required.
*
**********************************************************************
*/
void OnProjectLoad (void) {
//
// Dialog-generated settings
//
Project.AddPathSubstitute (".", "$(ProjectDir)");
Project.AddPathSubstitute (".", "$(ProjectDir)");
Project.SetDevice ("Cortex-M4");
Project.SetHostIF ("USB", "");
Project.SetTargetIF ("SWD");
Project.SetTIFSpeed ("20 MHz");
Project.AddSvdFile ("$(InstallDir)/Config/CPU/Cortex-M4F.svd");
//
// User settings
//
File.Open ("../../build/ble_firmware/ble_firmware.elf");
}
/*********************************************************************
*
* OnStartupComplete
*
* Function description
* Called when program execution has reached/passed
* the startup completion point. Optional.
*
**********************************************************************
*/
//void OnStartupComplete (void) {
//}
/*********************************************************************
*
* TargetReset
*
* Function description
* Replaces the default target device reset routine. Optional.
*
* Notes
* This example demonstrates the usage when
* debugging an application in RAM on a Cortex-M target device.
*
**********************************************************************
*/
//void TargetReset (void) {
//
// unsigned int SP;
// unsigned int PC;
// unsigned int VectorTableAddr;
//
// VectorTableAddr = Elf.GetBaseAddr();
// //
// // Set up initial stack pointer
// //
// if (VectorTableAddr != 0xFFFFFFFF) {
// SP = Target.ReadU32(VectorTableAddr);
// Target.SetReg("SP", SP);
// }
// //
// // Set up entry point PC
// //
// PC = Elf.GetEntryPointPC();
//
// if (PC != 0xFFFFFFFF) {
// Target.SetReg("PC", PC);
// } else if (VectorTableAddr != 0xFFFFFFFF) {
// PC = Target.ReadU32(VectorTableAddr + 4);
// Target.SetReg("PC", PC);
// } else {
// Util.Error("Project file error: failed to set entry point PC", 1);
// }
//}
/*********************************************************************
*
* BeforeTargetReset
*
* Function description
* Event handler routine. Optional.
*
**********************************************************************
*/
//void BeforeTargetReset (void) {
//}
/*********************************************************************
*
* AfterTargetReset
*
* Function description
* Event handler routine. Optional.
* The default implementation initializes SP and PC to reset values.
**
**********************************************************************
*/
void AfterTargetReset (void) {
_SetupTarget();
}
/*********************************************************************
*
* DebugStart
*
* Function description
* Replaces the default debug session startup routine. Optional.
*
**********************************************************************
*/
//void DebugStart (void) {
//}
/*********************************************************************
*
* TargetConnect
*
* Function description
* Replaces the default target IF connection routine. Optional.
*
**********************************************************************
*/
//void TargetConnect (void) {
//}
/*********************************************************************
*
* BeforeTargetConnect
*
* Function description
* Event handler routine. Optional.
*
**********************************************************************
*/
void BeforeTargetConnect (void) {
Project.SetJLinkScript("./MMDScript.JLinkScript");
}
/*********************************************************************
*
* AfterTargetConnect
*
* Function description
* Event handler routine. Optional.
*
**********************************************************************
*/
//void AfterTargetConnect (void) {
//}
/*********************************************************************
*
* TargetDownload
*
* Function description
* Replaces the default program download routine. Optional.
*
**********************************************************************
*/
//void TargetDownload (void) {
//}
/*********************************************************************
*
* BeforeTargetDownload
*
* Function description
* Event handler routine. Optional.
*
**********************************************************************
*/
//void BeforeTargetDownload (void) {
//}
/*********************************************************************
*
* AfterTargetDownload
*
* Function description
* Event handler routine. Optional.
* The default implementation initializes SP and PC to reset values.
*
**********************************************************************
*/
void AfterTargetDownload (void) {
_SetupTarget();
}
/*********************************************************************
*
* BeforeTargetDisconnect
*
* Function description
* Event handler routine. Optional.
*
**********************************************************************
*/
//void BeforeTargetDisconnect (void) {
//}
/*********************************************************************
*
* AfterTargetDisconnect
*
* Function description
* Event handler routine. Optional.
*
**********************************************************************
*/
//void AfterTargetDisconnect (void) {
//}
/*********************************************************************
*
* AfterTargetHalt
*
* Function description
* Event handler routine. Optional.
*
**********************************************************************
*/
//void AfterTargetHalt (void) {
//}
/*********************************************************************
*
* BeforeTargetResume
*
* Function description
* Event handler routine. Optional.
*
**********************************************************************
*/
//void BeforeTargetResume (void) {
//}
/*********************************************************************
*
* OnSnapshotLoad
*
* Function description
* Called upon loading a snapshot. Optional.
*
* Additional information
* This function is used to restore the target state in cases
* where values cannot simply be written to the target.
* Typical use: GPIO clock needs to be enabled, before
* GPIO is configured.
*
**********************************************************************
*/
//void OnSnapshotLoad (void) {
//}
/*********************************************************************
*
* OnSnapshotSave
*
* Function description
* Called upon saving a snapshot. Optional.
*
* Additional information
* This function is usually used to save values of the target
* state which can either not be trivially read,
* or need to be restored in a specific way or order.
* Typically use: Memory Mapped Registers,
* such as PLL and GPIO configuration.
*
**********************************************************************
*/
//void OnSnapshotSave (void) {
//}
/*********************************************************************
*
* OnError
*
* Function description
* Called when an error ocurred. Optional.
*
**********************************************************************
*/
//void OnError (void) {
//}
/*********************************************************************
*
* AfterProjectLoad
*
* Function description
* After Project load routine. Optional.
*
**********************************************************************
*/
//void AfterProjectLoad (void) {
//}
/*********************************************************************
*
* _SetupTarget
*
* Function description
* Setup the target.
* Called by AfterTargetReset() and AfterTargetDownload().
*
* Auto-generated function. May be overridden by Ozone.
*
**********************************************************************
*/
void _SetupTarget(void) {
//
// this function is intentionally empty because both inital PC and
// initial SP were chosen not to be set
//
}

@ -0,0 +1,627 @@
/**
* Copyright (c) 2014 - 2021, Nordic Semiconductor ASA
*
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
*
* 1. Redistributions of source code must retain the above copyright notice,
* this list of conditions and the following disclaimer.
*
* 2. Redistributions in binary form, except as embedded into a Nordic
* Semiconductor ASA integrated circuit in a product or a software update for
* such product, must reproduce the above copyright notice, this list of
* conditions and the following disclaimer in the documentation and/or other
* materials provided with the distribution.
*
* 3. Neither the name of Nordic Semiconductor ASA nor the names of its
* contributors may be used to endorse or promote products derived from this
* software without specific prior written permission.
*
* 4. This software, with or without modification, must only be used with a
* Nordic Semiconductor ASA integrated circuit.
*
* 5. Any software provided in binary form under this license must not be
* reverse engineered, decompiled, modified and/or disassembled.
*
* THIS SOFTWARE IS PROVIDED BY NORDIC SEMICONDUCTOR ASA "AS IS" AND ANY EXPRESS
* OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
* OF MERCHANTABILITY, NONINFRINGEMENT, AND FITNESS FOR A PARTICULAR PURPOSE ARE
* DISCLAIMED. IN NO EVENT SHALL NORDIC SEMICONDUCTOR ASA OR CONTRIBUTORS BE
* LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
* POSSIBILITY OF SUCH DAMAGE.
*
*/
/** @file
*
* @defgroup ble_sdk_uart_over_ble_main main.c
* @{
* @ingroup ble_sdk_app_nus_eval
* @brief UART over BLE application main file.
*
* This file contains the source code for a sample application that uses the
* Nordic UART service. This application uses the @ref srvlib_conn_params
* module.
*/
#include <stdint.h>
#include <string.h>
#include "app_scheduler.h"
#include "app_timer.h"
#include "app_uart.h"
#include "app_util_platform.h"
#include "ble_conn_params.h"
#include "ble_hci.h"
#include "nordic_common.h"
#include "nrf.h"
#include "nrf_ble_gatt.h"
#include "nrf_ble_qwr.h"
#include "nrf_drv_uart.h"
#include "nrf_gpio.h"
#include "nrf_pwr_mgmt.h"
#include "nrf_sdh.h"
#include "nrf_sdh_ble.h"
#include "nrf_sdh_soc.h"
#include "trezor_t3w1_d1_NRF.h"
#if defined(SOFTDEVICE_PRESENT) && SOFTDEVICE_PRESENT
#include "nrf_sdm.h"
#endif
#if defined(UART_PRESENT)
#include "nrf_uart.h"
#endif
#if defined(UARTE_PRESENT)
#include "nrf_uarte.h"
#endif
#include "nrf_log.h"
#include "nrf_log_ctrl.h"
#include "nrf_log_default_backends.h"
#include "advertising.h"
#include "ble_nus.h"
#include "connection.h"
#include "defs.h"
#include "dis.h"
#include "int_comm.h"
#include "nrf_ble_lesc.h"
#include "pm.h"
#include "power.h"
#define DEVICE_NAME \
"Trezor" /**< Name of device. Will be included in the advertising data. \
*/
#define APP_BLE_OBSERVER_PRIO \
3 /**< Application's BLE observer priority. You shouldn't need to modify \
this value. */
#define MIN_CONN_INTERVAL \
MSEC_TO_UNITS( \
7.5, UNIT_1_25_MS) /**< Minimum acceptable connection interval (20 ms), \
Connection interval uses 1.25 ms units. */
#define MAX_CONN_INTERVAL \
MSEC_TO_UNITS( \
7.5, UNIT_1_25_MS) /**< Maximum acceptable connection interval (75 ms), \
Connection interval uses 1.25 ms units. */
#define SLAVE_LATENCY 0 /**< Slave latency. */
#define CONN_SUP_TIMEOUT \
MSEC_TO_UNITS(4000, \
UNIT_10_MS) /**< Connection supervisory timeout (4 seconds), \
Supervision Timeout uses 10 ms units. */
#define FIRST_CONN_PARAMS_UPDATE_DELAY \
APP_TIMER_TICKS( \
5000) /**< Time from initiating event (connect or start of notification) \
to first time sd_ble_gap_conn_param_update is called (5 \
seconds). */
#define NEXT_CONN_PARAMS_UPDATE_DELAY \
APP_TIMER_TICKS( \
30000) /**< Time between each call to sd_ble_gap_conn_param_update after \
the first call (30 seconds). */
#define MAX_CONN_PARAMS_UPDATE_COUNT \
3 /**< Number of attempts before giving up the connection parameter \
negotiation. */
#define DEAD_BEEF \
0xDEADBEEF /**< Value used as error code on stack dump, can be used to \
identify stack location on stack unwind. */
#define UART_TX_BUF_SIZE 256 /**< UART TX buffer size. */
#define UART_RX_BUF_SIZE 256 /**< UART RX buffer size. */
NRF_BLE_GATT_DEF(m_gatt); /**< GATT module instance. */
NRF_BLE_QWR_DEF(m_qwr); /**< Context for the Queued Write module.*/
#define SCHED_MAX_EVENT_DATA_SIZE \
APP_TIMER_SCHED_EVENT_DATA_SIZE /**< Maximum size of scheduler events. */
#ifdef SVCALL_AS_NORMAL_FUNCTION
#define SCHED_QUEUE_SIZE \
20 /**< Maximum number of events in the scheduler queue. More is needed in \
case of Serialization. */
#else
#define SCHED_QUEUE_SIZE \
10 /**< Maximum number of events in the scheduler queue. */
#endif
static uint16_t m_ble_nus_max_data_len =
BLE_GATT_ATT_MTU_DEFAULT -
3; /**< Maximum length of data (in bytes) that can be transmitted to the
peer by the Nordic UART service module. */
/**@brief Function for assert macro callback.
*
* @details This function will be called in case of an assert in the SoftDevice.
*
* @warning On assert from the SoftDevice, the system can only recover on reset.
*
* @param[in] line_num Line number of the failing ASSERT call.
* @param[in] p_file_name File name of the failing ASSERT call.
*/
void assert_nrf_callback(uint16_t line_num, const uint8_t *p_file_name) {
app_error_handler(DEAD_BEEF, line_num, p_file_name);
}
/*lint -save -e14 */
/**
* Function is implemented as weak so that it can be overwritten by custom
* application error handler when needed.
*/
void app_error_fault_handler(uint32_t id, uint32_t pc, uint32_t info) {
__disable_irq();
// signalize firmware not running
nrf_gpio_pin_clear(GPIO_2_PIN);
NRF_LOG_FINAL_FLUSH();
#ifndef DEBUG
NRF_LOG_ERROR("Fatal error");
#else
switch (id) {
#if defined(SOFTDEVICE_PRESENT) && SOFTDEVICE_PRESENT
case NRF_FAULT_ID_SD_ASSERT:
NRF_LOG_ERROR("SOFTDEVICE: ASSERTION FAILED");
break;
case NRF_FAULT_ID_APP_MEMACC:
NRF_LOG_ERROR("SOFTDEVICE: INVALID MEMORY ACCESS");
break;
#endif
case NRF_FAULT_ID_SDK_ASSERT: {
assert_info_t *p_info = (assert_info_t *)info;
NRF_LOG_ERROR("ASSERTION FAILED at %s:%u", p_info->p_file_name,
p_info->line_num);
break;
}
case NRF_FAULT_ID_SDK_ERROR: {
error_info_t *p_info = (error_info_t *)info;
NRF_LOG_ERROR("ERROR %u [%s] at %s:%u\r\nPC at: 0x%08x", p_info->err_code,
nrf_strerror_get(p_info->err_code), p_info->p_file_name,
p_info->line_num, pc);
NRF_LOG_ERROR("End of error report");
break;
}
default:
NRF_LOG_ERROR("UNKNOWN FAULT at 0x%08X", pc);
break;
}
#endif
NRF_BREAKPOINT_COND;
// On assert, the system can only recover with a reset.
#ifndef DEBUG
NRF_LOG_WARNING("System reset");
NVIC_SystemReset();
#else
app_error_save_and_stop(id, pc, info);
#endif // DEBUG
}
/**@brief Function for initializing the timer module.
*/
static void timers_init(void) {
ret_code_t err_code = app_timer_init();
APP_ERROR_CHECK(err_code);
}
/**@brief Function for the GAP initialization.
*
* @details This function will set up all the necessary GAP (Generic Access
* Profile) parameters of the device. It also sets the permissions and
* appearance.
*/
static void gap_params_init(void) {
uint32_t err_code;
ble_gap_conn_params_t gap_conn_params;
ble_gap_conn_sec_mode_t sec_mode;
BLE_GAP_CONN_SEC_MODE_SET_OPEN(&sec_mode);
err_code = sd_ble_gap_device_name_set(&sec_mode, (const uint8_t *)DEVICE_NAME,
strlen(DEVICE_NAME));
APP_ERROR_CHECK(err_code);
err_code = sd_ble_gap_appearance_set(BLE_APPEARANCE_UNKNOWN);
APP_ERROR_CHECK(err_code);
memset(&gap_conn_params, 0, sizeof(gap_conn_params));
gap_conn_params.min_conn_interval = MIN_CONN_INTERVAL;
gap_conn_params.max_conn_interval = MAX_CONN_INTERVAL;
gap_conn_params.slave_latency = SLAVE_LATENCY;
gap_conn_params.conn_sup_timeout = CONN_SUP_TIMEOUT;
err_code = sd_ble_gap_ppcp_set(&gap_conn_params);
APP_ERROR_CHECK(err_code);
}
/**@brief Function for handling Queued Write Module errors.
*
* @details A pointer to this function will be passed to each service which may
* need to inform the application about an error.
*
* @param[in] nrf_error Error code containing information about what went
* wrong.
*/
static void nrf_qwr_error_handler(uint32_t nrf_error) {
APP_ERROR_HANDLER(nrf_error);
}
/**@brief Function for initializing services that will be used by the
* application.
*/
static void services_init(void) {
uint32_t err_code;
nrf_ble_qwr_init_t qwr_init = {0};
// Initialize Queued Write Module.
qwr_init.error_handler = nrf_qwr_error_handler;
err_code = nrf_ble_qwr_init(&m_qwr, &qwr_init);
APP_ERROR_CHECK(err_code);
dis_init();
nus_init();
}
/**@brief Function for handling errors from the Connection Parameters module.
*
* @param[in] nrf_error Error code containing information about what went
* wrong.
*/
static void conn_params_error_handler(uint32_t nrf_error) {
APP_ERROR_HANDLER(nrf_error);
}
/**@brief Function for initializing the Connection Parameters module.
*/
static void conn_params_init(void) {
uint32_t err_code;
ble_conn_params_init_t cp_init;
memset(&cp_init, 0, sizeof(cp_init));
cp_init.p_conn_params = NULL;
cp_init.first_conn_params_update_delay = FIRST_CONN_PARAMS_UPDATE_DELAY;
cp_init.next_conn_params_update_delay = NEXT_CONN_PARAMS_UPDATE_DELAY;
cp_init.max_conn_params_update_count = MAX_CONN_PARAMS_UPDATE_COUNT;
cp_init.start_on_notify_cccd_handle = BLE_GATT_HANDLE_INVALID;
cp_init.disconnect_on_fail = false;
cp_init.evt_handler = NULL;
cp_init.error_handler = conn_params_error_handler;
err_code = ble_conn_params_init(&cp_init);
APP_ERROR_CHECK(err_code);
}
/**@brief Function for handling BLE events.
*
* @param[in] p_ble_evt Bluetooth stack event.
* @param[in] p_context Unused.
*/
static void ble_evt_handler(ble_evt_t const *p_ble_evt, void *p_context) {
uint32_t err_code;
char passkey[BLE_GAP_PASSKEY_LEN + 1] = {0};
switch (p_ble_evt->header.evt_id) {
case BLE_GAP_EVT_CONNECTED:
NRF_LOG_INFO("Connected");
// err_code = bsp_indication_set(BSP_INDICATE_CONNECTED);
// APP_ERROR_CHECK(err_code);
uint16_t handle = p_ble_evt->evt.gap_evt.conn_handle;
set_connection_handle(handle);
send_status_event();
err_code = nrf_ble_qwr_conn_handle_assign(&m_qwr, handle);
APP_ERROR_CHECK(err_code);
break;
case BLE_GAP_EVT_DISCONNECTED:
NRF_LOG_INFO("Disconnected");
// bsp_indication_set(BSP_INDICATE_IDLE);
set_connection_handle(BLE_CONN_HANDLE_INVALID);
send_status_event();
break;
case BLE_GAP_EVT_PHY_UPDATE_REQUEST: {
NRF_LOG_DEBUG("PHY update request.");
ble_gap_phys_t const phys = {
.rx_phys = BLE_GAP_PHY_AUTO,
.tx_phys = BLE_GAP_PHY_AUTO,
};
err_code =
sd_ble_gap_phy_update(p_ble_evt->evt.gap_evt.conn_handle, &phys);
APP_ERROR_CHECK(err_code);
} break;
case BLE_GAP_EVT_PASSKEY_DISPLAY:
memcpy(passkey, p_ble_evt->evt.gap_evt.params.passkey_display.passkey,
BLE_GAP_PASSKEY_LEN);
NRF_LOG_INFO("BLE_GAP_EVT_PASSKEY_DISPLAY: passkey=%s match_req=%d",
nrf_log_push(passkey),
p_ble_evt->evt.gap_evt.params.passkey_display.match_request);
if (p_ble_evt->evt.gap_evt.params.passkey_display.match_request) {
bool ok =
send_comparison_request((uint8_t *)passkey, BLE_GAP_PASSKEY_LEN);
if (ok) {
sd_ble_gap_auth_key_reply(p_ble_evt->evt.gap_evt.conn_handle,
BLE_GAP_AUTH_KEY_TYPE_PASSKEY, NULL);
} else {
sd_ble_gap_auth_key_reply(p_ble_evt->evt.gap_evt.conn_handle,
BLE_GAP_AUTH_KEY_TYPE_NONE, NULL);
}
}
break;
case BLE_GAP_EVT_LESC_DHKEY_REQUEST:
NRF_LOG_INFO("BLE_GAP_EVT_LESC_DHKEY_REQUEST");
break;
case BLE_GAP_EVT_AUTH_KEY_REQUEST: {
NRF_LOG_INFO("Key requested.");
bool ok = send_auth_key_request((uint8_t *)passkey, BLE_GAP_PASSKEY_LEN);
sd_ble_gap_auth_key_reply(p_ble_evt->evt.gap_evt.conn_handle,
BLE_GAP_AUTH_KEY_TYPE_PASSKEY,
(uint8_t *)passkey);
if (ok) {
NRF_LOG_INFO("Received data: %c", passkey);
} else {
NRF_LOG_INFO("Auth key request failed.");
}
// APP_ERROR_CHECK(err_code);
break;
}
case BLE_GATTC_EVT_TIMEOUT:
// Disconnect on GATT Client timeout event.
err_code =
sd_ble_gap_disconnect(p_ble_evt->evt.gattc_evt.conn_handle,
BLE_HCI_REMOTE_USER_TERMINATED_CONNECTION);
APP_ERROR_CHECK(err_code);
break;
case BLE_GATTS_EVT_TIMEOUT:
// Disconnect on GATT Server timeout event.
err_code =
sd_ble_gap_disconnect(p_ble_evt->evt.gatts_evt.conn_handle,
BLE_HCI_REMOTE_USER_TERMINATED_CONNECTION);
APP_ERROR_CHECK(err_code);
break;
default:
// No implementation needed.
break;
}
}
/**@brief Function for the SoftDevice initialization.
*
* @details This function initializes the SoftDevice and the BLE event
* interrupt.
*/
static void ble_stack_init(void) {
ret_code_t err_code;
err_code = nrf_sdh_enable_request();
APP_ERROR_CHECK(err_code);
// Configure the BLE stack using the default settings.
// Fetch the start address of the application RAM.
uint32_t ram_start = 0;
err_code = nrf_sdh_ble_default_cfg_set(APP_BLE_CONN_CFG_TAG, &ram_start);
APP_ERROR_CHECK(err_code);
// Enable BLE stack.
err_code = nrf_sdh_ble_enable(&ram_start);
APP_ERROR_CHECK(err_code);
// Register a handler for BLE events.
NRF_SDH_BLE_OBSERVER(m_ble_observer, APP_BLE_OBSERVER_PRIO, ble_evt_handler,
NULL);
}
/**@brief Function for handling events from the GATT library. */
void gatt_evt_handler(nrf_ble_gatt_t *p_gatt, nrf_ble_gatt_evt_t const *p_evt) {
if ((get_connection_handle() == p_evt->conn_handle) &&
(p_evt->evt_id == NRF_BLE_GATT_EVT_ATT_MTU_UPDATED)) {
m_ble_nus_max_data_len =
p_evt->params.att_mtu_effective - OPCODE_LENGTH - HANDLE_LENGTH;
NRF_LOG_INFO("Data len is set to 0x%X(%d)", m_ble_nus_max_data_len,
m_ble_nus_max_data_len);
}
NRF_LOG_DEBUG("ATT MTU exchange completed. central 0x%x peripheral 0x%x",
p_gatt->att_mtu_desired_central,
p_gatt->att_mtu_desired_periph);
}
/**@brief Function for initializing the GATT library. */
void gatt_init(void) {
ret_code_t err_code;
err_code = nrf_ble_gatt_init(&m_gatt, gatt_evt_handler);
APP_ERROR_CHECK(err_code);
err_code =
nrf_ble_gatt_att_mtu_periph_set(&m_gatt, NRF_SDH_BLE_GATT_MAX_MTU_SIZE);
APP_ERROR_CHECK(err_code);
}
///**@brief Function for handling events from the BSP module.
// *
// * @param[in] event Event generated by button press.
// */
// void bsp_event_handler(bsp_event_t event) {
// uint32_t err_code;
// switch (event) {
// case BSP_EVENT_SLEEP:
// sleep_mode_enter();
// break;
//
// case BSP_EVENT_DISCONNECT:
// err_code = sd_ble_gap_disconnect(
// get_connection_handle(), BLE_HCI_REMOTE_USER_TERMINATED_CONNECTION);
// if (err_code != NRF_ERROR_INVALID_STATE) {
// APP_ERROR_CHECK(err_code);
// }
// break;
//
// case BSP_EVENT_WHITELIST_OFF:
// if (get_connection_handle() == BLE_CONN_HANDLE_INVALID) {
// advertising_restart_without_whitelist();
// }
// break;
//
// default:
// break;
// }
//}
/**@brief Function for initializing the UART module.
*/
/**@snippet [UART Initialization] */
static void uart_init(void) {
uint32_t err_code;
app_uart_comm_params_t const comm_params = {
.rx_pin_no = RX_PIN_NUMBER,
.tx_pin_no = TX_PIN_NUMBER,
.rts_pin_no = RTS_PIN_NUMBER,
.cts_pin_no = CTS_PIN_NUMBER,
.flow_control = APP_UART_FLOW_CONTROL_ENABLED,
.use_parity = false,
#if defined(UART_PRESENT)
.baud_rate = NRF_UART_BAUDRATE_1000000
#else
.baud_rate = NRF_UARTE_BAUDRATE_1000000
#endif
};
APP_UART_FIFO_INIT(&comm_params, UART_RX_BUF_SIZE, UART_TX_BUF_SIZE,
uart_event_handle, APP_IRQ_PRIORITY_LOWEST, err_code);
APP_ERROR_CHECK(err_code);
}
/**@snippet [UART Initialization] */
///**@brief Function for initializing buttons and leds.
// *
// * @param[out] p_erase_bonds Will be true if the clear bonding button was
// * pressed to wake the application up.
// */
// static void buttons_leds_init(bool *p_erase_bonds) {
// bsp_event_t startup_event;
//
// uint32_t err_code =
// bsp_init(BSP_INIT_LEDS | BSP_INIT_BUTTONS, bsp_event_handler);
// APP_ERROR_CHECK(err_code);
//
// err_code = bsp_btn_ble_init(NULL, &startup_event);
// APP_ERROR_CHECK(err_code);
//
// *p_erase_bonds = (startup_event == BSP_EVENT_CLEAR_BONDING_DATA);
//}
/**@brief Function for initializing the nrf log module.
*/
static void log_init(void) {
ret_code_t err_code = NRF_LOG_INIT(NULL);
APP_ERROR_CHECK(err_code);
NRF_LOG_DEFAULT_BACKENDS_INIT();
}
/**@brief Function for initializing power management.
*/
static void power_management_init(void) {
ret_code_t err_code;
err_code = nrf_pwr_mgmt_init();
APP_ERROR_CHECK(err_code);
}
/**@brief Function for handling the idle state (main loop).
*
* @details If there is no pending log operation, then sleep until next the next
* event occurs.
*/
static void idle_state_handle(void) {
app_sched_execute();
if (NRF_LOG_PROCESS() == false) {
nrf_pwr_mgmt_run();
}
}
/**@brief Function for the Event Scheduler initialization.
*/
static void scheduler_init(void) {
APP_SCHED_INIT(SCHED_MAX_EVENT_DATA_SIZE, SCHED_QUEUE_SIZE);
}
/**@brief Application main function.
*/
int main(void) {
nrf_gpio_cfg_output(GPIO_1_PIN);
nrf_gpio_cfg_output(GPIO_2_PIN);
nrf_gpio_cfg_input(GPIO_3_PIN, NRF_GPIO_PIN_NOPULL);
nrf_gpio_pin_clear(GPIO_1_PIN);
nrf_gpio_pin_clear(GPIO_2_PIN);
// Initialize.
int_comm_init();
uart_init();
log_init();
timers_init();
// buttons_leds_init(&erase_bonds);
power_management_init();
ble_stack_init();
scheduler_init();
gap_params_init();
gatt_init();
services_init();
advertising_init();
conn_params_init();
peer_manager_init();
// signalize firmware running
nrf_gpio_pin_set(GPIO_2_PIN);
send_status_event();
// Enter main loop.
for (;;) {
nrf_ble_lesc_request_handler();
idle_state_handle();
}
}
/**
* @}
*/

@ -0,0 +1,139 @@
/* Linker script to configure memory regions. */
SEARCH_DIR(.)
GROUP(-lgcc -lc -lnosys)
MEMORY
{
FLASH (rx) : ORIGIN = 0x27000, LENGTH = 0x49000
RAM (rwx) : ORIGIN = 0x20002ae8, LENGTH = 0x1d518
bootloader_settings_page (r) : ORIGIN = 0x0007F000, LENGTH = 0x1000
}
SECTIONS
{
. = ALIGN(4);
.bootloader_settings_page(NOLOAD) :
{
PROVIDE(__start_bootloader_settings_page = .);
KEEP(*(SORT(.bootloader_settings_page*)))
PROVIDE(__stop_bootloader_settings_page = .);
} > bootloader_settings_page
. = ALIGN(4);
}
SECTIONS
{
. = ALIGN(4);
.mem_section_dummy_ram :
{
}
.cli_sorted_cmd_ptrs :
{
PROVIDE(__start_cli_sorted_cmd_ptrs = .);
KEEP(*(.cli_sorted_cmd_ptrs))
PROVIDE(__stop_cli_sorted_cmd_ptrs = .);
} > RAM
.fs_data :
{
PROVIDE(__start_fs_data = .);
KEEP(*(.fs_data))
PROVIDE(__stop_fs_data = .);
} > RAM
.log_dynamic_data :
{
PROVIDE(__start_log_dynamic_data = .);
KEEP(*(SORT(.log_dynamic_data*)))
PROVIDE(__stop_log_dynamic_data = .);
} > RAM
.log_filter_data :
{
PROVIDE(__start_log_filter_data = .);
KEEP(*(SORT(.log_filter_data*)))
PROVIDE(__stop_log_filter_data = .);
} > RAM
} INSERT AFTER .data;
SECTIONS
{
.mem_section_dummy_rom :
{
}
.sdh_soc_observers :
{
PROVIDE(__start_sdh_soc_observers = .);
KEEP(*(SORT(.sdh_soc_observers*)))
PROVIDE(__stop_sdh_soc_observers = .);
} > FLASH
.sdh_ble_observers :
{
PROVIDE(__start_sdh_ble_observers = .);
KEEP(*(SORT(.sdh_ble_observers*)))
PROVIDE(__stop_sdh_ble_observers = .);
} > FLASH
.pwr_mgmt_data :
{
PROVIDE(__start_pwr_mgmt_data = .);
KEEP(*(SORT(.pwr_mgmt_data*)))
PROVIDE(__stop_pwr_mgmt_data = .);
} > FLASH
.sdh_req_observers :
{
PROVIDE(__start_sdh_req_observers = .);
KEEP(*(SORT(.sdh_req_observers*)))
PROVIDE(__stop_sdh_req_observers = .);
} > FLASH
.sdh_state_observers :
{
PROVIDE(__start_sdh_state_observers = .);
KEEP(*(SORT(.sdh_state_observers*)))
PROVIDE(__stop_sdh_state_observers = .);
} > FLASH
.sdh_stack_observers :
{
PROVIDE(__start_sdh_stack_observers = .);
KEEP(*(SORT(.sdh_stack_observers*)))
PROVIDE(__stop_sdh_stack_observers = .);
} > FLASH
.nrf_queue :
{
PROVIDE(__start_nrf_queue = .);
KEEP(*(.nrf_queue))
PROVIDE(__stop_nrf_queue = .);
} > FLASH
.nrf_balloc :
{
PROVIDE(__start_nrf_balloc = .);
KEEP(*(.nrf_balloc))
PROVIDE(__stop_nrf_balloc = .);
} > FLASH
.cli_command :
{
PROVIDE(__start_cli_command = .);
KEEP(*(.cli_command))
PROVIDE(__stop_cli_command = .);
} > FLASH
.crypto_data :
{
PROVIDE(__start_crypto_data = .);
KEEP(*(SORT(.crypto_data*)))
PROVIDE(__stop_crypto_data = .);
} > FLASH
.log_const_data :
{
PROVIDE(__start_log_const_data = .);
KEEP(*(SORT(.log_const_data*)))
PROVIDE(__stop_log_const_data = .);
} > FLASH
.log_backends :
{
PROVIDE(__start_log_backends = .);
KEEP(*(SORT(.log_backends*)))
PROVIDE(__stop_log_backends = .);
} > FLASH
} INSERT AFTER .text
INCLUDE "nrf_common.ld"

@ -0,0 +1,158 @@
#include "nrf_log.h"
#include "peer_manager_handler.h"
#include "int_comm.h"
#include "pm.h"
#define SEC_PARAM_BOND 1 /**< Perform bonding. */
#define SEC_PARAM_MITM 1 /**< Man In The Middle protection required. */
#define SEC_PARAM_LESC 1 /**< LE Secure Connections enabled. */
#define SEC_PARAM_KEYPRESS 0 /**< Keypress notifications not enabled. */
#define SEC_PARAM_IO_CAPABILITIES \
BLE_GAP_IO_CAPS_KEYBOARD_DISPLAY /**< Display and keyboard I/O capabilities. \
*/
#define SEC_PARAM_OOB 0 /**< Out Of Band data not available. */
#define SEC_PARAM_MIN_KEY_SIZE 7 /**< Minimum encryption key size. */
#define SEC_PARAM_MAX_KEY_SIZE 16 /**< Maximum encryption key size. */
static pm_peer_id_t
m_peer_id; /**< Device reference handle to the current bonded central. */
pm_peer_id_t get_peer_id(void) { return m_peer_id; }
/**@brief Function for setting filtered whitelist.
*
* @param[in] skip Filter passed to @ref pm_peer_id_list.
*/
void whitelist_set(pm_peer_id_list_skip_t skip) {
pm_peer_id_t peer_ids[BLE_GAP_WHITELIST_ADDR_MAX_COUNT];
uint32_t peer_id_count = BLE_GAP_WHITELIST_ADDR_MAX_COUNT;
ret_code_t err_code =
pm_peer_id_list(peer_ids, &peer_id_count, PM_PEER_ID_INVALID, skip);
APP_ERROR_CHECK(err_code);
NRF_LOG_INFO("\tm_whitelist_peer_cnt %d, MAX_PEERS_WLIST %d",
peer_id_count + 1, BLE_GAP_WHITELIST_ADDR_MAX_COUNT);
err_code = pm_whitelist_set(peer_ids, peer_id_count);
APP_ERROR_CHECK(err_code);
}
/**@brief Function for handling Peer Manager events.
*
* @param[in] p_evt Peer Manager event.
*/
void pm_evt_handler(pm_evt_t const *p_evt) {
pm_handler_on_pm_evt(p_evt);
pm_handler_disconnect_on_sec_failure(p_evt);
pm_handler_flash_clean(p_evt);
switch (p_evt->evt_id) {
case PM_EVT_CONN_SEC_SUCCEEDED:
m_peer_id = p_evt->peer_id;
break;
case PM_EVT_PEERS_DELETE_SUCCEEDED:
send_status_event();
break;
case PM_EVT_PEER_DATA_UPDATE_SUCCEEDED:
if (p_evt->params.peer_data_update_succeeded.flash_changed &&
(p_evt->params.peer_data_update_succeeded.data_id ==
PM_PEER_DATA_ID_BONDING)) {
NRF_LOG_INFO("New Bond, add the peer to the whitelist if possible");
// Note: You should check on what kind of white list policy your
// application should use.
whitelist_set(PM_PEER_ID_LIST_SKIP_NO_ID_ADDR);
send_status_event();
}
break;
case PM_EVT_CONN_SEC_CONFIG_REQ: {
bool ok = send_repair_request();
if (ok) {
// Allow pairing request from an already bonded peer.
pm_conn_sec_config_t conn_sec_config = {.allow_repairing = true};
pm_conn_sec_config_reply(p_evt->conn_handle, &conn_sec_config);
} else {
// Reject pairing request from an already bonded peer.
pm_conn_sec_config_t conn_sec_config = {.allow_repairing = false};
pm_conn_sec_config_reply(p_evt->conn_handle, &conn_sec_config);
}
} break;
default:
break;
}
}
/**@brief Function for the Peer Manager initialization.
*/
void peer_manager_init(void) {
ble_gap_sec_params_t sec_param;
pm_privacy_params_t privacy_params;
ret_code_t err_code;
err_code = pm_init();
APP_ERROR_CHECK(err_code);
memset(&sec_param, 0, sizeof(ble_gap_sec_params_t));
// Security parameters to be used for all security procedures.
sec_param.bond = SEC_PARAM_BOND;
sec_param.mitm = SEC_PARAM_MITM;
sec_param.lesc = SEC_PARAM_LESC;
sec_param.keypress = SEC_PARAM_KEYPRESS;
sec_param.io_caps = SEC_PARAM_IO_CAPABILITIES;
sec_param.oob = SEC_PARAM_OOB;
sec_param.min_key_size = SEC_PARAM_MIN_KEY_SIZE;
sec_param.max_key_size = SEC_PARAM_MAX_KEY_SIZE;
sec_param.kdist_own.enc = 1;
sec_param.kdist_own.id = 1;
sec_param.kdist_peer.enc = 1;
sec_param.kdist_peer.id = 1;
err_code = pm_sec_params_set(&sec_param);
APP_ERROR_CHECK(err_code);
privacy_params.p_device_irk = NULL;
privacy_params.privacy_mode = BLE_GAP_PRIVACY_MODE_DEVICE_PRIVACY;
privacy_params.private_addr_cycle_s = 0;
privacy_params.private_addr_type =
BLE_GAP_ADDR_TYPE_RANDOM_PRIVATE_RESOLVABLE;
pm_privacy_set(&privacy_params);
err_code = pm_register(pm_evt_handler);
APP_ERROR_CHECK(err_code);
}
/**@brief Function for setting filtered device identities.
*
* @param[in] skip Filter passed to @ref pm_peer_id_list.
*/
void identities_set(pm_peer_id_list_skip_t skip) {
pm_peer_id_t peer_ids[BLE_GAP_DEVICE_IDENTITIES_MAX_COUNT];
uint32_t peer_id_count = BLE_GAP_DEVICE_IDENTITIES_MAX_COUNT;
ret_code_t err_code =
pm_peer_id_list(peer_ids, &peer_id_count, PM_PEER_ID_INVALID, skip);
APP_ERROR_CHECK(err_code);
err_code = pm_device_identities_list_set(peer_ids, peer_id_count);
APP_ERROR_CHECK(err_code);
}
/////**@brief Clear bond information from persistent storage. */
void delete_bonds(void) {
ret_code_t err_code;
NRF_LOG_INFO("Erase bonds!");
// pm_whitelist_set(NULL, 0);
err_code = pm_peers_delete();
APP_ERROR_CHECK(err_code);
}

@ -0,0 +1,18 @@
#ifndef __PEER_MANAGER__
#define __PEER_MANAGER__
#include "peer_manager.h"
pm_peer_id_t get_peer_id(void);
void whitelist_set(pm_peer_id_list_skip_t skip);
void identities_set(pm_peer_id_list_skip_t skip);
/**@brief Function for the Peer Manager initialization.
*/
void peer_manager_init(void);
void delete_bonds(void);
#endif

@ -0,0 +1,21 @@
#include "power.h"
#include "app_error.h"
/**@brief Function for putting the chip into sleep mode.
*
* @note This function will not return.
*/
// void sleep_mode_enter(void) {
// uint32_t err_code = bsp_indication_set(BSP_INDICATE_IDLE);
// APP_ERROR_CHECK(err_code);
//
// // Prepare wakeup buttons.
// err_code = bsp_btn_ble_sleep_mode_prepare();
// APP_ERROR_CHECK(err_code);
//
// // Go to system-off mode (this function will not return; wakeup will cause
// a
// // reset).
// err_code = sd_power_system_off();
// APP_ERROR_CHECK(err_code);
// }

@ -0,0 +1,6 @@
#ifndef __POWER__
#define __POWER__
void sleep_mode_enter(void);
#endif

File diff suppressed because it is too large Load Diff

@ -0,0 +1,11 @@
__build__/
__pycache__
*.pyc
*.pyo
*.pyd
*.pyz
*.egg-info/
*.a
*.o
*.so
.DS_Store

@ -0,0 +1,21 @@
Copyright (c) 2014, Kenneth MacKay
All rights reserved.
Redistribution and use in source and binary forms, with or without modification,
are permitted provided that the following conditions are met:
* Redistributions of source code must retain the above copyright notice, this
list of conditions and the following disclaimer.
* Redistributions in binary form must reproduce the above copyright notice,
this list of conditions and the following disclaimer in the documentation
and/or other materials provided with the distribution.
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR
ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.

@ -0,0 +1,41 @@
micro-ecc
==========
A small and fast ECDH and ECDSA implementation for 8-bit, 32-bit, and 64-bit processors.
The static version of micro-ecc (ie, where the curve was selected at compile-time) can be found in the "static" branch.
Features
--------
* Resistant to known side-channel attacks.
* Written in C, with optional GCC inline assembly for AVR, ARM and Thumb platforms.
* Supports 8, 32, and 64-bit architectures.
* Small code size.
* No dynamic memory allocation.
* Support for 5 standard curves: secp160r1, secp192r1, secp224r1, secp256r1, and secp256k1.
* BSD 2-clause license.
Usage Notes
-----------
### Point Representation ###
Compressed points are represented in the standard format as defined in http://www.secg.org/sec1-v2.pdf; uncompressed points are represented in standard format, but without the `0x04` prefix. All functions except `uECC_decompress()` only accept uncompressed points; use `uECC_compress()` and `uECC_decompress()` to convert between compressed and uncompressed point representations.
Private keys are represented in the standard format.
### Using the Code ###
I recommend just copying (or symlink) the uECC files into your project. Then just `#include "uECC.h"` to use the micro-ecc functions.
For use with Arduino, you can use the Library Manager to download micro-ecc (**Sketch**=>**Include Library**=>**Manage Libraries**). You can then use uECC just like any other Arduino library (uECC should show up in the **Sketch**=>**Import Library** submenu).
See uECC.h for documentation for each function.
### Compilation Notes ###
* Should compile with any C/C++ compiler that supports stdint.h (this includes Visual Studio 2013).
* If you want to change the defaults for any of the uECC compile-time options (such as `uECC_OPTIMIZATION_LEVEL`), you must change them in your Makefile or similar so that uECC.c is compiled with the desired values (ie, compile uECC.c with `-DuECC_OPTIMIZATION_LEVEL=3` or whatever).
* When compiling for a Thumb-1 platform, you must use the `-fomit-frame-pointer` GCC option (this is enabled by default when compiling with `-O1` or higher).
* When compiling for an ARM/Thumb-2 platform with `uECC_OPTIMIZATION_LEVEL` >= 3, you must use the `-fomit-frame-pointer` GCC option (this is enabled by default when compiling with `-O1` or higher).
* When compiling for AVR, you must have optimizations enabled (compile with `-O1` or higher).
* When building for Windows, you will need to link in the `advapi32.lib` system library.

@ -0,0 +1,820 @@
/* Copyright 2015, Kenneth MacKay. Licensed under the BSD 2-clause license. */
#ifndef _UECC_ASM_ARM_H_
#define _UECC_ASM_ARM_H_
#if (uECC_SUPPORTS_secp256r1 || uECC_SUPPORTS_secp256k1)
#define uECC_MIN_WORDS 8
#endif
#if uECC_SUPPORTS_secp224r1
#undef uECC_MIN_WORDS
#define uECC_MIN_WORDS 7
#endif
#if uECC_SUPPORTS_secp192r1
#undef uECC_MIN_WORDS
#define uECC_MIN_WORDS 6
#endif
#if uECC_SUPPORTS_secp160r1
#undef uECC_MIN_WORDS
#define uECC_MIN_WORDS 5
#endif
#if (uECC_PLATFORM == uECC_arm_thumb)
#define REG_RW "+&l"
#define REG_WRITE "=&l"
#else
#define REG_RW "+&r"
#define REG_WRITE "=&r"
#endif
#if (uECC_PLATFORM == uECC_arm_thumb || uECC_PLATFORM == uECC_arm_thumb2)
#define REG_RW_LO "+&l"
#define REG_WRITE_LO "=&l"
#else
#define REG_RW_LO "+&r"
#define REG_WRITE_LO "=&r"
#endif
#if (uECC_PLATFORM == uECC_arm_thumb2)
#define RESUME_SYNTAX
#else
#define RESUME_SYNTAX ".syntax divided \n\t"
#endif
#if (uECC_OPTIMIZATION_LEVEL >= 2)
uECC_VLI_API uECC_word_t uECC_vli_add(uECC_word_t *result,
const uECC_word_t *left,
const uECC_word_t *right,
wordcount_t num_words) {
#if (uECC_MAX_WORDS != uECC_MIN_WORDS)
#if (uECC_PLATFORM == uECC_arm_thumb) || (uECC_PLATFORM == uECC_arm_thumb2)
uint32_t jump = (uECC_MAX_WORDS - num_words) * 4 * 2 + 1;
#else /* ARM */
uint32_t jump = (uECC_MAX_WORDS - num_words) * 4 * 4;
#endif
#endif
uint32_t carry;
uint32_t left_word;
uint32_t right_word;
__asm__ volatile (
".syntax unified \n\t"
"movs %[carry], #0 \n\t"
#if (uECC_MAX_WORDS != uECC_MIN_WORDS)
"adr %[left], 1f \n\t"
".align 4 \n\t"
"adds %[jump], %[left] \n\t"
#endif
"ldmia %[lptr]!, {%[left]} \n\t"
"ldmia %[rptr]!, {%[right]} \n\t"
"adds %[left], %[right] \n\t"
"stmia %[dptr]!, {%[left]} \n\t"
#if (uECC_MAX_WORDS != uECC_MIN_WORDS)
"bx %[jump] \n\t"
#endif
"1: \n\t"
REPEAT(DEC(uECC_MAX_WORDS),
"ldmia %[lptr]!, {%[left]} \n\t"
"ldmia %[rptr]!, {%[right]} \n\t"
"adcs %[left], %[right] \n\t"
"stmia %[dptr]!, {%[left]} \n\t")
"adcs %[carry], %[carry] \n\t"
RESUME_SYNTAX
: [dptr] REG_RW_LO (result), [lptr] REG_RW_LO (left), [rptr] REG_RW_LO (right),
#if (uECC_MAX_WORDS != uECC_MIN_WORDS)
[jump] REG_RW_LO (jump),
#endif
[carry] REG_WRITE_LO (carry), [left] REG_WRITE_LO (left_word),
[right] REG_WRITE_LO (right_word)
:
: "cc", "memory"
);
return carry;
}
#define asm_add 1
uECC_VLI_API uECC_word_t uECC_vli_sub(uECC_word_t *result,
const uECC_word_t *left,
const uECC_word_t *right,
wordcount_t num_words) {
#if (uECC_MAX_WORDS != uECC_MIN_WORDS)
#if (uECC_PLATFORM == uECC_arm_thumb) || (uECC_PLATFORM == uECC_arm_thumb2)
uint32_t jump = (uECC_MAX_WORDS - num_words) * 4 * 2 + 1;
#else /* ARM */
uint32_t jump = (uECC_MAX_WORDS - num_words) * 4 * 4;
#endif
#endif
uint32_t carry;
uint32_t left_word;
uint32_t right_word;
__asm__ volatile (
".syntax unified \n\t"
"movs %[carry], #0 \n\t"
#if (uECC_MAX_WORDS != uECC_MIN_WORDS)
"adr %[left], 1f \n\t"
".align 4 \n\t"
"adds %[jump], %[left] \n\t"
#endif
"ldmia %[lptr]!, {%[left]} \n\t"
"ldmia %[rptr]!, {%[right]} \n\t"
"subs %[left], %[right] \n\t"
"stmia %[dptr]!, {%[left]} \n\t"
#if (uECC_MAX_WORDS != uECC_MIN_WORDS)
"bx %[jump] \n\t"
#endif
"1: \n\t"
REPEAT(DEC(uECC_MAX_WORDS),
"ldmia %[lptr]!, {%[left]} \n\t"
"ldmia %[rptr]!, {%[right]} \n\t"
"sbcs %[left], %[right] \n\t"
"stmia %[dptr]!, {%[left]} \n\t")
"adcs %[carry], %[carry] \n\t"
RESUME_SYNTAX
: [dptr] REG_RW_LO (result), [lptr] REG_RW_LO (left), [rptr] REG_RW_LO (right),
#if (uECC_MAX_WORDS != uECC_MIN_WORDS)
[jump] REG_RW_LO (jump),
#endif
[carry] REG_WRITE_LO (carry), [left] REG_WRITE_LO (left_word),
[right] REG_WRITE_LO (right_word)
:
: "cc", "memory"
);
return !carry; /* Note that on ARM, carry flag set means "no borrow" when subtracting
(for some reason...) */
}
#define asm_sub 1
#endif /* (uECC_OPTIMIZATION_LEVEL >= 2) */
#if (uECC_OPTIMIZATION_LEVEL >= 3)
#if (uECC_PLATFORM != uECC_arm_thumb)
#if uECC_ARM_USE_UMAAL
#include "asm_arm_mult_square_umaal.inc"
#else
#include "asm_arm_mult_square.inc"
#endif
#if (uECC_OPTIMIZATION_LEVEL == 3)
uECC_VLI_API void uECC_vli_mult(uint32_t *result,
const uint32_t *left,
const uint32_t *right,
wordcount_t num_words) {
register uint32_t *r0 __asm__("r0") = result;
register const uint32_t *r1 __asm__("r1") = left;
register const uint32_t *r2 __asm__("r2") = right;
register uint32_t r3 __asm__("r3") = num_words;
__asm__ volatile (
".syntax unified \n\t"
#if (uECC_MIN_WORDS == 5)
FAST_MULT_ASM_5
#if (uECC_MAX_WORDS > 5)
FAST_MULT_ASM_5_TO_6
#endif
#if (uECC_MAX_WORDS > 6)
FAST_MULT_ASM_6_TO_7
#endif
#if (uECC_MAX_WORDS > 7)
FAST_MULT_ASM_7_TO_8
#endif
#elif (uECC_MIN_WORDS == 6)
FAST_MULT_ASM_6
#if (uECC_MAX_WORDS > 6)
FAST_MULT_ASM_6_TO_7
#endif
#if (uECC_MAX_WORDS > 7)
FAST_MULT_ASM_7_TO_8
#endif
#elif (uECC_MIN_WORDS == 7)
FAST_MULT_ASM_7
#if (uECC_MAX_WORDS > 7)
FAST_MULT_ASM_7_TO_8
#endif
#elif (uECC_MIN_WORDS == 8)
FAST_MULT_ASM_8
#endif
"1: \n\t"
RESUME_SYNTAX
: "+r" (r0), "+r" (r1), "+r" (r2)
: "r" (r3)
: "r4", "r5", "r6", "r7", "r8", "r9", "r10", "r11", "r12", "r14", "cc", "memory"
);
}
#define asm_mult 1
#if uECC_SQUARE_FUNC
uECC_VLI_API void uECC_vli_square(uECC_word_t *result,
const uECC_word_t *left,
wordcount_t num_words) {
register uint32_t *r0 __asm__("r0") = result;
register const uint32_t *r1 __asm__("r1") = left;
register uint32_t r2 __asm__("r2") = num_words;
__asm__ volatile (
".syntax unified \n\t"
#if (uECC_MIN_WORDS == 5)
FAST_SQUARE_ASM_5
#if (uECC_MAX_WORDS > 5)
FAST_SQUARE_ASM_5_TO_6
#endif
#if (uECC_MAX_WORDS > 6)
FAST_SQUARE_ASM_6_TO_7
#endif
#if (uECC_MAX_WORDS > 7)
FAST_SQUARE_ASM_7_TO_8
#endif
#elif (uECC_MIN_WORDS == 6)
FAST_SQUARE_ASM_6
#if (uECC_MAX_WORDS > 6)
FAST_SQUARE_ASM_6_TO_7
#endif
#if (uECC_MAX_WORDS > 7)
FAST_SQUARE_ASM_7_TO_8
#endif
#elif (uECC_MIN_WORDS == 7)
FAST_SQUARE_ASM_7
#if (uECC_MAX_WORDS > 7)
FAST_SQUARE_ASM_7_TO_8
#endif
#elif (uECC_MIN_WORDS == 8)
FAST_SQUARE_ASM_8
#endif
"1: \n\t"
RESUME_SYNTAX
: "+r" (r0), "+r" (r1)
: "r" (r2)
: "r3", "r4", "r5", "r6", "r7", "r8", "r9", "r10", "r11", "r12", "r14", "cc", "memory"
);
}
#define asm_square 1
#endif /* uECC_SQUARE_FUNC */
#else /* (uECC_OPTIMIZATION_LEVEL > 3) */
uECC_VLI_API void uECC_vli_mult(uint32_t *result,
const uint32_t *left,
const uint32_t *right,
wordcount_t num_words) {
register uint32_t *r0 __asm__("r0") = result;
register const uint32_t *r1 __asm__("r1") = left;
register const uint32_t *r2 __asm__("r2") = right;
register uint32_t r3 __asm__("r3") = num_words;
#if uECC_SUPPORTS_secp160r1
if (num_words == 5) {
__asm__ volatile (
".syntax unified \n\t"
FAST_MULT_ASM_5
RESUME_SYNTAX
: "+r" (r0), "+r" (r1), "+r" (r2)
: "r" (r3)
: "r4", "r5", "r6", "r7", "r8", "r9", "r10", "r11", "r12", "r14", "cc", "memory"
);
return;
}
#endif
#if uECC_SUPPORTS_secp192r1
if (num_words == 6) {
__asm__ volatile (
".syntax unified \n\t"
FAST_MULT_ASM_6
RESUME_SYNTAX
: "+r" (r0), "+r" (r1), "+r" (r2)
: "r" (r3)
: "r4", "r5", "r6", "r7", "r8", "r9", "r10", "r11", "r12", "r14", "cc", "memory"
);
return;
}
#endif
#if uECC_SUPPORTS_secp224r1
if (num_words == 7) {
__asm__ volatile (
".syntax unified \n\t"
FAST_MULT_ASM_7
RESUME_SYNTAX
: "+r" (r0), "+r" (r1), "+r" (r2)
: "r" (r3)
: "r4", "r5", "r6", "r7", "r8", "r9", "r10", "r11", "r12", "r14", "cc", "memory"
);
return;
}
#endif
#if (uECC_SUPPORTS_secp256r1 || uECC_SUPPORTS_secp256k1)
if (num_words == 8) {
__asm__ volatile (
".syntax unified \n\t"
FAST_MULT_ASM_8
RESUME_SYNTAX
: "+r" (r0), "+r" (r1), "+r" (r2)
: "r" (r3)
: "r4", "r5", "r6", "r7", "r8", "r9", "r10", "r11", "r12", "r14", "cc", "memory"
);
return;
}
#endif
}
#define asm_mult 1
#if uECC_SQUARE_FUNC
uECC_VLI_API void uECC_vli_square(uECC_word_t *result,
const uECC_word_t *left,
wordcount_t num_words) {
register uint32_t *r0 __asm__("r0") = result;
register const uint32_t *r1 __asm__("r1") = left;
register uint32_t r2 __asm__("r2") = num_words;
#if uECC_SUPPORTS_secp160r1
if (num_words == 5) {
__asm__ volatile (
".syntax unified \n\t"
FAST_SQUARE_ASM_5
RESUME_SYNTAX
: "+r" (r0), "+r" (r1)
: "r" (r2)
: "r3", "r4", "r5", "r6", "r7", "r8", "r9", "r10", "r11", "r12", "r14", "cc", "memory"
);
return;
}
#endif
#if uECC_SUPPORTS_secp192r1
if (num_words == 6) {
__asm__ volatile (
".syntax unified \n\t"
FAST_SQUARE_ASM_6
RESUME_SYNTAX
: "+r" (r0), "+r" (r1)
: "r" (r2)
: "r3", "r4", "r5", "r6", "r7", "r8", "r9", "r10", "r11", "r12", "r14", "cc", "memory"
);
return;
}
#endif
#if uECC_SUPPORTS_secp224r1
if (num_words == 7) {
__asm__ volatile (
".syntax unified \n\t"
FAST_SQUARE_ASM_7
RESUME_SYNTAX
: "+r" (r0), "+r" (r1)
: "r" (r2)
: "r3", "r4", "r5", "r6", "r7", "r8", "r9", "r10", "r11", "r12", "r14", "cc", "memory"
);
return;
}
#endif
#if (uECC_SUPPORTS_secp256r1 || uECC_SUPPORTS_secp256k1)
if (num_words == 8) {
__asm__ volatile (
".syntax unified \n\t"
FAST_SQUARE_ASM_8
RESUME_SYNTAX
: "+r" (r0), "+r" (r1)
: "r" (r2)
: "r3", "r4", "r5", "r6", "r7", "r8", "r9", "r10", "r11", "r12", "r14", "cc", "memory"
);
return;
}
#endif
}
#define asm_square 1
#endif /* uECC_SQUARE_FUNC */
#endif /* (uECC_OPTIMIZATION_LEVEL > 3) */
#endif /* uECC_PLATFORM != uECC_arm_thumb */
#endif /* (uECC_OPTIMIZATION_LEVEL >= 3) */
/* ---- "Small" implementations ---- */
#if !asm_add
uECC_VLI_API uECC_word_t uECC_vli_add(uECC_word_t *result,
const uECC_word_t *left,
const uECC_word_t *right,
wordcount_t num_words) {
uint32_t carry = 0;
uint32_t left_word;
uint32_t right_word;
__asm__ volatile (
".syntax unified \n\t"
"1: \n\t"
"ldmia %[lptr]!, {%[left]} \n\t" /* Load left word. */
"ldmia %[rptr]!, {%[right]} \n\t" /* Load right word. */
"lsrs %[carry], #1 \n\t" /* Set up carry flag (carry = 0 after this). */
"adcs %[left], %[left], %[right] \n\t" /* Add with carry. */
"adcs %[carry], %[carry], %[carry] \n\t" /* Store carry bit. */
"stmia %[dptr]!, {%[left]} \n\t" /* Store result word. */
"subs %[ctr], #1 \n\t" /* Decrement counter. */
"bne 1b \n\t" /* Loop until counter == 0. */
RESUME_SYNTAX
: [dptr] REG_RW (result), [lptr] REG_RW (left), [rptr] REG_RW (right),
[ctr] REG_RW (num_words), [carry] REG_RW (carry),
[left] REG_WRITE (left_word), [right] REG_WRITE (right_word)
:
: "cc", "memory"
);
return carry;
}
#define asm_add 1
#endif
#if !asm_sub
uECC_VLI_API uECC_word_t uECC_vli_sub(uECC_word_t *result,
const uECC_word_t *left,
const uECC_word_t *right,
wordcount_t num_words) {
uint32_t carry = 1; /* carry = 1 initially (means don't borrow) */
uint32_t left_word;
uint32_t right_word;
__asm__ volatile (
".syntax unified \n\t"
"1: \n\t"
"ldmia %[lptr]!, {%[left]} \n\t" /* Load left word. */
"ldmia %[rptr]!, {%[right]} \n\t" /* Load right word. */
"lsrs %[carry], #1 \n\t" /* Set up carry flag (carry = 0 after this). */
"sbcs %[left], %[left], %[right] \n\t" /* Subtract with borrow. */
"adcs %[carry], %[carry], %[carry] \n\t" /* Store carry bit. */
"stmia %[dptr]!, {%[left]} \n\t" /* Store result word. */
"subs %[ctr], #1 \n\t" /* Decrement counter. */
"bne 1b \n\t" /* Loop until counter == 0. */
RESUME_SYNTAX
: [dptr] REG_RW (result), [lptr] REG_RW (left), [rptr] REG_RW (right),
[ctr] REG_RW (num_words), [carry] REG_RW (carry),
[left] REG_WRITE (left_word), [right] REG_WRITE (right_word)
:
: "cc", "memory"
);
return !carry;
}
#define asm_sub 1
#endif
#if !asm_mult
uECC_VLI_API void uECC_vli_mult(uECC_word_t *result,
const uECC_word_t *left,
const uECC_word_t *right,
wordcount_t num_words) {
#if (uECC_PLATFORM != uECC_arm_thumb)
uint32_t c0 = 0;
uint32_t c1 = 0;
uint32_t c2 = 0;
uint32_t k = 0;
uint32_t i;
uint32_t t0, t1;
__asm__ volatile (
".syntax unified \n\t"
"1: \n\t" /* outer loop (k < num_words) */
"movs %[i], #0 \n\t" /* i = 0 */
"b 3f \n\t"
"2: \n\t" /* outer loop (k >= num_words) */
"movs %[i], %[k] \n\t" /* i = k */
"subs %[i], %[last_word] \n\t" /* i = k - (num_words - 1) (times 4) */
"3: \n\t" /* inner loop */
"subs %[t0], %[k], %[i] \n\t" /* t0 = k-i */
"ldr %[t1], [%[right], %[t0]] \n\t" /* t1 = right[k - i] */
"ldr %[t0], [%[left], %[i]] \n\t" /* t0 = left[i] */
"umull %[t0], %[t1], %[t0], %[t1] \n\t" /* (t0, t1) = left[i] * right[k - i] */
"adds %[c0], %[c0], %[t0] \n\t" /* add low word to c0 */
"adcs %[c1], %[c1], %[t1] \n\t" /* add high word to c1, including carry */
"adcs %[c2], %[c2], #0 \n\t" /* add carry to c2 */
"adds %[i], #4 \n\t" /* i += 4 */
"cmp %[i], %[last_word] \n\t" /* i > (num_words - 1) (times 4)? */
"bgt 4f \n\t" /* if so, exit the loop */
"cmp %[i], %[k] \n\t" /* i <= k? */
"ble 3b \n\t" /* if so, continue looping */
"4: \n\t" /* end inner loop */
"str %[c0], [%[result], %[k]] \n\t" /* result[k] = c0 */
"mov %[c0], %[c1] \n\t" /* c0 = c1 */
"mov %[c1], %[c2] \n\t" /* c1 = c2 */
"movs %[c2], #0 \n\t" /* c2 = 0 */
"adds %[k], #4 \n\t" /* k += 4 */
"cmp %[k], %[last_word] \n\t" /* k <= (num_words - 1) (times 4) ? */
"ble 1b \n\t" /* if so, loop back, start with i = 0 */
"cmp %[k], %[last_word], lsl #1 \n\t" /* k <= (num_words * 2 - 2) (times 4) ? */
"ble 2b \n\t" /* if so, loop back, start with i = (k + 1) - num_words */
/* end outer loop */
"str %[c0], [%[result], %[k]] \n\t" /* result[num_words * 2 - 1] = c0 */
RESUME_SYNTAX
: [c0] "+r" (c0), [c1] "+r" (c1), [c2] "+r" (c2),
[k] "+r" (k), [i] "=&r" (i), [t0] "=&r" (t0), [t1] "=&r" (t1)
: [result] "r" (result), [left] "r" (left), [right] "r" (right),
[last_word] "r" ((num_words - 1) * 4)
: "cc", "memory"
);
#else /* Thumb-1 */
uint32_t r4, r5, r6, r7;
__asm__ volatile (
".syntax unified \n\t"
"subs %[r3], #1 \n\t" /* r3 = num_words - 1 */
"lsls %[r3], #2 \n\t" /* r3 = (num_words - 1) * 4 */
"mov r8, %[r3] \n\t" /* r8 = (num_words - 1) * 4 */
"lsls %[r3], #1 \n\t" /* r3 = (num_words - 1) * 8 */
"mov r9, %[r3] \n\t" /* r9 = (num_words - 1) * 8 */
"movs %[r3], #0 \n\t" /* c0 = 0 */
"movs %[r4], #0 \n\t" /* c1 = 0 */
"movs %[r5], #0 \n\t" /* c2 = 0 */
"movs %[r6], #0 \n\t" /* k = 0 */
"push {%[r0]} \n\t" /* keep result on the stack */
"1: \n\t" /* outer loop (k < num_words) */
"movs %[r7], #0 \n\t" /* r7 = i = 0 */
"b 3f \n\t"
"2: \n\t" /* outer loop (k >= num_words) */
"movs %[r7], %[r6] \n\t" /* r7 = k */
"mov %[r0], r8 \n\t" /* r0 = (num_words - 1) * 4 */
"subs %[r7], %[r0] \n\t" /* r7 = i = k - (num_words - 1) (times 4) */
"3: \n\t" /* inner loop */
"mov r10, %[r3] \n\t"
"mov r11, %[r4] \n\t"
"mov r12, %[r5] \n\t"
"mov r14, %[r6] \n\t"
"subs %[r0], %[r6], %[r7] \n\t" /* r0 = k - i */
"ldr %[r4], [%[r2], %[r0]] \n\t" /* r4 = right[k - i] */
"ldr %[r0], [%[r1], %[r7]] \n\t" /* r0 = left[i] */
"lsrs %[r3], %[r0], #16 \n\t" /* r3 = a1 */
"uxth %[r0], %[r0] \n\t" /* r0 = a0 */
"lsrs %[r5], %[r4], #16 \n\t" /* r5 = b1 */
"uxth %[r4], %[r4] \n\t" /* r4 = b0 */
"movs %[r6], %[r3] \n\t" /* r6 = a1 */
"muls %[r6], %[r5], %[r6] \n\t" /* r6 = a1 * b1 */
"muls %[r3], %[r4], %[r3] \n\t" /* r3 = b0 * a1 */
"muls %[r5], %[r0], %[r5] \n\t" /* r5 = a0 * b1 */
"muls %[r0], %[r4], %[r0] \n\t" /* r0 = a0 * b0 */
/* Add middle terms */
"lsls %[r4], %[r3], #16 \n\t"
"lsrs %[r3], %[r3], #16 \n\t"
"adds %[r0], %[r4] \n\t"
"adcs %[r6], %[r3] \n\t"
"lsls %[r4], %[r5], #16 \n\t"
"lsrs %[r5], %[r5], #16 \n\t"
"adds %[r0], %[r4] \n\t"
"adcs %[r6], %[r5] \n\t"
"mov %[r3], r10\n\t"
"mov %[r4], r11\n\t"
"mov %[r5], r12\n\t"
"adds %[r3], %[r0] \n\t" /* add low word to c0 */
"adcs %[r4], %[r6] \n\t" /* add high word to c1, including carry */
"movs %[r0], #0 \n\t" /* r0 = 0 (does not affect carry bit) */
"adcs %[r5], %[r0] \n\t" /* add carry to c2 */
"mov %[r6], r14\n\t" /* r6 = k */
"adds %[r7], #4 \n\t" /* i += 4 */
"cmp %[r7], r8 \n\t" /* i > (num_words - 1) (times 4)? */
"bgt 4f \n\t" /* if so, exit the loop */
"cmp %[r7], %[r6] \n\t" /* i <= k? */
"ble 3b \n\t" /* if so, continue looping */
"4: \n\t" /* end inner loop */
"ldr %[r0], [sp, #0] \n\t" /* r0 = result */
"str %[r3], [%[r0], %[r6]] \n\t" /* result[k] = c0 */
"mov %[r3], %[r4] \n\t" /* c0 = c1 */
"mov %[r4], %[r5] \n\t" /* c1 = c2 */
"movs %[r5], #0 \n\t" /* c2 = 0 */
"adds %[r6], #4 \n\t" /* k += 4 */
"cmp %[r6], r8 \n\t" /* k <= (num_words - 1) (times 4) ? */
"ble 1b \n\t" /* if so, loop back, start with i = 0 */
"cmp %[r6], r9 \n\t" /* k <= (num_words * 2 - 2) (times 4) ? */
"ble 2b \n\t" /* if so, loop back, with i = (k + 1) - num_words */
/* end outer loop */
"str %[r3], [%[r0], %[r6]] \n\t" /* result[num_words * 2 - 1] = c0 */
"pop {%[r0]} \n\t" /* pop result off the stack */
RESUME_SYNTAX
: [r3] "+l" (num_words), [r4] "=&l" (r4),
[r5] "=&l" (r5), [r6] "=&l" (r6), [r7] "=&l" (r7)
: [r0] "l" (result), [r1] "l" (left), [r2] "l" (right)
: "r8", "r9", "r10", "r11", "r12", "r14", "cc", "memory"
);
#endif
}
#define asm_mult 1
#endif
#if uECC_SQUARE_FUNC
#if !asm_square
uECC_VLI_API void uECC_vli_square(uECC_word_t *result,
const uECC_word_t *left,
wordcount_t num_words) {
#if (uECC_PLATFORM != uECC_arm_thumb)
uint32_t c0 = 0;
uint32_t c1 = 0;
uint32_t c2 = 0;
uint32_t k = 0;
uint32_t i, tt;
uint32_t t0, t1;
__asm__ volatile (
".syntax unified \n\t"
"1: \n\t" /* outer loop (k < num_words) */
"movs %[i], #0 \n\t" /* i = 0 */
"b 3f \n\t"
"2: \n\t" /* outer loop (k >= num_words) */
"movs %[i], %[k] \n\t" /* i = k */
"subs %[i], %[last_word] \n\t" /* i = k - (num_words - 1) (times 4) */
"3: \n\t" /* inner loop */
"subs %[tt], %[k], %[i] \n\t" /* tt = k-i */
"ldr %[t1], [%[left], %[tt]] \n\t" /* t1 = left[k - i] */
"ldr %[t0], [%[left], %[i]] \n\t" /* t0 = left[i] */
"umull %[t0], %[t1], %[t0], %[t1] \n\t" /* (t0, t1) = left[i] * right[k - i] */
"cmp %[i], %[tt] \n\t" /* (i < k - i) ? */
"bge 4f \n\t" /* if i >= k - i, skip */
"adds %[c0], %[c0], %[t0] \n\t" /* add low word to c0 */
"adcs %[c1], %[c1], %[t1] \n\t" /* add high word to c1, including carry */
"adcs %[c2], %[c2], #0 \n\t" /* add carry to c2 */
"4: \n\t"
"adds %[c0], %[c0], %[t0] \n\t" /* add low word to c0 */
"adcs %[c1], %[c1], %[t1] \n\t" /* add high word to c1, including carry */
"adcs %[c2], %[c2], #0 \n\t" /* add carry to c2 */
"adds %[i], #4 \n\t" /* i += 4 */
"cmp %[i], %[k] \n\t" /* i >= k? */
"bge 5f \n\t" /* if so, exit the loop */
"subs %[tt], %[k], %[i] \n\t" /* tt = k - i */
"cmp %[i], %[tt] \n\t" /* i <= k - i? */
"ble 3b \n\t" /* if so, continue looping */
"5: \n\t" /* end inner loop */
"str %[c0], [%[result], %[k]] \n\t" /* result[k] = c0 */
"mov %[c0], %[c1] \n\t" /* c0 = c1 */
"mov %[c1], %[c2] \n\t" /* c1 = c2 */
"movs %[c2], #0 \n\t" /* c2 = 0 */
"adds %[k], #4 \n\t" /* k += 4 */
"cmp %[k], %[last_word] \n\t" /* k <= (num_words - 1) (times 4) ? */
"ble 1b \n\t" /* if so, loop back, start with i = 0 */
"cmp %[k], %[last_word], lsl #1 \n\t" /* k <= (num_words * 2 - 2) (times 4) ? */
"ble 2b \n\t" /* if so, loop back, start with i = (k + 1) - num_words */
/* end outer loop */
"str %[c0], [%[result], %[k]] \n\t" /* result[num_words * 2 - 1] = c0 */
RESUME_SYNTAX
: [c0] "+r" (c0), [c1] "+r" (c1), [c2] "+r" (c2),
[k] "+r" (k), [i] "=&r" (i), [tt] "=&r" (tt), [t0] "=&r" (t0), [t1] "=&r" (t1)
: [result] "r" (result), [left] "r" (left), [last_word] "r" ((num_words - 1) * 4)
: "cc", "memory"
);
#else
uint32_t r3, r4, r5, r6, r7;
__asm__ volatile (
".syntax unified \n\t"
"subs %[r2], #1 \n\t" /* r2 = num_words - 1 */
"lsls %[r2], #2 \n\t" /* r2 = (num_words - 1) * 4 */
"mov r8, %[r2] \n\t" /* r8 = (num_words - 1) * 4 */
"lsls %[r2], #1 \n\t" /* r2 = (num_words - 1) * 8 */
"mov r9, %[r2] \n\t" /* r9 = (num_words - 1) * 8 */
"movs %[r2], #0 \n\t" /* c0 = 0 */
"movs %[r3], #0 \n\t" /* c1 = 0 */
"movs %[r4], #0 \n\t" /* c2 = 0 */
"movs %[r5], #0 \n\t" /* k = 0 */
"push {%[r0]} \n\t" /* keep result on the stack */
"1: \n\t" /* outer loop (k < num_words) */
"movs %[r6], #0 \n\t" /* r6 = i = 0 */
"b 3f \n\t"
"2: \n\t" /* outer loop (k >= num_words) */
"movs %[r6], %[r5] \n\t" /* r6 = k */
"mov %[r0], r8 \n\t" /* r0 = (num_words - 1) * 4 */
"subs %[r6], %[r0] \n\t" /* r6 = i = k - (num_words - 1) (times 4) */
"3: \n\t" /* inner loop */
"mov r10, %[r2] \n\t"
"mov r11, %[r3] \n\t"
"mov r12, %[r4] \n\t"
"mov r14, %[r5] \n\t"
"subs %[r7], %[r5], %[r6] \n\t" /* r7 = k - i */
"ldr %[r3], [%[r1], %[r7]] \n\t" /* r3 = left[k - i] */
"ldr %[r0], [%[r1], %[r6]] \n\t" /* r0 = left[i] */
"lsrs %[r2], %[r0], #16 \n\t" /* r2 = a1 */
"uxth %[r0], %[r0] \n\t" /* r0 = a0 */
"lsrs %[r4], %[r3], #16 \n\t" /* r4 = b1 */
"uxth %[r3], %[r3] \n\t" /* r3 = b0 */
"movs %[r5], %[r2] \n\t" /* r5 = a1 */
"muls %[r5], %[r4], %[r5] \n\t" /* r5 = a1 * b1 */
"muls %[r2], %[r3], %[r2] \n\t" /* r2 = b0 * a1 */
"muls %[r4], %[r0], %[r4] \n\t" /* r4 = a0 * b1 */
"muls %[r0], %[r3], %[r0] \n\t" /* r0 = a0 * b0 */
/* Add middle terms */
"lsls %[r3], %[r2], #16 \n\t"
"lsrs %[r2], %[r2], #16 \n\t"
"adds %[r0], %[r3] \n\t"
"adcs %[r5], %[r2] \n\t"
"lsls %[r3], %[r4], #16 \n\t"
"lsrs %[r4], %[r4], #16 \n\t"
"adds %[r0], %[r3] \n\t"
"adcs %[r5], %[r4] \n\t"
/* Add to acc, doubling if necessary */
"mov %[r2], r10\n\t"
"mov %[r3], r11\n\t"
"mov %[r4], r12\n\t"
"cmp %[r6], %[r7] \n\t" /* (i < k - i) ? */
"bge 4f \n\t" /* if i >= k - i, skip */
"movs %[r7], #0 \n\t" /* r7 = 0 */
"adds %[r2], %[r0] \n\t" /* add low word to c0 */
"adcs %[r3], %[r5] \n\t" /* add high word to c1, including carry */
"adcs %[r4], %[r7] \n\t" /* add carry to c2 */
"4: \n\t"
"movs %[r7], #0 \n\t" /* r7 = 0 */
"adds %[r2], %[r0] \n\t" /* add low word to c0 */
"adcs %[r3], %[r5] \n\t" /* add high word to c1, including carry */
"adcs %[r4], %[r7] \n\t" /* add carry to c2 */
"mov %[r5], r14\n\t" /* r5 = k */
"adds %[r6], #4 \n\t" /* i += 4 */
"cmp %[r6], %[r5] \n\t" /* i >= k? */
"bge 5f \n\t" /* if so, exit the loop */
"subs %[r7], %[r5], %[r6] \n\t" /* r7 = k - i */
"cmp %[r6], %[r7] \n\t" /* i <= k - i? */
"ble 3b \n\t" /* if so, continue looping */
"5: \n\t" /* end inner loop */
"ldr %[r0], [sp, #0] \n\t" /* r0 = result */
"str %[r2], [%[r0], %[r5]] \n\t" /* result[k] = c0 */
"mov %[r2], %[r3] \n\t" /* c0 = c1 */
"mov %[r3], %[r4] \n\t" /* c1 = c2 */
"movs %[r4], #0 \n\t" /* c2 = 0 */
"adds %[r5], #4 \n\t" /* k += 4 */
"cmp %[r5], r8 \n\t" /* k <= (num_words - 1) (times 4) ? */
"ble 1b \n\t" /* if so, loop back, start with i = 0 */
"cmp %[r5], r9 \n\t" /* k <= (num_words * 2 - 2) (times 4) ? */
"ble 2b \n\t" /* if so, loop back, with i = (k + 1) - num_words */
/* end outer loop */
"str %[r2], [%[r0], %[r5]] \n\t" /* result[num_words * 2 - 1] = c0 */
"pop {%[r0]} \n\t" /* pop result off the stack */
RESUME_SYNTAX
: [r2] "+l" (num_words), [r3] "=&l" (r3), [r4] "=&l" (r4),
[r5] "=&l" (r5), [r6] "=&l" (r6), [r7] "=&l" (r7)
: [r0] "l" (result), [r1] "l" (left)
: "r8", "r9", "r10", "r11", "r12", "r14", "cc", "memory"
);
#endif
}
#define asm_square 1
#endif
#endif /* uECC_SQUARE_FUNC */
#endif /* _UECC_ASM_ARM_H_ */

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

@ -0,0 +1,132 @@
import os
c, link, asm, utils = emk.module("c", "link", "asm", "utils")
default_compile_flags = ["-fvisibility=hidden", "-Wall", "-Wextra", "-Wshadow", "-Werror", "-Wno-missing-field-initializers", "-Wno-unused-parameter", \
"-Wno-comment", "-Wno-unused", "-Wno-unknown-pragmas"]
default_link_flags = []
opt_flags = {"dbg":["-g"], "std":["-O2"], "max":["-O3"], "small":["-Os"]}
opt_link_flags = {"dbg":[], "std":[], "max":[], "small":[]}
c_flags = ["-std=c99"]
cxx_flags = ["-std=c++11", "-Wno-reorder", "-fno-rtti", "-fno-exceptions"]
c_link_flags = []
cxx_link_flags = ["-fno-rtti", "-fno-exceptions"]
if "root" in emk.options:
root = emk.options["root"]
else:
root = "/"
def setup_build_dir():
build_arch = None
if "arch" in emk.options:
build_arch = emk.options["arch"]
elif not emk.cleaning:
build_arch = "osx"
emk.options["arch"] = build_arch
opt_level = None
if "opt" in emk.options:
level = emk.options["opt"]
if level in opt_flags:
opt_level = level
else:
emk.log.warning("Unknown optimization level '%s'" % (level))
elif not emk.cleaning:
opt_level = "dbg"
emk.options["opt"] = opt_level
dirs = ["__build__"]
if build_arch:
dirs.append(build_arch)
if opt_level:
dirs.append(opt_level)
emk.build_dir = os.path.join(*dirs)
def setup_osx():
global c
global link
flags = [("-arch", "x86_64"), "-fno-common", "-Wnewline-eof"]
c.flags.extend(flags)
c.cxx.flags += ["-stdlib=libc++"]
link.cxx.flags += ["-stdlib=libc++"]
link_flags = [("-arch", "x86_64")]
link.local_flags.extend(link_flags)
def setup_avr():
global c
global link
c.compiler = c.GccCompiler(root + "Projects/avr-tools/bin/avr-")
c.flags += ["-mmcu=atmega256rfr2", "-ffunction-sections", "-fdata-sections"]
link.linker = link.GccLinker(root + "Projects/avr-tools/bin/avr-")
link.flags += ["-mmcu=atmega256rfr2", "-mrelax", "-Wl,--gc-sections"]
link.strip = True
def setup_arm_thumb():
global c
global link
global asm
global utils
asm.assembler = asm.GccAssembler(root + "cross/arm_cortex/bin/arm-none-eabi-")
c.compiler = c.GccCompiler(root + "cross/arm_cortex/bin/arm-none-eabi-")
link.linker = link.GccLinker(root + "cross/arm_cortex/bin/arm-none-eabi-")
c.flags.extend(["-mcpu=cortex-m0", "-mthumb", "-ffunction-sections", "-fdata-sections", "-fno-builtin-fprintf", "-fno-builtin-printf"])
c.defines["LPC11XX"] = 1
link.local_flags.extend(["-mcpu=cortex-m0", "-mthumb", "-nostartfiles", "-nostdlib", "-Wl,--gc-sections"])
link.local_flags.extend(["-Tflash.lds", "-L" + root + "Projects/lpc11xx/core", root + "Projects/lpc11xx/core/" + emk.build_dir + "/board_cstartup.o"])
link.local_syslibs += ["gcc"]
link.depdirs += [root + "Projects/lpc11xx/stdlib"]
def do_objcopy(produces, requires):
utils.call(root + "cross/arm_cortex/bin/arm-none-eabi-objcopy", "-O", "binary", requires[0], produces[0])
def handle_exe(path):
emk.depend(path, root + "Projects/lpc11xx/core/" + emk.build_dir + "/board_cstartup.o")
emk.rule(do_objcopy, path + ".bin", path, cwd_safe=True, ex_safe=True)
emk.autobuild(path + ".bin")
link.exe_funcs.append(handle_exe)
link.strip = True
emk.recurse(root + "Projects/lpc11xx/core")
def setup_linux_rpi():
global c
global link
c.compiler = c.GccCompiler("/Volumes/xtools/arm-none-linux-gnueabi/bin/arm-none-linux-gnueabi-")
link.linker = link.GccLinker("/Volumes/xtools/arm-none-linux-gnueabi/bin/arm-none-linux-gnueabi-")
c.flags.extend(["-fomit-frame-pointer"])
setup_build_dir()
setup_funcs = {"osx":setup_osx, "avr":setup_avr, "arm_thumb":setup_arm_thumb, "rpi": setup_linux_rpi}
if not emk.cleaning:
build_arch = emk.options["arch"]
opt_level = emk.options["opt"]
c.flags.extend(default_compile_flags)
c.flags.extend(opt_flags[opt_level])
c.c.flags.extend(c_flags)
c.cxx.flags.extend(cxx_flags)
link.local_flags.extend(default_link_flags)
link.local_flags.extend(opt_link_flags[opt_level])
link.c.local_flags.extend(c_link_flags)
link.cxx.local_flags.extend(cxx_link_flags)
c.include_dirs.append("$:proj:$")
if build_arch in setup_funcs:
setup_funcs[build_arch]()
else:
raise emk.BuildError("Unknown target arch '%s'" % (build_arch))
c.defines["TARGET_ARCH_" + build_arch.upper()] = 1

@ -0,0 +1,3 @@
c, link = emk.module("c", "link")
emk.subdir("test")

@ -0,0 +1,80 @@
#include <uECC.h>
static int RNG(uint8_t *dest, unsigned size) {
// Use the least-significant bits from the ADC for an unconnected pin (or connected to a source of
// random noise). This can take a long time to generate random data if the result of analogRead(0)
// doesn't change very frequently.
while (size) {
uint8_t val = 0;
for (unsigned i = 0; i < 8; ++i) {
int init = analogRead(0);
int count = 0;
while (analogRead(0) == init) {
++count;
}
if (count == 0) {
val = (val << 1) | (init & 0x01);
} else {
val = (val << 1) | (count & 0x01);
}
}
*dest = val;
++dest;
--size;
}
// NOTE: it would be a good idea to hash the resulting random data using SHA-256 or similar.
return 1;
}
void setup() {
Serial.begin(115200);
Serial.print("Testing ecc\n");
uECC_set_rng(&RNG);
}
void loop() {
const struct uECC_Curve_t * curve = uECC_secp160r1();
uint8_t private1[21];
uint8_t private2[21];
uint8_t public1[40];
uint8_t public2[40];
uint8_t secret1[20];
uint8_t secret2[20];
unsigned long a = millis();
uECC_make_key(public1, private1, curve);
unsigned long b = millis();
Serial.print("Made key 1 in "); Serial.println(b-a);
a = millis();
uECC_make_key(public2, private2, curve);
b = millis();
Serial.print("Made key 2 in "); Serial.println(b-a);
a = millis();
int r = uECC_shared_secret(public2, private1, secret1, curve);
b = millis();
Serial.print("Shared secret 1 in "); Serial.println(b-a);
if (!r) {
Serial.print("shared_secret() failed (1)\n");
return;
}
a = millis();
r = uECC_shared_secret(public1, private2, secret2, curve);
b = millis();
Serial.print("Shared secret 2 in "); Serial.println(b-a);
if (!r) {
Serial.print("shared_secret() failed (2)\n");
return;
}
if (memcmp(secret1, secret2, 20) != 0) {
Serial.print("Shared secrets are not identical!\n");
} else {
Serial.print("Shared secrets are identical\n");
}
}

@ -0,0 +1,9 @@
name=micro-ecc
version=1.0.0
author=Kenneth MacKay
maintainer=Kenneth MacKay
sentence=uECC
paragraph=A small and fast ECDH and ECDSA implementation for 8-bit, 32-bit, and 64-bit processors.
category=Other
url=https://github.com/kmackay/micro-ecc
architectures=*

@ -0,0 +1,94 @@
/* Copyright 2015, Kenneth MacKay. Licensed under the BSD 2-clause license. */
#ifndef _UECC_PLATFORM_SPECIFIC_H_
#define _UECC_PLATFORM_SPECIFIC_H_
#include "types.h"
#if (defined(_WIN32) || defined(_WIN64))
/* Windows */
// use pragma syntax to prevent tweaking the linker script for getting CryptXYZ function
#pragma comment(lib, "crypt32.lib")
#pragma comment(lib, "advapi32.lib")
#define WIN32_LEAN_AND_MEAN
#include <windows.h>
#include <wincrypt.h>
static int default_RNG(uint8_t *dest, unsigned size) {
HCRYPTPROV prov;
if (!CryptAcquireContext(&prov, NULL, NULL, PROV_RSA_FULL, CRYPT_VERIFYCONTEXT)) {
return 0;
}
CryptGenRandom(prov, size, (BYTE *)dest);
CryptReleaseContext(prov, 0);
return 1;
}
#define default_RNG_defined 1
#elif defined(unix) || defined(__linux__) || defined(__unix__) || defined(__unix) || \
(defined(__APPLE__) && defined(__MACH__)) || defined(uECC_POSIX)
/* Some POSIX-like system with /dev/urandom or /dev/random. */
#include <sys/types.h>
#include <fcntl.h>
#include <unistd.h>
#ifndef O_CLOEXEC
#define O_CLOEXEC 0
#endif
static int default_RNG(uint8_t *dest, unsigned size) {
int fd = open("/dev/urandom", O_RDONLY | O_CLOEXEC);
if (fd == -1) {
fd = open("/dev/random", O_RDONLY | O_CLOEXEC);
if (fd == -1) {
return 0;
}
}
char *ptr = (char *)dest;
size_t left = size;
while (left > 0) {
ssize_t bytes_read = read(fd, ptr, left);
if (bytes_read <= 0) { // read failed
close(fd);
return 0;
}
left -= bytes_read;
ptr += bytes_read;
}
close(fd);
return 1;
}
#define default_RNG_defined 1
#elif defined(RIOT_VERSION)
#include <random.h>
static int default_RNG(uint8_t *dest, unsigned size) {
random_bytes(dest, size);
return 1;
}
#define default_RNG_defined 1
#elif defined(NRF52_SERIES)
#include "app_error.h"
#include "nrf_crypto_rng.h"
static int default_RNG(uint8_t *dest, unsigned size)
{
// make sure to call nrf_crypto_init and nrf_crypto_rng_init first
ret_code_t ret_code = nrf_crypto_rng_vector_generate(dest, size);
return (ret_code == NRF_SUCCESS) ? 1 : 0;
}
#define default_RNG_defined 1
#endif /* platform */
#endif /* _UECC_PLATFORM_SPECIFIC_H_ */

@ -0,0 +1,188 @@
#!/usr/bin/env python
import sys
if len(sys.argv) < 2:
print "Provide the integer size in 32-bit words"
sys.exit(1)
size = int(sys.argv[1])
full_rows = size // 3
init_size = size % 3
if init_size == 0:
full_rows = full_rows - 1
init_size = 3
def emit(line, *args):
s = '"' + line + r' \n\t"'
print s % args
rx = [3, 4, 5]
ry = [6, 7, 8]
#### set up registers
emit("add r0, %s", (size - init_size) * 4) # move z
emit("add r2, %s", (size - init_size) * 4) # move y
emit("ldmia r1!, {%s}", ", ".join(["r%s" % (rx[i]) for i in xrange(init_size)]))
emit("ldmia r2!, {%s}", ", ".join(["r%s" % (ry[i]) for i in xrange(init_size)]))
print ""
if init_size == 1:
emit("umull r9, r10, r3, r6")
emit("stmia r0!, {r9, r10}")
else:
#### first two multiplications of initial block
emit("umull r11, r12, r3, r6")
emit("stmia r0!, {r11}")
print ""
emit("mov r10, #0")
emit("umull r11, r9, r3, r7")
emit("adds r12, r12, r11")
emit("adc r9, r9, #0")
emit("umull r11, r14, r4, r6")
emit("adds r12, r12, r11")
emit("adcs r9, r9, r14")
emit("adc r10, r10, #0")
emit("stmia r0!, {r12}")
print ""
#### rest of initial block, with moving accumulator registers
acc = [9, 10, 11, 12, 14]
if init_size == 3:
emit("mov r%s, #0", acc[2])
for i in xrange(0, 3):
emit("umull r%s, r%s, r%s, r%s", acc[3], acc[4], rx[i], ry[2 - i])
emit("adds r%s, r%s, r%s", acc[0], acc[0], acc[3])
emit("adcs r%s, r%s, r%s", acc[1], acc[1], acc[4])
emit("adc r%s, r%s, #0", acc[2], acc[2])
emit("stmia r0!, {r%s}", acc[0])
print ""
acc = acc[1:] + acc[:1]
emit("mov r%s, #0", acc[2])
for i in xrange(0, 2):
emit("umull r%s, r%s, r%s, r%s", acc[3], acc[4], rx[i + 1], ry[2 - i])
emit("adds r%s, r%s, r%s", acc[0], acc[0], acc[3])
emit("adcs r%s, r%s, r%s", acc[1], acc[1], acc[4])
emit("adc r%s, r%s, #0", acc[2], acc[2])
emit("stmia r0!, {r%s}", acc[0])
print ""
acc = acc[1:] + acc[:1]
emit("umull r%s, r%s, r%s, r%s", acc[3], acc[4], rx[init_size-1], ry[init_size-1])
emit("adds r%s, r%s, r%s", acc[0], acc[0], acc[3])
emit("adc r%s, r%s, r%s", acc[1], acc[1], acc[4])
emit("stmia r0!, {r%s}", acc[0])
emit("stmia r0!, {r%s}", acc[1])
print ""
#### reset y and z pointers
emit("sub r0, %s", (2 * init_size + 3) * 4)
emit("sub r2, %s", (init_size + 3) * 4)
#### load y registers
emit("ldmia r2!, {%s}", ", ".join(["r%s" % (ry[i]) for i in xrange(3)]))
#### load additional x registers
if init_size != 3:
emit("ldmia r1!, {%s}", ", ".join(["r%s" % (rx[i]) for i in xrange(init_size, 3)]))
print ""
prev_size = init_size
for row in xrange(full_rows):
emit("umull r11, r12, r3, r6")
emit("stmia r0!, {r11}")
print ""
emit("mov r10, #0")
emit("umull r11, r9, r3, r7")
emit("adds r12, r12, r11")
emit("adc r9, r9, #0")
emit("umull r11, r14, r4, r6")
emit("adds r12, r12, r11")
emit("adcs r9, r9, r14")
emit("adc r10, r10, #0")
emit("stmia r0!, {r12}")
print ""
acc = [9, 10, 11, 12, 14]
emit("mov r%s, #0", acc[2])
for i in xrange(0, 3):
emit("umull r%s, r%s, r%s, r%s", acc[3], acc[4], rx[i], ry[2 - i])
emit("adds r%s, r%s, r%s", acc[0], acc[0], acc[3])
emit("adcs r%s, r%s, r%s", acc[1], acc[1], acc[4])
emit("adc r%s, r%s, #0", acc[2], acc[2])
emit("stmia r0!, {r%s}", acc[0])
print ""
acc = acc[1:] + acc[:1]
#### now we need to start shifting x and loading from z
x_regs = [3, 4, 5]
for r in xrange(0, prev_size):
x_regs = x_regs[1:] + x_regs[:1]
emit("ldmia r1!, {r%s}", x_regs[2])
emit("mov r%s, #0", acc[2])
for i in xrange(0, 3):
emit("umull r%s, r%s, r%s, r%s", acc[3], acc[4], x_regs[i], ry[2 - i])
emit("adds r%s, r%s, r%s", acc[0], acc[0], acc[3])
emit("adcs r%s, r%s, r%s", acc[1], acc[1], acc[4])
emit("adc r%s, r%s, #0", acc[2], acc[2])
emit("ldr r%s, [r0]", acc[3]) # load stored value from initial block, and add to accumulator
emit("adds r%s, r%s, r%s", acc[0], acc[0], acc[3])
emit("adcs r%s, r%s, #0", acc[1], acc[1])
emit("adc r%s, r%s, #0", acc[2], acc[2])
emit("stmia r0!, {r%s}", acc[0])
print ""
acc = acc[1:] + acc[:1]
# done shifting x, start shifting y
y_regs = [6, 7, 8]
for r in xrange(0, prev_size):
y_regs = y_regs[1:] + y_regs[:1]
emit("ldmia r2!, {r%s}", y_regs[2])
emit("mov r%s, #0", acc[2])
for i in xrange(0, 3):
emit("umull r%s, r%s, r%s, r%s", acc[3], acc[4], x_regs[i], y_regs[2 - i])
emit("adds r%s, r%s, r%s", acc[0], acc[0], acc[3])
emit("adcs r%s, r%s, r%s", acc[1], acc[1], acc[4])
emit("adc r%s, r%s, #0", acc[2], acc[2])
emit("ldr r%s, [r0]", acc[3]) # load stored value from initial block, and add to accumulator
emit("adds r%s, r%s, r%s", acc[0], acc[0], acc[3])
emit("adcs r%s, r%s, #0", acc[1], acc[1])
emit("adc r%s, r%s, #0", acc[2], acc[2])
emit("stmia r0!, {r%s}", acc[0])
print ""
acc = acc[1:] + acc[:1]
# done both shifts, do remaining corner
emit("mov r%s, #0", acc[2])
for i in xrange(0, 2):
emit("umull r%s, r%s, r%s, r%s", acc[3], acc[4], x_regs[i + 1], y_regs[2 - i])
emit("adds r%s, r%s, r%s", acc[0], acc[0], acc[3])
emit("adcs r%s, r%s, r%s", acc[1], acc[1], acc[4])
emit("adc r%s, r%s, #0", acc[2], acc[2])
emit("stmia r0!, {r%s}", acc[0])
print ""
acc = acc[1:] + acc[:1]
emit("umull r%s, r%s, r%s, r%s", acc[3], acc[4], x_regs[2], y_regs[2])
emit("adds r%s, r%s, r%s", acc[0], acc[0], acc[3])
emit("adc r%s, r%s, r%s", acc[1], acc[1], acc[4])
emit("stmia r0!, {r%s}", acc[0])
emit("stmia r0!, {r%s}", acc[1])
print ""
prev_size = prev_size + 3
if row < full_rows - 1:
#### reset x, y and z pointers
emit("sub r0, %s", (2 * prev_size + 3) * 4)
emit("sub r1, %s", prev_size * 4)
emit("sub r2, %s", (prev_size + 3) * 4)
#### load x and y registers
emit("ldmia r1!, {%s}", ",".join(["r%s" % (rx[i]) for i in xrange(3)]))
emit("ldmia r2!, {%s}", ",".join(["r%s" % (ry[i]) for i in xrange(3)]))
print ""

@ -0,0 +1,203 @@
#!/usr/bin/env python
import sys
if len(sys.argv) < 2:
print "Provide the integer size in bytes"
sys.exit(1)
size = int(sys.argv[1])
full_rows = size // 10
init_size = size % 10
if init_size == 0:
full_rows = full_rows - 1
init_size = 10
def rx(i):
return i + 2
def ry(i):
return i + 12
def emit(line, *args):
s = '"' + line + r' \n\t"'
print s % args
#### set up registers
emit("adiw r30, %s", size - init_size) # move z
emit("adiw r28, %s", size - init_size) # move y
for i in xrange(init_size):
emit("ld r%s, x+", rx(i))
for i in xrange(init_size):
emit("ld r%s, y+", ry(i))
emit("ldi r25, 0")
print ""
if init_size == 1:
emit("mul r2, r12")
emit("st z+, r0")
emit("st z+, r1")
else:
#### first two multiplications of initial block
emit("ldi r23, 0")
emit("mul r2, r12")
emit("st z+, r0")
emit("mov r22, r1")
print ""
emit("ldi r24, 0")
emit("mul r2, r13")
emit("add r22, r0")
emit("adc r23, r1")
emit("mul r3, r12")
emit("add r22, r0")
emit("adc r23, r1")
emit("adc r24, r25")
emit("st z+, r22")
print ""
#### rest of initial block, with moving accumulator registers
acc = [23, 24, 22]
for r in xrange(2, init_size):
emit("ldi r%s, 0", acc[2])
for i in xrange(0, r+1):
emit("mul r%s, r%s", rx(i), ry(r - i))
emit("add r%s, r0", acc[0])
emit("adc r%s, r1", acc[1])
emit("adc r%s, r25", acc[2])
emit("st z+, r%s", acc[0])
print ""
acc = acc[1:] + acc[:1]
for r in xrange(1, init_size-1):
emit("ldi r%s, 0", acc[2])
for i in xrange(0, init_size-r):
emit("mul r%s, r%s", rx(r+i), ry((init_size-1) - i))
emit("add r%s, r0", acc[0])
emit("adc r%s, r1", acc[1])
emit("adc r%s, r25", acc[2])
emit("st z+, r%s", acc[0])
print ""
acc = acc[1:] + acc[:1]
emit("mul r%s, r%s", rx(init_size-1), ry(init_size-1))
emit("add r%s, r0", acc[0])
emit("adc r%s, r1", acc[1])
emit("st z+, r%s", acc[0])
emit("st z+, r%s", acc[1])
print ""
#### reset y and z pointers
emit("sbiw r30, %s", 2 * init_size + 10)
emit("sbiw r28, %s", init_size + 10)
#### load y registers
for i in xrange(10):
emit("ld r%s, y+", ry(i))
#### load additional x registers
for i in xrange(init_size, 10):
emit("ld r%s, x+", rx(i))
print ""
prev_size = init_size
for row in xrange(full_rows):
#### do x = 0-9, y = 0-9 multiplications
emit("ldi r23, 0")
emit("mul r2, r12")
emit("st z+, r0")
emit("mov r22, r1")
print ""
emit("ldi r24, 0")
emit("mul r2, r13")
emit("add r22, r0")
emit("adc r23, r1")
emit("mul r3, r12")
emit("add r22, r0")
emit("adc r23, r1")
emit("adc r24, r25")
emit("st z+, r22")
print ""
acc = [23, 24, 22]
for r in xrange(2, 10):
emit("ldi r%s, 0", acc[2])
for i in xrange(0, r+1):
emit("mul r%s, r%s", rx(i), ry(r - i))
emit("add r%s, r0", acc[0])
emit("adc r%s, r1", acc[1])
emit("adc r%s, r25", acc[2])
emit("st z+, r%s", acc[0])
print ""
acc = acc[1:] + acc[:1]
#### now we need to start shifting x and loading from z
x_regs = [2, 3, 4, 5, 6, 7, 8, 9, 10, 11]
for r in xrange(0, prev_size):
x_regs = x_regs[1:] + x_regs[:1]
emit("ld r%s, x+", x_regs[9]) # load next byte of left
emit("ldi r%s, 0", acc[2])
for i in xrange(0, 10):
emit("mul r%s, r%s", x_regs[i], ry(9 - i))
emit("add r%s, r0", acc[0])
emit("adc r%s, r1", acc[1])
emit("adc r%s, r25", acc[2])
emit("ld r0, z") # load stored value from initial block, and add to accumulator (note z does not increment)
emit("add r%s, r0", acc[0])
emit("adc r%s, r25", acc[1])
emit("adc r%s, r25", acc[2])
emit("st z+, r%s", acc[0]) # store next byte (z increments)
print ""
acc = acc[1:] + acc[:1]
# done shifting x, start shifting y
y_regs = [12, 13, 14, 15, 16, 17, 18, 19, 20, 21]
for r in xrange(0, prev_size):
y_regs = y_regs[1:] + y_regs[:1]
emit("ld r%s, y+", y_regs[9]) # load next byte of right
emit("ldi r%s, 0", acc[2])
for i in xrange(0, 10):
emit("mul r%s, r%s", x_regs[i], y_regs[9 -i])
emit("add r%s, r0", acc[0])
emit("adc r%s, r1", acc[1])
emit("adc r%s, r25", acc[2])
emit("ld r0, z") # load stored value from initial block, and add to accumulator (note z does not increment)
emit("add r%s, r0", acc[0])
emit("adc r%s, r25", acc[1])
emit("adc r%s, r25", acc[2])
emit("st z+, r%s", acc[0]) # store next byte (z increments)
print ""
acc = acc[1:] + acc[:1]
# done both shifts, do remaining corner
for r in xrange(1, 9):
emit("ldi r%s, 0", acc[2])
for i in xrange(0, 10-r):
emit("mul r%s, r%s", x_regs[r+i], y_regs[9 - i])
emit("add r%s, r0", acc[0])
emit("adc r%s, r1", acc[1])
emit("adc r%s, r25", acc[2])
emit("st z+, r%s", acc[0])
print ""
acc = acc[1:] + acc[:1]
emit("mul r%s, r%s", x_regs[9], y_regs[9])
emit("add r%s, r0", acc[0])
emit("adc r%s, r1", acc[1])
emit("st z+, r%s", acc[0])
emit("st z+, r%s", acc[1])
print ""
prev_size = prev_size + 10
if row < full_rows - 1:
#### reset x, y and z pointers
emit("sbiw r30, %s", 2 * prev_size + 10)
emit("sbiw r28, %s", prev_size + 10)
emit("sbiw r26, %s", prev_size)
#### load x and y registers
for i in xrange(10):
emit("ld r%s, x+", rx(i))
emit("ld r%s, y+", ry(i))
print ""
emit("eor r1, r1")

@ -0,0 +1,143 @@
#!/usr/bin/env python
import sys
if len(sys.argv) < 2:
print "Provide the integer size in bytes"
sys.exit(1)
size = int(sys.argv[1])
def lhi(i):
return i + 2
def rhi(i):
return i + 6
left_lo = [10, 11, 12, 13]
right_lo = [14, 15, 16, 17]
def llo(i):
return left_lo[i]
def rlo(i):
return right_lo[i]
def emit(line, *args):
s = '"' + line + r' \n\t"'
print s % args
def update_low():
global left_lo
global right_lo
left_lo = left_lo[1:] + left_lo[:1]
right_lo = right_lo[1:] + right_lo[:1]
emit("ld r%s, x+", left_lo[3])
emit("ld r%s, y+", right_lo[3])
accum = [19, 20, 21]
def acc(i):
return accum[i]
def rotate_acc():
global accum
accum = accum[1:] + accum[:1]
# Load high values
for i in xrange(4):
emit("ld r%s, x+", lhi(i))
emit("ld r%s, y+", rhi(i))
emit("sbiw r26, %s", size + 4)
emit("sbiw r28, %s", size + 4)
emit("sbiw r30, %s", size)
# Load low values
for i in xrange(4):
emit("ld r%s, x+", llo(i))
emit("ld r%s, y+", rlo(i))
print ""
# Compute initial triangles
emit("mul r%s, r%s", lhi(0), rlo(0))
emit("mov r%s, r0", acc(0))
emit("mov r%s, r1", acc(1))
emit("ldi r%s, 0", acc(2))
emit("ld r0, z")
emit("add r%s, r0", acc(0))
emit("adc r%s, r25", acc(1))
emit("mul r%s, r%s", rhi(0), llo(0))
emit("add r%s, r0", acc(0))
emit("adc r%s, r1", acc(1))
emit("adc r%s, r25", acc(2))
emit("st z+, r%s", acc(0))
print ""
rotate_acc()
for i in xrange(1, 4):
emit("ldi r%s, 0", acc(2))
emit("ld r0, z")
emit("add r%s, r0", acc(0))
emit("adc r%s, r25", acc(1))
for j in xrange(i + 1):
emit("mul r%s, r%s", lhi(j), rlo(i-j))
emit("add r%s, r0", acc(0))
emit("adc r%s, r1", acc(1))
emit("adc r%s, r25", acc(2))
emit("mul r%s, r%s", rhi(j), llo(i-j))
emit("add r%s, r0", acc(0))
emit("adc r%s, r1", acc(1))
emit("adc r%s, r25", acc(2))
emit("st z+, r%s", acc(0))
print ""
rotate_acc()
# Compute rows overlapping old block
for i in xrange(4, size):
emit("ldi r%s, 0", acc(2))
emit("ld r0, z")
emit("add r%s, r0", acc(0))
emit("adc r%s, r25", acc(1))
update_low()
for j in xrange(4):
emit("mul r%s, r%s", lhi(j), rlo(3-j))
emit("add r%s, r0", acc(0))
emit("adc r%s, r1", acc(1))
emit("adc r%s, r25", acc(2))
emit("mul r%s, r%s", rhi(j), llo(3-j))
emit("add r%s, r0", acc(0))
emit("adc r%s, r1", acc(1))
emit("adc r%s, r25", acc(2))
emit("st z+, r%s", acc(0))
print ""
rotate_acc()
# Compute new triangle
left_combined = [llo(1), llo(2), llo(3), lhi(0), lhi(1), lhi(2), lhi(3)]
right_combined = [rlo(1), rlo(2), rlo(3), rhi(0), rhi(1), rhi(2), rhi(3)]
def left(i):
return left_combined[i]
def right(i):
return right_combined[i]
for i in xrange(6):
emit("ldi r%s, 0", acc(2))
for j in xrange(7 - i):
emit("mul r%s, r%s", left(i+j), right(6-j))
emit("add r%s, r0", acc(0))
emit("adc r%s, r1", acc(1))
emit("adc r%s, r25", acc(2))
emit("st z+, r%s", acc(0))
print ""
rotate_acc()
emit("mul r%s, r%s", left(6), right(6))
emit("add r%s, r0", acc(0))
emit("adc r%s, r1", acc(1))
emit("st z+, r%s", acc(0))
emit("st z+, r%s", acc(1))
emit("adiw r26, 4")
emit("adiw r28, 4")

@ -0,0 +1,242 @@
#!/usr/bin/env python
import sys
if len(sys.argv) < 2:
print "Provide the integer size in 32-bit words"
sys.exit(1)
size = int(sys.argv[1])
if size > 8:
print "This script doesn't work with integer size %s due to laziness" % (size)
sys.exit(1)
init_size = 0
if size > 6:
init_size = size - 6
def emit(line, *args):
s = '"' + line + r' \n\t"'
print s % args
def mulacc(acc, r1, r2):
if size <= 6:
emit("umull r1, r14, r%s, r%s", r1, r2)
emit("adds r%s, r%s, r1", acc[0], acc[0])
emit("adcs r%s, r%s, r14", acc[1], acc[1])
emit("adc r%s, r%s, #0", acc[2], acc[2])
else:
emit("mov r14, r%s", acc[1])
emit("umlal r%s, r%s, r%s, r%s", acc[0], acc[1], r1, r2)
emit("cmp r14, r%s", acc[1])
emit("it hi")
emit("adchi r%s, r%s, #0", acc[2], acc[2])
r = [2, 3, 4, 5, 6, 7]
s = size - init_size
if init_size == 1:
emit("ldmia r1!, {r2}")
emit("add r1, %s", (size - init_size * 2) * 4)
emit("ldmia r1!, {r5}")
emit("add r0, %s", (size - init_size) * 4)
emit("umull r8, r9, r2, r5")
emit("stmia r0!, {r8, r9}")
emit("sub r0, %s", (size + init_size) * 4)
emit("sub r1, %s", (size) * 4)
print ""
elif init_size == 2:
emit("ldmia r1!, {r2, r3}")
emit("add r1, %s", (size - init_size * 2) * 4)
emit("ldmia r1!, {r5, r6}")
emit("add r0, %s", (size - init_size) * 4)
print ""
emit("umull r8, r9, r2, r5")
emit("stmia r0!, {r8}")
print ""
emit("umull r12, r10, r2, r6")
emit("adds r9, r9, r12")
emit("adc r10, r10, #0")
emit("stmia r0!, {r9}")
print ""
emit("umull r8, r9, r3, r6")
emit("adds r10, r10, r8")
emit("adc r11, r9, #0")
emit("stmia r0!, {r10, r11}")
print ""
emit("sub r0, %s", (size + init_size) * 4)
emit("sub r1, %s", (size) * 4)
# load input words
emit("ldmia r1!, {%s}", ", ".join(["r%s" % (r[i]) for i in xrange(s)]))
print ""
emit("umull r11, r12, r2, r2")
emit("stmia r0!, {r11}")
print ""
emit("mov r9, #0")
emit("umull r10, r11, r2, r3")
emit("adds r12, r12, r10")
emit("adcs r8, r11, #0")
emit("adc r9, r9, #0")
emit("adds r12, r12, r10")
emit("adcs r8, r8, r11")
emit("adc r9, r9, #0")
emit("stmia r0!, {r12}")
print ""
emit("mov r10, #0")
emit("umull r11, r12, r2, r4")
emit("adds r11, r11, r11")
emit("adcs r12, r12, r12")
emit("adc r10, r10, #0")
emit("adds r8, r8, r11")
emit("adcs r9, r9, r12")
emit("adc r10, r10, #0")
emit("umull r11, r12, r3, r3")
emit("adds r8, r8, r11")
emit("adcs r9, r9, r12")
emit("adc r10, r10, #0")
emit("stmia r0!, {r8}")
print ""
acc = [8, 9, 10]
old_acc = [11, 12]
for i in xrange(3, s):
emit("mov r%s, #0", old_acc[1])
tmp = [acc[1], acc[2]]
acc = [acc[0], old_acc[0], old_acc[1]]
old_acc = tmp
# gather non-equal words
emit("umull r%s, r%s, r%s, r%s", acc[0], acc[1], r[0], r[i])
for j in xrange(1, (i+1)//2):
mulacc(acc, r[j], r[i-j])
# multiply by 2
emit("adds r%s, r%s, r%s", acc[0], acc[0], acc[0])
emit("adcs r%s, r%s, r%s", acc[1], acc[1], acc[1])
emit("adc r%s, r%s, r%s", acc[2], acc[2], acc[2])
# add equal word (if any)
if ((i+1) % 2) != 0:
mulacc(acc, r[i//2], r[i//2])
# add old accumulator
emit("adds r%s, r%s, r%s", acc[0], acc[0], old_acc[0])
emit("adcs r%s, r%s, r%s", acc[1], acc[1], old_acc[1])
emit("adc r%s, r%s, #0", acc[2], acc[2])
# store
emit("stmia r0!, {r%s}", acc[0])
print ""
regs = list(r)
for i in xrange(init_size):
regs = regs[1:] + regs[:1]
emit("ldmia r1!, {r%s}", regs[5])
for limit in [4, 5]:
emit("mov r%s, #0", old_acc[1])
tmp = [acc[1], acc[2]]
acc = [acc[0], old_acc[0], old_acc[1]]
old_acc = tmp
# gather non-equal words
emit("umull r%s, r%s, r%s, r%s", acc[0], acc[1], regs[0], regs[limit])
for j in xrange(1, (limit+1)//2):
mulacc(acc, regs[j], regs[limit-j])
emit("ldr r14, [r0]") # load stored value from initial block, and add to accumulator
emit("adds r%s, r%s, r14", acc[0], acc[0])
emit("adcs r%s, r%s, #0", acc[1], acc[1])
emit("adc r%s, r%s, #0", acc[2], acc[2])
# multiply by 2
emit("adds r%s, r%s, r%s", acc[0], acc[0], acc[0])
emit("adcs r%s, r%s, r%s", acc[1], acc[1], acc[1])
emit("adc r%s, r%s, r%s", acc[2], acc[2], acc[2])
# add equal word
if limit == 4:
mulacc(acc, regs[2], regs[2])
# add old accumulator
emit("adds r%s, r%s, r%s", acc[0], acc[0], old_acc[0])
emit("adcs r%s, r%s, r%s", acc[1], acc[1], old_acc[1])
emit("adc r%s, r%s, #0", acc[2], acc[2])
# store
emit("stmia r0!, {r%s}", acc[0])
print ""
for i in xrange(1, s-3):
emit("mov r%s, #0", old_acc[1])
tmp = [acc[1], acc[2]]
acc = [acc[0], old_acc[0], old_acc[1]]
old_acc = tmp
# gather non-equal words
emit("umull r%s, r%s, r%s, r%s", acc[0], acc[1], regs[i], regs[s - 1])
for j in xrange(1, (s-i)//2):
mulacc(acc, regs[i+j], regs[s - 1 - j])
# multiply by 2
emit("adds r%s, r%s, r%s", acc[0], acc[0], acc[0])
emit("adcs r%s, r%s, r%s", acc[1], acc[1], acc[1])
emit("adc r%s, r%s, r%s", acc[2], acc[2], acc[2])
# add equal word (if any)
if ((s-i) % 2) != 0:
mulacc(acc, regs[i + (s-i)//2], regs[i + (s-i)//2])
# add old accumulator
emit("adds r%s, r%s, r%s", acc[0], acc[0], old_acc[0])
emit("adcs r%s, r%s, r%s", acc[1], acc[1], old_acc[1])
emit("adc r%s, r%s, #0", acc[2], acc[2])
# store
emit("stmia r0!, {r%s}", acc[0])
print ""
acc = acc[1:] + acc[:1]
emit("mov r%s, #0", acc[2])
emit("umull r1, r%s, r%s, r%s", old_acc[1], regs[s - 3], regs[s - 1])
emit("adds r1, r1, r1")
emit("adcs r%s, r%s, r%s", old_acc[1], old_acc[1], old_acc[1])
emit("adc r%s, r%s, #0", acc[2], acc[2])
emit("adds r%s, r%s, r1", acc[0], acc[0])
emit("adcs r%s, r%s, r%s", acc[1], acc[1], old_acc[1])
emit("adc r%s, r%s, #0", acc[2], acc[2])
emit("umull r1, r%s, r%s, r%s", old_acc[1], regs[s - 2], regs[s - 2])
emit("adds r%s, r%s, r1", acc[0], acc[0])
emit("adcs r%s, r%s, r%s", acc[1], acc[1], old_acc[1])
emit("adc r%s, r%s, #0", acc[2], acc[2])
emit("stmia r0!, {r%s}", acc[0])
print ""
acc = acc[1:] + acc[:1]
emit("mov r%s, #0", acc[2])
emit("umull r1, r%s, r%s, r%s", old_acc[1], regs[s - 2], regs[s - 1])
emit("adds r1, r1, r1")
emit("adcs r%s, r%s, r%s", old_acc[1], old_acc[1], old_acc[1])
emit("adc r%s, r%s, #0", acc[2], acc[2])
emit("adds r%s, r%s, r1", acc[0], acc[0])
emit("adcs r%s, r%s, r%s", acc[1], acc[1], old_acc[1])
emit("adc r%s, r%s, #0", acc[2], acc[2])
emit("stmia r0!, {r%s}", acc[0])
print ""
acc = acc[1:] + acc[:1]
emit("umull r1, r%s, r%s, r%s", old_acc[1], regs[s - 1], regs[s - 1])
emit("adds r%s, r%s, r1", acc[0], acc[0])
emit("adcs r%s, r%s, r%s", acc[1], acc[1], old_acc[1])
emit("stmia r0!, {r%s}", acc[0])
emit("stmia r0!, {r%s}", acc[1])

@ -0,0 +1,327 @@
#!/usr/bin/env python
import sys
if len(sys.argv) < 2:
print "Provide the integer size in bytes"
sys.exit(1)
size = int(sys.argv[1])
if size > 40:
print "This script doesn't work with integer size %s due to laziness" % (size)
sys.exit(1)
init_size = size - 20
if size < 20:
init_size = 0
def rg(i):
return i + 2
def lo(i):
return i + 2
def hi(i):
return i + 12
def emit(line, *args):
s = '"' + line + r' \n\t"'
print s % args
#### set up registers
zero = "r25"
emit("ldi %s, 0", zero) # zero register
if init_size > 0:
emit("movw r28, r26") # y = x
h = (init_size + 1)//2
for i in xrange(h):
emit("ld r%s, x+", lo(i))
emit("adiw r28, %s", size - init_size) # move y to other end
for i in xrange(h):
emit("ld r%s, y+", hi(i))
emit("adiw r30, %s", size - init_size) # move z
if init_size == 1:
emit("mul %s, %s", lo(0), hi(0))
emit("st z+, r0")
emit("st z+, r1")
else:
#### first one
print ""
emit("ldi r23, 0")
emit("mul %s, %s", lo(0), hi(0))
emit("st z+, r0")
emit("mov r22, r1")
print ""
#### rest of initial block, with moving accumulator registers
acc = [22, 23, 24]
for r in xrange(1, h):
emit("ldi r%s, 0", acc[2])
for i in xrange(0, (r+2)//2):
emit("mul r%s, r%s", lo(i), hi(r - i))
emit("add r%s, r0", acc[0])
emit("adc r%s, r1", acc[1])
emit("adc r%s, %s", acc[2], zero)
emit("st z+, r%s", acc[0])
print ""
acc = acc[1:] + acc[:1]
lo_r = range(2, 2 + h)
hi_r = range(12, 12 + h)
# now we need to start loading more from the high end
for r in xrange(h, init_size):
hi_r = hi_r[1:] + hi_r[:1]
emit("ld r%s, y+", hi_r[h-1])
emit("ldi r%s, 0", acc[2])
for i in xrange(0, (r+2)//2):
emit("mul r%s, r%s", lo(i), hi_r[h - 1 - i])
emit("add r%s, r0", acc[0])
emit("adc r%s, r1", acc[1])
emit("adc r%s, %s", acc[2], zero)
emit("st z+, r%s", acc[0])
print ""
acc = acc[1:] + acc[:1]
# loaded all of the high end bytes; now need to start loading the rest of the low end
for r in xrange(1, init_size-h):
lo_r = lo_r[1:] + lo_r[:1]
emit("ld r%s, x+", lo_r[h-1])
emit("ldi r%s, 0", acc[2])
for i in xrange(0, (init_size+1 - r)//2):
emit("mul r%s, r%s", lo_r[i], hi_r[h - 1 - i])
emit("add r%s, r0", acc[0])
emit("adc r%s, r1", acc[1])
emit("adc r%s, %s", acc[2], zero)
emit("st z+, r%s", acc[0])
print ""
acc = acc[1:] + acc[:1]
lo_r = lo_r[1:] + lo_r[:1]
emit("ld r%s, x+", lo_r[h-1])
# now we have loaded everything, and we just need to finish the last corner
for r in xrange(init_size-h, init_size-1):
emit("ldi r%s, 0", acc[2])
for i in xrange(0, (init_size+1 - r)//2):
emit("mul r%s, r%s", lo_r[i], hi_r[h - 1 - i])
emit("add r%s, r0", acc[0])
emit("adc r%s, r1", acc[1])
emit("adc r%s, %s", acc[2], zero)
emit("st z+, r%s", acc[0])
print ""
acc = acc[1:] + acc[:1]
lo_r = lo_r[1:] + lo_r[:1] # make the indexing easy
emit("mul r%s, r%s", lo_r[0], hi_r[h - 1])
emit("add r%s, r0", acc[0])
emit("adc r%s, r1", acc[1])
emit("st z+, r%s", acc[0])
emit("st z+, r%s", acc[1])
print ""
emit("sbiw r26, %s", init_size) # reset x
emit("sbiw r30, %s", size + init_size) # reset z
# TODO you could do more rows of size 20 here if your integers are larger than 40 bytes
s = size - init_size
for i in xrange(s):
emit("ld r%s, x+", rg(i))
#### first few columns
# NOTE: this is only valid if size >= 3
print ""
emit("ldi r23, 0")
emit("mul r%s, r%s", rg(0), rg(0))
emit("st z+, r0")
emit("mov r22, r1")
print ""
emit("ldi r24, 0")
emit("mul r%s, r%s", rg(0), rg(1))
emit("add r22, r0")
emit("adc r23, r1")
emit("adc r24, %s", zero)
emit("add r22, r0")
emit("adc r23, r1")
emit("adc r24, %s", zero)
emit("st z+, r22")
print ""
emit("ldi r22, 0")
emit("mul r%s, r%s", rg(0), rg(2))
emit("add r23, r0")
emit("adc r24, r1")
emit("adc r22, %s", zero)
emit("add r23, r0")
emit("adc r24, r1")
emit("adc r22, %s", zero)
emit("mul r%s, r%s", rg(1), rg(1))
emit("add r23, r0")
emit("adc r24, r1")
emit("adc r22, %s", zero)
emit("st z+, r23")
print ""
acc = [23, 24, 22]
old_acc = [28, 29]
for i in xrange(3, s):
emit("ldi r%s, 0", old_acc[1])
tmp = [acc[1], acc[2]]
acc = [acc[0], old_acc[0], old_acc[1]]
old_acc = tmp
# gather non-equal words
emit("mul r%s, r%s", rg(0), rg(i))
emit("mov r%s, r0", acc[0])
emit("mov r%s, r1", acc[1])
for j in xrange(1, (i+1)//2):
emit("mul r%s, r%s", rg(j), rg(i-j))
emit("add r%s, r0", acc[0])
emit("adc r%s, r1", acc[1])
emit("adc r%s, %s", acc[2], zero)
# multiply by 2
emit("lsl r%s", acc[0])
emit("rol r%s", acc[1])
emit("rol r%s", acc[2])
# add equal word (if any)
if ((i+1) % 2) != 0:
emit("mul r%s, r%s", rg(i//2), rg(i//2))
emit("add r%s, r0", acc[0])
emit("adc r%s, r1", acc[1])
emit("adc r%s, %s", acc[2], zero)
# add old accumulator
emit("add r%s, r%s", acc[0], old_acc[0])
emit("adc r%s, r%s", acc[1], old_acc[1])
emit("adc r%s, %s", acc[2], zero)
# store
emit("st z+, r%s", acc[0])
print ""
regs = range(2, 22)
for i in xrange(init_size):
regs = regs[1:] + regs[:1]
emit("ld r%s, x+", regs[19])
for limit in [18, 19]:
emit("ldi r%s, 0", old_acc[1])
tmp = [acc[1], acc[2]]
acc = [acc[0], old_acc[0], old_acc[1]]
old_acc = tmp
# gather non-equal words
emit("mul r%s, r%s", regs[0], regs[limit])
emit("mov r%s, r0", acc[0])
emit("mov r%s, r1", acc[1])
for j in xrange(1, (limit+1)//2):
emit("mul r%s, r%s", regs[j], regs[limit-j])
emit("add r%s, r0", acc[0])
emit("adc r%s, r1", acc[1])
emit("adc r%s, %s", acc[2], zero)
emit("ld r0, z") # load stored value from initial block, and add to accumulator (note z does not increment)
emit("add r%s, r0", acc[0])
emit("adc r%s, r25", acc[1])
emit("adc r%s, r25", acc[2])
# multiply by 2
emit("lsl r%s", acc[0])
emit("rol r%s", acc[1])
emit("rol r%s", acc[2])
# add equal word
if limit == 18:
emit("mul r%s, r%s", regs[9], regs[9])
emit("add r%s, r0", acc[0])
emit("adc r%s, r1", acc[1])
emit("adc r%s, %s", acc[2], zero)
# add old accumulator
emit("add r%s, r%s", acc[0], old_acc[0])
emit("adc r%s, r%s", acc[1], old_acc[1])
emit("adc r%s, %s", acc[2], zero)
# store
emit("st z+, r%s", acc[0])
print ""
for i in xrange(1, s-3):
emit("ldi r%s, 0", old_acc[1])
tmp = [acc[1], acc[2]]
acc = [acc[0], old_acc[0], old_acc[1]]
old_acc = tmp
# gather non-equal words
emit("mul r%s, r%s", regs[i], regs[s - 1])
emit("mov r%s, r0", acc[0])
emit("mov r%s, r1", acc[1])
for j in xrange(1, (s-i)//2):
emit("mul r%s, r%s", regs[i+j], regs[s - 1 - j])
emit("add r%s, r0", acc[0])
emit("adc r%s, r1", acc[1])
emit("adc r%s, %s", acc[2], zero)
# multiply by 2
emit("lsl r%s", acc[0])
emit("rol r%s", acc[1])
emit("rol r%s", acc[2])
# add equal word (if any)
if ((s-i) % 2) != 0:
emit("mul r%s, r%s", regs[i + (s-i)//2], regs[i + (s-i)//2])
emit("add r%s, r0", acc[0])
emit("adc r%s, r1", acc[1])
emit("adc r%s, %s", acc[2], zero)
# add old accumulator
emit("add r%s, r%s", acc[0], old_acc[0])
emit("adc r%s, r%s", acc[1], old_acc[1])
emit("adc r%s, %s", acc[2], zero)
# store
emit("st z+, r%s", acc[0])
print ""
acc = acc[1:] + acc[:1]
emit("ldi r%s, 0", acc[2])
emit("mul r%s, r%s", regs[17], regs[19])
emit("add r%s, r0", acc[0])
emit("adc r%s, r1", acc[1])
emit("adc r%s, %s", acc[2], zero)
emit("add r%s, r0", acc[0])
emit("adc r%s, r1", acc[1])
emit("adc r%s, %s", acc[2], zero)
emit("mul r%s, r%s", regs[18], regs[18])
emit("add r%s, r0", acc[0])
emit("adc r%s, r1", acc[1])
emit("adc r%s, %s", acc[2], zero)
emit("st z+, r%s", acc[0])
print ""
acc = acc[1:] + acc[:1]
emit("ldi r%s, 0", acc[2])
emit("mul r%s, r%s", regs[18], regs[19])
emit("add r%s, r0", acc[0])
emit("adc r%s, r1", acc[1])
emit("adc r%s, %s", acc[2], zero)
emit("add r%s, r0", acc[0])
emit("adc r%s, r1", acc[1])
emit("adc r%s, %s", acc[2], zero)
emit("st z+, r%s", acc[0])
print ""
emit("mul r%s, r%s", regs[19], regs[19])
emit("add r%s, r0", acc[1])
emit("adc r%s, r1", acc[2])
emit("st z+, r%s", acc[1])
emit("st z+, r%s", acc[2])
emit("eor r1, r1")

@ -0,0 +1,128 @@
/* Copyright 2020, Kenneth MacKay. Licensed under the BSD 2-clause license. */
#include "uECC.h"
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
typedef struct {
const char* private_key;
const char* public_key;
const char* k;
const char* hash;
const char* r;
const char* s;
} Test;
Test secp256k1_tests[] = {
{
"ebb2c082fd7727890a28ac82f6bdf97bad8de9f5d7c9028692de1a255cad3e0f",
"779dd197a5df977ed2cf6cb31d82d43328b790dc6b3b7d4437a427bd5847dfcde94b724a555b6d017bb7607c3e3281daf5b1699d6ef4124975c9237b917d426f",
"49a0d7b786ec9cde0d0721d72804befd06571c974b191efb42ecf322ba9ddd9a",
"4b688df40bcedbe641ddb16ff0a1842d9c67ea1c3bf63f3e0471baa664531d1a",
"241097efbf8b63bf145c8961dbdf10c310efbb3b2676bbc0f8b08505c9e2f795",
"021006b7838609339e8b415a7f9acb1b661828131aef1ecbc7955dfb01f3ca0e"
},
};
extern int uECC_sign_with_k(const uint8_t *private_key,
const uint8_t *message_hash,
unsigned hash_size,
const uint8_t *k,
uint8_t *signature,
uECC_Curve curve);
void vli_print(uint8_t *vli, unsigned int size) {
for(unsigned i=0; i<size; ++i) {
printf("%02X ", (unsigned)vli[i]);
}
printf("\n");
}
void strtobytes(const char* str, uint8_t* bytes, int count) {
for (int c = 0; c < count; ++c) {
if (sscanf(str, "%2hhx", &bytes[c]) != 1) {
printf("Failed to read string to bytes");
exit(1);
}
str += 2;
}
}
int run(Test* tests, int num_tests, uECC_Curve curve) {
uint8_t private[32] = {0};
uint8_t public[64] = {0};
uint8_t k[32] = {0};
uint8_t hash[32] = {0};
uint8_t r[32] = {0};
uint8_t s[32] = {0};
uint8_t signature[64] = {0};
int result;
int i;
int private_key_size;
int public_key_size;
int all_success = 1;
private_key_size = uECC_curve_private_key_size(curve);
public_key_size = uECC_curve_public_key_size(curve);
for (i = 0; i < num_tests; ++i) {
strtobytes(tests[i].private_key, private, private_key_size);
strtobytes(tests[i].public_key, public, public_key_size);
strtobytes(tests[i].k, k, private_key_size);
strtobytes(tests[i].hash, hash, private_key_size);
strtobytes(tests[i].r, r, private_key_size);
strtobytes(tests[i].s, s, private_key_size);
result = uECC_sign_with_k(private, hash, private_key_size, k, signature, curve);
if (!result) {
all_success = 0;
printf(" Sign failed for test %d\n", i);
}
if (result) {
if (memcmp(signature, r, private_key_size) != 0) {
all_success = 0;
printf(" Got incorrect r for test %d\n", i);
printf(" Expected: ");
vli_print(r, private_key_size);
printf(" Calculated: ");
vli_print(signature, private_key_size);
}
if (memcmp(signature + private_key_size, s, private_key_size) != 0) {
all_success = 0;
printf(" Got incorrect s for test %d\n", i);
printf(" Expected: ");
vli_print(s, private_key_size);
printf(" Calculated: ");
vli_print(signature + private_key_size, private_key_size);
}
result = uECC_verify(public, hash, private_key_size, signature, curve);
if (!result) {
printf(" Verify failed for test %d\n", i);
}
}
}
return all_success;
}
#define RUN_TESTS(curve) \
printf(#curve ":\n"); \
if (run(curve##_tests, sizeof(curve##_tests) / sizeof(curve##_tests[0]), uECC_##curve()) ) { \
printf(" All passed\n"); \
} else { \
printf(" Failed\n"); \
}
int main() {
#if uECC_SUPPORTS_secp256k1
RUN_TESTS(secp256k1)
#endif
return 0;
}

@ -0,0 +1,4 @@
c, link = emk.module("c", "link")
link.depdirs += [
"$:proj:$"
]

@ -0,0 +1,338 @@
/* Copyright 2020, Kenneth MacKay. Licensed under the BSD 2-clause license. */
#include "uECC.h"
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
typedef struct {
const char* k;
const char* Q;
int success;
} Test;
Test secp160r1_tests[] = {
/* Note, I couldn't find any test vectors for secp160r1 online, so these are just
generated on my desktop using uECC. */
{
"000000000000000000000000000000000000000000",
"00000000000000000000000000000000000000000000000000000000000000000000000000000000",
0
},
{
"000000000000000000000000000000000000000001",
"00000000000000000000000000000000000000000000000000000000000000000000000000000000",
0
},
{
"000000000000000000000000000000000000000002",
"02F997F33C5ED04C55D3EDF8675D3E92E8F46686F083A323482993E9440E817E21CFB7737DF8797B",
1
},
{
"000000000000000000000000000000000000000003",
"7B76FF541EF363F2DF13DE1650BD48DAA958BC59C915CA790D8C8877B55BE0079D12854FFE9F6F5A",
1
},
{ /* n - 4 */
"0100000000000000000001F4C8F927AED3CA752253",
"B4041D8683BE99F0AFE01C307B1AD4C100CF2A88C0CD35127BE0F73FF99F338B350B5A42864112F7",
1
},
{ /* n - 3 */
"0100000000000000000001F4C8F927AED3CA752254",
"7B76FF541EF363F2DF13DE1650BD48DAA958BC5936EA3586F27377884AA41FF862ED7AAF816090A5",
1
},
{ /* n - 2 */
"0100000000000000000001F4C8F927AED3CA752255",
"00000000000000000000000000000000000000000000000000000000000000000000000000000000",
0
},
{ /* n - 1 */
"0100000000000000000001F4C8F927AED3CA752256",
"00000000000000000000000000000000000000000000000000000000000000000000000000000000",
0
},
{ /* n */
"0100000000000000000001F4C8F927AED3CA752257",
"00000000000000000000000000000000000000000000000000000000000000000000000000000000",
0
},
};
Test secp192r1_tests[] = {
{
"000000000000000000000000000000000000000000000000",
"000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000",
0
},
{
"000000000000000000000000000000000000000000000001",
"188DA80EB03090F67CBF20EB43A18800F4FF0AFD82FF101207192B95FFC8DA78631011ED6B24CDD573F977A11E794811",
0
},
{
"000000000000000000000000000000000000000000000002",
"DAFEBF5828783F2AD35534631588A3F629A70FB16982A888DD6BDA0D993DA0FA46B27BBC141B868F59331AFA5C7E93AB",
1
},
{
"000000000000000000000000000000000000000000000003",
"76E32A2557599E6EDCD283201FB2B9AADFD0D359CBB263DA782C37E372BA4520AA62E0FED121D49EF3B543660CFD05FD",
1
},
{ /* n - 4 */
"FFFFFFFFFFFFFFFFFFFFFFFF99DEF836146BC9B1B4D2282D",
"35433907297CC378B0015703374729D7A4FE46647084E4BA5D9B667B0DECA3CFE15C534F88932B0DDAC764CEE24C41CD",
1
},
{ /* n - 3 */
"FFFFFFFFFFFFFFFFFFFFFFFF99DEF836146BC9B1B4D2282E",
"76E32A2557599E6EDCD283201FB2B9AADFD0D359CBB263DA87D3C81C8D45BADF559D1F012EDE2B600C4ABC99F302FA02",
1
},
{ /* n - 2 */
"FFFFFFFFFFFFFFFFFFFFFFFF99DEF836146BC9B1B4D2282F",
"DAFEBF5828783F2AD35534631588A3F629A70FB16982A888229425F266C25F05B94D8443EBE4796FA6CCE505A3816C54",
0
},
{ /* n - 1 */
"FFFFFFFFFFFFFFFFFFFFFFFF99DEF836146BC9B1B4D22830",
"188DA80EB03090F67CBF20EB43A18800F4FF0AFD82FF1012F8E6D46A003725879CEFEE1294DB32298C06885EE186B7EE",
0
},
{ /* n */
"FFFFFFFFFFFFFFFFFFFFFFFF99DEF836146BC9B1B4D22831",
"000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000",
0
},
};
Test secp224r1_tests[] = {
{
"00000000000000000000000000000000000000000000000000000000",
"0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000",
0
},
{
"00000000000000000000000000000000000000000000000000000001",
"B70E0CBD6BB4BF7F321390B94A03C1D356C21122343280D6115C1D21BD376388B5F723FB4C22DFE6CD4375A05A07476444D5819985007E34",
0
},
{
"00000000000000000000000000000000000000000000000000000002",
"706A46DC76DCB76798E60E6D89474788D16DC18032D268FD1A704FA61C2B76A7BC25E7702A704FA986892849FCA629487ACF3709D2E4E8BB",
1
},
{
"00000000000000000000000000000000000000000000000000000003",
"DF1B1D66A551D0D31EFF822558B9D2CC75C2180279FE0D08FD896D04A3F7F03CADD0BE444C0AA56830130DDF77D317344E1AF3591981A925",
1
},
{ /* n - 4 */
"FFFFFFFFFFFFFFFFFFFFFFFFFFFF16A2E0B8F03E13DD29455C5C2A39",
"AE99FEEBB5D26945B54892092A8AEE02912930FA41CD114E40447301FB7DA7F5F13A43B81774373C879CD32D6934C05FA758EEB14FCFAB38",
1
},
{ /* n - 3 */
"FFFFFFFFFFFFFFFFFFFFFFFFFFFF16A2E0B8F03E13DD29455C5C2A3A",
"DF1B1D66A551D0D31EFF822558B9D2CC75C2180279FE0D08FD896D045C080FC3522F41BBB3F55A97CFECF21F882CE8CBB1E50CA6E67E56DC",
1
},
{ /* n - 2 */
"FFFFFFFFFFFFFFFFFFFFFFFFFFFF16A2E0B8F03E13DD29455C5C2A3B",
"706A46DC76DCB76798E60E6D89474788D16DC18032D268FD1A704FA6E3D4895843DA188FD58FB0567976D7B50359D6B78530C8F62D1B1746",
0
},
{ /* n - 1 */
"FFFFFFFFFFFFFFFFFFFFFFFFFFFF16A2E0B8F03E13DD29455C5C2A3C",
"B70E0CBD6BB4BF7F321390B94A03C1D356C21122343280D6115C1D2142C89C774A08DC04B3DD201932BC8A5EA5F8B89BBB2A7E667AFF81CD",
0
},
{ /* n */
"FFFFFFFFFFFFFFFFFFFFFFFFFFFF16A2E0B8F03E13DD29455C5C2A3D",
"0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000",
0
},
};
Test secp256r1_tests[] = {
{
"0000000000000000000000000000000000000000000000000000000000000000",
"00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000",
0
},
{
"0000000000000000000000000000000000000000000000000000000000000001",
"6B17D1F2E12C4247F8BCE6E563A440F277037D812DEB33A0F4A13945D898C2964FE342E2FE1A7F9B8EE7EB4A7C0F9E162BCE33576B315ECECBB6406837BF51F5",
0
},
{
"0000000000000000000000000000000000000000000000000000000000000002",
"7CF27B188D034F7E8A52380304B51AC3C08969E277F21B35A60B48FC4766997807775510DB8ED040293D9AC69F7430DBBA7DADE63CE982299E04B79D227873D1",
1
},
{
"0000000000000000000000000000000000000000000000000000000000000003",
"5ECBE4D1A6330A44C8F7EF951D4BF165E6C6B721EFADA985FB41661BC6E7FD6C8734640C4998FF7E374B06CE1A64A2ECD82AB036384FB83D9A79B127A27D5032",
1
},
{ /* n - 4 */
"FFFFFFFF00000000FFFFFFFFFFFFFFFFBCE6FAADA7179E84F3B9CAC2FC63254D",
"E2534A3532D08FBBA02DDE659EE62BD0031FE2DB785596EF509302446B0308521F0EA8A4B39CC339E62011A02579D289B103693D0CF11FFAA3BD3DC0E7B12739",
1
},
{ /* n - 3 */
"FFFFFFFF00000000FFFFFFFFFFFFFFFFBCE6FAADA7179E84F3B9CAC2FC63254E",
"5ECBE4D1A6330A44C8F7EF951D4BF165E6C6B721EFADA985FB41661BC6E7FD6C78CB9BF2B6670082C8B4F931E59B5D1327D54FCAC7B047C265864ED85D82AFCD",
1
},
{ /* n - 2 */
"FFFFFFFF00000000FFFFFFFFFFFFFFFFBCE6FAADA7179E84F3B9CAC2FC63254F",
"7CF27B188D034F7E8A52380304B51AC3C08969E277F21B35A60B48FC47669978F888AAEE24712FC0D6C26539608BCF244582521AC3167DD661FB4862DD878C2E",
0
},
{ /* n - 1 */
"FFFFFFFF00000000FFFFFFFFFFFFFFFFBCE6FAADA7179E84F3B9CAC2FC632550",
"6B17D1F2E12C4247F8BCE6E563A440F277037D812DEB33A0F4A13945D898C296B01CBD1C01E58065711814B583F061E9D431CCA994CEA1313449BF97C840AE0A",
0
},
{ /* n */
"FFFFFFFF00000000FFFFFFFFFFFFFFFFBCE6FAADA7179E84F3B9CAC2FC632551",
"00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000",
0
},
};
Test secp256k1_tests[] = {
{
"0000000000000000000000000000000000000000000000000000000000000000",
"00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000",
0
},
{
"0000000000000000000000000000000000000000000000000000000000000001",
"79BE667EF9DCBBAC55A06295CE870B07029BFCDB2DCE28D959F2815B16F81798483ADA7726A3C4655DA4FBFC0E1108A8FD17B448A68554199C47D08FFB10D4B8",
0
},
{
"0000000000000000000000000000000000000000000000000000000000000002",
"C6047F9441ED7D6D3045406E95C07CD85C778E4B8CEF3CA7ABAC09B95C709EE51AE168FEA63DC339A3C58419466CEAEEF7F632653266D0E1236431A950CFE52A",
1
},
{
"0000000000000000000000000000000000000000000000000000000000000003",
"F9308A019258C31049344F85F89D5229B531C845836F99B08601F113BCE036F9388F7B0F632DE8140FE337E62A37F3566500A99934C2231B6CB9FD7584B8E672",
1
},
{ /* n - 4 */
"FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFEBAAEDCE6AF48A03BBFD25E8CD036413D",
"E493DBF1C10D80F3581E4904930B1404CC6C13900EE0758474FA94ABE8C4CD13AE1266C15F2BAA48A9BD1DF6715AEBB7269851CC404201BF30168422B88C630D",
1
},
{ /* n - 3 */
"FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFEBAAEDCE6AF48A03BBFD25E8CD036413E",
"F9308A019258C31049344F85F89D5229B531C845836F99B08601F113BCE036F9C77084F09CD217EBF01CC819D5C80CA99AFF5666CB3DDCE4934602897B4715BD",
1
},
{ /* n - 2 */
"FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFEBAAEDCE6AF48A03BBFD25E8CD036413F",
"C6047F9441ED7D6D3045406E95C07CD85C778E4B8CEF3CA7ABAC09B95C709EE5E51E970159C23CC65C3A7BE6B99315110809CD9ACD992F1EDC9BCE55AF301705",
0
},
{ /* n - 1 */
"FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFEBAAEDCE6AF48A03BBFD25E8CD0364140",
"79BE667EF9DCBBAC55A06295CE870B07029BFCDB2DCE28D959F2815B16F81798B7C52588D95C3B9AA25B0403F1EEF75702E84BB7597AABE663B82F6F04EF2777",
0
},
{ /* n */
"FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFEBAAEDCE6AF48A03BBFD25E8CD0364141",
"00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000",
0
},
};
void vli_print(uint8_t *vli, unsigned int size) {
for(unsigned i=0; i<size; ++i) {
printf("%02X ", (unsigned)vli[i]);
}
printf("\n");
}
void strtobytes(const char* str, uint8_t* bytes, int count) {
for (int c = 0; c < count; ++c) {
if (sscanf(str, "%2hhx", &bytes[c]) != 1) {
printf("Failed to read string to bytes");
exit(1);
}
str += 2;
}
}
int run(Test* tests, int num_tests, uECC_Curve curve) {
uint8_t private[32] = {0};
uint8_t public[64] = {0};
uint8_t expected[64] = {0};
int result;
int i;
int private_key_size;
int public_key_size;
int all_success = 1;
private_key_size = uECC_curve_private_key_size(curve);
public_key_size = uECC_curve_public_key_size(curve);
for (i = 0; i < num_tests; ++i) {
strtobytes(tests[i].k, private, private_key_size);
result = uECC_compute_public_key(private, public, curve);
if (result != tests[i].success) {
all_success = 0;
printf(" Got unexpected result from test %d: %d\n", i, result);
}
if (result) {
strtobytes(tests[i].Q, expected, public_key_size);
if (memcmp(public, expected, public_key_size) != 0) {
all_success = 0;
printf(" Got incorrect public key for test %d\n", i);
printf(" Expected: ");
vli_print(expected, public_key_size);
printf(" Calculated: ");
vli_print(public, public_key_size);
}
}
}
return all_success;
}
#define RUN_TESTS(curve) \
printf(#curve ":\n"); \
if (run(curve##_tests, sizeof(curve##_tests) / sizeof(curve##_tests[0]), uECC_##curve()) ) { \
printf(" All passed\n"); \
} else { \
printf(" Failed\n"); \
}
int main() {
#if uECC_SUPPORTS_secp160r1
RUN_TESTS(secp160r1)
#endif
#if uECC_SUPPORTS_secp192r1
RUN_TESTS(secp192r1)
#endif
#if uECC_SUPPORTS_secp224r1
RUN_TESTS(secp224r1)
#endif
#if uECC_SUPPORTS_secp256r1
RUN_TESTS(secp256r1)
#endif
#if uECC_SUPPORTS_secp256k1
RUN_TESTS(secp256k1)
#endif
return 0;
}

@ -0,0 +1,79 @@
/* Copyright 2014, Kenneth MacKay. Licensed under the BSD 2-clause license. */
#include "uECC.h"
#include <stdio.h>
#include <string.h>
#ifndef uECC_TEST_NUMBER_OF_ITERATIONS
#define uECC_TEST_NUMBER_OF_ITERATIONS 256
#endif
void vli_print(char *str, uint8_t *vli, unsigned int size) {
printf("%s ", str);
for(unsigned i=0; i<size; ++i) {
printf("%02X ", (unsigned)vli[i]);
}
printf("\n");
}
int main() {
uint8_t public[64];
uint8_t private[32];
uint8_t compressed_point[33];
uint8_t decompressed_point[64];
int i;
int c;
const struct uECC_Curve_t * curves[5];
int num_curves = 0;
#if uECC_SUPPORTS_secp160r1
curves[num_curves++] = uECC_secp160r1();
#endif
#if uECC_SUPPORTS_secp192r1
curves[num_curves++] = uECC_secp192r1();
#endif
#if uECC_SUPPORTS_secp224r1
curves[num_curves++] = uECC_secp224r1();
#endif
#if uECC_SUPPORTS_secp256r1
curves[num_curves++] = uECC_secp256r1();
#endif
#if uECC_SUPPORTS_secp256k1
curves[num_curves++] = uECC_secp256k1();
#endif
printf("Testing compression and decompression of %d random EC points\n",
uECC_TEST_NUMBER_OF_ITERATIONS);
for (c = 0; c < num_curves; ++c) {
for (i = 0; i < uECC_TEST_NUMBER_OF_ITERATIONS; ++i) {
printf(".");
fflush(stdout);
memset(public, 0, sizeof(public));
memset(decompressed_point, 0, sizeof(decompressed_point));
/* Generate arbitrary EC point (public) on Curve */
if (!uECC_make_key(public, private, curves[c])) {
printf("uECC_make_key() failed\n");
continue;
}
/* compress and decompress point */
uECC_compress(public, compressed_point, curves[c]);
uECC_decompress(compressed_point, decompressed_point, curves[c]);
if (memcmp(public, decompressed_point, sizeof(public)) != 0) {
printf("Original and decompressed points are not identical!\n");
vli_print("Original point = ", public, sizeof(public));
vli_print("Compressed point = ", compressed_point, sizeof(compressed_point));
vli_print("Decompressed point = ", decompressed_point, sizeof(decompressed_point));
}
}
printf("\n");
}
return 0;
}

@ -0,0 +1,81 @@
/* Copyright 2014, Kenneth MacKay. Licensed under the BSD 2-clause license. */
#include "uECC.h"
#include <stdio.h>
#include <string.h>
void vli_print(char *str, uint8_t *vli, unsigned int size) {
printf("%s ", str);
for(unsigned i=0; i<size; ++i) {
printf("%02X ", (unsigned)vli[i]);
}
printf("\n");
}
int main() {
int i;
int success;
uint8_t private[32];
uint8_t public[64];
uint8_t public_computed[64];
int c;
const struct uECC_Curve_t * curves[5];
int num_curves = 0;
#if uECC_SUPPORTS_secp160r1
curves[num_curves++] = uECC_secp160r1();
#endif
#if uECC_SUPPORTS_secp192r1
curves[num_curves++] = uECC_secp192r1();
#endif
#if uECC_SUPPORTS_secp224r1
curves[num_curves++] = uECC_secp224r1();
#endif
#if uECC_SUPPORTS_secp256r1
curves[num_curves++] = uECC_secp256r1();
#endif
#if uECC_SUPPORTS_secp256k1
curves[num_curves++] = uECC_secp256k1();
#endif
printf("Testing 256 random private key pairs\n");
for (c = 0; c < num_curves; ++c) {
for (i = 0; i < 256; ++i) {
printf(".");
fflush(stdout);
memset(public, 0, sizeof(public));
memset(public_computed, 0, sizeof(public_computed));
if (!uECC_make_key(public, private, curves[c])) {
printf("uECC_make_key() failed\n");
continue;
}
if (!uECC_compute_public_key(private, public_computed, curves[c])) {
printf("uECC_compute_public_key() failed\n");
}
if (memcmp(public, public_computed, sizeof(public)) != 0) {
printf("Computed and provided public keys are not identical!\n");
vli_print("Computed public key = ", public_computed, sizeof(public_computed));
vli_print("Provided public key = ", public, sizeof(public));
vli_print("Private key = ", private, sizeof(private));
}
}
printf("\n");
printf("Testing private key = 0\n");
memset(private, 0, sizeof(private));
success = uECC_compute_public_key(private, public_computed, curves[c]);
if (success) {
printf("uECC_compute_public_key() should have failed\n");
}
printf("\n");
}
return 0;
}

@ -0,0 +1,90 @@
/* Copyright 2014, Kenneth MacKay. Licensed under the BSD 2-clause license. */
#include "uECC.h"
#include <stdio.h>
#include <string.h>
void vli_print(uint8_t *vli, unsigned int size) {
for(unsigned i=0; i<size; ++i) {
printf("%02X ", (unsigned)vli[i]);
}
}
int main() {
int i, c;
uint8_t private1[32] = {0};
uint8_t private2[32] = {0};
uint8_t public1[64] = {0};
uint8_t public2[64] = {0};
uint8_t secret1[32] = {0};
uint8_t secret2[32] = {0};
const struct uECC_Curve_t * curves[5];
int num_curves = 0;
#if uECC_SUPPORTS_secp160r1
curves[num_curves++] = uECC_secp160r1();
#endif
#if uECC_SUPPORTS_secp192r1
curves[num_curves++] = uECC_secp192r1();
#endif
#if uECC_SUPPORTS_secp224r1
curves[num_curves++] = uECC_secp224r1();
#endif
#if uECC_SUPPORTS_secp256r1
curves[num_curves++] = uECC_secp256r1();
#endif
#if uECC_SUPPORTS_secp256k1
curves[num_curves++] = uECC_secp256k1();
#endif
printf("Testing 256 random private key pairs\n");
for (c = 0; c < num_curves; ++c) {
for (i = 0; i < 256; ++i) {
printf(".");
fflush(stdout);
if (!uECC_make_key(public1, private1, curves[c]) ||
!uECC_make_key(public2, private2, curves[c])) {
printf("uECC_make_key() failed\n");
return 1;
}
if (!uECC_shared_secret(public2, private1, secret1, curves[c])) {
printf("shared_secret() failed (1)\n");
return 1;
}
if (!uECC_shared_secret(public1, private2, secret2, curves[c])) {
printf("shared_secret() failed (2)\n");
return 1;
}
if (memcmp(secret1, secret2, sizeof(secret1)) != 0) {
printf("Shared secrets are not identical!\n");
printf("Private key 1 = ");
vli_print(private1, 32);
printf("\n");
printf("Private key 2 = ");
vli_print(private2, 32);
printf("\n");
printf("Public key 1 = ");
vli_print(public1, 64);
printf("\n");
printf("Public key 2 = ");
vli_print(public2, 64);
printf("\n");
printf("Shared secret 1 = ");
vli_print(secret1, 32);
printf("\n");
printf("Shared secret 2 = ");
vli_print(secret2, 32);
printf("\n");
}
}
printf("\n");
}
return 0;
}

@ -0,0 +1,59 @@
/* Copyright 2014, Kenneth MacKay. Licensed under the BSD 2-clause license. */
#include "uECC.h"
#include <stdio.h>
#include <string.h>
int main() {
int i, c;
uint8_t private[32] = {0};
uint8_t public[64] = {0};
uint8_t hash[32] = {0};
uint8_t sig[64] = {0};
const struct uECC_Curve_t * curves[5];
int num_curves = 0;
#if uECC_SUPPORTS_secp160r1
curves[num_curves++] = uECC_secp160r1();
#endif
#if uECC_SUPPORTS_secp192r1
curves[num_curves++] = uECC_secp192r1();
#endif
#if uECC_SUPPORTS_secp224r1
curves[num_curves++] = uECC_secp224r1();
#endif
#if uECC_SUPPORTS_secp256r1
curves[num_curves++] = uECC_secp256r1();
#endif
#if uECC_SUPPORTS_secp256k1
curves[num_curves++] = uECC_secp256k1();
#endif
printf("Testing 256 signatures\n");
for (c = 0; c < num_curves; ++c) {
for (i = 0; i < 256; ++i) {
printf(".");
fflush(stdout);
if (!uECC_make_key(public, private, curves[c])) {
printf("uECC_make_key() failed\n");
return 1;
}
memcpy(hash, public, sizeof(hash));
if (!uECC_sign(private, hash, sizeof(hash), sig, curves[c])) {
printf("uECC_sign() failed\n");
return 1;
}
if (!uECC_verify(public, hash, sizeof(hash), sig, curves[c])) {
printf("uECC_verify() failed\n");
return 1;
}
}
printf("\n");
}
return 0;
}

@ -0,0 +1,93 @@
/* Copyright 2014, Kenneth MacKay. Licensed under the BSD 2-clause license. */
#include "uECC.h"
#include <stdio.h>
#include <string.h>
#define SHA256_BLOCK_LENGTH 64
#define SHA256_DIGEST_LENGTH 32
typedef struct SHA256_CTX {
uint32_t state[8];
uint64_t bitcount;
uint8_t buffer[SHA256_BLOCK_LENGTH];
} SHA256_CTX;
extern void SHA256_Init(SHA256_CTX *ctx);
extern void SHA256_Update(SHA256_CTX *ctx, const uint8_t *message, size_t message_size);
extern void SHA256_Final(uint8_t digest[SHA256_DIGEST_LENGTH], SHA256_CTX *ctx);
typedef struct SHA256_HashContext {
uECC_HashContext uECC;
SHA256_CTX ctx;
} SHA256_HashContext;
static void init_SHA256(const uECC_HashContext *base) {
SHA256_HashContext *context = (SHA256_HashContext *)base;
SHA256_Init(&context->ctx);
}
static void update_SHA256(const uECC_HashContext *base,
const uint8_t *message,
unsigned message_size) {
SHA256_HashContext *context = (SHA256_HashContext *)base;
SHA256_Update(&context->ctx, message, message_size);
}
static void finish_SHA256(const uECC_HashContext *base, uint8_t *hash_result) {
SHA256_HashContext *context = (SHA256_HashContext *)base;
SHA256_Final(hash_result, &context->ctx);
}
int main() {
int i, c;
uint8_t private[32] = {0};
uint8_t public[64] = {0};
uint8_t hash[32] = {0};
uint8_t sig[64] = {0};
uint8_t tmp[2 * SHA256_DIGEST_LENGTH + SHA256_BLOCK_LENGTH];
SHA256_HashContext ctx = {{
&init_SHA256,
&update_SHA256,
&finish_SHA256,
SHA256_BLOCK_LENGTH,
SHA256_DIGEST_LENGTH,
tmp
}};
const struct uECC_Curve_t * curves[5];
curves[0] = uECC_secp160r1();
curves[1] = uECC_secp192r1();
curves[2] = uECC_secp224r1();
curves[3] = uECC_secp256r1();
curves[4] = uECC_secp256k1();
printf("Testing 256 signatures\n");
for (c = 0; c < 5; ++c) {
for (i = 0; i < 256; ++i) {
printf(".");
fflush(stdout);
if (!uECC_make_key(public, private, curves[c])) {
printf("uECC_make_key() failed\n");
return 1;
}
memcpy(hash, public, sizeof(hash));
if (!uECC_sign_deterministic(private, hash, sizeof(hash), &ctx.uECC, sig, curves[c])) {
printf("uECC_sign() failed\n");
return 1;
}
if (!uECC_verify(public, hash, sizeof(hash), sig, curves[c])) {
printf("uECC_verify() failed\n");
return 1;
}
}
printf("\n");
}
return 0;
}

@ -0,0 +1,108 @@
/* Copyright 2015, Kenneth MacKay. Licensed under the BSD 2-clause license. */
#ifndef _UECC_TYPES_H_
#define _UECC_TYPES_H_
#ifndef uECC_PLATFORM
#if __AVR__
#define uECC_PLATFORM uECC_avr
#elif defined(__thumb2__) || defined(_M_ARMT) /* I think MSVC only supports Thumb-2 targets */
#define uECC_PLATFORM uECC_arm_thumb2
#elif defined(__thumb__)
#define uECC_PLATFORM uECC_arm_thumb
#elif defined(__arm__) || defined(_M_ARM)
#define uECC_PLATFORM uECC_arm
#elif defined(__aarch64__)
#define uECC_PLATFORM uECC_arm64
#elif defined(__i386__) || defined(_M_IX86) || defined(_X86_) || defined(__I86__)
#define uECC_PLATFORM uECC_x86
#elif defined(__amd64__) || defined(_M_X64)
#define uECC_PLATFORM uECC_x86_64
#else
#define uECC_PLATFORM uECC_arch_other
#endif
#endif
#ifndef uECC_ARM_USE_UMAAL
#if (uECC_PLATFORM == uECC_arm) && (__ARM_ARCH >= 6)
#define uECC_ARM_USE_UMAAL 1
#elif (uECC_PLATFORM == uECC_arm_thumb2) && (__ARM_ARCH >= 6) && !__ARM_ARCH_7M__
#define uECC_ARM_USE_UMAAL 1
#else
#define uECC_ARM_USE_UMAAL 0
#endif
#endif
#ifndef uECC_WORD_SIZE
#if uECC_PLATFORM == uECC_avr
#define uECC_WORD_SIZE 1
#elif (uECC_PLATFORM == uECC_x86_64 || uECC_PLATFORM == uECC_arm64)
#define uECC_WORD_SIZE 8
#else
#define uECC_WORD_SIZE 4
#endif
#endif
#if (uECC_WORD_SIZE != 1) && (uECC_WORD_SIZE != 4) && (uECC_WORD_SIZE != 8)
#error "Unsupported value for uECC_WORD_SIZE"
#endif
#if ((uECC_PLATFORM == uECC_avr) && (uECC_WORD_SIZE != 1))
#pragma message ("uECC_WORD_SIZE must be 1 for AVR")
#undef uECC_WORD_SIZE
#define uECC_WORD_SIZE 1
#endif
#if ((uECC_PLATFORM == uECC_arm || uECC_PLATFORM == uECC_arm_thumb || \
uECC_PLATFORM == uECC_arm_thumb2) && \
(uECC_WORD_SIZE != 4))
#pragma message ("uECC_WORD_SIZE must be 4 for ARM")
#undef uECC_WORD_SIZE
#define uECC_WORD_SIZE 4
#endif
#if defined(__SIZEOF_INT128__) || ((__clang_major__ * 100 + __clang_minor__) >= 302)
#define SUPPORTS_INT128 1
#else
#define SUPPORTS_INT128 0
#endif
typedef int8_t wordcount_t;
typedef int16_t bitcount_t;
typedef int8_t cmpresult_t;
#if (uECC_WORD_SIZE == 1)
typedef uint8_t uECC_word_t;
typedef uint16_t uECC_dword_t;
#define HIGH_BIT_SET 0x80
#define uECC_WORD_BITS 8
#define uECC_WORD_BITS_SHIFT 3
#define uECC_WORD_BITS_MASK 0x07
#elif (uECC_WORD_SIZE == 4)
typedef uint32_t uECC_word_t;
typedef uint64_t uECC_dword_t;
#define HIGH_BIT_SET 0x80000000
#define uECC_WORD_BITS 32
#define uECC_WORD_BITS_SHIFT 5
#define uECC_WORD_BITS_MASK 0x01F
#elif (uECC_WORD_SIZE == 8)
typedef uint64_t uECC_word_t;
#if SUPPORTS_INT128
typedef unsigned __int128 uECC_dword_t;
#endif
#define HIGH_BIT_SET 0x8000000000000000ull
#define uECC_WORD_BITS 64
#define uECC_WORD_BITS_SHIFT 6
#define uECC_WORD_BITS_MASK 0x03F
#endif /* uECC_WORD_SIZE */
#endif /* _UECC_TYPES_H_ */

File diff suppressed because it is too large Load Diff

@ -0,0 +1,367 @@
/* Copyright 2014, Kenneth MacKay. Licensed under the BSD 2-clause license. */
#ifndef _UECC_H_
#define _UECC_H_
#include <stdint.h>
/* Platform selection options.
If uECC_PLATFORM is not defined, the code will try to guess it based on compiler macros.
Possible values for uECC_PLATFORM are defined below: */
#define uECC_arch_other 0
#define uECC_x86 1
#define uECC_x86_64 2
#define uECC_arm 3
#define uECC_arm_thumb 4
#define uECC_arm_thumb2 5
#define uECC_arm64 6
#define uECC_avr 7
/* If desired, you can define uECC_WORD_SIZE as appropriate for your platform (1, 4, or 8 bytes).
If uECC_WORD_SIZE is not explicitly defined then it will be automatically set based on your
platform. */
/* Optimization level; trade speed for code size.
Larger values produce code that is faster but larger.
Currently supported values are 0 - 4; 0 is unusably slow for most applications.
Optimization level 4 currently only has an effect ARM platforms where more than one
curve is enabled. */
#ifndef uECC_OPTIMIZATION_LEVEL
#define uECC_OPTIMIZATION_LEVEL 2
#endif
/* uECC_SQUARE_FUNC - If enabled (defined as nonzero), this will cause a specific function to be
used for (scalar) squaring instead of the generic multiplication function. This can make things
faster somewhat faster, but increases the code size. */
#ifndef uECC_SQUARE_FUNC
#define uECC_SQUARE_FUNC 0
#endif
/* uECC_VLI_NATIVE_LITTLE_ENDIAN - If enabled (defined as nonzero), this will switch to native
little-endian format for *all* arrays passed in and out of the public API. This includes public
and private keys, shared secrets, signatures and message hashes.
Using this switch reduces the amount of call stack memory used by uECC, since less intermediate
translations are required.
Note that this will *only* work on native little-endian processors and it will treat the uint8_t
arrays passed into the public API as word arrays, therefore requiring the provided byte arrays
to be word aligned on architectures that do not support unaligned accesses.
IMPORTANT: Keys and signatures generated with uECC_VLI_NATIVE_LITTLE_ENDIAN=1 are incompatible
with keys and signatures generated with uECC_VLI_NATIVE_LITTLE_ENDIAN=0; all parties must use
the same endianness. */
#ifndef uECC_VLI_NATIVE_LITTLE_ENDIAN
#define uECC_VLI_NATIVE_LITTLE_ENDIAN 0
#endif
/* Curve support selection. Set to 0 to remove that curve. */
#ifndef uECC_SUPPORTS_secp160r1
#define uECC_SUPPORTS_secp160r1 1
#endif
#ifndef uECC_SUPPORTS_secp192r1
#define uECC_SUPPORTS_secp192r1 1
#endif
#ifndef uECC_SUPPORTS_secp224r1
#define uECC_SUPPORTS_secp224r1 1
#endif
#ifndef uECC_SUPPORTS_secp256r1
#define uECC_SUPPORTS_secp256r1 1
#endif
#ifndef uECC_SUPPORTS_secp256k1
#define uECC_SUPPORTS_secp256k1 1
#endif
/* Specifies whether compressed point format is supported.
Set to 0 to disable point compression/decompression functions. */
#ifndef uECC_SUPPORT_COMPRESSED_POINT
#define uECC_SUPPORT_COMPRESSED_POINT 1
#endif
struct uECC_Curve_t;
typedef const struct uECC_Curve_t * uECC_Curve;
#ifdef __cplusplus
extern "C"
{
#endif
#if uECC_SUPPORTS_secp160r1
uECC_Curve uECC_secp160r1(void);
#endif
#if uECC_SUPPORTS_secp192r1
uECC_Curve uECC_secp192r1(void);
#endif
#if uECC_SUPPORTS_secp224r1
uECC_Curve uECC_secp224r1(void);
#endif
#if uECC_SUPPORTS_secp256r1
uECC_Curve uECC_secp256r1(void);
#endif
#if uECC_SUPPORTS_secp256k1
uECC_Curve uECC_secp256k1(void);
#endif
/* uECC_RNG_Function type
The RNG function should fill 'size' random bytes into 'dest'. It should return 1 if
'dest' was filled with random data, or 0 if the random data could not be generated.
The filled-in values should be either truly random, or from a cryptographically-secure PRNG.
A correctly functioning RNG function must be set (using uECC_set_rng()) before calling
uECC_make_key() or uECC_sign().
Setting a correctly functioning RNG function improves the resistance to side-channel attacks
for uECC_shared_secret() and uECC_sign_deterministic().
A correct RNG function is set by default when building for Windows, Linux, or OS X.
If you are building on another POSIX-compliant system that supports /dev/random or /dev/urandom,
you can define uECC_POSIX to use the predefined RNG. For embedded platforms there is no predefined
RNG function; you must provide your own.
*/
typedef int (*uECC_RNG_Function)(uint8_t *dest, unsigned size);
/* uECC_set_rng() function.
Set the function that will be used to generate random bytes. The RNG function should
return 1 if the random data was generated, or 0 if the random data could not be generated.
On platforms where there is no predefined RNG function (eg embedded platforms), this must
be called before uECC_make_key() or uECC_sign() are used.
Inputs:
rng_function - The function that will be used to generate random bytes.
*/
void uECC_set_rng(uECC_RNG_Function rng_function);
/* uECC_get_rng() function.
Returns the function that will be used to generate random bytes.
*/
uECC_RNG_Function uECC_get_rng(void);
/* uECC_curve_private_key_size() function.
Returns the size of a private key for the curve in bytes.
*/
int uECC_curve_private_key_size(uECC_Curve curve);
/* uECC_curve_public_key_size() function.
Returns the size of a public key for the curve in bytes.
*/
int uECC_curve_public_key_size(uECC_Curve curve);
/* uECC_make_key() function.
Create a public/private key pair.
Outputs:
public_key - Will be filled in with the public key. Must be at least 2 * the curve size
(in bytes) long. For example, if the curve is secp256r1, public_key must be 64
bytes long.
private_key - Will be filled in with the private key. Must be as long as the curve order; this
is typically the same as the curve size, except for secp160r1. For example, if the
curve is secp256r1, private_key must be 32 bytes long.
For secp160r1, private_key must be 21 bytes long! Note that the first byte will
almost always be 0 (there is about a 1 in 2^80 chance of it being non-zero).
Returns 1 if the key pair was generated successfully, 0 if an error occurred.
*/
int uECC_make_key(uint8_t *public_key, uint8_t *private_key, uECC_Curve curve);
/* uECC_shared_secret() function.
Compute a shared secret given your secret key and someone else's public key. If the public key
is not from a trusted source and has not been previously verified, you should verify it first
using uECC_valid_public_key().
Note: It is recommended that you hash the result of uECC_shared_secret() before using it for
symmetric encryption or HMAC.
Inputs:
public_key - The public key of the remote party.
private_key - Your private key.
Outputs:
secret - Will be filled in with the shared secret value. Must be the same size as the
curve size; for example, if the curve is secp256r1, secret must be 32 bytes long.
Returns 1 if the shared secret was generated successfully, 0 if an error occurred.
*/
int uECC_shared_secret(const uint8_t *public_key,
const uint8_t *private_key,
uint8_t *secret,
uECC_Curve curve);
#if uECC_SUPPORT_COMPRESSED_POINT
/* uECC_compress() function.
Compress a public key.
Inputs:
public_key - The public key to compress.
Outputs:
compressed - Will be filled in with the compressed public key. Must be at least
(curve size + 1) bytes long; for example, if the curve is secp256r1,
compressed must be 33 bytes long.
*/
void uECC_compress(const uint8_t *public_key, uint8_t *compressed, uECC_Curve curve);
/* uECC_decompress() function.
Decompress a compressed public key.
Inputs:
compressed - The compressed public key.
Outputs:
public_key - Will be filled in with the decompressed public key.
*/
void uECC_decompress(const uint8_t *compressed, uint8_t *public_key, uECC_Curve curve);
#endif /* uECC_SUPPORT_COMPRESSED_POINT */
/* uECC_valid_public_key() function.
Check to see if a public key is valid.
Note that you are not required to check for a valid public key before using any other uECC
functions. However, you may wish to avoid spending CPU time computing a shared secret or
verifying a signature using an invalid public key.
Inputs:
public_key - The public key to check.
Returns 1 if the public key is valid, 0 if it is invalid.
*/
int uECC_valid_public_key(const uint8_t *public_key, uECC_Curve curve);
/* uECC_compute_public_key() function.
Compute the corresponding public key for a private key.
Inputs:
private_key - The private key to compute the public key for
Outputs:
public_key - Will be filled in with the corresponding public key
Returns 1 if the key was computed successfully, 0 if an error occurred.
*/
int uECC_compute_public_key(const uint8_t *private_key, uint8_t *public_key, uECC_Curve curve);
/* uECC_sign() function.
Generate an ECDSA signature for a given hash value.
Usage: Compute a hash of the data you wish to sign (SHA-2 is recommended) and pass it in to
this function along with your private key.
Inputs:
private_key - Your private key.
message_hash - The hash of the message to sign.
hash_size - The size of message_hash in bytes.
Outputs:
signature - Will be filled in with the signature value. Must be at least 2 * curve size long.
For example, if the curve is secp256r1, signature must be 64 bytes long.
Returns 1 if the signature generated successfully, 0 if an error occurred.
*/
int uECC_sign(const uint8_t *private_key,
const uint8_t *message_hash,
unsigned hash_size,
uint8_t *signature,
uECC_Curve curve);
/* uECC_HashContext structure.
This is used to pass in an arbitrary hash function to uECC_sign_deterministic().
The structure will be used for multiple hash computations; each time a new hash
is computed, init_hash() will be called, followed by one or more calls to
update_hash(), and finally a call to finish_hash() to produce the resulting hash.
The intention is that you will create a structure that includes uECC_HashContext
followed by any hash-specific data. For example:
typedef struct SHA256_HashContext {
uECC_HashContext uECC;
SHA256_CTX ctx;
} SHA256_HashContext;
void init_SHA256(uECC_HashContext *base) {
SHA256_HashContext *context = (SHA256_HashContext *)base;
SHA256_Init(&context->ctx);
}
void update_SHA256(uECC_HashContext *base,
const uint8_t *message,
unsigned message_size) {
SHA256_HashContext *context = (SHA256_HashContext *)base;
SHA256_Update(&context->ctx, message, message_size);
}
void finish_SHA256(uECC_HashContext *base, uint8_t *hash_result) {
SHA256_HashContext *context = (SHA256_HashContext *)base;
SHA256_Final(hash_result, &context->ctx);
}
... when signing ...
{
uint8_t tmp[32 + 32 + 64];
SHA256_HashContext ctx = {{&init_SHA256, &update_SHA256, &finish_SHA256, 64, 32, tmp}};
uECC_sign_deterministic(key, message_hash, &ctx.uECC, signature);
}
*/
typedef struct uECC_HashContext {
void (*init_hash)(const struct uECC_HashContext *context);
void (*update_hash)(const struct uECC_HashContext *context,
const uint8_t *message,
unsigned message_size);
void (*finish_hash)(const struct uECC_HashContext *context, uint8_t *hash_result);
unsigned block_size; /* Hash function block size in bytes, eg 64 for SHA-256. */
unsigned result_size; /* Hash function result size in bytes, eg 32 for SHA-256. */
uint8_t *tmp; /* Must point to a buffer of at least (2 * result_size + block_size) bytes. */
} uECC_HashContext;
/* uECC_sign_deterministic() function.
Generate an ECDSA signature for a given hash value, using a deterministic algorithm
(see RFC 6979). You do not need to set the RNG using uECC_set_rng() before calling
this function; however, if the RNG is defined it will improve resistance to side-channel
attacks.
Usage: Compute a hash of the data you wish to sign (SHA-2 is recommended) and pass it to
this function along with your private key and a hash context. Note that the message_hash
does not need to be computed with the same hash function used by hash_context.
Inputs:
private_key - Your private key.
message_hash - The hash of the message to sign.
hash_size - The size of message_hash in bytes.
hash_context - A hash context to use.
Outputs:
signature - Will be filled in with the signature value.
Returns 1 if the signature generated successfully, 0 if an error occurred.
*/
int uECC_sign_deterministic(const uint8_t *private_key,
const uint8_t *message_hash,
unsigned hash_size,
const uECC_HashContext *hash_context,
uint8_t *signature,
uECC_Curve curve);
/* uECC_verify() function.
Verify an ECDSA signature.
Usage: Compute the hash of the signed data using the same hash as the signer and
pass it to this function along with the signer's public key and the signature values (r and s).
Inputs:
public_key - The signer's public key.
message_hash - The hash of the signed data.
hash_size - The size of message_hash in bytes.
signature - The signature value.
Returns 1 if the signature is valid, 0 if it is invalid.
*/
int uECC_verify(const uint8_t *public_key,
const uint8_t *message_hash,
unsigned hash_size,
const uint8_t *signature,
uECC_Curve curve);
#ifdef __cplusplus
} /* end of extern "C" */
#endif
#endif /* _UECC_H_ */

@ -0,0 +1,172 @@
/* Copyright 2015, Kenneth MacKay. Licensed under the BSD 2-clause license. */
#ifndef _UECC_VLI_H_
#define _UECC_VLI_H_
#include "uECC.h"
#include "types.h"
/* Functions for raw large-integer manipulation. These are only available
if uECC.c is compiled with uECC_ENABLE_VLI_API defined to 1. */
#ifndef uECC_ENABLE_VLI_API
#define uECC_ENABLE_VLI_API 0
#endif
#ifdef __cplusplus
extern "C"
{
#endif
#if uECC_ENABLE_VLI_API
void uECC_vli_clear(uECC_word_t *vli, wordcount_t num_words);
/* Constant-time comparison to zero - secure way to compare long integers */
/* Returns 1 if vli == 0, 0 otherwise. */
uECC_word_t uECC_vli_isZero(const uECC_word_t *vli, wordcount_t num_words);
/* Returns nonzero if bit 'bit' of vli is set. */
uECC_word_t uECC_vli_testBit(const uECC_word_t *vli, bitcount_t bit);
/* Counts the number of bits required to represent vli. */
bitcount_t uECC_vli_numBits(const uECC_word_t *vli, const wordcount_t max_words);
/* Sets dest = src. */
void uECC_vli_set(uECC_word_t *dest, const uECC_word_t *src, wordcount_t num_words);
/* Constant-time comparison function - secure way to compare long integers */
/* Returns one if left == right, zero otherwise */
uECC_word_t uECC_vli_equal(const uECC_word_t *left,
const uECC_word_t *right,
wordcount_t num_words);
/* Constant-time comparison function - secure way to compare long integers */
/* Returns sign of left - right, in constant time. */
cmpresult_t uECC_vli_cmp(const uECC_word_t *left, const uECC_word_t *right, wordcount_t num_words);
/* Computes vli = vli >> 1. */
void uECC_vli_rshift1(uECC_word_t *vli, wordcount_t num_words);
/* Computes result = left + right, returning carry. Can modify in place. */
uECC_word_t uECC_vli_add(uECC_word_t *result,
const uECC_word_t *left,
const uECC_word_t *right,
wordcount_t num_words);
/* Computes result = left - right, returning borrow. Can modify in place. */
uECC_word_t uECC_vli_sub(uECC_word_t *result,
const uECC_word_t *left,
const uECC_word_t *right,
wordcount_t num_words);
/* Computes result = left * right. Result must be 2 * num_words long. */
void uECC_vli_mult(uECC_word_t *result,
const uECC_word_t *left,
const uECC_word_t *right,
wordcount_t num_words);
/* Computes result = left^2. Result must be 2 * num_words long. */
void uECC_vli_square(uECC_word_t *result, const uECC_word_t *left, wordcount_t num_words);
/* Computes result = (left + right) % mod.
Assumes that left < mod and right < mod, and that result does not overlap mod. */
void uECC_vli_modAdd(uECC_word_t *result,
const uECC_word_t *left,
const uECC_word_t *right,
const uECC_word_t *mod,
wordcount_t num_words);
/* Computes result = (left - right) % mod.
Assumes that left < mod and right < mod, and that result does not overlap mod. */
void uECC_vli_modSub(uECC_word_t *result,
const uECC_word_t *left,
const uECC_word_t *right,
const uECC_word_t *mod,
wordcount_t num_words);
/* Computes result = product % mod, where product is 2N words long.
Currently only designed to work for mod == curve->p or curve_n. */
void uECC_vli_mmod(uECC_word_t *result,
uECC_word_t *product,
const uECC_word_t *mod,
wordcount_t num_words);
/* Calculates result = product (mod curve->p), where product is up to
2 * curve->num_words long. */
void uECC_vli_mmod_fast(uECC_word_t *result, uECC_word_t *product, uECC_Curve curve);
/* Computes result = (left * right) % mod.
Currently only designed to work for mod == curve->p or curve_n. */
void uECC_vli_modMult(uECC_word_t *result,
const uECC_word_t *left,
const uECC_word_t *right,
const uECC_word_t *mod,
wordcount_t num_words);
/* Computes result = (left * right) % curve->p. */
void uECC_vli_modMult_fast(uECC_word_t *result,
const uECC_word_t *left,
const uECC_word_t *right,
uECC_Curve curve);
/* Computes result = left^2 % mod.
Currently only designed to work for mod == curve->p or curve_n. */
void uECC_vli_modSquare(uECC_word_t *result,
const uECC_word_t *left,
const uECC_word_t *mod,
wordcount_t num_words);
/* Computes result = left^2 % curve->p. */
void uECC_vli_modSquare_fast(uECC_word_t *result, const uECC_word_t *left, uECC_Curve curve);
/* Computes result = (1 / input) % mod.*/
void uECC_vli_modInv(uECC_word_t *result,
const uECC_word_t *input,
const uECC_word_t *mod,
wordcount_t num_words);
#if uECC_SUPPORT_COMPRESSED_POINT
/* Calculates a = sqrt(a) (mod curve->p) */
void uECC_vli_mod_sqrt(uECC_word_t *a, uECC_Curve curve);
#endif
/* Converts an integer in uECC native format to big-endian bytes. */
void uECC_vli_nativeToBytes(uint8_t *bytes, int num_bytes, const uECC_word_t *native);
/* Converts big-endian bytes to an integer in uECC native format. */
void uECC_vli_bytesToNative(uECC_word_t *native, const uint8_t *bytes, int num_bytes);
unsigned uECC_curve_num_words(uECC_Curve curve);
unsigned uECC_curve_num_bytes(uECC_Curve curve);
unsigned uECC_curve_num_bits(uECC_Curve curve);
unsigned uECC_curve_num_n_words(uECC_Curve curve);
unsigned uECC_curve_num_n_bytes(uECC_Curve curve);
unsigned uECC_curve_num_n_bits(uECC_Curve curve);
const uECC_word_t *uECC_curve_p(uECC_Curve curve);
const uECC_word_t *uECC_curve_n(uECC_Curve curve);
const uECC_word_t *uECC_curve_G(uECC_Curve curve);
const uECC_word_t *uECC_curve_b(uECC_Curve curve);
int uECC_valid_point(const uECC_word_t *point, uECC_Curve curve);
/* Multiplies a point by a scalar. Points are represented by the X coordinate followed by
the Y coordinate in the same array, both coordinates are curve->num_words long. Note
that scalar must be curve->num_n_words long (NOT curve->num_words). */
void uECC_point_mult(uECC_word_t *result,
const uECC_word_t *point,
const uECC_word_t *scalar,
uECC_Curve curve);
/* Generates a random integer in the range 0 < random < top.
Both random and top have num_words words. */
int uECC_generate_random_int(uECC_word_t *random,
const uECC_word_t *top,
wordcount_t num_words);
#endif /* uECC_ENABLE_VLI_API */
#ifdef __cplusplus
} /* end of extern "C" */
#endif
#endif /* _UECC_VLI_H_ */

@ -0,0 +1,4 @@
#define VERSION_MAJOR 0
#define VERSION_MINOR 0
#define VERSION_PATCH 0
#define VERSION_BUILD 0

@ -99,6 +99,25 @@ def get_version(file: str) -> str:
return f"{major}.{minor}.{patch}"
def get_version_int(file):
major = 0
minor = 0
patch = 0
file = PROJECT_ROOT / file
with open(file, 'r') as f:
for line in f:
if line.startswith('#define VERSION_MAJOR '):
major = int(line.split('VERSION_MAJOR')[1].strip())
if line.startswith('#define VERSION_MINOR '):
minor = int(line.split('VERSION_MINOR')[1].strip())
if line.startswith('#define VERSION_PATCH '):
patch = int(line.split('VERSION_PATCH')[1].strip())
if major > 99 or minor > 99 or patch > 99:
raise Exception("Version number too large")
return major * 10000 + minor * 100 + patch
def get_git_revision_hash() -> str:
return subprocess.check_output(["git", "rev-parse", "HEAD"]).decode("ascii").strip()

@ -0,0 +1,35 @@
import click
import zipfile
def convert_file(archive, infile, outfile, name):
data = archive.read(infile)
with open(outfile, "w") as outfile:
outfile.write("// Firmware BLOB - automatically generated\n")
outfile.write("\n")
outfile.write(f"#ifndef __FW_BLOB_{name}_H__\n")
outfile.write(f"#define __FW_BLOB_{name}_H__ 1\n")
outfile.write("\n")
outfile.write(f"uint8_t {name}[] = " + "{")
for i, byte in enumerate(data):
if i % 16 == 0:
outfile.write("\n ")
outfile.write("0x{:02x}, ".format(byte))
outfile.write("\n};\n")
outfile.write("\n")
outfile.write("#endif\n")
@click.command()
@click.argument("infile", type=click.File("rb"))
def convert(infile):
with zipfile.ZipFile(infile) as archive:
convert_file(archive, "ble_firmware.bin", "./embed/firmware/dfu/ble_firmware_bin.h", "binfile")
convert_file(archive, "ble_firmware.dat", "./embed/firmware/dfu/ble_firmware_dat.h", "datfile")
if __name__ == "__main__":
convert()

@ -0,0 +1 @@
nrfutil settings generate --family NRF52 --bootloader-version 0 --bl-settings-version 2 --app-boot-validation VALIDATE_ECDSA_P256_SHA256 --application ./build/ble_firmware/ble_firmware.hex --application-version 0 --sd-boot-validation VALIDATE_ECDSA_P256_SHA256 --softdevice ./embed/sdk/nrf52/components/softdevice/s140/hex/s140_nrf52_7.2.0_softdevice.hex --key-file ./embed/ble_bootloader/priv.pem ./build/ble_bootloader/settings.hex

@ -12,3 +12,6 @@
^\./crypto/sha3
^\./legacy/vendor
^\./core/embed/segger
^\./core/embed/ble_bootloader/dfu
^\./core/embed/ble_firmware/uecc
^\./core/embed/sdk

Loading…
Cancel
Save