Why do we need a bootloader in an embedded device?
A boot loader is a computer program that loads the main operating system or runtime environment for the computer after completion of the self-tests.
^ From Wikipedia Article
So basically bootloader is doing just what you wanted - copying data from flash into operating memory. It's really that simple.
If you want to know more about boostrapping the OS, I highly recommend you read the linked article. Boot phase consists, apart from tests, also of checking peripherals and some other things. Skipping them makes sense only on very simple embedded devices, and that's why their bootloaders are even simpler:
Some embedded systems do not require a noticeable boot sequence to begin functioning and when turned on may simply run operational programs that are stored in ROM.
The same source
Bootloader Working
When any hardware system is designed, the designer must consider where the executable code will be located. The answer depends on the microcontroller, the included memory types, and the system requirements. So the answer varies from system to system. Some systems execute code located in RAM. Other systems execute code located in flash. You didn't tell us enough about your system to know what it is designed to do.
A system might be designed to execute code from RAM because RAM access times are faster than flash so code can execute faster. A system might be designed to execute code from flash because flash is plentiful and RAM may not be. A system might be designed to execute code from flash so that it boots more quickly. These are just some examples and there are other considerations as well.
RAM is volatile so it does not retain code through a power cycle. If the system executes code located in RAM then a bootloader is required to obtain and write the code to RAM at powerup. Flash is non-volatile so execution can start right away at powerup and a bootloader is not necessary (but may still be useful).
Regarding Q3, the answer is yes. If the system is running from RAM then the .text will be located in RAM (but not until after the bootloader has copied it to there). If the system is running from flash then the .text section will be located in flash. The .bss section is variables and will be in RAM regardless of where the .text section is.
What is the difference between a Bootrom vs bootloader on ARM systems
Here's how I understand the terms.
Bootrom
Bootrom (or Boot ROM) is a small piece of mask ROM or write-protected flash embedded inside the processor chip. It contains the very first code which is executed by the processor on power-on or reset. Depending on the configuration of some strap pins or internal fuses it may decide from where to load the next part of the code to be executed and how or whether to verify it for correctness or validity. Sometimes it may contain additional functionality, possibly usable by user code during or after booting. Some examples:
iPhone boot ROM. Embedded in the mask ROM and can't be modified. Loads the next stage boot loader from flash or USB (in DFU mode) and verifies its signature using built-in RSA implementation. Also provides accelerated decryption functions for the next stage bootloader.
TI's OMAP4 boot ROM. Can load user code from flash (NOR, NAND, OneNAND), external memory, SD/MMC, USB or UART. Boot order and options are set by strap (SYSBOOT) pins. Provides some functionality for later stages (cache/TLB management etc.)
NXP's LPCxxxx series Boot ROM. Placed in a hidden portion of the internal flash which is mapped at 0 on power-on. Implements CRP (code read protection), ISP (In-System Programming) which allows to upload and flash new code over UART. If a valid user code is in flash (needs to have proper checksum), maps it to 0 and jumps to it. A part of bootrom remains mapped to provide IAP (In-Application Programming) and some other services.
Bootloader
Bootloader is responsible for finding and loading the final OS or firmware which is supposed to run on the chip. One main difference from bootrom is that it's usually in writable flash and can be replaced or upgraded.
Sometimes bootrom can perform the job of the bootloader. For example, OMAP's bootrom is complex enough (it can parse FAT32!) that you can probably have it load and start a Linux kernel directly.
However, in many cases a separate bootloader is used, either because the bootrom is not capable enough (or absent), or because extra flexibility is needed. It can be very simple (load kernel from a fixed flash location in RAM and jump to it), or can be much more complicated. For example, U-Boot is a like a mini-OS by itself - it has a console, some commands, allows you break the boot process and e.g. modify the kernel command line arguments or even load the kernel from a different location (SD/MMC or USB), run some tests and so on.
Bootloaders are usually used when you have a more or less complex OS which may need some set up before it can be started. Smaller microcontrollers like NXP's LPC series usually use a monolithic firmware so they can get by without it (however, there may be custom bootloaders for them too).
On the very simplest chips there may be no boot ROM or boot loader at all - they just try to fetch and execute instructions from a fixed startup address. In fact, most x86 chips to this day work like this - they just start executing code at FFFFFFF0 with the expectation that the chipset has mapped the BIOS flash chip there. Here, you can say that BIOS is the bootloader (though it also provides services to the OS, similar to bootrom).
Developing a simple bootloader for an Embedded system
You can (in principle) link the object file generated from the assembler code like you would link any object from your program.
The catch is that you need to lay out the generated executable so that your startup code is in the beginning. If you use GNU ld, the way to do that is a linker script.
Primitive setup (not checked for syntax errors):
MEMORY
{
FLASH (RX) : ORIGIN = 0, LENGTH = 256K
RAM (RWX) : ORIGIN = 0x40000000, LENGTH = 4M
}
SECTIONS
{
.bootloader 0 : AT(0) { bootloader.o(.text) } >FLASH AT>FLASH
.text : { _stext = .; *(.text .text.* .rodata .rodata.*); _etext = . } >FLASH AT>FLASH
.data : { _sdata = .; *(.data .data.*); _edata = .; _sdata_load = LOADADDR(.data) } >RAM AT>FLASH
.bss (NOLOAD) { _sbss = .; *(.bss .bss.*); _ebss = . } >RAM
}
The basic idea is to give the linker a rough idea of the memory map, then assign sections from the input files to sections in the final program.
The linker keeps the distinction between the "virtual" and the "load" address for every output section, so you can tell it to generate a binary where the code is relocated for the final addresses, but the layout in the executable is different (here, I tell it to place the .data section in RAM, but append it to the .text section in flash).
Your bootloader can then use the symbols provided (_sdata
, _edata
, _sdata_load
) to find the data section both in RAM and in flash, and copy it.
Final caveat: if your program uses static constructors, you also need a constructor table, and the bootloader needs to call the static constructors.
How does a typical embedded boot loader end?
Once a bootloader has finished it's initialization tasks, it transfers control of the system to the operating program/system. The specific instruction is typically a jump or a branch depending on the specific bootloader or architecture.
Since you specifically mention an operating system, I will reference the Embedded Linux Primer:
Note that the
bootm
command is the death knell for U-Boot. This is
an important concept. Unlike the BIOS in a desktop PC, most embedded
systems are architected in such a way that when the Linux kernel takes
control, the bootloader ceases to exist. The kernel claims any memory
and system resources that the bootloader previously used. The only way
to pass control back to the bootloader is to reboot the board.
And looking at the AT91 Assembler Code Startup Sequence for C Code Applications Software we can see that it uses bx
which is the Branch and Exchange command of the THUMB Instruction Set:
;---------------------------------------------------------------------------
;- Branch on C code Main function (with interworking)
;---------------------------------------------------------------------------
IMPORT __main
ldr r0, =__main
bx r0
END
What are techniques for allowing safe software upgrades in embedded systems
It all depends on how critical the application is. The two basic approaches (backup and bootloader) are also combined sometimes.
Many systems have a read only bootloader (like redboot), and then two banks of flash memory (on the same chip, most often). The bootloader then has a flag to choose which bank to boot from. The flag will then change based on events like upgrades (failed or successful), and so on.
So, when upgrading, the running version copies the new load into the backup bank, checks the checksum, toggles the boot flag, and then reboots the device. The device reboots on the new bank, with the new load. After the reboot, the new load can copy itself into the backup bank.
Often there is also a watchdog timer with a hardware reset. This way, if the firmware goes insane, it fails to kick the watchdog, the hardware reset will reboot the device, and the bootloader will look for a sane load.
The Open Mesh project is a good example of this approach.
STM32 boot loader
There two main options:
SWD
Implement an SWD programming connector. Basically the pins GND, SWDIO, SWCLK and preferably 3.3V are made available. No resisters are needed. You can fit a 4 pin header, an official 10 pin SWD connector or just 4 pads (for connecting using an adapter with pogo pins).
This option requires an SWD debug adapter like ST-Link or J-Link. In addition to uploading firmware, this option supports debugging.
USART
Make the USART (RX, TX) pins plus GND and 3.3V available on the board. This option requires a USB-to-serial adapter.
It's also possible to use I2C or SPI instead, though there are no standard solutions for connecting to your board that I'm aware of.
USB isn't an option for this particular chip. It is supported on many of the more expensive STM32 chips though.
I strongly recommend the first option. It is far more versatile than the other options. And an ST-Link adapter isn't expensive.
Details regarding the bootloader capabilities and pins:
https://www.st.com/resource/en/application_note/cd00167594-stm32-microcontroller-system-memory-boot-mode-stmicroelectronics.pdf
Related Topics
Compare Integer in Bash, Unary Operator Expected
Shell - Write Variable Contents to a File
How to Compile Glut + Opengl Project with Cmake and Kdevelop in Linux
Cross-Compile a Rust Application from Linux to Windows
How to Upgrade Aws Cli to the Latest Version
How to Install Nuget from Command Line on Linux
What Is the Correct Way to Start a Mongod Service on Linux/Os X
Getting Pids from Ps -Ef |Grep Keyword
Why Doesn't Linux Use the Hardware Context Switch via the Tss
Run Shell Command in Jenkins as Root User
Bash - How to Pipe Result from the Which Command to Cd
How to Sort a File, Based on Its Numerical Values for a Field
What Are the Real Rules for Linux Usernames on Centos 6 and Rhel 6
Difference Between Posix Aio and Libaio on Linux
How to Install PHP 7 on Ec2 T2.Micro Instance Running Amazon Linux Distro