Bootloader - how can it tell if there is a valid appliction?

Go To Last Post
23 posts / 0 new
Author
Message
#1
  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

I have written a bootloader for my mega128 using the xmodem protocol. One role of the bootloader is to tell whether it should enter the application code or keep repeating itself, based on whether there is a valid application in the program memory.

Is there a good way to tell if there is a valid application?

At the moment my bootloader, if it runs into any difficulty associated with the Xmodem data transfer (it assumes all page writes and other internal operations are successful) writes a few words of zeros at the start of flash. Upon booting, it checks these words and if they are full of zeros, it keeps looping until it gets a new program loaded.

This works, but doesn't seem very tidy. I read one guy did a CRC check, but on what? The whole flash memory? And how would the resulting CRC word tell me if the application were valid or not?

I'm a bit new to this stuff, so if you pros have a better method of checking for a valid application, I would love to hear about it!

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

The best way would be to CRC check each flash page as it is written or, alternatively, a CRC of all the memory after it is written. If it matches the precalculated CRC value (sent from the PC) you can be certain that the FLASH contains the exact same code as was sent. That's the only form of validation you can really do, making sure that no errors occurred while transferring the code from the PC to the flash memory.

- Dean :twisted:

Make Atmel Studio better with my free extensions. Open source and feedback welcome!

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Quote:
I read one guy did a CRC check, but on what? The whole flash memory? And how would the resulting CRC word tell me if the application were valid or not?

You'd CRC the entire application space - that is everything beneath the BLS boundary and maybe use the very last 2 or 4 bytes in that area to hold the CRC of everything that precedes it.

At boot time you just feed every byte in the app space into a CRC generator and see if the result is the same as found in the last 2/4 bytes. Launch if it agrees, wait for update if it doesn't.

Cliff

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Thanks Dean,

with the Xmodem protocol, I get a nice little CRC word at the end of each page and no CRC information at the end of the program, so I am controlling each page after I get the information, but controlling each page after writing it seems like a good idea.

I think the problem I could potentially have is that the couple of pages somehow get written and power gets cut or something, leaving my processor with half an application...

but perhaps I can begin by writing some zeros to the first page then save the first page of data from the PC and write it last, that way there will always be zeros in the first page, unless the whole code is programmed properly.

Still seems a bit rough around the edges. What do you think about this idea of using the zeros at the start of flash as a sort of 'flag'?

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

The CRC on Xmodem just proves the data got from the PC to the AVR intact - it doesn't prove that the data then got programmed into the AVR flash correctly (you discard the packet CRC once it's been validated). The bootloader CRC is different in that it's a check over the entire image that it's all in place and intact once programmed into the flash.

Cliff

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Thanks Cliff,
I am assuming that I would generate the CRC bytes following a successful write of all pages to flash...

so if I check each page of flash after it is written, then create then generate the CRC byte for the whole flash within the controller, I should be pretty safe. Unless a whole new program is successfully written, the CRC bytes will not change.

That answers my last question Dean.

Thanks Dean and Cliff.

If anyone else is interested in this method, there is a CRC appnote on the Atmel site that I found useful.

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Quote:
I am assuming that I would generate the CRC bytes following a successful write of all pages to flash...

Well depending on your build system you'd probably actually arrange for the original .hex file with the entire program to have a CRC generated across it. Tools in both IAR and GCC toolchains allow this to be done automatically and I'm guessing the other C compilers have equivalent mechanisms.

If it wasn't generated on the PC consider the occasion where you transfer 7K of code into the AVR in 128 byte Xmodem/CRC packets. Sure the CRC on each 128 bytes says it got to the AVR OK but now assume that one packet didn't program into flash for some reason (so that 128 bytes almost certainly remains at 0xFF). You finish up by the bootloader calculating a complete CRC over the entire app and store that away. But when it gets to the "missing" page it'll just add in 128 bytes of 0xFF assuming that is what was meant to be there.

Later when the bootloader starts up and calculates the CRC over the app it will get the "right answer" because the stored CRC already accounts for those 128 bytes of 0xFF.

If, however, the CRC had been calculated back on the PC then the "rogue page" would be spotted as an error.

Cliff

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

I guess I am relying on the Xmodem protocol page numbers to detect any missing pages.

Perhaps I can correspond the Xmodem page number with the flash page number, and then CRC each page after writing it.

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Why, what's your objection to the simple answer of a complete program CRC ? Isn't it the obvious (and easiest!) way to check the validity of the image?

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Quote:
Isn't it the obvious (and easiest!) way to check the validity of the image?

It probably is. I am currently using kontrollerlab on linux and then converting my hex file to binary using a tool called srec. I have had some trouble adding compiler options using kontrollerlab but srec can probably add a crc check at the end.

Adding a CRC for the whole program using the controller means one less thing I have to do on the PC, at the cost of a few extra lines of code.

I also have the option of placing the CRC where I want (i.e. just before the BLS) without having to write pages of 0xFF in the gap between my application and the CRC.

