Author Topic: Copy data from ROM to RAM and execute  (Read 9640 times)

0 Members and 1 Guest are viewing this topic.

Offline jtronixTopic starter

  • Regular Contributor
  • *
  • Posts: 125
Copy data from ROM to RAM and execute
« on: July 13, 2017, 07:50:13 am »
Hi,

I want to write data into internal flash where code is being executed. When i perform write operation on flash at that time i can not read or execute from flash so in this case i have to copy flash related code into RAM.

using __attribute__(("section name")) command I'd successfully  mapped function into RAM but don't know how to copy that function from ROM to RAM so execution can happen. even i couldn't found ROM address for copy in .map file

 

Offline AndyC_772

  • Super Contributor
  • ***
  • Posts: 4283
  • Country: gb
  • Professional design engineer
    • Cawte Engineering | Reliable Electronics
Re: Copy data from ROM to RAM and execute
« Reply #1 on: July 13, 2017, 07:53:37 am »
You'll need to let us know which processor and development environment you're using.

Offline jtronixTopic starter

  • Regular Contributor
  • *
  • Posts: 125
Re: Copy data from ROM to RAM and execute
« Reply #2 on: July 13, 2017, 10:27:18 am »
Microcontroller : Renesas RX113
IDE: e2Studio
Compiler: GNU

 

Offline dgtl

  • Regular Contributor
  • *
  • Posts: 183
  • Country: ee
Re: Copy data from ROM to RAM and execute
« Reply #3 on: July 13, 2017, 12:50:14 pm »
For gcc, it is the same as for ARM. The whole thing comes together in the linker script (.ld file). The linker script contains the information, at which address the code is executed and at which address the code is placed in the binary. It is important that the code is linked to the correct address (in your case, RAM address), otherwise location-dependent parts will not work. For reference you can look how the data section is handled. The global/static variables are placed in the data section and the initial values of those need to be in the flash. You need to the same.
Later, something needs to copy the code to flash, this is usually somewhere right after reset vector (startup.s or similar). Either you find the data section copy code and extend your section there (usually it means adding your section right after data section and moving some end-of-data-section pointer after your section in linker script) or you add your own memcpy at the correct location. The latter may be a little more safe as something might have messed up the code in ram and you jump into bad code (or worse, partially bad code that erases the flash but can not program). For this, just add pointers in linker script and use those with memcpy-like code to do the fresh copy after you have disabled interrupts.
Adding your section inside .data can sometimes be the simplest solution, but for some architectures, .data sections may be execute-protected and things do not work; in addition, the linker will throw warnings.
Things get more difficult when interrupts need to be left enabled while programming flash. For ARM, the isr vector table needs to be moved to RAM etc. as well.
For my projects, typical arrangement is:
Code: [Select]
  .data :
  {
    . = ALIGN(4);
    _sdata = .;
    *(.ramfunc*)
    *(.data)
    *(.data*)
    . = ALIGN(4);
    _edata = .;
  } >RAM AT> FLASH
  _sidata = LOADADDR(.data);
 
The following users thanked this post: jtronix

Offline John Coloccia

  • Super Contributor
  • ***
  • Posts: 1217
  • Country: us
Re: Copy data from ROM to RAM and execute
« Reply #4 on: July 15, 2017, 05:34:47 am »
A general technique is something like:

1) define a section in RAM where it will execute from
2) define a section in ROM where it lives
3) on startup, copy the section from ROM to RAM

Doing it by section is neat and convenient, though you obviously don't absolutely need to do it like that.

In particular, I believe you specify a Load From and Run From address in a GNU linker script. If you search on that, you'll get all the information you need on how to do it.
 

Offline jtronixTopic starter

  • Regular Contributor
  • *
  • Posts: 125
Re: Copy data from ROM to RAM and execute
« Reply #5 on: July 15, 2017, 02:00:52 pm »
Thanks for all reply


*(.data*)

what is the use of * at the end of data?

Apart from this i'd see many other terms but i couldn't found the answer Is there have any reference document where syntax is explained?
 

Online ejeffrey

  • Super Contributor
  • ***
  • Posts: 3922
  • Country: us
