2017年4月18日 星期二

nRF51/52 ROM Protection : Prevent Someone Else From Dumping the Hex File


   To avoid being piracy is very important for software and firmware development. Of course, you should protect your source code from being spreaded out. But from firmware perspective, it is a way to piracy your intelligence: burglar might clone your WHOLE device, including the mechanism, circuit and firmware for mass production directly. It is not necessary to obtain your source code.
  In nRF51822 and 52832, There is a mechanism to prevent that happens. I will demonstrate that:
 My SDK versions are 10 for nRF51, and 11 for nRF52.

  To Simplify the demonstration. I copy the header file from peripheral\uicr_config\uicr_config.h to my project folder, and the main.c includes the file.
    Open the uicr_config.h, you could read that there is many address listed, you could modify the values on those addresses. The values I changing be :

// const uint32_t UICR_CLENR0    __attribute__((at(0x10001000))) __attribute__((used)) = 0xFFFFFFFF;
// const uint32_t UICR_RBPCONF   __attribute__((at(0x10001004))) __attribute__((used)) = 0xFFFFFFFF;
// const uint32_t UICR_XTALFREQ  __attribute__((at(0x10001008))) __attribute__((used)) = 0xFFFFFFFF;

const uint32_t UICR_ADDR_0x80 __attribute__((at(0x10001080))) __attribute__((used)) = 0x12345678;
// const uint32_t UICR_ADDR_0x84 __attribute__((at(0x10001084))) __attribute__((used)) = 0xFFFFFFFF;
// const uint32_t UICR_ADDR_0x88 __attribute__((at(0x10001088))) __attribute__((used)) = 0xFFFFFFFF;
// const uint32_t UICR_ADDR_0x8C __attribute__((at(0x1000108C))) __attribute__((used)) = 0xFFFFFFFF;
 const uint32_t UICR_ADDR_0x90 __attribute__((at(0x10001090))) __attribute__((used)) = 0x11223344;
 const uint32_t UICR_ADDR_0x94 __attribute__((at(0x10001094))) __attribute__((used)) = 0x55667788;
// const uint32_t UICR_ADDR_0x98 __attribute__((at(0x10001098))) __attribute__((used)) = 0xFFFFFFFF;
// const uint32_t UICR_ADDR_0x9C __attribute__((at(0x1000109C))) __attribute__((used)) = 0xFFFFFFFF;
// const uint32_t UICR_ADDR_0xA0 __attribute__((at(0x100010A0))) __attribute__((used)) = 0xFFFFFFFF;
// const uint32_t UICR_ADDR_0xA4 __attribute__((at(0x100010A4))) __attribute__((used)) = 0xFFFFFFFF;
// const uint32_t UICR_ADDR_0xA8 __attribute__((at(0x100010A8))) __attribute__((used)) = 0xFFFFFFFF;
// const uint32_t UICR_ADDR_0xAC __attribute__((at(0x100010AC))) __attribute__((used)) = 0xFFFFFFFF;
// const uint32_t UICR_ADDR_0xB0 __attribute__((at(0x100010B0))) __attribute__((used)) = 0xFFFFFFFF;
 const uint32_t UICR_ADDR_0xB4 __attribute__((at(0x100010B4))) __attribute__((used)) = 0xAABBCCDD;
// const uint32_t UICR_ADDR_0xB8 __attribute__((at(0x100010B8))) __attribute__((used)) = 0xFFFFFFFF;
// const uint32_t UICR_ADDR_0xBC __attribute__((at(0x100010BC))) __attribute__((used)) = 0xFFFFFFFF;
// const uint32_t UICR_ADDR_0xC0 __attribute__((at(0x100010C0))) __attribute__((used)) = 0xFFFFFFFF;
// const uint32_t UICR_ADDR_0xC4 __attribute__((at(0x100010C4))) __attribute__((used)) = 0xFFFFFFFF;
// const uint32_t UICR_ADDR_0xC8 __attribute__((at(0x100010C8))) __attribute__((used)) = 0xFFFFFFFF;
// const uint32_t UICR_ADDR_0xCC __attribute__((at(0x100010CC))) __attribute__((used)) = 0xFFFFFFFF;
// const uint32_t UICR_ADDR_0xD0 __attribute__((at(0x100010D0))) __attribute__((used)) = 0xFFFFFFFF;
// const uint32_t UICR_ADDR_0xD4 __attribute__((at(0x100010D4))) __attribute__((used)) = 0xFFFFFFFF;

  By the way,  What is UICR ? UICR is the short for User Information Configuration Registers, where the values are non-alterable. The purpose for UICR is to make a space for manufacturer signing.


Build and download the hex to your device, and type the command line (I use nRF52832 as my target device):


> nrfjprog --family NRF52 --memrd 0x10001080 --n 128
0x10001080: 12345678 FFFFFFFF FFFFFFFF FFFFFFFF   |xV4.............|
0x10001090: 11223344 55667788 FFFFFFFF FFFFFFFF   |D3"..wfU........|
0x100010A0: FFFFFFFF FFFFFFFF FFFFFFFF FFFFFFFF   |................|
0x100010B0: FFFFFFFF AABBCCDD FFFFFFFF FFFFFFFF   |................|
0x100010C0: FFFFFFFF FFFFFFFF FFFFFFFF FFFFFFFF   |................|
0x100010D0: FFFFFFFF FFFFFFFF FFFFFFFF FFFFFFFF   |................|
0x100010E0: FFFFFFFF FFFFFFFF FFFFFFFF FFFFFFFF   |................|
0x100010F0: FFFFFFFF FFFFFFFF FFFFFFFF FFFFFFFF   |................|

 The address values have been changed.

You could use the command the dump the whole hex :


> nrfjprog --family NRF52 --readcode output.hex

That is what I prevent from.


To avoid the dumping, Add below code in the beginning of main function :


#include "ble_flash.h"

/**@brief Function for application main entry.
 */
int main(void)
{
#if(1)
 if(UICR_RBPCONF_PALL_Enabled !=
  (uint32_t)((NRF_UICR->RBPCONF & UICR_RBPCONF_PALL_Msk) >> UICR_RBPCONF_PALL_Pos)) 
 {
  ble_flash_word_write((uint32_t *)&NRF_UICR->RBPCONF, 
   (NRF_UICR->RBPCONF & ~UICR_RBPCONF_PALL_Msk));
 }/*if */
#endif 
    uint32_t err_code;
    bool erase_bonds;

and you should include folder SDK_ROOT\components\drivers_nrf\ble_flash and the file SDK_ROOT\components\drivers_nrf\ble_flash\ble_flash.c in your working porject.

Take Keil C as the project modification example:




After download to the device, you could find the readback command would not work:


> nrfjprog --family NRF52 --memrd 0x10001080 --n 128
ERROR: The operation attempted is unavailable due to readback protection in
ERROR: your device. Please use --recover to unlock the device.

  That is, the SWD (Serial Wired Debug) function has been forbidden, the SWD could accept recover request from now.

NOTE :If you use Keil C, the IDE would not reset the device after the downloading. but you could press the download button twice to make sure the SWD has been disabled:

* JLink Info: Found SWD-DP with ID 0x2BA01477
* JLink Info: Found Cortex-M4 r0p1, Little endian.
* JLink Info: FPUnit: 6 code (BP) slots and 2 literal slots
* JLink Info: CoreSight components:
* JLink Info: ROMTbl 0 @ E00FF000
* JLink Info: ROMTbl 0 [0]: FFF0F000, CID: B105E00D, PID: 000BB00C SCS
* JLink Info: ROMTbl 0 [1]: FFF02000, CID: B105E00D, PID: 003BB002 DWT
* JLink Info: ROMTbl 0 [2]: FFF03000, CID: B105E00D, PID: 002BB003 FPB
* JLink Info: ROMTbl 0 [3]: FFF01000, CID: B105E00D, PID: 003BB001 ITM
* JLink Info: ROMTbl 0 [4]: FFF41000, CID: B105900D, PID: 000BB9A1 TPIU
* JLink Info: ROMTbl 0 [5]: FFF42000, CID: B105900D, PID: 000BB925 ETM
ROMTableAddr = 0xE00FF000
* JLink Info: SYSRESETREQ has confused core. Trying to reconnect and use VECTRESET.
* JLink Info: Found SWD-DP with ID 0x2BA01477
**JLink Warning: Failed to reset CPU. VECTRESET has confused core.
* JLink Info: Core is locked-up, trying to disable WDT.
**JLink Warning: Could not set S_RESET_ST
* JLink Info: Found SWD-DP with ID 0x2BA01477
* JLink Info: SYSRESETREQ has confused core. Trying to reconnect and use VECTRESET.
* JLink Info: Found SWD-DP with ID 0x2BA01477
**JLink Warning: Failed to reset CPU. VECTRESET has confused core.
* JLink Info: Core is locked-up, trying to disable WDT.
**JLink Warning: Could not set S_RESET_ST


Now you could see, the dumping has not been permitted, the only way to manipulate the storage (ROM) is to recover whole space: it is, erase all.

2017年4月4日 星期二

nRF51/52 : Disable Unused GPIOs


      

          By this forum thread, for unused GPIOs in nRF51822/nRF52832, programmer should set those as input pin, and set those in disconnection (from input buffer).

Following the rule, the code be:


//#include "nrf_gpio.h"

/**@brief Function to disable all gpio
*/
static void disable_all_gpio(void)
{
 uint32_t i;

 for( i = 0; i< NUMBER_OF_PINS; i++){
  NRF_GPIO->PIN_CNF[i] = 
  (GPIO_PIN_CNF_SENSE_Disabled << GPIO_PIN_CNF_SENSE_Pos)
  | (GPIO_PIN_CNF_DRIVE_S0S1 << GPIO_PIN_CNF_DRIVE_Pos)
  | (GPIO_PIN_CNF_PULL_Disabled << GPIO_PIN_CNF_PULL_Pos)
  | (GPIO_PIN_CNF_INPUT_Disconnect << GPIO_PIN_CNF_INPUT_Pos)
  | (GPIO_PIN_CNF_DIR_Input << GPIO_PIN_CNF_DIR_Pos);
 }/*for i*/

}/*disable_all_gpio*/



        If you avoid to manipulate the GPIO registers directly, you could call the wrapping function, nrf_gpio_input_disconnect.


//#include "nrf_gpio.h"

/**@brief Function to disable all gpio
*/
static void disable_all_gpio(void)
{
 uint32_t i;
 
 for( i = 0; i< NUMBER_OF_PINS; i++)
  nrf_gpio_input_disconnect(i);
}/*disable_all_gpio*/


      Theoretically, if you set the unused GPIOs in that way, the power-consumption will be lower.