Linker Problem: Implementing Boot-loader On Coldfire V1

cancel
Showing results for 
Show  only  | Search instead for 
Did you mean: 

Linker Problem: Implementing Boot-loader On Coldfire V1

Jump to solution
2,179 Views
dougpaulsen
Contributor IV

I have been trying to implement Paul Zhang's Coldfire V1 bootloader (see: <http://read.pudn.com/downloads132/sourcecode/embed/561869/Implement%20UART%20Bootloader%20On%20CF%20...>) and I am having the most bizarre problem trying to get CW 6.3 to include my Vector Redirection Table.  I hope someone can point out  the error in my ways.

 

Basically, Zhang's approach is straightforward.  His example is for the MCF51QE128.  My project is for a MCF51AC256, but the approach should be pretty much the same except for the memory boundaries.  Zhang sets up four memory segments:  1) the primary vector table is fixed at 0x0 for the MCF51s, 2) the Bootloader itself above that table beginning at 0x00000410, 3) the Vector Redirection Table on top of the bootloader code beginning at 0x00000c000, and finally 4) the application area beginning at 0x00001000 to the end of flash.

 

Preparing these segments involves modifying CW's LCF file as follows:


MEMORY

{

      userram (RWX)          :      ORIGIN = 0x00800000, LENGTH = 0x00002000

      BootLoad (RX)           :      ORIGIN = 0x00000410, LENGTH = 0x000007F0      #this is new...

      VectorReMap (RX)     :      ORIGIN = 0x00000C00, LENGTH = 0x00000400      #...as is this...

      code (RX)                 :       ORIGIN = 0x00001000, LENGTH = 0x0001F000      #... and finally the code start has been moved from 0x0000410 to allow space for Bootloader & VectorReMap

}

 

then adding tge following to the SECTIONS space:

 

     # define code sections

     .BootLoad           :      {}      >      BootLoad

     .VectorReMap     :      {}     >      VectorReMap

 

     # Code placement for boot-loader section

      .text_bootload :

      {

      BootLoad.c (.text_bootload)

      . = ALIGN (0x4);

      } >> BootLoad

 

     # Code placement for remapped vector section

      .text_vectormap :

      {

      VectorMap.c (.text_vectormap)

      . = ALIGN (0x4);

      } >> VectorReMap

 

I have added file VectorMap.c to my project, and it begins as Zhang demonstrates:

 

    #pragma CODE_SEG __FAR_SEG text_vectormap

 

     void StartupEntry(void)

     {

          asm (jmp _startup);

     }

 

Now, before I invest in filling out the other 119 vectors to be remapped, I thought I'd take a peak at my Project.abs.xMAP file.  I've got a segment .text_vectormap and it is fixed at 0x00000c00 as instructed. 

 

But what's this?  .text_vectormap is empty!?  Length of zero.  What happened to my function StartupEntry()?  It's nowhere to be found in the xMAP file.  I even loaded the project onto hardware and checked at address 0x00000c00.  It's plain 0xFFs, which is very much un-good.. 

 

It appears the linker is smart enough to know that StartupEntry() is never called and therefore the linker does not include it.  To verify this, I've made a extern declaration and call to StartupEntry() in main() (which I of course very much do NOT want to do), rebuild the project, and then checked my xMAP file.  StartupEntry() now is shown at 0x00000c00, as intended.

 

I have tried variations on a theme such as the following in VectorMap.c:

 

     #pragma define_section TEST ".text_vectormap" ".text_vectormap"

     _declspec(TEST)void StartupEntry(void)

     {...

 

but again, the linker chooses not to include my very important but, from the linker's perspective, unused/unreferenced code at 0x00000c00.

 

I've done bootloader in HCS08 machines.  There the technique used was to create a table such as the following:

 

     T_VECTORENTRY const VectorJmpTable[]@0x00000c00

     =

     {

          { 0xCC, _startup     },

          { 0xCC, UNASSIGNED_ISR },

          ....

 

This will actually work in my project.  VectorJmpTable[] will be fixed at 0x00000c00.  The problem comes in that 0xCC is a plain old jump instruction in the HCS08.  The MCF51 jump instruction is much more complex so that hard coding looks to be fraught with error opportunities.  This option to create a vector redirection table is definitely out.

 

So we're back to trying to fix asm( jmp <addr>) pseudo functions as our vector redirection table, except the linker decides they are not necessary and saves the code space for me (thanks, linker!).

 

Is there something obvious I'm missing?  Some pragma or other way to make the linker include code regardless?  I tried the "Disable Deadstripping" option, only to have all sorts of other errors show up before abandoning that.

 

I fear, although I haven't gotten there yet, I'm going to have similar problems trying to get the boot loader code in there.  But, I'm sure whatever solution forces the linker to include my table will do the same for the also uncalled boot loader.

 

Thanks for any comments/suggestions!

Labels (1)
1 Solution
1,465 Views
Jorge_Gonzalez
NXP Employee
NXP Employee

Hello Doug:

Here you have 3 alternatives to avoid the linker being "smart" with those functions:

1) Place those functions in the "Force Active Symbols" section of the Linker options, separated by a comma and with an underscore before each one. Refer to the next picture:

Linker_force_symbols.png

2) When declaring the functions, use the force_active pragma. Below is an example for your functions:

In Bootload.c:

#pragma force_active on

#pragma CODE_SEG __FAR_SEG text_bootload

//=============================================================================

// Boot-loader main routine

//=============================================================================

void BootLoader(void)

{

//....CODE

}

#pragma force_active off

In VectorMap.c:

#pragma force_active on

void StartupEntry(void)

{

  asm (jmp _startup);

}

#pragma force_active off

3) In the linker file (lcf) include a FORCE_ACTIVE segment and add your functions there. Below an example:

MEMORY {

   userram (RWX)     : ORIGIN = 0x00800000, LENGTH = 0x00002000

   BootLoad (RX)     : ORIGIN = 0x00000410, LENGTH = 0x000007F0

   VectorReMap (RX)  : ORIGIN = 0x00000C00, LENGTH = 0x00000400

   code (RX)         : ORIGIN = 0x00001000, LENGTH = 0x0001F000

}

FORCE_ACTIVE {

_BootLoader,

_StartupEntry

}

SECTIONS {

#...

You only need one of the 3 options, not all.

Hope this solves the problem.

Regards!,
Jorge Gonzalez

-----------------------------------------------------------------------------------------------------------------------
Note: If this post answers your question, please click the Correct Answer button. Thank you!
-----------------------------------------------------------------------------------------------------------------------

View solution in original post

0 Kudos
3 Replies
1,465 Views
dougpaulsen
Contributor IV

Under the assumption that I left out or otherwise obscured a crucial part of my CW 6.3 linker observation above, I have created the attached example project which demonstrates the problem.

As directed by the included LCF file, function BootLoader() in module BootLoad.c should be located at address 0x0000 0410.  Similarly, function StartupEntry() in module VectorMap.c should be located at address 0x0000 0c00.  Neither are, as reported by the Project.abs.xMAP file.

It sure looks like the linker is finding functions BootLoader() and StartupEntry() un-referenced and is therefore excluding them as dead code.  Indeed, if you make calls to them in function main(), the linker will include them at the specified addresses, but of course that will not achieve the desired behavior so that option is out.

I'm ever hopeful I have made a silly oversight.  Any thoughts what that might be?

Thanks!

1,466 Views
Jorge_Gonzalez
NXP Employee
NXP Employee

Hello Doug:

Here you have 3 alternatives to avoid the linker being "smart" with those functions:

1) Place those functions in the "Force Active Symbols" section of the Linker options, separated by a comma and with an underscore before each one. Refer to the next picture:

Linker_force_symbols.png

2) When declaring the functions, use the force_active pragma. Below is an example for your functions:

In Bootload.c:

#pragma force_active on

#pragma CODE_SEG __FAR_SEG text_bootload

//=============================================================================

// Boot-loader main routine

//=============================================================================

void BootLoader(void)

{

//....CODE

}

#pragma force_active off

In VectorMap.c:

#pragma force_active on

void StartupEntry(void)

{

  asm (jmp _startup);

}

#pragma force_active off

3) In the linker file (lcf) include a FORCE_ACTIVE segment and add your functions there. Below an example:

MEMORY {

   userram (RWX)     : ORIGIN = 0x00800000, LENGTH = 0x00002000

   BootLoad (RX)     : ORIGIN = 0x00000410, LENGTH = 0x000007F0

   VectorReMap (RX)  : ORIGIN = 0x00000C00, LENGTH = 0x00000400

   code (RX)         : ORIGIN = 0x00001000, LENGTH = 0x0001F000

}

FORCE_ACTIVE {

_BootLoader,

_StartupEntry

}

SECTIONS {

#...

You only need one of the 3 options, not all.

Hope this solves the problem.

Regards!,
Jorge Gonzalez

-----------------------------------------------------------------------------------------------------------------------
Note: If this post answers your question, please click the Correct Answer button. Thank you!
-----------------------------------------------------------------------------------------------------------------------

0 Kudos
1,465 Views
dougpaulsen
Contributor IV

Jorge:

Thank you for your solutions!  I had uncovered the #pragma force_active approach late yesterday after I switch my search inquiries from bootloading, et al., to the subject of dead stripping.  I haven't completed coding my implementation, but initial testing finds my intermediate interrupt jump table is indeed being located in the desired memory map addresses.  The rest is just details, right?

It's good to know there are alternative approaches, too. 

My previous bootloaders have used an array of structures to form the jump table, rather than stacking up a sequence of bogus functions to form the same thing in code.  I think that approach makes more readable code.  I wasn't able to hard locate such a structure here (the @ symbol apparently only locates data, not code).  Now that I have a solution to fall back on, I will explore that approach more fully (the major advantage of the function approach is that you can use the "asm (jmp <addr>)" and let the compiler figure out which of the numerous jmp assembly instructions is the correct one).

Again, thank you.

doug