Let’s look at how the hardware lives with RTOS.
The hardware from, at least from the RTOS perspective, can be broadly classified of two types. The first part is what is used by the RTOS, the second is what RTOS supports the applications with.
The fundamental hardware required for a given RTOS is CPU, Memory and some boot store, the red blocks. Most RISC CPUs often tend to have a small static memory on the die, about a few KB on board. Though a given RTOS can be implemented using just the internal memory, the RTOS still needs to manage the memory resources for itself, house-keeping and of course the applications. Hence, the external memory is also a required hardware resource, though it is not something it cannot do without.
The additional hardware, or the ‘application’ hardware, the blue blocks, are not used by the RTOS itself, but they should have drivers developed and run on top of RTOS kernel itself to make up the BSP or Board Support Package. Unless all the four blocks are effectively covered by the RTOS and the BSP, an application cannot use the complete system effectively.
Next, let’s look at the boot up process till we bring up the applications, which should help us cover all the hardware blocks.
Let’s start with the Power On Self Test, a.k.a POST and pre boot phase. These routines must be stored in a permanant non voaltile storage, usually ROM or Flash. The post and pre boot phase normally begins with the execution jumping to the reset vector. In other words, the POST and pre boot stuff live at the reset vector. If you got mail for them, you know where to deliver now.
Alright, fun aside. The POST, as it abbreviates, are a set of routines helping the processor to verify that the coast is clear for it to boot. Once the processor gets a go from the POST, the pre boot kicks in. Usually, the pre boot up routines are packaged and shipped along with POST and most probably the boot loader itself.
The pre boot routines setup minimal environment for the boot loader to take over. At the minimum, they either initialize the internal memory, if available. Otherwise, they have to enable the external memory controller, initialize the external memory itself, e.g SDRAM. Once the memory is initialized, the pre boot routines give way to the boot loader. Occassionally, the pre boot routines relocate the boot loader from the permanant storage to RAM.
Ah, the big guy, the boot loader. Usually, the boot loader has got more than one job to do. The boot loaders are often designed to do a bit more than just setting up the memory space, configuring the resources, loading the kernel and OS into the memory and passing the control to it. Often, boot loaders are also designed to download the OS images, verify the filesystems, uncompress the OS images or even give an early access to board diagnostics. In any case, let’s just follow the regular boot path.
Once the boot loader is in control, it sets up a bit more of the hardware, configures the resources and address space, fiddle with caching and starts unpacking the OS image. In some cases, the OS image may need a bit of uncompression, in other it’s a good to go off the shelf. Usually, the OS image has it’s home in the flash store.
In cases, there could be two flash stores, one a bit of high reliability parallel flash at the reset vector and another high capacity serial or parallel flash living somewhere else. May even be a NAND flash or hard disk also. In such cases, the boot loader should also know a bit about how they are stored in the secondary store, e.g. filesystem and drivers to access the media.
If the boot loader store is separated, it could be because of multiple reasons. One, the flash store large enough for entire OS image could be really costly, because it has to be high reliability NOR type. Two, OS upgrades may impact the stability of the boot loaders also. Another, in case of corruption by some OS writes, the bootloader may be overwritten, corrupting the same. A serial flash store such as SPI flash or even SD cards cannot provide parallel access during POST phases.
On with the tour, once the boot loader gets hold of OS image, it may unpack the same in to RAM, uncompress if needed. Some smaller systems may directly run OS off the flash. In such cases, boot loader simply passes on the control to the OS image after checking for any OS update events pending. Otherwise, the loading into the RAM goes first and then control is passed to the OS boot up routines.
Once the OS gets control, the boot up part of the kernel routines take up the charge. They verify internal resources, setup address spaces etc. Occassionally, an uncompressing job is handled by the pre-kernel part itself. The pre-kernel may also set the stack up for the kernel, heap and other minimal memory management stuff. Usually, the pre-kernel messes with only a minor part of the avaialble RAM, leaving rest for the big guys. Finally, the kernel kicks in.
The kernel does a bit of housekeeping work, such as reconfiguring the memory regions, brings up the memory management and resource management stuff such as traps, task queues, timer queues etc. Once the kernel is done with the housekeeping work, it will finally enter the scheduling routine, from where it will load the task whose address is given to it at the shipping time and starts the same. A simple mechanism is a pre-defined function, with resources also predefined. In a way, we may call this the init task.
Usually, timer routines are provided by the BSP to the kernel. Just before starting off the first task, the timer is kicked, ISRs are setup and the control is passed to the init task. This way, the RTOS can flex it’s time slicing muscle at tasks that refuse to give the CPU up.
The init task, by design, spawns a bunch of tasks. The ones that go in first are the device driver tasks. If you are familiar with *nix, you may ask, what does this mean? Let’s look at the RTOS drivers, a bit later, to understand what they really are.
Once the driver tasks are up and running, the application tasks are brought in. These are the guys who do the final job. Be it showing up some video on the screen or issuing a defibrillating shock to the heart or even launching an atom bomb, depending upon the hardware resources and what they are programmed to do.
One thing to notice in the context of RTOS applications is that they directly work on the hardware, with drivers are just a bunch of synchronized routines for doing the dirty job of working with the hardware. In other words, the RTOS applications, for the most part, should be aware of the harware to do their job. There are a bit of exceptions, but most real time tasks, do their job, of course, both As Simple As Possible and As Quick As Possible.
Though some POSIX and other library implementations exist on a given RTOS, for the most part, at least for time critical jobs, the task should know what it is dealing with. Abstractions are distractions.
Coming up next: A typical RTOS device driver.