28
\$\begingroup\$

Why do we need a separate program in the same flash program memory of a microcontroller, specifically STM32F103, which is called a bootloader?

What is special about it to keep it separate from the main application program?

Generally speaking, does a bootloader of a microprocessor-based system (say PowerPC MPC8270) do the same job as that of a microcontroller (say ARM STM32F103) or are they doing fundamentally different jobs from each other and yet both are called a 'bootloader'?

\$\endgroup\$
  • 2
    \$\begingroup\$ the same reason you have individual chips and parts and not one giant monolithic structure \$\endgroup\$ – Emobe Jul 3 at 6:50
  • \$\begingroup\$ You don't. Just enter your program with the switches and lights on the computer console. \$\endgroup\$ – Hot Licks Jul 4 at 12:50
  • 1
    \$\begingroup\$ Strictly speaking you do not need a separate bootloader program on a microcontroller. But we most often elect to have one for the additional utility functions it offers. If these functions are not needed, not wanted, then you can remove the bootloader. The microcontroller bootloader is typically used to burn a new program into flash. It can sometimes be used for debugging functions, some support breakpoints and other nice-to-have functions. On a microcomputer, typically the bootloader loads programs from mass memory and will be necessary there. \$\endgroup\$ – ghellquist Jul 4 at 19:26
55
\$\begingroup\$

A bootloader on a microcontroller is responsible for updating the main firmware over a communication channel other than the programming header. This is useful for updating firmware in the field over BLE, UART, I2C, SD cards, USB, etc. It would be extremely inconvenient to require customers to purchase programmers just to update the firmware on their devices.

The reason why the bootloader is kept separate is for reliability. The bootloader and application code are placed in separate sections of flash, so that the application code can be erased and re-written by the bootloader without changing anything related to the bootloader code.

If the bootloader and application were kept together, then the bootloader code would need to be copied to RAM before it could run, since any firmware update would erase the bootloader code in flash. If power were cut with the bootloader code in RAM and the flash erased, the device would be bricked.

\$\endgroup\$
  • 3
    \$\begingroup\$ Ours is the same reason. They're in the same flash but the bootloader is flash erase-boundry aligned and smart enough to only erase the flash higher than its own addresses. \$\endgroup\$ – Joshua Jul 2 at 23:17
  • 3
    \$\begingroup\$ In some instances, the microprocessor's programming header may actually be inaccessible without having to disassemble the product's chassis, so being able to reprogram it over the comms bus without extra hardware is a key factor for reliability. \$\endgroup\$ – John Go-Soco Jul 3 at 7:24
  • 6
    \$\begingroup\$ @alt-rose The bootloader and application program are separately compiled programs, each with their own startup code and main() function. At power up the bootloader startup code runs and calls the bootloader's main(). The bootloader program checks for a valid application program and then jumps to the application program's startup code which calls the application program's main(). Each program's startup code initializes the C run-time environment for the respective program (i.e. initialize variables, stack, etc.) and typically, neither program's main() ever returns to startup code. \$\endgroup\$ – kkrambo Jul 3 at 12:29
  • 1
    \$\begingroup\$ @alt-rose: In the same way that the CPU gets the starting address of the bootloader - it doesn't. Instead, the CPU specifies what it will use as the starting address of the bootloader, and the bootloader specifies what it will use as the starting address of the application program. \$\endgroup\$ – MSalters Jul 4 at 13:26
  • 4
    \$\begingroup\$ @kkrambo While commonly true, there is no requirement (nor universally true fact) that a bootloader be written in C or a C-derived language with a main at all. \$\endgroup\$ – Yakk Jul 4 at 20:12
26
\$\begingroup\$
  1. So that the loading process can recover from errors. Suppose there is a communication error or power disconnects during an upgrade. If the boot loader were part of the application you were upgrading then the user wouldn't be able to try again without using special hardware to reflash to boot loader.

  2. Some microcontrollers can't execute code from RAM. If the boot loader was mixed in with the rest of the software then you wouldn't actually be able to upgrade your software because you can't erase pages of flash that you are currently executing out of. The work around is to first burn the new code to the second half of flash, then jump to it. The new code then copies itself to the first half of flash. Of course the downside is that burning flash is usually slow and now that you have to do it twice the loading process might take up to twice as long. Also this work-around limits your application size to be no larger than half of your total flash.

  3. Well written boot loaders try to verify that valid code exists on the device before trying to execute it. If the boot loader and other code were mixed together then how could you be sure that your validation routine would work if all the code didn't load?

  4. Authentication. Secure boot loaders try to verify that the loaded application matches a digital signature before executing. But if the boot loader and other code were mixed together then you can't control what runs on the device because once the user loads new code you can't control what happens at startup.

