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 }
The original code is: unsigned char volatile xdata * write_ptr; *write_ptr=CBYTE[0xFA00];
You also need to ensure interrupts are disabled, so some interrupt handler won't inadvertantly corrupt flash by issuing a MOVX when the redirect bit is on.
Since write_pointer is a pointer to xdata, the compiler will generate a movc to read the CBYTE, but generate a MOVX for the write.
You can use CBYTE to read flash, but you have to use XBYTE to write to flash if you are not using an intermediate pointer conversion, explicit or implicit.
The Silabs part allows flash programming by the following trick.
"The FLASH memory can be programmed by software using the MOVX write instruction with the address and data byte to be programmed provided as normal operands. Before writing to FLASH memory using MOVX, FLASH write operations must be enabled by setting the PSWE Program Store Write Enable bit (PSCTL.0) to logic 1. This directs the MOVX writes to FLASH memory instead of to XRAM, which is the default target. The PSWE bit remains set until cleared by software. To avoid errant FLASH writes, it is recommended that interrupts be disabled while the PSWE bit is logic 1. FLASH memory is read using the MOVC instruction. MOVX reads are always directed to XRAM, regardless of the state of PSWE." " In 'C', the pointer used to de-reference FLASH writes should NOT be located in xdata space (data and idata are appropriate)."
Disable interrupts before setting PSWE to ‘1’ to prevent interrupt service routines, which may access variables in xdata space, from generating MOVX writes which could corrupt FLASH memory.
MOVX A,@dptr will read xdata MOVX @dptr,a will write code space. In this case their hardware reads and writes flash.
To prevent errors when actually writing something from XRAM into flash, it is recommended that you move the data to data space or idata space first. The above code is writing reading from flash with a movc generated by the CBYTE and writing to flash via movx generated by the pointer.
if you want to write a byte from data space directly, you have to use XBYTE so
XBYTE[checksum] will generate code to load checksum of of data space, and then do a MOVX, which if the redirect bit is turned on, will directly write to flash. if it is not turned on, then it will directly write to XRAM.
CBYTE[checksum] will generate code to load the byte from data space and do a movc to codespace which will result in nothing happening to code space on a silabs flash based part. IF it were a ram based part, then it would modify ram. BUT the silabs parts won't execute out of ram.
Some of the original code was just compiler test cases, to see what the compiler produced.
NOW: you can actually write to flash, without erasing it, as long as you are just clearing bits and you don't do enough of them to fatigue the flash cell.
I hope this clears up your confusion on the issue...
The original post deals with how to generate a pointer that the CBYTE or XBYTE routines can work with that points to a function...