0
\$\begingroup\$

The more I learn about all the steps required for bringing a µC to the phase of finally executing the program, the more I get the impression that there is no "golden path". It seems to me that the exact steps required are different from project to project.

In general, following steps are required for execution of a normal bare-metal C program on a common 32bit µC like the ARM Cortex-M3:

  1. Clock must be configured. (Internal, external clock, prescalers and so on)
  2. Stack pointer must be initialized.
  3. .data region must be initialized with the right values.
  4. .bss region must be zeroed.
  5. Code to be executed must be in the memory range it was linked into.

My question: Which of the steps above are done by the loader? Which are done by a boot-loader such as U-Boot? What's the difference of a boot loader to a normal loader?

When I use U-Boot, it can copy the program (.text and .data) from ROM or even network to RAM and execute it from there. Does that mean that U-Boot is loading my program? What about .bss, it still has to be set up. If my program zeroes-out .bss myself, does that mean that my project is partly loaded by U-Boot and partly self-loading?

There might also be projects which can run from ROM and don't have any global variables. (Hence, no .bss and .data) Is the wording correct, that such a program dosn't require any loading?

\$\endgroup\$
3
\$\begingroup\$

Ok, let's first define some terms and the differences between them.

  • Bootloader

This is a small program coded into the chip's Flash or PROM. Its purpose is to allow you to install a program from outside into the Flash or other internal storage. Apart from that it is usually completely passive and doesn't affect your running program in any way.

  • Loader

This is a small program coded into the chip's Flash or PROM. It is usually installed using the bootloader originally if one exists, or it can take the place of a bootloader and also perform the functions associated with that. It's main function is to load a program from some storage medium - be that flash, SD card, or whatever - and execute it. It often also provides some IO facilities, such as routines for accessing the console. Loaders also often provide a configuration environment with NVRAM (often just a block of Flash) for storing system settings.

As you can see a loader is far more complex than a bootloader.

So they are just both concerned with getting your program into the right place, be that into Flash or RAM, depending on a) how your program is written, and b) what your system is designed to do. That is the "loading" phase of the program. With the bootloader the "loading" is done once by you when you burn your program into the chip. With the loader it is done every time at reset (if needed).

Then control is transferred to your program - be that in RAM (with the loader) or Flash (with either the loader or the bootloader). From then on everything else that happens is purely down to what your program does.

If you happened to write your program in C, then you will have certain C conventions and C library code in place. One of those conventions is the concept of the .data, .bss, etc. C library code manages those sections for you, copying data from .rodata into .data (or wherever for your system) if you are executing from Flash, blanking .bss, etc. That routine is called "crt0", or C Run-Time stage 0, and is responsible for the initialization of your program and passing control to the main() function.

If you didn't write your program in C - say you wrote it in Assembly, then what happens when control is passed to your program is entirely up to you. You might decide to have some block of RAM set aside for global variables. You may not. It's entirely up to you.

So in general, once control has been passed to your program, what happens then is entirely down to your program.

As for setting things like clocks and such, well, that depends entirely on the chip. Most of them have the basic clock settings stored in flash and are loaded up at power-on before anything else happens. On some chips they form part of the bootloader, on some they are separate, etc. Some chips provide a way of adjusting the clock from software, some don't. If they do, then when that would happen is anyone's guess. The bootloader may set the clock, or maybe a loader, or even your own program might set a specific clock speed.

For the stack pointer, each environment in the boot sequence is a separate system in its own right. Typically the bootloader or loader would set the stack pointer for its own usage. Then when control is passed to your program the stack pointer will be re-initialized by your program to suit its own needs. Once your program executes the bootloader or loader as good as doesn't exist any more. Yes, there may be the ability to call functions based in the loader (like a PC'S BIOS calls) but the loader is no longer running as such.

\$\endgroup\$

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.