Welcome!

This training is intended to provide you with the theoretical knowledge and practical experience necessary to navigate the world of embedded Linux development. By the end you should "know enough to be dangerous", but please do keep in mind that this is only an introduction to the subject, and as such you will be expected to put in more work if you want to be able to solve problems that may arise in a professional environment.

Throughout the training we will assume that you are familiar with the C programming language, as well as the basics of UNIX-based operating systems. We will make extensive use of the terminal, so it is expected that you feel comfortable with that environment. That being said, the main goal here is to learn, so feel free to reach out to the instructor if you have a question or are stuck.

A good test would be to take the following program and compile it from the terminal using GCC, Clang, or whatever compiler you prefer:

#include <stdio.h>

int main(void) {
  printf("Hello there!\n");
  return 0;
}

If you are not able to do this easily, please tell the instructor so we can take some time and go through it! Again, this is one of the most basic things we will be doing in the next few weeks, so it is important that you are able to do it on your own.

With that out of the way, let us get going...

Linux and embedded systems

In general, a CPU is referred to as "embedded" when it is in a product where users may not even know (or care) that there is a CPU. A mobile phone would be a good example of this, but also digital watches, elevator control systems, automobile parts, etc.

If a piece of hardware has a CPU, then it is capable of executing programs. Sometimes an embedded system performs a very simple task, and as such it is conceivable that there is only one program running on it, and therefore something like an operating system is not needed.

In most cases, however, systems need to perform more than one task. This is blatantly obvious for an automobile, for example. For those systems it makes sense to have an operating system that can mediate access to hardware and offer protection mechanisms for the various programs that are going to be running. Many historical embedded systems had no protection against application failure. In these systems application programs ran at the most-trusted hardware privilege (e.g., ring 0 on Intel) and could access any and all instructions, memory and I/O locations. In some of these systems there was no mechanism to regain control should an application program execute a simple fault such as an attempt to divide by zero.

This approach worked as long as the manufacturer could control the application programs that could be run on the system, which made a lot of sense for embedded products of the time, and still does for some. For example, a toaster with an embedded CPU rarely needs to run applications from outside.

That being said, more and more modern embedded systems (such as mobile phones and tablets) are capable of accepting new application programs on a dynamic basis. This had led to a distinct need for embedded systems to survive an application crash, and as a result, systems with robust protection (that permit applications to access only their allocated memory and other resources) have grown in importance. These systems are usually also capable of “cleaning up” after an application failure.

Accordingly, for many years now the trend in embedded computing has been to use microprocessors capable of strong protection in hardware and to deploy operating systems capable of handling application crashes. It is in this context that we will consider Linux, which is one of the many options available when it comes to choosing an operating system for an embedded platform.

Keep in mind that, strictly speaking, Linux is not an operating system, but a kernel. By itself, Linux is not sufficient to make a piece of hardware “work”: you need other components such as a bootloader and a file system. We will explore these in detail in future modules.

People often use the term “Linux” when they actually mean “a Linux-based operating system”. Distributions like Ubuntu, Debian and Arch Linux are exactly this: they use Linux as the kernel of the operating system and then add a plethora of software to create something that can bring life to a computer.
  • Linux supports a large number of CPUs designed for embedded applications, including those with low power requirements.
  • In addition, Linux also supports development boards supplied by CPU manufacturers for potential customers to gain familiarity with the part.
  • An ever-increasing number of embedded products require network connectivity. Linux has a robust and efficient network stack which has been proven portable across a wide range of CPU architectures.
  • Many peripheral devices needed by embedded products are well supported by drivers contributed by the Linux community.
In most cases, multi-tasking, multi-user operating systems such as Linux are not generally suitable for hard real-time embedded systems. There was nothing in these systems preventing some kernel code (typically a device driver) from disabling interrupts for a period of time exceeding the latency requirement of an application.

That being said, quite a few attempts have been made to add real-time capability to Linux.

One such approach is the CONFIG_PREEMPT_RT project, which at its core is a patch set that introduces some modifications to the internals of Linux. Such a topic is outside of the scope of this training, but the important point being made here is that, by default, Linux is not a real-time kernel.