Important changes to forums and questions
All forums and questions are now archived. To start a new conversation or read the latest updates go to forums.mbed.com.
LPC Signature Generator
And we have progress!!! It turns out that AN11208 over at LPCware has the code for generating a signature in software! In light of this, I think the obvious course of action is to create an mbed library that will work on any mbed-enabled microcontroller. The hardware-based code will be used on LPC microcontrollers, while the software-based code will be used on everything else. Here's the software routine from the app note:
/***************************************************************************//** ** @brief Function starts the execution of the software signature generation. ** @param[in] startAddrs This variable is the starting address of where the signature generation will start. ** @param[in] length The length variable is the region size to used for the signature generation. ** @param[in] *pResultSign The result after generation completion will be put in the pointed location by the pResultSign pointer. ** @return NONE *****************************************************************************/ void StartSoftSignatureGen (UINT32 startAddr, UINT32 length, FlashSign_t *pResultSign) { FlashSign_t flashWord; FlashSign_t refSignature = {0,0,0,0}; FlashSign_t nextSign; UINT32 *PageAddr = 0, i; PageAddr = (UINT32 *)((UINT32)startAddr); for ( i = 0; i <= (length>>4); i++ ) { flashWord.word0 = *PageAddr; PageAddr++; flashWord.word1 = *PageAddr; PageAddr++; flashWord.word2 = *PageAddr; PageAddr++; flashWord.word3 = *PageAddr; PageAddr++; /* update 128 bit signature */ nextSign.word0 = flashWord.word0 ^ refSignature.word0>>1 ^ refSignature.word1<<31; nextSign.word1 = flashWord.word1 ^ refSignature.word1>>1 ^ refSignature.word2<<31; nextSign.word2 = flashWord.word2 ^ refSignature.word2>>1 ^ refSignature.word3<<31; nextSign.word3 = flashWord.word3 ^ refSignature.word3>>1 ^ ( refSignature.word0 & 1<<29 )<<2 ^ ( refSignature.word0 & 1<<27 )<<4 ^ ( refSignature.word0 & 1<<2 )<<29 ^ ( refSignature.word0 & 1<<0 )<<31; /* point to the calculated value */ refSignature.word0 = nextSign.word0; refSignature.word1 = nextSign.word1; refSignature.word2 = nextSign.word2; refSignature.word3 = nextSign.word3; } /* Copy the reference signature to the result pointer */ pResultSign->word0 = refSignature.word0; pResultSign->word1 = refSignature.word1; pResultSign->word2 = refSignature.word2; pResultSign->word3 = refSignature.word3; }
Now all we need is a way to run the hardware-based routine (or at least part of it) in RAM. It doesn't look like RVDS has any magic attributes for placing functions in RAM, you have to use Keil to do it. That being said, all this code is doing is poking a few registers, so it shouldn't be hard to cheat the system and do it at runtime. Anybody have any ideas?
Well, after some initial confusion I was able to port the hardware and software routines from AN11208 and run them on an LPC11U24. There are a few math bugs in the AN11208 code that show up when you try to generate a signature for anything but the entire flash, so I had to make some modifications to get everything to work. Here's what I have so far:
#include "mbed.h" typedef struct { unsigned int word0; //Word 0 of 128-bit signature (bits 31 to 0). unsigned int word1; //Word 1 of 128-bit signature (bits 63 to 32). unsigned int word2; //Word 2 of 128-bit signature (bits 95 to 64). unsigned int word3; //Word 3 of 128-bit signature (bits 127 to 96). } FLASH_SIG_Type; void hardSig(unsigned int startAddr, unsigned int length, FLASH_SIG_Type *pSig) { //Make sure the done flag is cleared LPC_FLASHCTRL->FMSTATCLR = (1 << 2); //Convert the byte addresses to 128-bit flash word addresses startAddr = (startAddr >> 4) & 0x0001ffff; length = (startAddr + ((length - 1) >> 4)) & 0x0001ffff; //Write the start address LPC_FLASHCTRL->FMSSTART = startAddr; //Write stop address and start the signature generator LPC_FLASHCTRL->FMSSTOP = length | (1 << 17); //Wait for signature to be generated while(!(LPC_FLASHCTRL->FMSTAT & (1 << 2))); //Clear the done flag LPC_FLASHCTRL->FMSTATCLR = (1 << 2); //Store the signature words in the structure pSig->word0 = LPC_FLASHCTRL->FMSW0; pSig->word1 = LPC_FLASHCTRL->FMSW1; pSig->word2 = LPC_FLASHCTRL->FMSW2; pSig->word3 = LPC_FLASHCTRL->FMSW3; } void softSig(unsigned int startAddr, unsigned int length, FLASH_SIG_Type *pSig) { FLASH_SIG_Type flashWord; FLASH_SIG_Type refSignature = {0, 0, 0, 0}; FLASH_SIG_Type nextSign; unsigned int* PageAddr = (unsigned int*)((unsigned int)startAddr); for (unsigned int i = 0; i < (length >> 4); i++) { flashWord.word0 = *PageAddr; PageAddr++; flashWord.word1 = *PageAddr; PageAddr++; flashWord.word2 = *PageAddr; PageAddr++; flashWord.word3 = *PageAddr; PageAddr++; //Update 128 bit signature nextSign.word0 = flashWord.word0 ^ refSignature.word0 >> 1 ^ refSignature.word1 << 31; nextSign.word1 = flashWord.word1 ^ refSignature.word1 >> 1 ^ refSignature.word2 << 31; nextSign.word2 = flashWord.word2 ^ refSignature.word2 >> 1 ^ refSignature.word3 << 31; nextSign.word3 = flashWord.word3 ^ refSignature.word3 >> 1 ^ (refSignature.word0 & 1 << 29) << 2 ^ (refSignature.word0 & 1 << 27) << 4 ^ (refSignature.word0 & 1 << 2) << 29 ^ (refSignature.word0 & 1 << 0) << 31; //Point to the calculated value refSignature.word0 = nextSign.word0; refSignature.word1 = nextSign.word1; refSignature.word2 = nextSign.word2; refSignature.word3 = nextSign.word3; } //Copy the reference signature to the result pointer pSig->word0 = refSignature.word0; pSig->word1 = refSignature.word1; pSig->word2 = refSignature.word2; pSig->word3 = refSignature.word3; } //Flash word 1024 (0x400) const char dummyData1[16] __attribute__((at(0x4000))) = { 0xFF, 0x00, 0xFF, 0x11, 0xFF, 0x22, 0xFF, 0x33, 0xFF, 0x44, 0xFF, 0x55, 0xFF, 0x66, 0xFF, 0x77 }; //Flash word 1025 (0x401) const char dummyData2[16] __attribute__((at(0x4010))) = { 0x00, 0x11, 0x22, 0x33, 0x44, 0x55, 0x66, 0x77, 0x88, 0x99, 0xAA, 0xBB, 0xCC, 0xDD, 0xEE, 0xFF }; //Flash word 1026 (0x402) const char dummyData3[16] __attribute__((at(0x4020))) = { 0x11, 0x22, 0x44, 0x88, 0xFF, 0xFF, 0x88, 0x44, 0x22, 0x11, 0x11, 0x22, 0x44, 0x88, 0xFF, 0xFF }; int main() { FLASH_SIG_Type sig1; hardSig((unsigned int)dummyData1, 16, &sig1); printf("\nHard Signature 1: 0x%x%x%x%x", sig1.word3, sig1.word2, sig1.word1, sig1.word0); FLASH_SIG_Type sig2; softSig((unsigned int)dummyData1, 16, &sig2); printf("\nSoft Signature 1: 0x%x%x%x%x", sig2.word3, sig2.word2, sig2.word1, sig2.word0); FLASH_SIG_Type sig3; hardSig((unsigned int)dummyData2, 16, &sig3); printf("\nHard Signature 2: 0x%x%x%x%x", sig3.word3, sig3.word2, sig3.word1, sig3.word0); FLASH_SIG_Type sig4; softSig((unsigned int)dummyData2, 16, &sig4); printf("\nSoft Signature 2: 0x%x%x%x%x", sig4.word3, sig4.word2, sig4.word1, sig4.word0); FLASH_SIG_Type sig5; hardSig((unsigned int)dummyData3, 16, &sig5); printf("\nHard Signature 3: 0x%x%x%x%x", sig5.word3, sig5.word2, sig5.word1, sig5.word0); FLASH_SIG_Type sig6; softSig((unsigned int)dummyData3, 16, &sig6); printf("\nSoft Signature 3: 0x%x%x%x%x", sig6.word3, sig6.word2, sig6.word1, sig6.word0); }
The code will generate signatures for 3 different flash words using both routines. Obviously the hardware routine is running out of flash instead of RAM, but it appears to work just fine...
Just finished an initial port of the software generator routine to C#. This is basically a straight port and hasn't been optimized for C# at all, but I tested it out on 16, 32, and 48 byte arrays and it does work:
public struct FLASH_SIG_Type { public uint word0; //Word 0 of 128-bit signature (bits 31 to 0). public uint word1; //Word 1 of 128-bit signature (bits 63 to 32). public uint word2; //Word 2 of 128-bit signature (bits 95 to 64). public uint word3; //Word 3 of 128-bit signature (bits 127 to 96). } private void softSig(ref byte[] data, uint length, ref FLASH_SIG_Type pSig) { FLASH_SIG_Type flashWord; FLASH_SIG_Type refSignature; refSignature.word0 = 0; refSignature.word1 = 0; refSignature.word2 = 0; refSignature.word3 = 0; FLASH_SIG_Type nextSign; uint PageAddr = 0; for (uint i = 0; i < (length >> 4); i++) { flashWord.word0 = (uint)data[PageAddr++] + ((uint)data[PageAddr++] << 8) + ((uint)data[PageAddr++] << 16) + ((uint)data[PageAddr++] << 24); flashWord.word1 = (uint)data[PageAddr++] + ((uint)data[PageAddr++] << 8) + ((uint)data[PageAddr++] << 16) + ((uint)data[PageAddr++] << 24); flashWord.word2 = (uint)data[PageAddr++] + ((uint)data[PageAddr++] << 8) + ((uint)data[PageAddr++] << 16) + ((uint)data[PageAddr++] << 24); flashWord.word3 = (uint)data[PageAddr++] + ((uint)data[PageAddr++] << 8) + ((uint)data[PageAddr++] << 16) + ((uint)data[PageAddr++] << 24); //Update 128 bit signature nextSign.word0 = flashWord.word0 ^ refSignature.word0 >> 1 ^ refSignature.word1 << 31; nextSign.word1 = flashWord.word1 ^ refSignature.word1 >> 1 ^ refSignature.word2 << 31; nextSign.word2 = flashWord.word2 ^ refSignature.word2 >> 1 ^ refSignature.word3 << 31; nextSign.word3 = flashWord.word3 ^ refSignature.word3 >> 1 ^ (refSignature.word0 & 1 << 29) << 2 ^ (refSignature.word0 & 1 << 27) << 4 ^ (refSignature.word0 & 1 << 2) << 29 ^ (refSignature.word0 & 1 << 0) << 31; //Point to the calculated value refSignature.word0 = nextSign.word0; refSignature.word1 = nextSign.word1; refSignature.word2 = nextSign.word2; refSignature.word3 = nextSign.word3; } //Copy the reference signature to the result pointer pSig.word0 = refSignature.word0; pSig.word1 = refSignature.word1; pSig.word2 = refSignature.word2; pSig.word3 = refSignature.word3; }
Code is now up! This should work on any mbed-enabled microcontroller, although I was only able to test it on the LPC11U24 and KL25Z:
[Repository '/users/neilt6/code/FlashSig_HelloWorld/latest/' not found]
I've also written improved C# code for generating reference signatures:
public struct FLASH_SIG_Type { public uint word0; //Word 0 of 128-bit signature (bits 31 to 0). public uint word1; //Word 1 of 128-bit signature (bits 63 to 32). public uint word2; //Word 2 of 128-bit signature (bits 95 to 64). public uint word3; //Word 3 of 128-bit signature (bits 127 to 96). } private FLASH_SIG_Type generate(ref byte[] data) { //Initialize the local variables FLASH_SIG_Type refSignature = new FLASH_SIG_Type(); FLASH_SIG_Type nextSignature; FLASH_SIG_Type dataWord; //The initial data index uint dataIndex = 0; //Calculate the signature for the specified region for (uint i = 0; i < (data.Length >> 4); i++) { //Load the next 128-bit data word dataWord.word0 = (uint)data[dataIndex++] + ((uint)data[dataIndex++] << 8) + ((uint)data[dataIndex++] << 16) + ((uint)data[dataIndex++] << 24); dataWord.word1 = (uint)data[dataIndex++] + ((uint)data[dataIndex++] << 8) + ((uint)data[dataIndex++] << 16) + ((uint)data[dataIndex++] << 24); dataWord.word2 = (uint)data[dataIndex++] + ((uint)data[dataIndex++] << 8) + ((uint)data[dataIndex++] << 16) + ((uint)data[dataIndex++] << 24); dataWord.word3 = (uint)data[dataIndex++] + ((uint)data[dataIndex++] << 8) + ((uint)data[dataIndex++] << 16) + ((uint)data[dataIndex++] << 24); //Calculate the word's signature using the previous signature as a reference nextSignature.word0 = dataWord.word0 ^ refSignature.word0 >> 1 ^ refSignature.word1 << 31; nextSignature.word1 = dataWord.word1 ^ refSignature.word1 >> 1 ^ refSignature.word2 << 31; nextSignature.word2 = dataWord.word2 ^ refSignature.word2 >> 1 ^ refSignature.word3 << 31; nextSignature.word3 = dataWord.word3 ^ refSignature.word3 >> 1 ^ (refSignature.word0 & 1 << 29) << 2 ^ (refSignature.word0 & 1 << 27) << 4 ^ (refSignature.word0 & 1 << 2) << 29 ^ (refSignature.word0 & 1 << 0) << 31; //The calculated signature is the new reference signature refSignature.word0 = nextSignature.word0; refSignature.word1 = nextSignature.word1; refSignature.word2 = nextSignature.word2; refSignature.word3 = nextSignature.word3; } //Return the reference signature return refSignature; }
Has anybody ever used the signature generator on the NXP microcontrollers? I noticed it at 20.16.4.7 on page 403 of the LPC11UXX user manual while I was reading up on the IAP commands. I could see this being extremely useful for control devices that store data in the flash. If the data is ever corrupted, the system could detect it and refuse to run as opposed to just going haywire. The way I see it there are a couple of things that have to happen to make this work... First of all, the calling code needs to run from RAM, so does anybody know how to define RAM-based functions using the online compiler? I'm not sure how important this is, since I was able to generate a signature WITHOUT running from RAM, but who knows maybe it could fail at some point? Secondly, there needs to be a desktop application that can generate reference signatures for a block of data. There's pseudo code in the user manual, but I couldn't get it to work in C#... Anyway, here's the code I used to generate a signature for the entire flash contents on an LPC11U24: