EmbeddedRelated.com
Forums
Memfault Beyond the Launch

initializing memory before/after main()

Started by alb February 6, 2012
Dear all,

I am using an Analog Devices DSP from the old days (ADSP21020) and the g21k 
toolset (even though the VisualDSP would do exactly the same in this 
respect).
When using the runtime header, the vendor provides three calls to setup the 
hardware, the environment and the processor prior to the execution of the 
main() program. The mechanism is very simple: the reset vector table looks 
like this:

CALL ___lib_setup_hardware;
CALL ___lib_setup_processor;
CALL ___lib_setup_environment;
JUMP _main (DB);

When using the mem21k utility after linking (you can opt out in case you 
need to use the loader utility ldr21k which produces a bootloader and takes 
care of memory initialization), the segment seg_init will contain the 
necessary information that is needed to configure the memory during the
___lib_setup_processor call.

Since my system has already a boot loader and the way is done is such that 
to run my main() application it would copy it from flash and then jump to a 
specific location, I have no way to perform the memory initialization before 
my main() is called. What I still can do is to call ___lib_setup_processor 
(and maybe the others as well) as first instruction(s) in my program. This 
will lead to initializing the memory after the main() is called but before 
any memory is used. I would like to know if there is any caveat with this 
approach and if there's something I need to take care about that goes beyond 
these library calls.

Certainly I may as well take care about memory initialization explicetely, 
in my program,  without any need to care about seg_init.

Any suggestions/ideas are appreciated.

Al
On 06/02/2012 09:42, alb wrote:
> Dear all, > > I am using an Analog Devices DSP from the old days (ADSP21020) and the > g21k toolset (even though the VisualDSP would do exactly the same in > this respect). > When using the runtime header, the vendor provides three calls to setup > the hardware, the environment and the processor prior to the execution > of the main() program. The mechanism is very simple: the reset vector > table looks like this: > > CALL ___lib_setup_hardware; > CALL ___lib_setup_processor; > CALL ___lib_setup_environment; > JUMP _main (DB); > > When using the mem21k utility after linking (you can opt out in case you > need to use the loader utility ldr21k which produces a bootloader and > takes care of memory initialization), the segment seg_init will contain > the necessary information that is needed to configure the memory during the > ___lib_setup_processor call. > > Since my system has already a boot loader and the way is done is such > that to run my main() application it would copy it from flash and then > jump to a specific location, I have no way to perform the memory > initialization before my main() is called. What I still can do is to > call ___lib_setup_processor (and maybe the others as well) as first > instruction(s) in my program. This will lead to initializing the memory > after the main() is called but before any memory is used. I would like > to know if there is any caveat with this approach and if there's > something I need to take care about that goes beyond these library calls. > > Certainly I may as well take care about memory initialization > explicetely, in my program, without any need to care about seg_init. > > Any suggestions/ideas are appreciated. > > Al
As a minimum you must ensure the stack that main() is going to use is setup and configured before main() is called - and then that none of the initialisation functions you explicitly call from main() change the stack configuration - or write over the stack frame that, by that point, will already be in use by main(). Regards, Richard. + http://www.FreeRTOS.org Designed for Microcontrollers. More than 7000 downloads per month.
Dear Richard,

FreeRTOS info writes:
> On 06/02/2012 09:42, alb wrote:
[...]
>> Certainly I may as well take care about memory initialization >> explicetely, in my program, without any need to care about seg_init. >>
[...]
> > As a minimum you must ensure the stack that main() is going to use is > setup and configured before main() is called - and then that none of the > initialisation functions you explicitly call from main() change the > stack configuration - or write over the stack frame that, by that point, > will already be in use by main().
At the moment the main is called I believe the stack is configured for the loader which was running before the 'jump to main'. At this point, since there's no need to go back to the loader I believe I can re-initialize the stack from scratch with the lib_setup_environment call which should do the job. The beginning of my main will look like this then: void main (void) { SETUP_HWR(); // setup hardware (cache, irptl and memory banks) SETUP_PRO(); // setup processor (registers, modes and memory) SETUP_ENV(); // setup environment (stacks, errno, heaps, rand, interrupts // exit and arguments) ... } Where SETUP_HWR/PRO/ENV are defines like: #define SETUP_HWR() asm("CALL ___lib_setup_hardware;") #define SETUP_PRO() asm("CALL ___lib_setup_processor;") #define SETUP_ENV() asm("CALL ___lib_setup_environment;") Even though the main is running, the stack should be empty, as well as the heap, the registers and all the rest. Have I understood your concerns correctly?
> > Regards, > Richard. > > + http://www.FreeRTOS.org > Designed for Microcontrollers. > More than 7000 downloads per month. > >

