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.

Compiler/TM4C1294NCPDT: Flash memory read protection

Part Number: TM4C1294NCPDT

Tool/software: TI C/C++ Compiler

Hi Folks,

I want to protect my binary from unauthorized reuse, so I want to lock the device's flash. As I know well, it is only possible to protect the .text section (it is  the executable), but my .cmd file looks like this:

    .intvecs:   > 0x00000000
    .text   :   > FLASH
    .const  :   > FLASH
    .cinit  :   > FLASH
    .pinit  :   > FLASH
    .init_array : > FLASH


I think, the .text section should stay at the end and the linker should be forced to align into the lockable page boundary. Can anybody suggest me, what is the right way / best practice to do that?

Regards,
Norbert
  • Hello Norbert

    The right method to protect the code is by using the Flash protection registers. Do note that when performing a Read protection, you must ensure that the literal pool tables are not created as from CPU it will result in a read of the flash causing Bus Fault. This can be handled using changing the optimization setting and avoiding literal pool setting in the CCS project settings.
  • Adding a few more details. You partition the flash into the readable and the execute only portions in the link command file. Here is a sample that I did.

    /* System memory map */
    
    MEMORY
    {
        /* Application stored in and executes from internal flash */
        FLASH (RX) : origin = APP_BASE, length = 0x00010000
        FLASH2 (X) : origin = 0x00010000, length = 0x00030000
        /* Application uses internal RAM for data */
        SRAM (RWX) : origin = 0x20000000, length = 0x00008000
    }
    
    /* Section allocation in memory */
    
    SECTIONS
    {
        .intvecs:   > APP_BASE
        .libtext:
        {
        	driverlib.lib<*.obj>(.text)
        	rtsv7M4_T_le_v4SPD16_eabi.lib<*.obj>(.text)
        }    > FLASH
        .text   :   > FLASH2
        .const  :   > FLASH
        .cinit  :   > FLASH
        .pinit  :   > FLASH
        .init_array : > FLASH
    
        .vtable :   > RAM_BASE
        .data   :   > SRAM
        .bss    :   > SRAM
        .sysmem :   > SRAM
        .stack  :   > SRAM
    }
    
    __STACK_TOP = __stack + 256;
    

    In lines 6 and 7 I broke the flash into two memory blocks. The readable part I left named FLASH and the execute only part I gave the name of FLASH2. In the sections directive I changed the .text section to point to FLASH2 (line 22). Now as Amit mentioned, you must compile the code so it does not embedded constants in the .text section. If you don't want to recompile the libraries with that option, the .text section from the libraries must be linked into the readable flash. My code referenced two libraries. I redirected the .text sections from those two libraries into FLASH in lines 17 through 21.

    Disallow embedding constants in your runtime code by changing the project settings as shown below:

  • Norbert Toth said:
    I want to protect my binary from unauthorized reuse...

    Good that - many share that desire - yet can you (really) build a wall/moat tall and deep enough?    With a (roughly) 10 USD MCU?

    If your desire is "real" why not ask this vendor (or any similar others) to "place into writing" language which "guarantees" the success of these "secure your code" measures?

    Having past worked at another semi "giant" - I can tell you that those who WANT your code shall HAVE your code - even if - and ESPECIALLY if - you follow these (demanding) directions.

    Those seeking your code are likely far better equipped than you - have superior resources - and are (very) highly skilled.   (and very well paid)

    Note that this vendor is NOT alone in presenting an (overly) optimistic case for a long standing MCU vulnerability...    Is a "band-aid" adequate treatment for a "nicked" artery?

    Again - ask for your security guarantee "in writing" - that tells the REAL tale...

  • Hi,

    thanks for your reply. Can you help me, how I can get the address of FLASH2 from source? I don't want to hard code register access, or memory address into my code, but I know, somehow I can build the start address of a section into my source.

    Regards,
    Norbert
  • The distinction between the memory regions FLASH and FLASH2 is that for the range defined as FLASH2 you will program the Flash Memory Protection register bits to make that memory Execute Only. Since you don't know how much Execute Only flash you need and how much readable flash you need until your code development is complete here is another way to link your file:

    #define APP_BASE 0x00000000
    #define RAM_BASE 0x20000000
    
    /* System memory map */
    
    MEMORY
    {
        /* Application stored in and executes from internal flash */
        FLASH (RX) : origin = APP_BASE, length = 0x00040000
        /* Application uses internal RAM for data */
        SRAM (RWX) : origin = 0x20000000, length = 0x00008000
    }
    
    /* Section allocation in memory */
    
    SECTIONS
    {
        .intvecs:   > APP_BASE
        .libtext:
        {
        	driverlib.lib<*.obj>(.text)
        	rtsv7M4_T_le_v4SPD16_eabi.lib<*.obj>(.text)
        }    > FLASH
        .text   :   > FLASH palign = 2048, fill = 0xffffffff
        .const  :   > FLASH
        .cinit  :   > FLASH
        .pinit  :   > FLASH
        .init_array : > FLASH
    
        .vtable :   > RAM_BASE
        .data   :   > SRAM
        .bss    :   > SRAM
        .sysmem :   > SRAM
        .stack  :   > SRAM
    }
    
    __STACK_TOP = __stack + 256;
    

    In this link command file, all 1MB of flash is represented by FLASH. Note that in line 24 I added the key words "palign" and "fill". Since the Execute Only portion of the flash must be contained in some number of 2KB segments, I used "palign = 2048" to align this output section to a 2KB boundary, and pad to the end of a 2KB boundary. The "fill" keyword says to use 0xffffffff as the fill value for the padding. The padding prevents the linker from packing any other code that may need read access onto the end of my Execute Only code.

    Once my code development is complete, I can look at the .map file generated by the linker and see which 2KB section of flash to convert to Execute Only. If I want to put the Execute Only section in a particular place, such as at the top end of the flash, then I could break the FLASH memory directive into FLASH and FLASH2 like I did before, but now I know the exact sizes needed.