\$\endgroup\$
  • 4
    \$\begingroup\$ As an example of point 2, some microcontrollers might not even have accessible RAM at startup: for example, the Raspberry Pi uses its GPU to load the bootloader from an SD card, which then enables the ARM processor and memory. \$\endgroup\$ – ErikF Jul 2 at 22:30
11
\$\begingroup\$

They're generally there to allow you to update your main application program.

You need some code which knows how to erase and reprogram some of the internal flash, that can't be the main program as when it's erased itself it wouldn't be able to reprogram.

\$\endgroup\$
9
\$\begingroup\$

The bootloader allows the MCU to communicate with something else to accept a new program, store it, and run it after a reset. If you didn't have a bootloader, then a Programmer is needed to access the memory and put the program in place.

\$\endgroup\$
  • 2
    \$\begingroup\$ That's pretty much it. The MCU can only get code through a special programming subsystem (like AVRICE or JTAG) or by already having a bootloader in flash. It's an application decision as to how complex the bootloader is, e.g. some systems can load code from WiFi. On very low end MCUs like an ATTiny, a bootloader (and serial pins) are a big overhead, so you always use a programmer. \$\endgroup\$ – Rich Jul 3 at 3:14
7
\$\begingroup\$

In addition to the other correct answers about allowing reprogramming of the main firmware from the bootloader, another benefit of having the bootloader be separate is that you can logically separate the "do once on boot" tasks from the code you need during runtime. Then, after the bootloader finishes its initial configuration tasks, the main firmware can evict the bootloader with all its no-longer-needed code from memory, saving significant RAM space. It's possible to achieve this in other ways, but the bootloader/firmware split makes it much easier on many architectures.

\$\endgroup\$
  • 1
    \$\begingroup\$ On a microcontroller, the code most likely never is in RAM, so it can't be evicted. You can discard the bootloader's data from RAM of course. \$\endgroup\$ – Ben Voigt Jul 5 at 13:54
  • \$\begingroup\$ @BenVoigt, it depends on the microcontroller. Some (primarily those with NOR flash) will let you execute directly out of flash, but others (usually with NAND flash, which is becoming more common) require you to execute out of RAM. Sometimes there isn't even any on-board flash, and you have to copy the code from an external flash chip into local SRAM before you can execute anything. \$\endgroup\$ – Nate S - Reinstate Monica Jul 8 at 16:39
2
\$\begingroup\$

The short answer, is because software is awesome.

You could have everything the bootloader does be "pure hardware". But it is far, far, far easier to have the tasks the bootloader does be written as software, then interpreted by hardware.

These tasks can involve setting up the hardware for the "real" software to run (for example, on a Raspberry Pi (via @ErikF)), having a protocol to replace the "real" program before it runs (check a pin, if that pin is set then reflash the real program), or even setting up the software environment for the "real" program.

On less micro-scale software, when you run an executable the application loader moves does stuff like loading parts of your data into memory, sometimes fixes up addresses, sets up arguments to main or other global stuff, spins up your OS provided libraries, and then jumps to the start of the _main code. Some of these things can be done by a bootloader.

In a microcontroller, some of the tasks that a bootloader does could be split off into the program. The compiler for your platform could automatically inject the "setup" code into every executable.

But, having it in the bootloader means that the same compiler might work on different hardware, as the bootloader can "hide" the difference between the platforms.

Top that off with the fact that a flash of the main program doesn't risk the bootloader (and the ability to reflash the main program), and having a non-trivial bootloader is a pretty great thing.

\$\endgroup\$
-1
\$\begingroup\$

One answer that hasn't been covered is the need for separation of concerns due to the limitations of the C language.

Generally bootloaders are written in a mix of Assembly and C, with the very early boot stage in Assembly.

This is done to setup certain things like:

  • allocating the C stack
  • reading the stack pointer into the register
  • reading the program counter into the register
  • declaring reset vectors
  • loading the second stage (initramfs) into RAM.

This is a very rough approximation of the steps taken and I am describing the ARM boot process, it is different again for x86 and other architectures.

However, the principle reason remains the same: allocating the C stack must be done from assembly.

