cleaning, ejected dfu

tychovrahe/T3W1/devkit1_with_ble_crypto2b
tychovrahe 8 months ago
parent e9509ae4d2
commit dd797fa767

@ -43,6 +43,8 @@ CPPDEFINES_MOD += [
'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'),
@ -67,48 +69,35 @@ SOURCE_MOD += [
CPPPATH_MOD += [
'embed/sdk/nrf52/modules/nrfx/drivers/include',
'embed/sdk/nrf52/components/libraries/crypto/backend/micro_ecc',
'embed/sdk/nrf52/components/libraries/memobj',
'embed/sdk/nrf52/components/libraries/crc32',
'embed/sdk/nrf52/components/libraries/sha256',
'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/crypto/backend/oberon',
'embed/sdk/nrf52/components/libraries/crypto/backend/cifra',
'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/dfu',
'embed/sdk/nrf52/components/libraries/bootloader/serial_dfu',
'embed/sdk/nrf52/external/nrf_cc310_bl/include',
'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/crypto/backend/nrf_hw',
'embed/sdk/nrf52/components/libraries/log',
'embed/sdk/nrf52/components/libraries/strerror',
'embed/sdk/nrf52/components/libraries/crypto/backend/mbedtls',
'embed/sdk/nrf52/components/libraries/crypto/backend/cc310',
'embed/sdk/nrf52/components/libraries/bootloader',
'embed/sdk/nrf52/components/softdevice/mbr/headers',
'embed/sdk/nrf52/components/libraries/crypto',
'embed/sdk/nrf52/components/libraries/crypto/backend/optiga',
'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/components/libraries/crypto/backend/nrf_sw',
'embed/sdk/nrf52/modules/nrfx/mdk',
'embed/sdk/nrf52/external/nrf_cc310/include',
'embed/sdk/nrf52/components/libraries/queue',
'embed/sdk/nrf52/components/libraries/mutex',
'embed/sdk/nrf52/components/libraries/ringbuf',
@ -165,27 +154,28 @@ SOURCE_NRFHAL = [
'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/dfu/dfu-cc.pb.c',
'embed/sdk/nrf52/components/libraries/bootloader/dfu/nrf_dfu.c',
'embed/sdk/nrf52/components/libraries/bootloader/dfu/nrf_dfu_flash.c',
'embed/sdk/nrf52/components/libraries/bootloader/dfu/nrf_dfu_handling_error.c',
'embed/sdk/nrf52/components/libraries/bootloader/dfu/nrf_dfu_mbr.c',
'embed/sdk/nrf52/components/libraries/bootloader/dfu/nrf_dfu_req_handler.c',
'embed/sdk/nrf52/components/libraries/bootloader/dfu/nrf_dfu_settings.c',
'embed/sdk/nrf52/components/libraries/bootloader/dfu/nrf_dfu_transport.c',
'embed/sdk/nrf52/components/libraries/bootloader/dfu/nrf_dfu_utils.c',
'embed/sdk/nrf52/components/libraries/bootloader/dfu/nrf_dfu_ver_validation.c',
'embed/sdk/nrf52/components/libraries/bootloader/serial_dfu/nrf_dfu_serial.c',
]
SOURCE_BLE_BOOTLOADER = [
'embed/ble_bootloader/main.c',
'embed/ble_bootloader/uecc/uECC.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',
'embed/ble_bootloader/nrf_dfu_validation.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',
@ -255,11 +245,11 @@ CPU_CCFLAGS = '-mthumb -mabi=aapcs -mcpu=cortex-m4 -mfloat-abi=hard -mfpu=fpv4-s
env.Replace(
COPT=env.get('ENV').get('OPTIMIZE', '-Og'),
COPT=env.get('ENV').get('OPTIMIZE', '-Os'),
CCFLAGS='$COPT '
'-g3 '
'-nostdlib '
'-std=gnu99 -Wall -Werror -Wdouble-promotion -Wpointer-arith -Wno-missing-braces -Wno-unused-function '
'-std=gnu11 -Wall -Werror -Wdouble-promotion -Wpointer-arith -Wno-missing-braces -Wno-unused-function '
'-fdata-sections -ffunction-sections '
'-fno-strict-aliasing '
'-fno-builtin '
@ -268,7 +258,7 @@ env.Replace(
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/uecc',
'embed/ble_bootloader/dfu',
'embed/sdk/nrf52',
] + CPPPATH_MOD,
CPPDEFINES=[

@ -46,6 +46,8 @@ CPPDEFINES_MOD += [
'S140',
('__HEAP_SIZE','8192'),
('__STACK_SIZE','8192'),
'__STARTUP_CLEAR_BSS',
('__START', 'main'),
('uECC_ENABLE_VLI_API', '0'),
('uECC_OPTIMIZATION_LEVEL', '3'),
@ -323,9 +325,9 @@ SOURCE_BLE_FIRMWARE = [
'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',
'embed/ble_bootloader/uecc/uECC.c',
]
if MMD:
@ -384,7 +386,7 @@ env.Replace(
COPT=env.get('ENV').get('OPTIMIZE', '-Og'),
CCFLAGS='$COPT '
'-g3 '
'-std=c99 -Wall -Werror -Wdouble-promotion -Wpointer-arith -Wno-missing-braces -Wno-unused-function '
'-std=gnu11 -Wall -Werror -Wdouble-promotion -Wpointer-arith -Wno-missing-braces -Wno-unused-function '
'-fdata-sections -ffunction-sections '
'-fno-strict-aliasing '
'-fno-builtin '
@ -397,7 +399,7 @@ env.Replace(
'embed/sdk/nrf52',
'embed/lib',
'vendor/nanopb',
'embed/ble_bootloader/uecc',
'embed/ble_firmware/uecc',
] + CPPPATH_MOD,
CPPDEFINES=[
'BLE_FIRMWARE',

@ -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,31 @@
/* 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,239 @@
/* 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;
typedef enum _dfu_ValidationType {
dfu_ValidationType_NO_VALIDATION = 0,
dfu_ValidationType_VALIDATE_GENERATED_CRC = 1,
dfu_ValidationType_VALIDATE_SHA256 = 2,
dfu_ValidationType_VALIDATE_ECDSA_P256_SHA256 = 3
} dfu_ValidationType;
/* 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))
#define _dfu_ValidationType_MIN dfu_ValidationType_NO_VALIDATION
#define _dfu_ValidationType_MAX dfu_ValidationType_VALIDATE_ECDSA_P256_SHA256
#define _dfu_ValidationType_ARRAYSIZE ((dfu_ValidationType)(dfu_ValidationType_VALIDATE_ECDSA_P256_SHA256+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,76 @@
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;
}
enum ValidationType {
NO_VALIDATION = 0;
VALIDATE_GENERATED_CRC = 1;
VALIDATE_SHA256 = 2;
VALIDATE_ECDSA_P256_SHA256 = 3;
}
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__
/** @} */

@ -48,8 +48,6 @@
#include "pb_decode.h"
#include "dfu-cc.pb.h"
#include "crc32.h"
#include "nrf_crypto.h"
#include "nrf_crypto_shared.h"
#include "nrf_assert.h"
#include "nrf_dfu_validation.h"
#include "nrf_dfu_ver_validation.h"
@ -382,7 +380,7 @@ static nrf_dfu_result_t nrf_dfu_validation_signature_check(uint32_t sigmask,
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_ERROR_CRYPTO_ECDSA_INVALID_SIGNATURE;
err_code = NRF_DFU_ERROR_INVALID_SIGNATURE;
}
if (err_code != NRF_SUCCESS)
@ -635,13 +633,13 @@ static bool nrf_dfu_validation_hash_ok(uint8_t const * p_hash, uint32_t src_addr
blake2s( (uint8_t*)src_addr, data_len, hash, BLAKE2S_DIGEST_LENGTH);
if (memcmp(hash, p_hash, NRF_CRYPTO_HASH_SIZE_SHA256) != 0)
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, NRF_CRYPTO_HASH_SIZE_SHA256);
NRF_LOG_HEXDUMP_DEBUG(p_hash, BLAKE2S_DIGEST_LENGTH);
NRF_LOG_DEBUG("Actual FW hash:")
NRF_LOG_HEXDUMP_DEBUG(hash, NRF_CRYPTO_HASH_SIZE_SHA256);
NRF_LOG_HEXDUMP_DEBUG(hash, BLAKE2S_DIGEST_LENGTH);
NRF_LOG_FLUSH();
result = false;
@ -881,7 +879,7 @@ bool nrf_dfu_validation_boot_validate(boot_validation_t const * p_validation, ui
nrf_dfu_result_t res_code = nrf_dfu_validation_signature_check(
p_validation->sigmask,
p_validation->bytes,
NRF_CRYPTO_ECDSA_SECP256R1_SIGNATURE_SIZE,
64,
p_data,
data_len);
return (res_code == NRF_DFU_RES_CODE_SUCCESS);

@ -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

@ -5,7 +5,7 @@ GROUP(-lgcc -lc -lnosys)
MEMORY
{
FLASH (rx) : ORIGIN = 0x60000, LENGTH = 0x1e000
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

@ -788,7 +788,7 @@
// <e> NRF_CRYPTO_BACKEND_MICRO_ECC_ENABLED - Enable the micro-ecc backend.
//==========================================================
#ifndef NRF_CRYPTO_BACKEND_MICRO_ECC_ENABLED
#define NRF_CRYPTO_BACKEND_MICRO_ECC_ENABLED 1
#define NRF_CRYPTO_BACKEND_MICRO_ECC_ENABLED 0
#endif
// <q> NRF_CRYPTO_BACKEND_MICRO_ECC_ECC_SECP192R1_ENABLED - Enable secp192r1 (NIST 192-bit) curve

@ -5,7 +5,7 @@ GROUP(-lgcc -lc -lnosys)
MEMORY
{
FLASH (rx) : ORIGIN = 0x27000, LENGTH = 0x39000
FLASH (rx) : ORIGIN = 0x27000, LENGTH = 0x49000
RAM (rwx) : ORIGIN = 0x20002ae8, LENGTH = 0x1d518
}

@ -1,31 +1,123 @@
/**
* 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.
*
*/
/* Automatically generated nanopb constant definitions */
/* Generated by nanopb-0.4.5 */
/* Generated by nanopb-0.3.6-dev at Tue Sep 11 14:37:18 2018. */
#include "dfu-cc.pb.h"
#if PB_PROTO_HEADER_VERSION != 40
/* @@protoc_insertion_point(includes) */
#if PB_PROTO_HEADER_VERSION != 30
#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)
const bool dfu_init_command_is_debug_default = false;
const pb_field_t dfu_hash_fields[3] = {
PB_FIELD( 1, UENUM , REQUIRED, STATIC , FIRST, dfu_hash_t, hash_type, hash_type, 0),
PB_FIELD( 2, BYTES , REQUIRED, STATIC , OTHER, dfu_hash_t, hash, hash_type, 0),
PB_LAST_FIELD
};
const pb_field_t dfu_boot_validation_fields[3] = {
PB_FIELD( 1, UENUM , REQUIRED, STATIC , FIRST, dfu_boot_validation_t, type, type, 0),
PB_FIELD( 2, BYTES , REQUIRED, STATIC , OTHER, dfu_boot_validation_t, bytes, type, 0),
PB_LAST_FIELD
};
const pb_field_t dfu_init_command_fields[11] = {
PB_FIELD( 1, UINT32 , OPTIONAL, STATIC , FIRST, dfu_init_command_t, fw_version, fw_version, 0),
PB_FIELD( 2, UINT32 , OPTIONAL, STATIC , OTHER, dfu_init_command_t, hw_version, fw_version, 0),
PB_FIELD( 3, UINT32 , REPEATED, STATIC , OTHER, dfu_init_command_t, sd_req, hw_version, 0),
PB_FIELD( 4, UENUM , OPTIONAL, STATIC , OTHER, dfu_init_command_t, type, sd_req, 0),
PB_FIELD( 5, UINT32 , OPTIONAL, STATIC , OTHER, dfu_init_command_t, sd_size, type, 0),
PB_FIELD( 6, UINT32 , OPTIONAL, STATIC , OTHER, dfu_init_command_t, bl_size, sd_size, 0),
PB_FIELD( 7, UINT32 , OPTIONAL, STATIC , OTHER, dfu_init_command_t, app_size, bl_size, 0),
PB_FIELD( 8, MESSAGE , OPTIONAL, STATIC , OTHER, dfu_init_command_t, hash, app_size, &dfu_hash_fields),
PB_FIELD( 9, BOOL , OPTIONAL, STATIC , OTHER, dfu_init_command_t, is_debug, hash, &dfu_init_command_is_debug_default),
PB_FIELD( 10, MESSAGE , REPEATED, STATIC , OTHER, dfu_init_command_t, boot_validation, is_debug, &dfu_boot_validation_fields),
PB_LAST_FIELD
};
const pb_field_t dfu_command_fields[3] = {
PB_FIELD( 1, UENUM , OPTIONAL, STATIC , FIRST, dfu_command_t, op_code, op_code, 0),
PB_FIELD( 2, MESSAGE , OPTIONAL, STATIC , OTHER, dfu_command_t, init, op_code, &dfu_init_command_fields),
PB_LAST_FIELD
};
const pb_field_t dfu_signed_command_fields[4] = {
PB_FIELD( 1, MESSAGE , REQUIRED, STATIC , FIRST, dfu_signed_command_t, command, command, &dfu_command_fields),
PB_FIELD( 2, UENUM , REQUIRED, STATIC , OTHER, dfu_signed_command_t, signature_type, command, 0),
PB_FIELD( 3, BYTES , REQUIRED, STATIC , OTHER, dfu_signed_command_t, signature, signature_type, 0),
PB_LAST_FIELD
};
const pb_field_t dfu_packet_fields[3] = {
PB_FIELD( 1, MESSAGE , OPTIONAL, STATIC , FIRST, dfu_packet_t, command, command, &dfu_command_fields),
PB_FIELD( 2, MESSAGE , OPTIONAL, STATIC , OTHER, dfu_packet_t, signed_command, command, &dfu_signed_command_fields),
PB_LAST_FIELD
};
/* Check that field information fits in pb_field_t */
#if !defined(PB_FIELD_32BIT)
/* If you get an error here, it means that you need to define PB_FIELD_32BIT
* compile-time option. You can do that in pb.h or on compiler command line.
*
* The reason you need to do this is that some of your messages contain tag
* numbers or field sizes that are larger than what can fit in 8 or 16 bit
* field descriptors.
*/
PB_STATIC_ASSERT((pb_membersize(dfu_init_command_t, hash) < 65536 && pb_membersize(dfu_init_command_t, boot_validation[0]) < 65536 && pb_membersize(dfu_command_t, init) < 65536 && pb_membersize(dfu_signed_command_t, command) < 65536 && pb_membersize(dfu_packet_t, command) < 65536 && pb_membersize(dfu_packet_t, signed_command) < 65536), YOU_MUST_DEFINE_PB_FIELD_32BIT_FOR_MESSAGES_dfu_hash_dfu_boot_validation_dfu_init_command_dfu_command_dfu_signed_command_dfu_packet)
#endif
#if !defined(PB_FIELD_16BIT) && !defined(PB_FIELD_32BIT)
/* If you get an error here, it means that you need to define PB_FIELD_16BIT
* compile-time option. You can do that in pb.h or on compiler command line.
*
* The reason you need to do this is that some of your messages contain tag
* numbers or field sizes that are larger than what can fit in the default
* 8 bit descriptors.
*/
PB_STATIC_ASSERT((pb_membersize(dfu_init_command_t, hash) < 256 && pb_membersize(dfu_init_command_t, boot_validation[0]) < 256 && pb_membersize(dfu_command_t, init) < 256 && pb_membersize(dfu_signed_command_t, command) < 256 && pb_membersize(dfu_packet_t, command) < 256 && pb_membersize(dfu_packet_t, signed_command) < 256), YOU_MUST_DEFINE_PB_FIELD_16BIT_FOR_MESSAGES_dfu_hash_dfu_boot_validation_dfu_init_command_dfu_command_dfu_signed_command_dfu_packet)
#endif
/* @@protoc_insertion_point(eof) */

@ -1,239 +1,241 @@
/**
* 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.
*
*/
/* Automatically generated nanopb header */
/* Generated by nanopb-0.4.5 */
/* Generated by nanopb-0.3.6-dev at Tue Sep 11 14:37:18 2018. */
#ifndef PB_DFU_DFU_CC_PB_H_INCLUDED
#define PB_DFU_DFU_CC_PB_H_INCLUDED
#ifndef PB_DFU_CC_PB_H_INCLUDED
#define PB_DFU_CC_PB_H_INCLUDED
#include <pb.h>
#if PB_PROTO_HEADER_VERSION != 40
/* @@protoc_insertion_point(includes) */
#if PB_PROTO_HEADER_VERSION != 30
#error Regenerate this file with the current version of nanopb generator.
#endif
#ifdef __cplusplus
extern "C" {
#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;
typedef enum _dfu_ValidationType {
dfu_ValidationType_NO_VALIDATION = 0,
dfu_ValidationType_VALIDATE_GENERATED_CRC = 1,
dfu_ValidationType_VALIDATE_SHA256 = 2,
dfu_ValidationType_VALIDATE_ECDSA_P256_SHA256 = 3
} dfu_ValidationType;
typedef enum
{
DFU_FW_TYPE_APPLICATION = 0,
DFU_FW_TYPE_SOFTDEVICE = 1,
DFU_FW_TYPE_BOOTLOADER = 2,
DFU_FW_TYPE_SOFTDEVICE_BOOTLOADER = 3,
DFU_FW_TYPE_EXTERNAL_APPLICATION = 4
} dfu_fw_type_t;
#define DFU_FW_TYPE_MIN DFU_FW_TYPE_APPLICATION
#define DFU_FW_TYPE_MAX DFU_FW_TYPE_EXTERNAL_APPLICATION
#define DFU_FW_TYPE_ARRAYSIZE ((dfu_fw_type_t)(DFU_FW_TYPE_EXTERNAL_APPLICATION+1))
typedef enum
{
DFU_HASH_TYPE_NO_HASH = 0,
DFU_HASH_TYPE_CRC = 1,
DFU_HASH_TYPE_SHA128 = 2,
DFU_HASH_TYPE_SHA256 = 3,
DFU_HASH_TYPE_SHA512 = 4
} dfu_hash_type_t;
#define DFU_HASH_TYPE_MIN DFU_HASH_TYPE_NO_HASH
#define DFU_HASH_TYPE_MAX DFU_HASH_TYPE_SHA512
#define DFU_HASH_TYPE_ARRAYSIZE ((dfu_hash_type_t)(DFU_HASH_TYPE_SHA512+1))
typedef enum
{
DFU_OP_CODE_INIT = 1
} dfu_op_code_t;
#define DFU_OP_CODE_MIN DFU_OP_CODE_INIT
#define DFU_OP_CODE_MAX DFU_OP_CODE_INIT
#define DFU_OP_CODE_ARRAYSIZE ((dfu_op_code_t)(DFU_OP_CODE_INIT+1))
typedef enum
{
DFU_VALIDATION_TYPE_NO_VALIDATION = 0,
DFU_VALIDATION_TYPE_VALIDATE_GENERATED_CRC = 1,
DFU_VALIDATION_TYPE_VALIDATE_SHA256 = 2,
DFU_VALIDATION_TYPE_VALIDATE_ECDSA_P256_SHA256 = 3
} dfu_validation_type_t;
#define DFU_VALIDATION_TYPE_MIN DFU_VALIDATION_TYPE_NO_VALIDATION
#define DFU_VALIDATION_TYPE_MAX DFU_VALIDATION_TYPE_VALIDATE_ECDSA_P256_SHA256
#define DFU_VALIDATION_TYPE_ARRAYSIZE ((dfu_validation_type_t)(DFU_VALIDATION_TYPE_VALIDATE_ECDSA_P256_SHA256+1))
typedef enum
{
DFU_SIGNATURE_TYPE_ECDSA_P256_SHA256 = 0,
DFU_SIGNATURE_TYPE_ED25519 = 1
} dfu_signature_type_t;
#define DFU_SIGNATURE_TYPE_MIN DFU_SIGNATURE_TYPE_ECDSA_P256_SHA256
#define DFU_SIGNATURE_TYPE_MAX DFU_SIGNATURE_TYPE_ED25519
#define DFU_SIGNATURE_TYPE_ARRAYSIZE ((dfu_signature_type_t)(DFU_SIGNATURE_TYPE_ED25519+1))
/* 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 {
typedef PB_BYTES_ARRAY_T(64) dfu_boot_validation_bytes_t;
typedef struct {
dfu_validation_type_t type;
dfu_boot_validation_bytes_t bytes;
/* @@protoc_insertion_point(struct:dfu_boot_validation_t) */
} dfu_boot_validation_t;
typedef PB_BYTES_ARRAY_T(32) dfu_hash_hash_t;
typedef struct {
dfu_hash_type_t hash_type;
dfu_hash_hash_t hash;
/* @@protoc_insertion_point(struct:dfu_hash_t) */
} dfu_hash_t;
typedef struct {
bool has_fw_version;
uint32_t fw_version;
uint32_t fw_version;
bool has_hw_version;
uint32_t hw_version;
uint32_t hw_version;
pb_size_t sd_req_count;
uint32_t sd_req[16];
uint32_t sd_req[16];
bool has_type;
dfu_FwType type;
dfu_fw_type_t type;
bool has_sd_size;
uint32_t sd_size;
uint32_t sd_size;
bool has_bl_size;
uint32_t bl_size;
uint32_t bl_size;
bool has_app_size;
uint32_t app_size;
uint32_t app_size;
bool has_hash;
dfu_Hash hash;
dfu_hash_t hash;
bool has_is_debug;
bool is_debug;
bool is_debug;
pb_size_t boot_validation_count;
dfu_BootValidation boot_validation[3];
} dfu_InitCommand;
dfu_boot_validation_t boot_validation[3];
/* @@protoc_insertion_point(struct:dfu_init_command_t) */
} dfu_init_command_t;
/* Command type */
typedef struct _dfu_Command {
typedef struct {
bool has_op_code;
dfu_OpCode op_code;
dfu_op_code_t 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 {
dfu_init_command_t init;
/* @@protoc_insertion_point(struct:dfu_command_t) */
} dfu_command_t;
typedef PB_BYTES_ARRAY_T(64) dfu_signed_command_signature_t;
typedef struct {
dfu_command_t command;
dfu_signature_type_t signature_type;
dfu_signed_command_signature_t signature;
/* @@protoc_insertion_point(struct:dfu_signed_command_t) */
} dfu_signed_command_t;
typedef struct {
bool has_command;
dfu_Command command;
dfu_command_t 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))
#define _dfu_ValidationType_MIN dfu_ValidationType_NO_VALIDATION
#define _dfu_ValidationType_MAX dfu_ValidationType_VALIDATE_ECDSA_P256_SHA256
#define _dfu_ValidationType_ARRAYSIZE ((dfu_ValidationType)(dfu_ValidationType_VALIDATE_ECDSA_P256_SHA256+1))
dfu_signed_command_t signed_command;
/* @@protoc_insertion_point(struct:dfu_packet_t) */
} dfu_packet_t;
#ifdef __cplusplus
extern "C" {
#endif
/* Default values for struct fields */
extern const bool dfu_init_command_is_debug_default;
/* 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}
#define DFU_HASH_INIT_DEFAULT {(dfu_hash_type_t)0, {0, {0}}}
#define DFU_BOOT_VALIDATION_INIT_DEFAULT {(dfu_validation_type_t)0, {0, {0}}}
#define DFU_INIT_COMMAND_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_fw_type_t)0, false, 0, false, 0, false, 0, false, DFU_HASH_INIT_DEFAULT, false, false, 0, {DFU_BOOT_VALIDATION_INIT_DEFAULT, DFU_BOOT_VALIDATION_INIT_DEFAULT, DFU_BOOT_VALIDATION_INIT_DEFAULT}}
#define DFU_COMMAND_INIT_DEFAULT {false, (dfu_op_code_t)0, false, DFU_INIT_COMMAND_INIT_DEFAULT}
#define DFU_SIGNED_COMMAND_INIT_DEFAULT {DFU_COMMAND_INIT_DEFAULT, (dfu_signature_type_t)0, {0, {0}}}
#define DFU_PACKET_INIT_DEFAULT {false, DFU_COMMAND_INIT_DEFAULT, false, DFU_SIGNED_COMMAND_INIT_DEFAULT}
#define DFU_HASH_INIT_ZERO {(dfu_hash_type_t)0, {0, {0}}}
#define DFU_BOOT_VALIDATION_INIT_ZERO {(dfu_validation_type_t)0, {0, {0}}}
#define DFU_INIT_COMMAND_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_fw_type_t)0, false, 0, false, 0, false, 0, false, DFU_HASH_INIT_ZERO, false, 0, 0, {DFU_BOOT_VALIDATION_INIT_ZERO, DFU_BOOT_VALIDATION_INIT_ZERO, DFU_BOOT_VALIDATION_INIT_ZERO}}
#define DFU_COMMAND_INIT_ZERO {false, (dfu_op_code_t)0, false, DFU_INIT_COMMAND_INIT_ZERO}
#define DFU_SIGNED_COMMAND_INIT_ZERO {DFU_COMMAND_INIT_ZERO, (dfu_signature_type_t)0, {0, {0}}}
#define DFU_PACKET_INIT_ZERO {false, DFU_COMMAND_INIT_ZERO, false, DFU_SIGNED_COMMAND_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
#define DFU_BOOT_VALIDATION_TYPE_TAG 1
#define DFU_BOOT_VALIDATION_BYTES_TAG 2
#define DFU_HASH_HASH_TYPE_TAG 1
#define DFU_HASH_HASH_TAG 2
#define DFU_INIT_COMMAND_FW_VERSION_TAG 1
#define DFU_INIT_COMMAND_HW_VERSION_TAG 2
#define DFU_INIT_COMMAND_SD_REQ_TAG 3
#define DFU_INIT_COMMAND_TYPE_TAG 4
#define DFU_INIT_COMMAND_SD_SIZE_TAG 5
#define DFU_INIT_COMMAND_BL_SIZE_TAG 6
#define DFU_INIT_COMMAND_APP_SIZE_TAG 7
#define DFU_INIT_COMMAND_HASH_TAG 8
#define DFU_INIT_COMMAND_IS_DEBUG_TAG 9
#define DFU_INIT_COMMAND_BOOT_VALIDATION_TAG 10
#define DFU_COMMAND_OP_CODE_TAG 1
#define DFU_COMMAND_INIT_TAG 2
#define DFU_SIGNED_COMMAND_COMMAND_TAG 1
#define DFU_SIGNED_COMMAND_SIGNATURE_TYPE_TAG 2
#define DFU_SIGNED_COMMAND_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
extern const pb_field_t dfu_hash_fields[3];
extern const pb_field_t dfu_boot_validation_fields[3];
extern const pb_field_t dfu_init_command_fields[11];
extern const pb_field_t dfu_command_fields[3];
extern const pb_field_t dfu_signed_command_fields[4];
extern const pb_field_t dfu_packet_fields[3];
/* 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
#define DFU_HASH_SIZE 36
#define DFU_BOOT_VALIDATION_SIZE 68
#define DFU_INIT_COMMAND_SIZE 378
#define DFU_COMMAND_SIZE 383
#define DFU_SIGNED_COMMAND_SIZE 454
#define DFU_PACKET_SIZE 843
/* Message IDs (where set with "msgid" option) */
#ifdef PB_MSGID
#define DFU_CC_MESSAGES \
#endif
#ifdef __cplusplus
} /* extern "C" */
#endif
/* @@protoc_insertion_point(eof) */
#endif

@ -36,7 +36,7 @@ message Hash {
message BootValidation {
required uint32 sigmask = 1;
required ValidationType type = 1;
required bytes bytes = 2;
}
@ -63,9 +63,15 @@ message Command {
optional InitCommand init = 2;
}
// Signed command types
enum SignatureType {
ECDSA_P256_SHA256 = 0;
ED25519 = 1;
}
message SignedCommand {
required Command command = 1;
required uint32 sigmask = 2;
required SignatureType signature_type = 2;
required bytes signature = 3;
}

@ -71,7 +71,7 @@ NRF_LOG_MODULE_REGISTER();
#define NRF_DFU_PROTOCOL_REDUCED 0
#endif
STATIC_ASSERT(dfu_SignedCommand_size <= INIT_COMMAND_MAX_SIZE);
STATIC_ASSERT(DFU_SIGNED_COMMAND_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. */

@ -258,9 +258,19 @@ void nrf_dfu_settings_reinit(void)
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;
NRF_LOG_INFO("Old settings page detected. Upgrading info.");
// Old version. Translate.
memcpy(&s_dfu_settings.peer_data, (uint8_t *)&s_dfu_settings + DFU_SETTINGS_BOND_DATA_OFFSET_V1, NRF_DFU_PEER_DATA_LEN);
memcpy(&s_dfu_settings.adv_name, (uint8_t *)&s_dfu_settings + DFU_SETTINGS_ADV_NAME_OFFSET_V1, NRF_DFU_ADV_NAME_LEN);
// Initialize with defaults.
s_dfu_settings.boot_validation_softdevice.type = NO_VALIDATION;
s_dfu_settings.boot_validation_app.type = VALIDATE_CRC;
s_dfu_settings.boot_validation_bootloader.type = NO_VALIDATION;
memcpy(s_dfu_settings.boot_validation_app.bytes, &s_dfu_settings.bank_0.image_crc, sizeof(uint32_t));
s_dfu_settings.settings_version = NRF_DFU_SETTINGS_VERSION;
}
return;

@ -295,7 +295,7 @@ typedef enum
typedef struct
{
uint32_t sigmask;
boot_validation_type_t type;
uint8_t bytes[SETTINGS_BOOT_VALIDATION_SIZE];
} boot_validation_t;

@ -185,7 +185,7 @@ nrf_dfu_result_t nrf_dfu_validation_activation_prepare(uint32_t data_addr, uint3
*
* @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);
nrf_dfu_result_t nrf_dfu_validation_post_external_app_execute(dfu_init_command_t const * p_init, bool is_trusted);
/**
* @brief Function to check if there is a valid external app in Bank 1.

@ -78,7 +78,7 @@ static bool sd_req_check(uint32_t const * p_sd_req, uint8_t sd_req_cnt, bool acc
}
static bool sd_req_ok(dfu_InitCommand const * p_init)
static bool sd_req_ok(dfu_init_command_t const * p_init)
{
ASSERT(p_init != NULL);
bool result;
@ -100,9 +100,9 @@ static bool sd_req_ok(dfu_InitCommand const * p_init)
{
result = sd_req_check(p_init->sd_req,
p_init->sd_req_count,
(p_init->type == dfu_FwType_EXTERNAL_APPLICATION));
(p_init->type == DFU_FW_TYPE_EXTERNAL_APPLICATION));
}
else if (p_init->type == dfu_FwType_APPLICATION)
else if (p_init->type == DFU_FW_TYPE_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))
@ -131,7 +131,7 @@ static bool sd_req_ok(dfu_InitCommand const * p_init)
else
{
// Don't allow SoftDevice updates which assume no SD is present already.
result = !prevent_downgrade || (p_init->type != dfu_FwType_SOFTDEVICE);
result = !prevent_downgrade || (p_init->type != DFU_FW_TYPE_SOFTDEVICE);
}
}
@ -158,23 +158,23 @@ static bool sd_req_ok(dfu_InitCommand const * p_init)
}
static bool fw_hash_type_ok(dfu_InitCommand const * p_init)
static bool fw_hash_type_ok(dfu_init_command_t const * p_init)
{
ASSERT(p_init != NULL);
return (p_init->hash.hash_type == dfu_HashType_SHA256);
return (p_init->hash.hash_type == DFU_HASH_TYPE_SHA256);
}
static bool fw_version_required(dfu_FwType new_fw_type)
static bool fw_version_required(dfu_fw_type_t new_fw_type)
{
bool result = true;
if (new_fw_type == dfu_FwType_SOFTDEVICE)
if (new_fw_type == DFU_FW_TYPE_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)
else if (new_fw_type == DFU_FW_TYPE_APPLICATION)
{
result = NRF_DFU_APP_DOWNGRADE_PREVENTION; // fw_version is configurable in app updates.
}
@ -191,15 +191,15 @@ static bool fw_version_required(dfu_FwType new_fw_type)
}
static bool fw_type_ok(dfu_InitCommand const * p_init)
static bool fw_type_ok(dfu_init_command_t 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)
&& ( (p_init->type == DFU_FW_TYPE_APPLICATION)
|| (p_init->type == DFU_FW_TYPE_SOFTDEVICE)
|| (p_init->type == DFU_FW_TYPE_BOOTLOADER)
|| (p_init->type == DFU_FW_TYPE_SOFTDEVICE_BOOTLOADER)
#if NRF_DFU_SUPPORTS_EXTERNAL_APP
|| (p_init->type == DFU_FW_TYPE_EXTERNAL_APPLICATION)
#endif // NRF_DFU_SUPPORTS_EXTERNAL_APP
@ -214,13 +214,13 @@ static bool fw_type_ok(dfu_InitCommand const * p_init)
// This function assumes p_init->has_fw_version.
static bool fw_version_ok(dfu_InitCommand const * p_init)
static bool fw_version_ok(dfu_init_command_t 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 ((p_init->type == DFU_FW_TYPE_APPLICATION) ||
(p_init->type == DFU_FW_TYPE_SOFTDEVICE))
{
if (!NRF_DFU_APP_DOWNGRADE_PREVENTION)
{
@ -259,7 +259,7 @@ static bool fw_version_ok(dfu_InitCommand const * p_init)
}
nrf_dfu_result_t nrf_dfu_ver_validation_check(dfu_InitCommand const * p_init)
nrf_dfu_result_t nrf_dfu_ver_validation_check(dfu_init_command_t const * p_init)
{
nrf_dfu_result_t ret_val = NRF_DFU_RES_CODE_SUCCESS;
if (!fw_type_ok(p_init))

@ -59,6 +59,6 @@
*
* @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);
nrf_dfu_result_t nrf_dfu_ver_validation_check(dfu_init_command_t const * p_init);
#endif //__NRF_DFU_VER_VALIDATION_H

@ -253,6 +253,7 @@ Reset_Handler:
*
* All addresses must be aligned to 4 bytes boundary.
*/
#ifdef __STARTUP_CLEAR_BSS
ldr r1, =__bss_start__
ldr r2, =__bss_end__
@ -267,6 +268,7 @@ Reset_Handler:
bgt .L_loop3
.L_loop3_done:
#endif /* __STARTUP_CLEAR_BSS */
/* Execute SystemInit function. */
bl SystemInit
@ -275,7 +277,7 @@ Reset_Handler:
* If those libraries are not accessible, define __START as your entry point.
*/
#ifndef __START
#define __START main
#define __START _start
#endif
bl __START

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

Loading…
Cancel
Save