alb wrote:

> Since my system has already a boot loader and the way is done is such > that to run my main() application it would copy it from flash and then > jump to a specific location, I have no way to perform the memory > initialization before my main() is called. What I still can do is to > call ___lib_setup_processor (and maybe the others as well) as first > instruction(s) in my program. This will lead to initializing the memory > after the main() is called but before any memory is used. I would like > to know if there is any caveat with this approach and if there's > something I need to take care about that goes beyond these library calls. > Certainly I may as well take care about memory initialization > explicetely, in my program, without any need to care about seg_init.
It is a bad idea to do initializations in non-standard way. It could create unforeseen complications. The constructors of static objects must be called before main(). The compiler optimizer might rearrange the beginning of main() in unexpected way. The library initialization can destroy the stack of main itself. The debugger might expect the environment to be set up in a certain way before main(). A programmer could edit out some cryptic calls.
> Any suggestions/ideas are appreciated.
Rewrite the startup code once forever so the initializations would be called in prescribed manner. Vladimir Vassilevsky DSP and Mixed Signal Design Consultant http://www.abvolt.com
On Mon, 06 Feb 2012 15:43:23 +0000, alb wrote:

> Dear Richard, > > FreeRTOS info writes: >> On 06/02/2012 09:42, alb wrote: > [...] >>> Certainly I may as well take care about memory initialization >>> explicetely, in my program, without any need to care about seg_init. >>> > [...] >> >> As a minimum you must ensure the stack that main() is going to use is >> setup and configured before main() is called - and then that none of >> the initialisation functions you explicitly call from main() change the >> stack configuration - or write over the stack frame that, by that >> point, will already be in use by main(). > > At the moment the main is called I believe the stack is configured for > the loader which was running before the 'jump to main'. At this point, > since there's no need to go back to the loader I believe I can > re-initialize the stack from scratch with the lib_setup_environment call > which should do the job. > > The beginning of my main will look like this then: > > void main (void) { > > SETUP_HWR(); // setup hardware (cache, irptl and memory banks) > SETUP_PRO(); // setup processor (registers, modes and memory) > SETUP_ENV(); // setup environment (stacks, errno, heaps, rand, > interrupts > // exit and arguments) > > ... > } > > Where SETUP_HWR/PRO/ENV are defines like: > > #define SETUP_HWR() asm("CALL ___lib_setup_hardware;") #define > SETUP_PRO() asm("CALL ___lib_setup_processor;") #define SETUP_ENV() > asm("CALL ___lib_setup_environment;") > > > Even though the main is running, the stack should be empty, as well as > the heap, the registers and all the rest. Have I understood your > concerns correctly? >
That will probably work if main does not define any variables. If it does (even if occurs in the text after all the SETUP_xxx() functions) then when you change the stack pointer those variable locations will be toast. Depending on your optimizations, they may already have something in them, too. -- Tim Wescott Control system and signal processing consulting www.wescottdesign.com
Vladimir Vassilevsky writes:
[...]
> > It is a bad idea to do initializations in non-standard way. It could > create unforeseen complications. The constructors of static objects must > be called before main(). The compiler optimizer might rearrange the > beginning of main() in unexpected way. The library initialization can > destroy the stack of main itself. The debugger might expect the > environment to be set up in a certain way before main(). A programmer > could edit out some cryptic calls. >
I understand that doing initialization in non-standard way is very bad idea and I wouldn't have done it if I had a choice. Unfortunately I don't have any way to change the way the code jumps to the main. This part is written in a protected area of the flash and cannot be changed. I can say that from the assembly code produced by the compiler the first three calls are as expected, no funny rearrengement and/or optimization. If the static objects need to be constructed before the main is called then I have no choice but avoiding the usage of static objects. For what concerns the debugger the answer is easy, I don't use one (maybe unwise, but not yet convinced). Worries about a programmer editing out those details can be solved by documentation and/or comments. I don't want to defend the approach, my aim is to be aware of what are the consequences and act accordingly.
>> Any suggestions/ideas are appreciated. > > Rewrite the startup code once forever so the initializations would be > called in prescribed manner.
Well indeed I can think of an additional segment of code which can be located in the place where the main was supposed to be and move the main segment somewhere else. In this way I can call the initialization function before the main is called (how about that).
> > Vladimir Vassilevsky > DSP and Mixed Signal Design Consultant > http://www.abvolt.com
On Mon, 06 Feb 2012 09:42:53 +0000, alb wrote:

