CS452 - Real-Time Programming - Winter 2017

Lecture 4 - Tasks & Kernels

Public Service Annoucements

  1. Marking of a0.
  2. Due date for kernel 1: 26 January, 2017

A few interesting things about RedBoot

What's in the flash ROM of the board is a partial implementation of Redboot. Redboot is a product of the ecos project, initiated in the distant past by Cygnus to create a set of components from which a real-time OS could be instantiated. The boot loader parts became RedBoot when Red Hat was acquired by Cygnus. What Technologic calls RedBoot is a collection of components that they put together that offers a particular set of operations at the RedBoot prompt. The "useful" ones are

You can, for example, send a byte through a UART by examining the status register then filling the data register.

The program you have written so far is allocating local memory on a stack?

This enables you to get a clean return to RedBoot when your program terminates.

When your program crashes it's because an exception has been generated because of, for example,

Redboot catches the exception, and puts out some information for gcc to hook into your program. (ecos and RedHat are strongly connected to the GNU project. (Don't bother trying to use gdb!) You see it on the bottom two lines of output. It's useless except for one 8 digit number starting 00218 or 00219. This is the address of the last instruction the CPU attempted to execute. Using the load map and the assembly code you can find exactly how far the program got before crashing. Unfortunately, the error may have occurred long before execution stopped.


Kernel of a Real-time Operating System

Introduction

The base unit of a polling loop is

      if ( condition ) action;
    
We generalize this structure only a little in constructing the kernel of our operating system: the kernel determines when the condition is true, then readies the task that executes the action, which terminates by informing the kernel of the condition for its next execution.

It cannot be emphasized too strongly that the kernel may -- but is NOT guaranteed to -- run a task immediately after it is made ready. The kernel's task handling code must be correct whether the task is run immediately or only after other tasks have run. The bugs created when this is wrong are neither subtle nor easy to repair. They should de designed out.

In the next few weeks we will build, from scratch, a micro-kernel. The micro-kernel supervises the execution of tasks, which are the elements of our systems. A task consists of

  1. a set of instructions that it executes,
  2. memory in which it stores data, and
  3. state, such as processor state, kernel state, and so on.

The kernel provides support for a running task (the active task), allowing it to

  1. create a new task,
  2. send a message to another task,
  3. receive a message from another task, and
  4. wait for an interrupt to occur.

These basic needs are provided by the kernel of every operating system. The kernel we create in cs452 is a microkernel, because it provides these capabilities and nothing more.

We build the microkernel in four assignments

  1. task creation and scheduling
  2. inter-task communication
  3. the interrupt primitive
  4. complex servers


Microkernels

The real-time operating system we build consists of

  1. an uninterruptible microkernel, plus
  2. interruptible device-handling server tasks that run in user-space.

What Does a Microkernel Provide?

Tasks

A program is conceived as a collection of co-operating tasks. Tasks provide applications with modularity. Task structure as a method of program organization will be discussed about the time you are finishing the OS.

Tasks consist of

Two tasks can have the same set of instructions but no two tasks share state.

Why are tasks important?

The programmer can then separate reasoning about his or her program into reasoning about single-threaded task execution (easy, provided that ...) and inter-task communication (easy, provided that ...).

Communication

Communication has two aspects

  1. sharing information and
  2. synchronization.

We use Send/Receive/Reply (SRR) to do both.

  1. Send blocks
  2. Receive blocks: synchronizes with the call to send
  3. Reply doesn't block: synchronizes its return with the return from send.

Sharing data

Data is usually shared in the form of a struct, which requires a common name space of types, but removes parsing and formating. The kernel copies the data from the memory of one task to the memory of another.

Two transfers of data occur between the call to send and the return from it. (The idea is that Send requests something without which it cannot continue computing.) Send does transfers both ways at once. Receive and Reply both have one transfer of data between the call and the return.

Synchronization

  1. Between tasks
  2. With internal events
  3. With external events

Interrupts

In the polling loop you polled a register

Almost every test failed, which wastes CPU. Even worse, it increases the response time, the time from when the event occurs until the first instruction of user code responding to it occurs.

You can get rid of the polling tests if you program the hardware to send the CPU a signal when the condition for which you are waiting occurs. Such a signal is called an exception and the CPU goes into a privileged state when the interrupt occurs.

The kernel responds to the exception by reading volatile data and readying the task that is waiting on the interrupt. This task is essentially the action that was conditioned on the event in the polling loop.


Tasks

This recapitulates what was said above. What is a task?

  1. A set of instructions
  2. The current state, which is changed by executing instructions. The state of a task includes which includes

Two tasks can use the same set of instructions, but

The kernel keeps track of every task's state

The TD normally contains

  1. The task's stack pointer, which points to a private stack, in the memory of the task, containing all ready to be reloaded whenever the task next runs.
  2. Possibly the return value for when the task is next activated
  3. The task's parent
  4. The task's state
  5. Links to queues on which the task is located

Possible states of the task

  1. Active: running or about to run
  2. Ready: can run if scheduled
  3. Blocked: waiting for something to happen


Kernel Structure

The kernel is just a function (with no arguments and no return value like a task), and which runs forever.

    void main( ) {
      initialize( );  // includes starting the first user task
      FOREVER {
	active = schedule( );
	request = activate( active );
	handle( request );
      }
    }
  

Where is the OS?

Where are the user tasks?

What's inside activate( active )?

  1. transfer of control to the active task
  2. execution to completion of the active task
  3. transfer of control back to the kernel
  4. getting the request

The hard part to get right is "transfer of control" which we call a context switch.


The Hardware/Software Provided in the Undergraduate Environment

TS-7200

Specific documentation from Technologic

System on Chip (SoC)

EP9302, designed and manufactured by Cirrus semiconductor

Memory

Byte addressable, word size 32 bits

Hardware configuration created by RedBoot

Separate instruction and data caches

`COM' ports

Connected to two UARTs implemented on the SoC

Reset switch

The reset switch may be red or black, even though documentation says black.

EP-9302

Specific documentation from Cirrus

System on chip

ARM 920T core

Specific documentation from ARM, which covers


Return to: