This thread has been locked.

If you have a related question, please click the "Ask a related question" button in the top right corner. The newly created question will be automatically linked to this question.

OTP programming fails when writing checksum, where to look?

Hi,

I'm trying to implement code protection in boot loader for RM46L852PGFT. I got AJSM example from this forum and embedded it into my code. Now I have:

AJSM_key.c:

/*
* AJSM_Key.c
*
* Created on: Nov 14, 2014
* Author: a0406448
*/

#pragma DATA_SECTION(AJSM_Key, "AJSM_Sec"); /* Specify Memory Section to link the key to */
#pragma DATA_ALIGN (AJSM_Key, 16); /* Ensure alignment to 128Bit = 16Byte */
#pragma RETAIN (AJSM_Key); /* Ensure that the Key will be linked */

const unsigned int AJSM_Key[4] = {0xAECD0000ul, 0xAECD0001ul, 0xAECD0002ul, 0xAECD0003ul};
/*
* New OTP = AECD0000 AECD0001 AECD0002 AECD0003
* Visible Key = EFFDFFFF FFFFFFFF FFFDFFFE FFEFFFFF
*/

Linker script:

--retain="*(.intvecs)"


MEMORY
{
VECTORS (X) : origin=0x00000000 length=0x00000020 fill=0xFFFFFFFF
FLASH_API (RX) : origin=0x00000020 length=0x000014E0 vfill=0xFFFFFFFF
FLASH0 (RX) : origin=0x00001500 length=0x00010000 vfill=0xFFFFFFFF 

/* Bank 0 ECC */
ECC_VEC (R) : origin=(0xf0400000 + (start(VECTORS) >> 3))
length=(size(VECTORS) >> 3)
ECC={algorithm=algoR4F021, input_range=VECTORS}
ECC_FLAA (R) : origin=(0xf0400000 + (start(FLASH_API) >> 3))
length=(size(FLASH_API) >> 3)
ECC={algorithm=algoR4F021, input_range=FLASH_API }
ECC_FLA0 (R) : origin=(0xf0400000 + (start(FLASH0) >> 3))
length=(size(FLASH0) >> 3)
ECC={algorithm=algoR4F021, input_range=FLASH0 }

AJSMKey (R) : origin=0xF0000000 length=0x00000010 vfill=0xffffffff

AJSMECC (R) : origin=0xF0040000 length=(size(AJSMKey) >> 3) ECC={algorithm=algoR4F021, input_range=AJSMKey}

SRAM (RW) : origin=0x08002000 length=0x0002D000
STACK (RW) : origin=0x08000000 length=0x00002000
}
SECTIONS
{
.intvecs : {} > VECTORS
flashAPI :
{
..\Release\Fapi_UserDefinedFunctions.obj (.text)
..\Release\bl_flash.obj (.text)

--library= F021_API_CortexR4_LE_V3D16.lib < FlashStateMachine.IssueFsmCommand.obj
FlashStateMachine.SetActiveBank.obj
FlashStateMachine.InitializeFlashBanks.obj
FlashStateMachine.EnableMainSectors.obj
FlashStateMachine.IssueFsmCommand.obj
FlashStateMachine.ScaleFclk.obj
Init.obj
Utilities.CalculateEcc.obj
Utilities.WaitDelay.obj
Utilities.CalculateFletcher.obj
Read.MarginByByte.obj
Read.Common.obj
Read.FlushPipeline.obj
Read.WdService.obj
Async.WithAddress.obj
Program.obj > (.text)
} load = FLASH_API, run = SRAM, LOAD_START(api_load), RUN_START(api_run), SIZE(api_size)


AJSM_Sec : palign(8) {} > AJSMKey

.text : palign(8) {} > FLASH0
.const : palign(8) {} > FLASH0
.cinit : palign(8) {} > FLASH0
.pinit : palign(8) {} > FLASH0
.data : {} > SRAM
.bss : {} > SRAM
}

/*----------------------------------------------------------------------------*/
/* Misc */
ECC {
algoR4F021 : address_mask = 0x003ffff8 /* Address Bits 21:3 */
hamming_mask = R4 /* Use R4 build in Mask */
parity_mask = 0x0c /* Set which ECC bits are Even and Odd parity */
mirroring = F021 /* RM4x are build in F021 */
}

/*----------------------------------------------------------------------------*/

Console output:

CortexR4: GEL Output: Memory Map Setup for Flash @ Address 0x0CortexR4: GEL Output: Memory Map Setup for Flash @ Address 0x0 due to System Reset
CortexR4: Writing Flash @ Address 0x00000000 of Length 0x00000020
CortexR4: Erasing Flash Bank 0, Sector 0
CortexR4: Writing Flash @ Address 0x00000020 of Length 0x00000cc4
CortexR4: Writing Flash @ Address 0x00001500 of Length 0x00007ff0
CortexR4: Erasing Flash Bank 0, Sector 1
CortexR4: Erasing Flash Bank 0, Sector 2
CortexR4: Writing Flash @ Address 0x000094f0 of Length 0x00000720
CortexR4: Writing Flash @ Address 0xf0000000 of Length 0x00000010
CortexR4: Writing Flash @ Address 0xf0040000 of Length 0x00000002
CortexR4: File Loader: Memory write failed: Flash algorithm returned an error during Flash programming. Note: Auto ECC generation is on, please make sure that the data sections are 64-bit memory aligned in your linker file; althernately, turn off Auto ECC generation in the On-Chip Flash settings
CortexR4: GEL: File: C:\Users\Andrus\Documents\ti\boot_uart\Release\boot_uart.out: Load failed.
CortexR4: GEL Output: Memory Map Setup for Flash @ Address 0x0 due to System Reset

result: jtag port is now secured and I cannot access the chip and my code also does not work.

I have 64-bit alignment turned on in project properties and auto ecc generation turned off. What else should I check to pinpoint this issue?

  • The ECC limits the valid visible unlock codes you can use. The visible unlock code in a blank part are: EFFDFFFF FFFFFFFF FFFDFFFE FFEFFFFF, which gives ECC values of ED C0. You properly chose a new visible unlock code that can be made by programming 1's to 0's, AECD0000 AECD0001 AECD0002 AECD0003. The ECC for this new code is 43 5C. You cannot program 43 5C on top of ED C0, some bits must be erased, but you cannot erase OTP.

    So how do you generate valid visible unlock codes for the RM4xx parts? We are working on a more elegant solution, but in the meantime, here is a small EXE file that runs from a PC command prompt and generates valid codes. It uses the PC time and srand() so you get different values each time you run it. The C source is included in the zip for your reference.

    /cfs-file/__key/communityserver-discussions-components-files/312/1777.AJSM.zip

  • Thank you for your answer, it was vewry helpful for understanding the failure I had. Now, I modified your source in following way, in order to generate output, which I can directly insert into AJSM_Key.c:

    line 38: printf("const unsigned int AJSM_Key[4]= {0x%08X, 0x%08X, 0x%08X, 0x%08X};\n",w[0],w[1],w[2],w[3]);

    This generated line:
    const unsigned int AJSM_Key[4] = {0x66BE0108, 0x1661D15A, 0x7C82C5C5, 0x26D62EA1};

    However, programming failed while writing OTP. Did I make incorrect modification?
  • Something is wrong with the generated value, maybe the order;

    Original: EFFDFFFF FFFFFFFF FFFDFFFE FFEFFFFF

    New:      66BE0108 1661D15A 7C82C5C5 26D62EA1

    You cannot change a D to an E, a D to a e, or an E to a 5 by only programming 1's to 0s.

  • Hi, in the code you sent, visible key is not:

    Original: EFFDFFFF FFFFFFFF FFFDFFFE FFEFFFFF

    It is: const unsigned int visible_key[4]= {0xfffffdef  , 0xFFFFFFFF , 0xfefffdff  , 0xffffefff};

    Should this be changed to:  

    const unsigned int visible_key[4]= {0xEFFDFFFF, 0xFFFFFFFF, 0xFFFDFFFE, 0xFFEFFFFF}; ?

  • Hi, I found, that also ECC endianess is wrong. I reversed it and now I got copy protection working! J

    Here is WORKING AJSM key generation code:

    #include <stdio.h>
    #include <stdlib.h>
    #include <time.h>

    const unsigned int visible_key[4]= {0xEFFDFFFF, 0xFFFFFFFF, 0xFFFDFFFE, 0xFFEFFFFF};
    const unsigned char visible_ecc[2]={0xED,0xC0};


    unsigned char calc_ecc(unsigned int data, unsigned int data1, unsigned int address);
    unsigned int evenparity(unsigned int ub, unsigned int lb);

    int main(int argc, char* argv[])
    {
    unsigned int w[4];
    unsigned char ecc[2];
    unsigned int i,j,number_solutions,pass;

    printf("AJSM Valid Lock Key Generator Hercules RM Parts\n");
    if(argc == 2)
    sscanf(argv[1],"%d",&number_solutions);
    else
    number_solutions=1;

    srand(time(0));
    for(i=0;i<number_solutions;i++)
    { do
    { pass=1;
    for(j=0;j<4;j++)
    {
    w[j]=(rand() & visible_key[j]);
    }
    ecc[0]=calc_ecc(w[0],w[1],0);
    if(((ecc[0] & (~visible_ecc[0]))!=0))pass=0;
    ecc[1]=calc_ecc(w[2],w[3],8);
    if(((ecc[1] & (~visible_ecc[1]))!=0))pass=0;
    } while(pass==0);
    printf("const unsigned int AJSM_Key[4]= {0x%08X, 0x%08X, 0x%08X, 0x%08X}; //ECC 0x%02X%02X\n",w[0],w[1],w[2],w[3],ecc[1],ecc[0]);
    }
    return 0;

    }

    const int ecc_addr[]={0x002AA750,0x0005D688,0x00154DA8,0x000353C68,0x000CFC18,0x0003FC00,0x003FFC00,0x000003F8};
    const int upper[]={0xb4d1b4d1,0x15571557,0xa699a699,0x38e338e3,0xc0fcc0fc,0xff00ff00,0xff0000ff,0x00ffff00};
    const int lower[]={0x4b2e4b2e,0x15571557,0xa699a699,0x38e338e3,0xc0fcc0fc,0xff00ff00,0xff0000ff,0xff0000ff};

    unsigned char calc_ecc(unsigned int data, unsigned int data1, unsigned int address)
    {
    unsigned int b[8],ub[8],lb[8],addr1[8],k;
    unsigned char ecc;

    for(k=0;k<8;k++)
    {
    ub[k]=upper[k] & data1;
    lb[k]=lower[k] & data;
    b[k]=evenparity(ub[k],lb[k]);
    addr1[k]=ecc_addr[k] & address;
    b[k]=evenparity(b[k],addr1[k]);
    }

    ecc = 0;

    for(k=0;k<8;k++)
    if(b[k])
    ecc+=(1<<k);

    ecc^=0x0C;
    return ecc;
    }


    unsigned int evenparity(unsigned int ub, unsigned int lb)
    {
    unsigned int p;

    p=ub^lb; // now 32 bits
    p=(p&0xffff)^((p>>16)); // now 16 bits
    p=(p&0xff)^((p>>8)); // now 8 bits
    p=(p&0xf)^((p>>4)); // now 4 bits
    p=(p&0x3)^((p>>2)); // now 2 bits
    p=(p&0x1)^((p>>1)); // now 1 bit
    return p;
    }