Custom loader for xflash

Technical questions regarding the XTC tools and programming with XMOS.
User avatar
skoe
Experienced Member
Posts: 94
Joined: Tue Apr 27, 2010 10:55 pm

Custom loader for xflash

Post by skoe »

Is there example code for a loader I can use with xflash --loader? Maybe even source code of the original loader?

What I want to do is a two-stage startup: First execute an application which does some initialization and check for an upgrade and then start the real application.

Thank you,
Thomas

Edit after thinking about it for a while: It should work to write a small flash loader in assembly and copy it to e.g. 0x1FF00. This code can run a binary to 0x10000 and jump to there. At least this should be work on a single core device. And of course this loader code must not use stack nor call other functions. Did I miss something?


User avatar
skoe
Experienced Member
Posts: 94
Joined: Tue Apr 27, 2010 10:55 pm

Post by skoe »

In the meantime I implemented a boot loader which can run or update itself and/or the main application from SD card or flash. It works well, but one final problem exists:

When I put the disable CRC value 0x0D15AB1E into the file, it starts up sucessfully. When I use a calculated CRC, it doesn't start up.

I use the start value 0xFFFFFFFF and the polynomial 0xEDB88320. The final result is EORed with 0xFFFFFFFF. Is this meant by "the residue is inverted to produce the CRC"?

I tried also to reflect the bytes. Still no success. Does anybody have a code snippet or a hint?
User avatar
segher
XCore Expert
Posts: 844
Joined: Sun Jul 11, 2010 1:31 am

Post by segher »

Start with ffffffff. Now run everything through the crc function; this should
result in ffffffff again.

"Everything" includes the length word at the start and the crc word at the end!
m_y
Experienced Member
Posts: 69
Joined: Mon May 17, 2010 10:19 am

Post by m_y »

Sorry for the delay in replying; didn't see this thread when it was started.

First off, the --loader option doesn't allow you to replace the standard loader, just implement some callbacks. Below is some code which boots an image with version id 0 or 1 depending whether a button is held down or not. To increase robustness, if that version can't be found it will boot the first one (i.e. the factory image).

It shoud be compiled to object with something like

Code: Select all

xcc -c decide_button.xc -target=XK-1
and the resultant object file passed to xflash using the --loader option.

Code: Select all

#include <platform.h>

unsigned int keptRef=0;
unsigned int wantedVersion=0;

port buttonPort = PORT_BUT_1;

void init()
{
  int buttState = 0;
  buttonPort :> buttState;
  wantedVersion = buttState ? 1 : 0;
  keptRef = 0;
}

int checkCandidateImageVersion( int version )
{
  return( (keptRef==0) || ( (version?1:0) == wantedVersion ) );
}

int recordCandidateImage( int version, unsigned int ref )
{
  keptRef = ref;
}

unsigned int reportSelectedImage()
{
  return( keptRef );
}

Here's a slightly more complex example that uses both C and XC. Again this one uses a button on the board. If pressed then the factory image is booted, else the first page of the flash's data partition is read but only the bottom two bits of the first byte are kept. It then proceeds to boot the last image which has a version number where the bottom two bits match those read from flash.

First the XC, used only to declare and read a port:

Code: Select all

#include <platform.h>

port buttPort = PORT_BUTTON;

unsigned int buttonState()
{
  unsigned int res;
  buttPort :> res;
  return( res&0xf );
}
Then the C:

Code: Select all

extern void* readFlashDataPage(unsigned int addr);
extern unsigned int buttonState();

unsigned int keptRef;
unsigned int wantedClass;

void init(void)
{
  if( (buttonState()&0xf) == 0xf )
  {
    unsigned int* page = (unsigned int*)readFlashDataPage(0);
    keptRef = 0;
    wantedClass = page[0] & 0x3;
  }
  else
  {
    while( buttonState() != 0xf );
    wantedClass = 0;
  }
}

int checkCandidateImageVersion( int version )
{
  return( (keptRef==0) || ( (version&0x3) == wantedClass ) );
}

void recordCandidateImage( int version, unsigned int ref )
{
  keptRef = ref;
}

unsigned int reportSelectedImage(void)
{
  return( keptRef );
}
Again these would need compiling to obect code and passing to xflash (which will accept multiple --loader options).


For the CRC, the initial state is 0xffffffff, the poly is 0xedb88320 and we append 32 zero bits to the end of the input. The result is bit-inverted.

If you're building a complete loader from scratch then yes, copying high up in memory then loading the real application to 0x10000 is the way to go. This is what the Xmos loaders do.
User avatar
skoe
Experienced Member
Posts: 94
Joined: Tue Apr 27, 2010 10:55 pm

Post by skoe »

Thanks for the response and the very detailed description.

The default booter is designed very well and most probably suitable for most use cases.

I made my own booter because I want the booter to take care for the updates directly from SD card. The reason is that I want to save (code) memory in the main application, even if this would be only 1 kByte.

Of course this boot concept could also be done with a 3 stage solution starting with the default booter.

That's not the problem, my booter works and it took a few hours only to implement it. But only as long as I use CRC 0x0D15AB1E.
For the CRC, the initial state is 0xffffffff, the poly is 0xedb88320 and we append 32 zero bits to the end of the input. The result is bit-inverted.
Sounds like 802.3 CRC. Sounds simple, but I'm not able to calculate the right CRC with a small C tool. I use pycrc (http://www.tty1.net/pycrc/pycrc.html) to generate the CRC code. But as far as I know the CRC implementation from zlib should do the same. The byte order I use should be okay, otherwise 0x0D15AB1E wouldn't work

I tried to play with the configuration for pycrc. I tried to do it with and without the 32 0-bits you mentioned. No luck.

According to http://en.wikipedia.org/wiki/Cyclic_redundancy_check the non-reversed poly 0x04C11DB7 belongs to the reversed poly 0xedb88320, that's what I used for pycrc.

I'll give up now and use 0x0D15AB1E. But in case somebody could enlighten me with a small C tool, I'm really curious now.
User avatar
skoe
Experienced Member
Posts: 94
Joined: Tue Apr 27, 2010 10:55 pm

Post by skoe »

\o/ It works!

Segher gave me the hint to compare my CRC implementation with the CRC opcode of the XMOS instruction set. With this I found out that my bitorder was wrong. I though I tried different bit orders of words and bytes *sight*.

I ported the stuff to Python and made a small tool. I'll attach it here for anybody who might need it.
You do not have the required permissions to view the files attached to this post.