avr-chat
[Top][All Lists]
Advanced

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

Re: [Fwd: RE: [avr-chat] BOOTLOADER on ATMega644]


From: Peter LaDow
Subject: Re: [Fwd: RE: [avr-chat] BOOTLOADER on ATMega644]
Date: Mon, 22 Dec 2008 22:48:53 -0800
User-agent: Thunderbird 2.0.0.18 (Windows/20081105)

Robert von Knobloch wrote:
I will only write here very occasionally (when a new product must be supported, 
the new data will be loaded by hand, so lifetime of the flash is not a problem).

OK I can do this by creating 'fake' initialised variables (it's just a bit 
tedious to create them), then I can access them symbolically and do not need to 
know the address for a specific entry.
I assume you are saying that there is no support for un-initialised variables 
in flash ?



I did something very similar on a project. We had a "library" that the user could use to "patch" the firmware. Now, this library was provided only by us, and came to them encrypted and "signed" (we did a poor-man's digital signature by encrypting a 32-bit CRC of the library). When an SD card is inserted, we check for the library file. If it exists, we decrypt and check the signature. If clean, we compare the signature to the one in flash. If the same, we are done. If different, we then go about programming the library into the flash.

In order to do this, we had to do a few things.

1) We had entry points into the bootloader the erase and program flash. At startup, the bootloader passed function pointers to the main firmware of where to find the functions. When the main firmware needed to do any operations, it used these function pointers.

2) We had to locate the library on a flash sector boundary and limit the use of certain flash sectors for only the library. To make things easy, we allowed the library to use all flash from a certain point up to the bootloader. We had a memory map something like:

0x00000 - 0x0XFFF : Application Data
0x0Y000 - 0x1DFFF : Library  Data
0x1E000 - 0x1FFFF : Bootloader

3) We organized our library data to contain both data and functions. Because this could change from library to library, we put a table at the start of the library that looked something like:

library_entry_t library_table[];

Where library_entry_t is:

typedef enum { DATA, FUNCTION } entry_type_t;

typedef struct
{
 entry_type_t etype;
 UINT16 size;
 UINT16 offset;
 CHAR name[];
} library_entry_t;

Where etype indicated the type of data, size is the size of the entry (applicable to DATA types only), offset is the offset from the start of the library, and name is the name of the symbol. The size entry wasn't always used since we often already knew the size, but in some cases, notably strings, it made it faster to use than doing a strlen() first. There were other cases, but that is getting into too much detail.

The point of this library was to patch the main firmware. That is, the library would be capable of overriding some functions and data with its own. Only certain functions and data could be overwritten. This table was parsed at powerup, and our RAM based version of a table was updated with the data from the library. If a symbol was overridden, that library symbol was used instead. Otherwise the default was done.

Now, to locate this table in flash from the application, we defined in the linker script something like:

.library :
{
 _lib_start = .;
} > LIBRARY

Where LIBRARY was defined as a memory region reserved for the library. Now to load the library, all we had to do was something like:

extern UINT8 _lib_start;

const void *ptr = &_lib_start; // Yes, this leading "&" looks weird, but it is correct.

Now ptr has a pointer to the start of the library. From there we could parse the library.

4) One goal of this structure was to generate a library that could live anywhere in flash. Then we could have multiple libraries loaded, and they could live anywhere. By having this table, we could initialize our function pointers easily from the library table and we didn't care where it lived. Unfortunately we were using a compiler other than GCC for our work, and our compiler did not support position-independent code. Even though we couldn't do this with the compiler we were using, we had the infrastructure in place to support such a mechanism when the time did come.



Now, if I were to try and load some arbitrary data into a section, that is uninitialized, I might do something like this in the linker script:

/* The (NOLOAD) tells LD not to load the section */
.library (NOLOAD) :
{
 . = ALIGN(2);

 _symbol_1 = .;
 . += XXX; /* XXX is the size of _symbol_1 */
 . = ALIGN(2);

 _symbol_2 = .;
 . += YYY; /* YYY is the size of _symbol_2 */
 . = ALIGN(2);

 ...

} > LIBRARY

Now, I've never tried this, but it is one way. And you could have a script generate this portion of the linker script, then run it through the C pre-processor for you to fill it in to an overall linker script. I'll be honest though, I don't like this approach for a couple of reasons:

1) You don't have any way of know if the data in the flash is valid, unless you define a symbol for a checksum or CRC. And generating that to be correct can be iffy. Then again, if you do this programmatically (i.e. a download), you can generate it on the fly. 2) If your symbol sizes change, you not only have to upgrade your application, but also your data. So a simple checksum/CRC may not be enough. 3) You now effectively have symbols being hand placed. This is no different than just defining a bunch of initialized pointers in flash that point to fixed memory locations. Why not just have a table of pointers in flash that you load and use?

This seems like a maintenance nightmare to me. Better to have the symbols either fixed in the main application, or have the symbols self-describe themselves.

Just my $0.019999999 worth.

Pete




reply via email to

[Prev in Thread] Current Thread [Next in Thread]