1.
4 Embedded Operating System are designed for a specific
purpose, historically embedded operating systems were simple, time
constrained, and operated in limited memory. This distinction has
changed over time as the sophistication of embedded hardware has
increased. Features, traditionally found on desktop computers, such
as virtual memory, have migrated into the embedded system world.
Fundamental Components
There are few fundamental steps that form an operating system.
They are:
1. Initialization is the first code of the operating system to execute
and involves setting up internal data structures, global variables, and
the hardware. Initialization starts after the firmware hands over
control. For hardware initialization an operating system sets up
various control registers, initializes the device drivers, and, if the
operating system is pre-emptive, sets up a periodic interrupt. Sample
code for initialization is given in figure 4.4.
Figure 4.4 : Sample Initialization code
As a part of initialization Low-Level Debug Initialization is performed .
The banked FIQ mode registers (r8–r10) are temporarily used to store
status information. The function bringupInitFIQRegisters switches to FIQ
mode, clears r8–r10, and returns to SVC mode. This creates a simple low-
level debug mechanism, though the FIQ registers may not always be
available for this purpose. These registers are used to store status
information. It is not always possible to use FIQ registers since they may
be used for another purpose.
bringupInitFIQRegisters
MOV r2,r14
BL switchToFIQMode
MOV r8,#0
MOV r9,#0
MOV r10,#0
BL switchToSVCMode
MOV pc,r2
; save r14
; change FIQ mode
; r8_fiq=0
; r9_fiq=0
; r10_fiq=0
; change SVC mode
; return
coreInitialize
BL bringupInitFIQRegisters
Fig 4.5 Code for setting up FIQRegisters
Stack Setup for Different Modes
The next stage is to set up the SVC, IRQ, and System base stack registers. For the SVC
stack, this is straightforward since the processor is already in SVC mode. The code is
MOV sp,#0x80000 ; SVC stack
MSR cpsr_c,#NoInt|SYS32md
MOV sp,#0x40000 ; user/system stack
MSR cpsr_c,#NoInt|IRQ32md
MOV sp,#0x9000; IRQ stack
MSR cpsr_c,#NoInt|SVC32md
Fig 4.5 Code for setting up Stack
Separate stack pointers (sp) are initialized for:
o SVC mode → sp = 0x80000
o System/User mode → sp = 0x40000
o IRQ mode → sp = 0x9000
After setting stacks, the processor returns to SVC (Supervisor) mode,
a privileged mode, to continue system setup. The results of executing the
startup code are the following: Low-level debug mechanism is initialized.
SVC, IRQ, and System base stacks are set. The processor then transitions
to User mode to start normal execution.
Task Control (PCB Initialization)
To start OS running, the PCB for each task has to be initialized. A
PCB is a reserved data structure and holds a copy of the entire ARM
register set .
A task is made active by copying the appropriate task’s PCB data
into the processor registers.
Each task has a Process Control Block (PCB) holding a full copy
of the ARM register set (r0–r15, cpsr) and offset is as
mentioned in Figure 4.6.
To make a task active, its PCB contents are loaded into the
processor registers.
If PCBs are not properly initialized, a context switch would load
invalid (garbage) data into the CPU registers.
Figure 4.6: Registers for PCB
There are four major parts of the PCB that have to be initialized: the
program counter, the link register, the user mode stack, and the saved
processor status register (in other words registers r13, r14, r15, and the
spsr) for each task. Figure 4.7 shows the code for PCB setup.
Figure 4.7: Code for PCB setup
The final part of setting up the PCBs is to set up the current task identifier,
which is used by the scheduling algorithm to determine which task is to be
executed.
Figure 4.8 Code Identifying the task to be executed
The results of executing the PCB setup code are the following:
Initialize the PCB for all three tasks.
Set the current PCB to be executed as task 1 (identifier 0).
2. Memory handling involves setting up the system and task stacks.
The positioning of the stacks determines how much memory is
available for either the tasks or the system. Setting up the task stack
depends upon whether the task is static or dynamic. A static task is
defined at build time and is included in the operating system image.
For these tasks the stack can be set up during operating system
initialization. A dynamic task loads and executes after the operating
system is installed and executing and is not part of the operating
system image. The stack is set up when the task is created (for
example, as in Linux). Memory handling varies in complexity from one
operating system to another. It depends upon a number of factors,
such as the ARM processor core selected, the capabilities of the
microcontroller, and the physical memory layout of the end target
hardware. A simple memory map is depicted in figure 4.9.
Figure 4.9: Memory Map
3. The method for handling interrupts and exceptions: exception
handling is part of the architecture design of the operating system.
The various exceptions are: Data Abort, Fast Interrupt Request,
Interrupt Request, Prefetch Abort, Reset, and Software Interrupt (SWI).
Reset Exception : The reset vector is only called once during the
initialization phase. In theory, it could be called again to reinitialize
the system—for example, in response to a watchdog timer event
resetting the processor. Watchdog timers are used to reset a
system when prolonged inactivity occurs.
SWI Exception : Whenever a device driver is called from an
application, the call goes through the SWI handler mechanism. The
SWI instruction forces the processor to change from user to SVC
mode.. The first action of the handler is to store registers r0 to r12
to the SVC stack. The next action calculates the address of the SWI
instruction and loads that instruction into register r10. The SWI
number is obtained by masking the top 8 bits. The address of the
SVC stack is then copied into register r1 and is used as the second
parameter when calling the SWI C handler. The spsr is then copied
to register r2 and stored on the stack. This is only required when a
nested SWI call occurs. The handler then jumps to the code that
calls the C handler routine.
Figure 4.10 Code for SWI Handler
The code that follows the BL instruction returns back to the callee
program as shown here. This is achieved by restoring the spsr from the
stack and loading all the user banked registers back, including the pc.
Figure 4.11 Code for resetting the registers
This code is executed when the SWI C handler is complete.
swi_jumptable
MOV r0,r10 ; move the SWI number to r0
B eventsSWIHandler ; branch to SWI handler
Figure 4.12 : C code for SWI handler
IRQ Exception : The handler first saves the context and then
copies the contents of the interrupt controller status register,
INTPND, into register r0. Each service routine then compares
register r0 with a particular interrupt source. If the source and
interrupt match, then the service routine is called; otherwise the
interrupt is treated as being a phantom interrupt and ignored. The
code for IRQ exception is shown in figure 4.13
Figure 4.13 : code for IRQ Exception
In the code first resets the timer, eventsTickService (platform- specific
call), and the second, kernelScheduler, calls the scheduler, which in turn
calls a context switch.
eventsTickVeneer
BL eventsTickService ; reset tick hardware
B kernelScheduler ; branch to scheduler
There is no requirement to have registers r4 to r12 on the IRQ stack, since
the scheduling algorithm and the context switch handle all the register
details.
4. The scheduler is an algorithm that determines which task is to be
executed next. There are many scheduling algorithms available. One
of the simplest is called a round-robin algorithm—it activates tasks in
a fixed cyclic order. Scheduling algorithms have to balance efficiency
and size with complexity.
Figure 4.14: Code for round robin scheduler
2. Device driver framework- The last component is the device
driver framework—the mechanism an operating system uses to
provide a consistent interface between different hardware
peripherals. The frame- work allows a standard and easy way of
integrating new support for a particular peripheral into the operating
system. For an application to access a particular peripheral there
has to be a specific device driver available. The framework must
provide a safe method of accessing the peripheral (for example, not
allowing the simultaneous access of the same peripheral by more
than one application).