Ask John or Jane Doe off the street for a definition of Bare Metal and you would likely hear about AC/DC crossed with the Full Monte. In embedded systems parlance, Bare Metal refers to systems that run on the hardware platform without the support of a commercial operating system. Bare Metal systems make up the vast majority of applications in the real world. Running programs native on the CPU or micro-controller creates some interesting challenges that developers don’t face when they have the support of an operating system.
- How does the program start?
- How can I tell if the program is working?
- How do I trace bugs in my program?
- What happens if there is a fundamental error in my program?
- Who’s keeping track of time?
What happens before main()?
For some who are new to bare metal, this may sound like an existential philosophical question, but trust me, it’s not. In fact, this is a question that I often use as an interview question. Or maybe better said, what happens and what needs to happen before main(). While some details are platform-dependent, the process is similar for most systems. After power-up, the processor starts execution at some known address. In ARM’s case, it starts by securing the reset exception/reset vector and runs the code at that program address.
Many platforms have some kind of non-volatile memory where a small startup program called the boot loader is stored. This boot loader ‘catches’ the processor right after power-up and loads a second-level, more sophisticated boot loader or the main embedded firmware. Other systems simply look to a specific address for the first instructions.
As an embedded system programmer, this is where your job begins. Whether you are taking over at the second level boot loader or just at the start of your program, you are now in complete control and everything that happens next (or doesn’t) is up to you.
In future installments we will discuss some basic foundational components that embedded programs should provide and how to go about setting them up.