As long as both application check methods are just as reliable, it may be a matter of personal preference.

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Quote:
but srec can probably add a crc check at the end.

Quote:
without having to write pages of 0xFF in the gap between my application and the CRC

srec will do all that for you. Surely 10 minutes reading the manual for a few hours less work and an ultimately far more reliable system is worthwhile?

Cliff

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Hopefully your application, once loaded, has a way for you to get back to the bootloader. Or some other little trick it can play.

Otherwise once an application is loaded, the bootloader will recognize it as valid and always jump to it, and you won't be able to update the old one.

Chuck Baird

"I wish I were dumber so I could be more certain about my opinions. It looks fun." -- Scott Adams

http://www.cbaird.org

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

It can, of course, corrupt itself to make that happen but the irony of that is that you have to get back above the BLS to do that anyway so that SPM can be used.

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Quote:
Well depending on your build system you'd probably actually arrange for the original .hex file with the entire program to have a CRC generated across it. Tools in both IAR and GCC toolchains allow this to be done automatically

Please enlighten me, what is the GCC tool flow to get a whole program checksum into the hex file?

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

dbc wrote:
Please enlighten me, what is the GCC tool flow to get a whole program checksum into the hex file?
A web search that I performed found the following link. Perhaps it will be of help: http://www.mail-archive.com/avr-...

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

kmr,

Thanks, interesting link. Since I just spent most of yesterday digging into the avr5.x linker script in detail, I had to go check what he was doing. It's a little snakey using a byte beyond __data_load_end, by my reading it depends on the linker scripts never putting anything in flash past the initialization data.

Seems to me a more general solution would be to actually create a checksum section and then call out that section in the linker script explicitly so that you never do anything behind the back of the linker.

Of course, now you have to figure out how to get a checksum in there, which the linker won't do, and it can only be done at or after link time. Presumeably, it wouldn't be that difficult to write a little tool that generated the contents of that section using the result of a first link without checksum, then you could do a second link to pull in the checksum.

It might not even require a custom linker script, maybe you could belly-flop on the linker script *(.data*) wild card and place your checksum variable in the .datawhatever section.

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

dbc wrote:
Quote:
Well depending on your build system you'd probably actually arrange for the original .hex file with the entire program to have a CRC generated across it. Tools in both IAR and GCC toolchains allow this to be done automatically

Please enlighten me, what is the GCC tool flow to get a whole program checksum into the hex file?

As the thread that Kevin linked to shows it was srec_cat I was thinking of.

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

dbc wrote:
Thanks, interesting link.
You're welcome, but you can thank Google, mostly. I just typed in the search parameters and used Google's database to get relevant information for you.

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Quote:
As the thread that Kevin linked to shows it was srec_cat I was thinking of.

That would seem to do the job. Probably a better solution than creating a new section and trying to stuff data into it after the fact. Although I think if it was me I'd make a linker script that provided a label something like "__yes_this_really_is_the_end_of_flash_so_put_checksum_here"... OK, well I'd probably come up with a shorter name :) But I'd like to make that explicit rather than bending another label. But it certainly works with the linker scripts as written.

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

or look in a defined flash location for a certain bit pattern (cookie) instead of CRC.

Presumes that your code was flashed and the verify succeeded, which is the norm.

fails to deal with 20 years of flying beta rays that alters the flash!

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0
//mega164p
//x.c-> x.hex-> x_crc.hex
#include 
//#define BOOT_START 0x3C00
uint16_t crcdata __attribute__((section(".crc")));
//store crc-> BOOT_START - 2bytes
//-Wl,-section-start=.crc=0x3bfe
int main(){
}

//in makefile, or manually run srec_cat
/*
srec_cat \
x.hex -intel \
-fill 0xFF 0 0x3C00 \
-exclude 0x3BFE 0x3C00 \
-b-e-crc16 0x3BFE \
-unfill 0xFF 0x10 \
-o x_crc.hex -intel \
--line-length=44 \
--address-length=2 
*/

the crc will be calculated up to the last word before the bootloader start, including the erased flash. The unfill could need tweaking, or even left out if you don't mind a full hex file.

I don't use this myself, but it doesn't seem to be too terribly hard to get done. A little makefile work would be required to automate.

I figure I'm sitting at the pc, with me and my bootloader communicating with each other, and I will know when the programming fails just like when I use ISP. So my bootloader assumes a good app is in the avr (just like everyone does with ISP). In 20-100 years, I may be sorry, although I'm not making pacemakers or anti-lock brakes either.

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0
uint16_t crcdata __attribute__((section(".crc"))); 
//store crc-> BOOT_START - 2bytes 
//-Wl,-section-start=.crc=0x3bfe

Oh yeah, of course. Simple and no linker script tweakage involved.

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

One added benefit, is if your app becomes too large and gets into the bootloader section, you will now know it (sooner) because you will run into that crc word first (at compile time, rather than hearing about it from the bootloader when loading the app).