This discussion has been locked.
You can no longer post new replies to this discussion. If you have a question you can start a new discussion

Flash protection

I'm using silabs parts. The 040 has a vmon protection that resets the process when the supply voltage drops to a point where flash could be corrupted.
That is enabled in my code.
We are seeing devices come back with apparently corrupted flash (these are locked so we actually
cannot see the flash contents, but they appear to be locked in reset loops or partially run and then get crazy.

In order to ensure that rouge code doesn't execute the flash write routines, I'd like to be able
to alter the flash by using code to overwrite the flash enable lines with nops so it will
physically be impossible for the code to alter flags required to initiate a flash write.

Generating code that can overwrite a function is proving to be difficult. How can I force
Keil 7.5 C51 compiler to do this?

To enable the flash writes on the silab part, you have to set a bit that enables
flash write/erase, then you set a bit that changes the target of the MOVX instruction so that it targets flash. you need code that looks like this:
CBYTE can also be used, but it is throwing some strange error messages.

unsigned char code* ptr;

ptr=&lcation; // point to a byte in flash boo();
....
boo()
{ FLSCL=1; PCTL=1; // *ptr=0xAA; // generates a MOVX which, due to the bits above, will target flash PCTL=0; FLSCL=0; // now movx instructions access xram, and writes are disabled.
}


What I want to do is to add in a line of code after the bits are set, that will reference foo + some offset.
For example, foo+3 happens the be the FLSCL instruction. The CBYTE macro throws an error.
When I do a manual replace like this:


      *((unsigned char volatile code * &(foo))=0x00;


The compiler swallows it nicely, and completely eliminates the above line.
I thought about using a label and generating a point to it, but C doesn't allow that. Then
the thought occurred : "Well you can take the address of a function:..."

Currently I have code running that does something similar to this as part of a personalization/configuration procedure:

but I can't make the compiler generate a pointer to foo (see above) CBYTE[foo] throws an
error. CBYTE[&foo()] throws an error.....


This is from working code:

void configure_me()
    {
    unsigned char volatile xdata * write_ptr;

    unsigned int t;

    saved_ie = IE;
    EA = 0;                            // disable interrupts (precautionary)
    write_ptr=&(security[0]);    // it is critical that this comes before flash
                                // enable.  The damn compiler uses movx
                                // otherwise and screws things up

    FLSCL=0x01;               // enable flash write/erase
    PSCTL=0x01;               // NOT 2, which would erase flash, but 1 write to flash
    *write_ptr=CBYTE[0xFA00];
    PSCTL = 0x00;              // MOVX writes target XRAM
    FLSCL=0;                   // disable flash write

    write_flash(&(security[1]),0xFA00,20);   // copy serial number
    FLSCL=0x01;               // enable flash write/erase
        PSCTL = 0x03;         // MOVX writes target FLASH memory, and erase is ENabled
    XBYTE[0xFA00]=0;          // erase the flash page
    PSCTL=0x00;
    FLSCL=0x00;                // disable flash write

    IE=saved_ie;
}

idata unsigned char byt2wrt;


void write_flash( unsigned char  * dest,  unsigned char  code*  srce,   int len)
    {
    char EA_save;                      // saves the current state of the interrupts
    register volatile unsigned char code * source;
    register volatile unsigned char xdata * destination;

    EA_save = EA;
    EA = 0;                            // disable interrupts (precautionary)
    source=srce;
    destination=dest;
    FLSCL=0x01;               // enable flash write/erase

    do
        {                          // copy until len is 0
        byt2wrt=*srce;             // ensure that no MOVX is used. Variable is in idata.
        PSCTL = 0x01;              // MOVX writes target FLASH memory, and erase is disabled
        *destination=byt2wrt;
        PSCTL=0;                   // MOVX writes to xdata
        srce++;                    // advance pointers
        destination++;
        len--;
        }
    while (len != 0);
    PSCTL = 0x00;              // MOVX writes target XRAM
    FLSCL=0x00;                // disable flash write
    EA = EA_save;                      // re-enable interrupts

    }



Parents
  • O.k. Here is more information:

    This device requires personalization. That is:
    Once the hex file has been downloaded into a blank silabs part (the 040 in this case),
    the person loading the firmware needs to enter a serial number and a device type.
    He does that by entering the information into page 0xFA00. When the unit is power cycled, or
    reset, it checks to see if 0xFA00 is either a 0xFF (unprogrammed) or 0x20 (programmed).
    If it is anything else, it means that the production person has put in the serialization and production code.
    It then needs to put the serial number etc into a secure place in flash elsewhere.
    So it copies the serial number from 0xFA00 into an array living somewhere else in the flash
    image. It then erases the FA00 page, and writes the model, the serial number and the copyright
    into page 0xFA00, and a 0x20 into 0xFA00. This way, the power up code can compare the security array (where the serial number is stored) with the FA00 serial number to detect tampering...

    Thats way to much stuff for a person to manually enter..

    This is a hold over from the F310 code. In the F310 code, this was at 7A00.
    This was done so that you could lock all the pages but the last one, and when a unit came back
    in for service, you could use the debugger and open the single unprotected page, and see the unit type, serial number and copyright.

    Unfortunatly, the 040 does not allow you to do that, but we still have to have the
    personalization step. So, the code is still there.

    Upon power up, the serial number is checked against the FA00 serial number, and if they don't match it locks up. This, on the 310 was done just in case some yoyo figured out to hook a silabs debugger up to the programming port. We also, in the 310, cleared consecutive bits in flash starting at 0xFB00 to to the flash protect byte, on each power on. This way, we could at least make a sanity check if someone returned a unit claiming they had used it only a few tiems....

    In the 040, this is done by writing the time, power ups and some other information to a serial eeprom, as well as the model, checksum etc.

    For some reason, we rarely got any 310 based ones back that were bad, but occasionally we did. In the 310 version there was no checksum.

    So the write to flash routines are needed only at production time, or service (if a unit comes back in for service).

    And, no, the silabs parts will not allow you to run from xram. I wish they did, it would make life a lot easier.

    I recently (today) while making some tweaks to this code, discovered that the Keil 7.5 compiler seems to have a bug in the CWORD macro...
    What I was doing:
    I checksum 0-FAFF. I write the checksum to the serial eeprom, but also want to write the checksum to flash as well, just outside of the the checksummed area.

    This works:
            FLSCL=0x01;               // enable flash write/erase
            PSCTL=0x01;                     // BUGG  NOT 2, which would erase flash, but 1write to flash
         //   *write_ptr=(unsigned char) ((chksum >> 8)&0xFF);
            //      *write_ptr+1=(unsigned char) (chksum &0xFF);
                    XBYTE[0xFB00]=(unsigned char) ((chksum >> 8)&0xFF);
                    XBYTE[0xFB01]=(unsigned char) (chksum &0xFF);
            PSCTL = 0x00;              // MOVX writes target XRAM
            FLSCL=0;                // disable flash write
    


    BUT trying to access this as a word for comparison purposes using CWORD[0xFB00] fails by generating a 0xF600 load into dptr rather than the correct FB00....

Reply
  • O.k. Here is more information:

    This device requires personalization. That is:
    Once the hex file has been downloaded into a blank silabs part (the 040 in this case),
    the person loading the firmware needs to enter a serial number and a device type.
    He does that by entering the information into page 0xFA00. When the unit is power cycled, or
    reset, it checks to see if 0xFA00 is either a 0xFF (unprogrammed) or 0x20 (programmed).
    If it is anything else, it means that the production person has put in the serialization and production code.
    It then needs to put the serial number etc into a secure place in flash elsewhere.
    So it copies the serial number from 0xFA00 into an array living somewhere else in the flash
    image. It then erases the FA00 page, and writes the model, the serial number and the copyright
    into page 0xFA00, and a 0x20 into 0xFA00. This way, the power up code can compare the security array (where the serial number is stored) with the FA00 serial number to detect tampering...

    Thats way to much stuff for a person to manually enter..

    This is a hold over from the F310 code. In the F310 code, this was at 7A00.
    This was done so that you could lock all the pages but the last one, and when a unit came back
    in for service, you could use the debugger and open the single unprotected page, and see the unit type, serial number and copyright.

    Unfortunatly, the 040 does not allow you to do that, but we still have to have the
    personalization step. So, the code is still there.

    Upon power up, the serial number is checked against the FA00 serial number, and if they don't match it locks up. This, on the 310 was done just in case some yoyo figured out to hook a silabs debugger up to the programming port. We also, in the 310, cleared consecutive bits in flash starting at 0xFB00 to to the flash protect byte, on each power on. This way, we could at least make a sanity check if someone returned a unit claiming they had used it only a few tiems....

    In the 040, this is done by writing the time, power ups and some other information to a serial eeprom, as well as the model, checksum etc.

    For some reason, we rarely got any 310 based ones back that were bad, but occasionally we did. In the 310 version there was no checksum.

    So the write to flash routines are needed only at production time, or service (if a unit comes back in for service).

    And, no, the silabs parts will not allow you to run from xram. I wish they did, it would make life a lot easier.

    I recently (today) while making some tweaks to this code, discovered that the Keil 7.5 compiler seems to have a bug in the CWORD macro...
    What I was doing:
    I checksum 0-FAFF. I write the checksum to the serial eeprom, but also want to write the checksum to flash as well, just outside of the the checksummed area.

    This works:
            FLSCL=0x01;               // enable flash write/erase
            PSCTL=0x01;                     // BUGG  NOT 2, which would erase flash, but 1write to flash
         //   *write_ptr=(unsigned char) ((chksum >> 8)&0xFF);
            //      *write_ptr+1=(unsigned char) (chksum &0xFF);
                    XBYTE[0xFB00]=(unsigned char) ((chksum >> 8)&0xFF);
                    XBYTE[0xFB01]=(unsigned char) (chksum &0xFF);
            PSCTL = 0x00;              // MOVX writes target XRAM
            FLSCL=0;                // disable flash write
    


    BUT trying to access this as a word for comparison purposes using CWORD[0xFB00] fails by generating a 0xF600 load into dptr rather than the correct FB00....

Children
  • Once the hex file has been downloaded into a blank silabs part (the 040 in this case),
    the person loading the firmware needs to enter a serial number and a device type.

    I don't see that as sufficient justification for deciding to put a flash write routine into the software. That could just as well be handled by modifying the hex file to be flashed, before flashing the chip. And save you a whole lot of hassle while at it.

    I recently (today) while making some tweaks to this code, discovered that the Keil 7.5 compiler seems to have a bug in the CWORD macro...

    As explained elsewhere, your reasoning towards this discovery was incorrect. You failed to read and/or understand the documentation about CWORD.

  • So the write to flash routines are needed only at production time, or service (if a unit comes back in for service).

    your problem will be gone with the puillup resistor (if not, you have a REAL problem with runaway code even without power cycling), however, if you can not modify the hardware, what about making a SEPARATE program for setting these values.

    Again, I strongly recommend the hardware option, even without the flash write routines, you may get dropouts till you install the resistor (I use 2k2, anything between 1k and 22k will work)

    Erik

    PS the "pullup, no cap" is the concensus of the 'gurus' at the SILabs forum>

  • um... might be, but you have to understand that the guys programming the parts would be totally
    incapable of doing this.

    Additionally, since this is an FDA cleared device, you cannot alter the hex file (binary) if you
    do you have to completely do a new Verification and Validation, and that is a good 10 days of work on this device. If you had to alter the binary for every device programmed, i.e. sold, you would hit the verification trap. So that is completely out of the question. If discovered on an audit, it would get the company completely shut down...

  • If you had to alter the binary for every device programmed, i.e. sold, you would hit the verification trap.

    But that's exactly what you are doing: you're changing the actual binary contents of every single device. You're just not doing it in one go, but doing it in two separate steps.

    And even if all that writing of data wasn't seen as a modification of the binary, what you're about to try here certainly is one. You're planning to modify the verified code, post-verification. You're essentially trying to cure diarrhea by infection with the flu.

  • According to silabs the pullup is not required. HOWEVER:
    What we are going to do is to put an external reset monitor on the reset line.
    Here is what I suspect is going on.

    The silabs data sheet says that VMON resets the processor when VDD is < 2.7 v. BUT what it DOES NOT say, is how long the reset is asserted for. Does it just do a instant reset and allow it to
    start running, or does it hold it in reset for some time after the voltage comes back up.

    The behavior leads me to believe that they are just pulling and releasing the reset line. That
    would allow for the possibility of flash corruption.

    So I've asked the hardware guys to put in a vdd monitor and put a pull up on the rst line as well. will probably use the APX803 200ms (Typ) because the hardware guys are all ex TI guys, and Diodes inc is a TI spinoff and they know the company....

    Sometimes design wins are not about merit, but about who you know or prior experiences.

  • According to silabs the pullup is not required
    yeah, yeah, have a look of the 'schematic' of the reset circuitry that you will find in some of the datahseets (I know it is in the f12x) and you will see it is open drain (wired-OR). SILabs also persist in us having to tell devboard purchasers to remove the capacitor when they post their reset problems.

    What we are going to do is to put an external reset monitor on the reset line.
    well, if my handgun is not enough for you, by all means use a RPG. That will fix it too

    The silabs data sheet says that VMON resets the processor when VDD is < 2.7 v. BUT what it DOES NOT say, is how long the reset is asserted for. Does it just do a instant reset and allow it to start running, or does it hold it in reset for some time after the voltage comes back up.
    it is static, but just visualize an open drain without any pullup but a CMOS input.

    will probably use the APX803 200ms (Typ)
    make sure it an open collector/open drain device or it will pop when te watchdog (or internal Vdd monitor) bites

    Sometimes design wins are not about merit, but about who you know or prior experiences.
    fer sure, fer sure

    BTW you switched from a deviate <f3x -up) to a derivative how many of the "subtle differences" did you get caught in

    Erik

  • BTW you switched from a deviate <f3x -up) to a derivative how many of the "subtle differences" did you get caught in?...

    Grin. it was a process:
    We first used the 320 because we planned on using a usb connection for supplying control tables.
    We then changed to a 310 because we decided not to use a usb connection, and it was a cheaper part.
    I then ported the 320 code to a 342 so I had more code space to implement a prototype of the
    display unit.
    I then ported the 310 code to a 361 for more code space, but could not get the company to spring
    for the extra cost to replace the 310 (which is has 10 lbs of stuff jammed into a 5 lb bag, with about 3 bytes to spare) with the 361.
    Then we considered to use a 124 for the display unit, so I ported the code to that, but I decided not to use it (I don't remember the exact issue) , and switched over to the 040.

    I got caught in about every one of the "subtle differences" over this course of time.
    I started the project in 2004 with the 320....

    Silabs makes great parts, good documentation, but they seem to be more of a shotgun approach with features. They are all over the map, with a limited pin compatible migration path from small memory to larger memory. I think it took them 4 years to come out with the 342, which is a 320 with 32K memory.

    Microchip makes good parts, crappy documentation, but the are more consistent with pinouts and features. There is almost always a clear pin compatible migration path from small memory to large memory. However, anyone that makes a 6 bit processor with an odd number of memory addresses needs their head examined.... :)