\$\endgroup\$
  • \$\begingroup\$ Why the downvote? This is both relevant and accurate. \$\endgroup\$ – BitShift Aug 2 at 5:13
-1
\$\begingroup\$

One part of the question that hasn't been answered so far is the difference between bootloaders on microcontrollers and microprocessor systems.

Microcontroller

Most microcontrollers have built-in ROM memory that contains their program code. Changing this code usually requires a programmer device that connects to the programming interface of the microcontroller (e.g. ISP on ATMega). But these programming interfaces usually often are not very convenient to use, compared to other interfaces, since they might not be readily available in the given context. So for example, while almost every computer features USB ports, the SPI interface needed for ISP is much rarer, and other interfaces like the PID interface used on ATXMega are only supported by dedicated programming hardware.

So, e.g., if you want to update the software from a regular computer without any external hardware you can use a bootloader that reads from a different kind of interface (e.g. RS232, USB or RS232 over USB like on the Arduino) to program the device over common interfaces.

That said, if you don't need this functionality the bootloader is completely optional. The microcontroller can still run it's code completely without the bootloader.

Microprocessor

On a microprocessor things are a little different. While most microprocessors feature a ROM that is large enough for a bootloader, those ROMs are not nearly large enough to hold a full OS. So the purpose of the bootloader is to initialise hardware, look for a bootable OS, load it and run it. So the bootloader is critical for every single boot.

On x86/x64 systems this bootloader is either the BIOS or the UEFI (basically a newer version of a BIOS).

Sometimes you might even have multiple bootloaders running in a chain. For example if you have a dual-boot system with Windows and Linux you might end up with the following:

  • BIOS/UEFI boots up and finds GRUB installed. It then loads GRUB (=Grand Unified Bootloader)
  • GRUB finds some kind of Linux and the Windows Bootloader. The user selects the Windows Bootloader.
  • The Windows bootloader starts and finds Windows 7 and Windows 10 installed. The user selects Windows 10.
  • Windows 10 finally boots.

So in this case there were three pieces of software that can be considered a bootloader. Both GRUB and the Windows Bootloader are mostly there to give the user a more convenient boot selection option than the BIOS/UEFI would give them. It also allows for multiple OSes to be launched from the same hard drive or even the same partition.

TLDR

So while in both systems the bootloader does kinda similar things (helping the user to choose what code to boot) they both differ greatly in how they accomplish that and what they do exactly.

\$\endgroup\$
  • \$\begingroup\$ While it's useful to distinguish systems with enough random-access non-volatile storage (ROM or flash) to hold the entire program from those that need to run code from RAM, there are microcontrollers of both types and microprocessors of both types. \$\endgroup\$ – supercat Jul 4 at 20:47
  • \$\begingroup\$ Of course the difference between a microcontroller and a microprocessor is not a hard border and some microcontrollers behave more like a microprocessor and vice versa. That's why I took the AtMega/Arduino and the x86/x64 as examples, because they behave in that way. \$\endgroup\$ – Dakkaron Jul 5 at 11:07
  • \$\begingroup\$ "microprocessors feature a ROM that is large enough for a bootloader... On x86/x64 systems this bootloader is either the BIOS or the UEFI" Nope. BIOS or UEFI are stored in off-chip flash memory. The on-chip ROM is for even lower level functions, like initialization of the microcode. \$\endgroup\$ – Ben Voigt Jul 5 at 13:57
  • \$\begingroup\$ @Dakkaron: I would draw the line between a microprocessor and microcontroller based upon whether the chip is designed to be usable for non-trivial purposes without anything else on the address bus. The 8031 wouldn't qualify except that it is functionally 8051 (which is definitely a microcontroller) which isn't specified as having anything useful in the internal ROM, but would otherwise be designed to be usable entirely from internal storage). Something like an RCA/CDP 1802 wouldn't qualify even though it can be used to drive an LED nametag... \$\endgroup\$ – supercat Jul 5 at 16:37
  • \$\begingroup\$ ...with no external RAM and ROM, because RAMless/ROMless designs are limited to trivial tasks. Something like a TMS 32050 which if I recall has a bootloader and a few thousand words 16-bit words of RAM internally would qualify as a microcontroller, however; although many applications would require more adding more RAM, if connected via UART to another system it could serve many purposes without anything on its memory bus. \$\endgroup\$ – supercat Jul 5 at 16:46

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.