Re: Copy data from ROM to RAM and execute
« Reply #6 on: July 16, 2017, 03:19:44 am »
*(.data*) means: from any input file, collect any sections whose name starts with "data" with any suffix.

The reason you use the wildcard section name is because you can instruct GCC to put every object in its own section.  The section prefix would be the standard .text, .data, .bss etc. with a name based suffix to make the section unique.  The reason for this is so that the linker can do garbage collection and eliminate variables and functions that are never referenced.  The slight downside of this is that if your architecture supports more efficient local references, you may not be able to use them if the assembler can't tell if two sections will be near each other.

Here is the documentation on the gnu linker SECTIONS commands: https://access.redhat.com/documentation/en-US/Red_Hat_Enterprise_Linux/4/html/Using_ld_the_GNU_Linker/sections.html

Basically you want to look at the "LMA" vs. "VMA" information.  VMA is the "virtual" address, which is the address in RAM (not really virtual on most microcontrollers) where the code will actually be located at runtime.  The LMA is the "load memory address", which is the address in ROM/FLASH where the code will be stored.

You also want to create symbols pointing to the beginning and end of the section, both in ROM and RAM so that you can copy the data at startup.  You can probably find examples in your platform linker script that copies the volatile data sections into RAM at startup.  You just need to do the same thing with some text sections.
 
The following users thanked this post: jtronix

Offline rstofer

  • Super Contributor
  • ***
  • Posts: 9935
  • Country: us
Re: Copy data from ROM to RAM and execute
« Reply #7 on: July 16, 2017, 08:03:51 pm »
Maybe a concrete example will help.  The two attached files (in the .zip, I can't post a .s and .ld file) describe how code is loaded on an LPC2106.  Let's look at the linker script first as it lays out memory and decides where various segments are placed.  lpc2106-FLASH.ld

The program ENTRY point is _startup which is used in crt.s - we'll get there in a moment.
In the MEMORY block, we set up flash at 0x0000000h with length 128k.  Then we set up ram_isp_low_(A) and ram_isp_high(A) as areas we won't allocate.  Ram is set to 0x40000200 with a length of 64992.
Next we define the address for the stack and that will be used in crt.s
In SECTIONS, we set the load pointer to 0 and define the section 'startup' (implicitly org'd at 0x00000000) and place it in flash (> flash).  This will always be the first section allocated in flash.  Next we allocate all of the .text sections - this is the executable code that resides just after the startup code.  It too is loaded into flash (> flash).  Next we load all of the .data sections but things are a little different.  Note the >ram AT >flash.  The addresses are allocated in the RAM area but the initial values reside in the flash.  These sections are initialized data that will get copied to RAM in crt.s
Finally, we get to .bss (block started by symbol) where we allocate all uninitialized RAM.  Notice that all of the .bss sections are allocated >ram.  Finally, there is an alignment issue to deal with and note the very important symbol _bss_end.  Earlier there was a _bss_start symbol.  So, crt.s will clear all ram between _bss_start and _bss_end.

Enough with the linker script, let's look at crt.s - the startup code

We get interested with _startup.  Remember that symbol from above?  Here is where the code execution actually begins  And the first instruction jumps to Reset_Handler by way of an indirection through Reset_Addr.  The very first thing Reset_handler does is set the stack.  Remember the _stack_end symbol?  Well, here's where we use it to set the SP.

Skip ahead to the comment /* copy .data section...  Here is where we copy the initialized data from flash to ram using the various addresses and length symbols from the .ld script.  Next is the section that clears .bss from _bss_start to _bss_end.

Finally, we have everything in place and we jump to main().

It took me a while to figure out how all this worked but it's pretty straightforward when it's all written down.  This linker script is for a processor you are unlikely to be using but the ideas carry across the entire GNU toolchain.

This is a hacked over file and there is an error in the comments about the various stack sizes.  For some reason I will never remember, I felt like 4 bytes wasn't adequate.  Ignore the various stacks...
« Last Edit: July 17, 2017, 01:09:40 pm by rstofer »
 
The following users thanked this post: jtronix


Share me

Digg  Facebook  SlashDot  Delicious  Technorati  Twitter  Google  Yahoo
Smf