> Dear all, > > I am using an Analog Devices DSP from the old days (ADSP21020) and the > g21k toolset (even though the VisualDSP would do exactly the same in > this respect). > When using the runtime header, the vendor provides three calls to setup > the hardware, the environment and the processor prior to the execution > of the main() program. The mechanism is very simple: the reset vector > table looks like this: > > CALL ___lib_setup_hardware; > CALL ___lib_setup_processor; > CALL ___lib_setup_environment; > JUMP _main (DB); > > When using the mem21k utility after linking (you can opt out in case you > need to use the loader utility ldr21k which produces a bootloader and > takes care of memory initialization), the segment seg_init will contain > the necessary information that is needed to configure the memory during > the ___lib_setup_processor call. > > Since my system has already a boot loader and the way is done is such > that to run my main() application it would copy it from flash and then > jump to a specific location, I have no way to perform the memory > initialization before my main() is called. What I still can do is to > call ___lib_setup_processor (and maybe the others as well) as first > instruction(s) in my program. This will lead to initializing the memory > after the main() is called but before any memory is used. I would like > to know if there is any caveat with this approach and if there's > something I need to take care about that goes beyond these library > calls. > > Certainly I may as well take care about memory initialization > explicetely, in my program, without any need to care about seg_init. > > Any suggestions/ideas are appreciated.
In descending order of desirability/safety: 1: Fix your boot loader so that it either does the requisite setup, or so that it calls a "pre_main" function that you write (in assembly) to do the setup and call main. 2: Write main in assembly to do the "pre_main" function mentioned above. 3: Write main in C, but put _nothing_ into it except for those three function calls you have mentioned. 1 is the right solution. 2 is a kludge. 3 is a really desperate kludge. -- Tim Wescott Control system and signal processing consulting www.wescottdesign.com
On Mon, 06 Feb 2012 16:40:08 +0000, alb wrote:

> Vladimir Vassilevsky writes: > [...] >> >> It is a bad idea to do initializations in non-standard way. It could >> create unforeseen complications. The constructors of static objects >> must be called before main(). The compiler optimizer might rearrange >> the beginning of main() in unexpected way. The library initialization >> can destroy the stack of main itself. The debugger might expect the >> environment to be set up in a certain way before main(). A programmer >> could edit out some cryptic calls. >> >> > I understand that doing initialization in non-standard way is very bad > idea and I wouldn't have done it if I had a choice. Unfortunately I > don't have any way to change the way the code jumps to the main. This > part is written in a protected area of the flash and cannot be changed. > > I can say that from the assembly code produced by the compiler the first > three calls are as expected, no funny rearrengement and/or optimization. > If the static objects need to be constructed before the main is called > then I have no choice but avoiding the usage of static objects. > > For what concerns the debugger the answer is easy, I don't use one > (maybe unwise, but not yet convinced). > > Worries about a programmer editing out those details can be solved by > documentation and/or comments. > > I don't want to defend the approach, my aim is to be aware of what are > the consequences and act accordingly. > >>> Any suggestions/ideas are appreciated. >> >> Rewrite the startup code once forever so the initializations would be >> called in prescribed manner. > > Well indeed I can think of an additional segment of code which can be > located in the place where the main was supposed to be and move the main > segment somewhere else. In this way I can call the initialization > function before the main is called (how about that).
That would be a very good way to do it, IMHO. Just edit the 'standard' startup code so that it's entry point is where the boot code jumps on startup, and go from there. -- My liberal friends think I'm a conservative kook. My conservative friends think I'm a liberal kook. Why am I not happy that they have found common ground? Tim Wescott, Communications, Control, Circuits & Software http://www.wescottdesign.com
On 06/02/2012 16:38, Tim Wescott wrote:
> On Mon, 06 Feb 2012 15:43:23 +0000, alb wrote: > >> Dear Richard, >> >> FreeRTOS info writes: >>> On 06/02/2012 09:42, alb wrote: >> [...] >>>> Certainly I may as well take care about memory initialization >>>> explicetely, in my program, without any need to care about seg_init. >>>> >> [...] >>> >>> As a minimum you must ensure the stack that main() is going to use is >>> setup and configured before main() is called - and then that none of >>> the initialisation functions you explicitly call from main() change the >>> stack configuration - or write over the stack frame that, by that >>> point, will already be in use by main(). >> >> At the moment the main is called I believe the stack is configured for >> the loader which was running before the 'jump to main'. At this point, >> since there's no need to go back to the loader I believe I can >> re-initialize the stack from scratch with the lib_setup_environment call >> which should do the job. >> >> The beginning of my main will look like this then: >> >> void main (void) { >> >> SETUP_HWR(); // setup hardware (cache, irptl and memory banks) >> SETUP_PRO(); // setup processor (registers, modes and memory) >> SETUP_ENV(); // setup environment (stacks, errno, heaps, rand, >> interrupts >> // exit and arguments) >> >> ... >> } >> >> Where SETUP_HWR/PRO/ENV are defines like: >> >> #define SETUP_HWR() asm("CALL ___lib_setup_hardware;") #define >> SETUP_PRO() asm("CALL ___lib_setup_processor;") #define SETUP_ENV() >> asm("CALL ___lib_setup_environment;") >> >> >> Even though the main is running, the stack should be empty, as well as >> the heap, the registers and all the rest. Have I understood your >> concerns correctly? >> > That will probably work if main does not define any variables. If it > does (even if occurs in the text after all the SETUP_xxx() functions) > then when you change the stack pointer those variable locations will be > toast. Depending on your optimizations, they may already have something > in them, too. >
Looking at the asm generated by the compiler is the only real way of knowing what the environment expects. For example, ignoring the stack pointer, where is the frame pointer pointing before main() calls another function that is going to attempt to set up its own stack frame? What happens when the compiler implementation changes? Etc. Also take care about the implementation of your initialisation routines - do they rely on anything? Some systems will set up a temporary environment for the initialisation code, then scrub it before setting up the environment for main(). All things considered, it might (probably will) work, but you would be better off using functions as they are intended to be used, or writing your own versions of them. Regards, Richard. + http://www.FreeRTOS.org Designed for Microcontrollers. More than 7000 downloads per month.
On Tue, 07 Feb 2012 11:25:55 +0000, FreeRTOS info wrote:

> On 06/02/2012 16:38, Tim Wescott wrote: >> On Mon, 06 Feb 2012 15:43:23 +0000, alb wrote: >> >>> Dear Richard, >>> >>> FreeRTOS info writes: >>>> On 06/02/2012 09:42, alb wrote: >>> [...] >>>>> Certainly I may as well take care about memory initialization >>>>> explicetely, in my program, without any need to care about >>>>> seg_init. >>>>> >>> [...] >>>> >>>> As a minimum you must ensure the stack that main() is going to use is >>>> setup and configured before main() is called - and then that none of >>>> the initialisation functions you explicitly call from main() change >>>> the stack configuration - or write over the stack frame that, by that >>>> point, will already be in use by main(). >>> >>> At the moment the main is called I believe the stack is configured for >>> the loader which was running before the 'jump to main'. At this point, >>> since there's no need to go back to the loader I believe I can >>> re-initialize the stack from scratch with the lib_setup_environment >>> call which should do the job. >>> >>> The beginning of my main will look like this then: >>> >>> void main (void) { >>> >>> SETUP_HWR(); // setup hardware (cache, irptl and memory banks) >>> SETUP_PRO(); // setup processor (registers, modes and memory) >>> SETUP_ENV(); // setup environment (stacks, errno, heaps, rand, >>> interrupts >>> // exit and arguments) >>> >>> ... >>> } >>> >>> Where SETUP_HWR/PRO/ENV are defines like: >>> >>> #define SETUP_HWR() asm("CALL ___lib_setup_hardware;") #define >>> SETUP_PRO() asm("CALL ___lib_setup_processor;") #define SETUP_ENV() >>> asm("CALL ___lib_setup_environment;") >>> >>> >>> Even though the main is running, the stack should be empty, as well as >>> the heap, the registers and all the rest. Have I understood your >>> concerns correctly? >>> >> That will probably work if main does not define any variables. If it >> does (even if occurs in the text after all the SETUP_xxx() functions) >> then when you change the stack pointer those variable locations will be >> toast. Depending on your optimizations, they may already have >> something in them, too. >> >> > > Looking at the asm generated by the compiler is the only real way of > knowing what the environment expects. For example, ignoring the stack
I always forget to mention that... -- Tim Wescott Control system and signal processing consulting www.wescottdesign.com

Memfault Beyond the Launch