The operating system, BIOS and device drivers

Hiding the hardware, managing resources, booting from the BIOS, and a driver table for the robot.

A10.2Operating systems, software and translatorsA level35 min

Do this lesson in the simulator

At GCSE (F9.9) you listed what an operating system does: the user interface, memory management, multitasking, peripherals, users and files. At A level the question is why it is organised that way. The answer is two ideas: the operating system hides the complexity of the hardware, and it manages resources that many programs compete for. This lesson covers both, then the two pieces of low-level software that make them possible: the BIOS, which starts the machine, and device drivers, which let the operating system talk to hardware it has never seen.

Hiding the hardware

A program that wants to save a file does not know which sectors of which disk are free, how to spin the disk up, or how the flash chip's controller wants to be addressed. It calls something like open("log.txt", "w"), and the operating system does the rest.

The operating system gives every program a simpler, imaginary machine to work with: one where files have names, memory starts at address 0, and a printer is a thing you send text to. This is why the operating system is sometimes said to provide a virtual machine: the programmer works with the machine the OS presents, not the real hardware underneath.

Programs ask the operating system for these services through system calls, the functions the OS provides in its application programming interface (API). The core of the OS that runs with full access to the hardware is the kernel. Ordinary programs run with restricted access and must go through the kernel, which is what stops one program wrecking another.

Managing resources

A running program is a process. Many processes want the same hardware at the same time, and the operating system decides who gets what:

Resource What the OS does Lesson
Processor time schedules processes so each gets turns on the processor A10.5
Memory allocates memory to each process, keeps processes apart, uses virtual memory when RAM is full A10.3
Input and output devices queues requests to devices, handles interrupts when devices need attention A10.4
Storage the file system: names, folders, free space, permissions
Security user accounts, access rights, keeping processes out of each other's memory

On BugBot the operating system is FreeRTOS, a small real-time operating system. It has no desktop and no user accounts, but it still shares the processor between the motor loop, the camera, the radio and your program, and hands out memory to each.

Device drivers

There are thousands of models of printer, camera and motor controller, each with its own commands. The operating system cannot contain code for all of them. Instead, each device comes with a device driver: a program that translates the operating system's general requests ("print this page", "set this pin high") into the specific commands that one device understands, and passes the device's responses and interrupts back.

This gives three benefits worth stating in an exam:

  • the operating system stays the same size however many devices exist;
  • a new device works as soon as its driver is installed, with no change to the OS or to applications;
  • application programmers write print or led once, and it works on every device that has a driver.

Drivers are written for a particular operating system, which is why a device can work on Windows but not on Linux.

# the two lines every program starts with: the commands, then the robot
from bugbot import *
connect()

# two drivers for two different "lamps": the same request, different hardware commands
def rgb_led_driver(level):
    led(level, level, level)             # this lamp takes a red, green and blue level

def piezo_click_driver(level):
    tone(200 + 8 * level, 0.1)           # this "lamp" can only make a sound

drivers = {"lamp": rgb_led_driver, "click": piezo_click_driver}

for device in ["lamp", "click"]:
    drivers[device](100)                 # the program asks both for level 100
    print("asked", device, "for level 100")

Run this in the simulator

The program makes the same request to both devices. Only the driver knows what "level 100" means for its hardware.

The BIOS and booting

When a computer is switched on, RAM is empty, so the operating system cannot be running yet. Something must already be in non-volatile memory to start it. On a PC that is the BIOS (Basic Input Output System), stored in flash memory on the motherboard. Modern PCs use its successor, UEFI, which does the same job.

When the power comes on, the processor starts executing the BIOS. It:

  1. runs the power-on self-test (POST), checking the processor, memory and essential hardware are present and working;
  2. sets up the hardware using settings kept in non-volatile memory, such as the date, time and the order of boot devices;
  3. finds a boot device and loads a small bootstrap loader (bootloader) from it into RAM;
  4. hands over to the bootloader, which loads the operating system's kernel from storage into RAM and starts it.

BugBot's ESP32 does the same thing with different names: a first-stage bootloader in the chip's ROM loads a second-stage bootloader from flash, which loads and starts the firmware with FreeRTOS inside.

Task: the driver table

Build a tiny operating system layer for the robot. Write three driver functions, each taking one argument value:

  • a driver for "led": value is a colour name string; it sets the LED to that colour;
  • a driver for "piezo": value is a frequency in hertz (an integer from 100 to 10000); it plays that note for 0.2 seconds;
  • a driver for "motor": value is a distance in centimetres (a positive integer); it drives forward that far at speed 50.

Put them in a dictionary called drivers, keyed by the device names "led", "piezo" and "motor". Then write the system call syscall(device, value). If device is a key in drivers, it calls that driver with value, prints ok: <device> <value>, and returns True. Otherwise it prints error: no driver for <device>, does nothing else, and returns False. Do not test the device name with ==: the table is the whole point.

Finally, call syscall for each (device, value) pair in requests, in order. The robot should end 20 cm ahead with a green LED.

# the two lines every program starts with: the commands, then the robot
from bugbot import *
connect()

requests = [("led", "blue"), ("piezo", 880), ("motor", 20), ("camera", "on"), ("led", "green")]

Challenges

  1. Add a driver for "turn" that turns right by value degrees, and a request that uses it. Which part of your program had to change, and which did not?
  2. Make syscall refuse a "motor" request when distance() shows a wall closer than the distance asked for. Is that check better in the driver or in the system call? Why?
  3. Write the steps of the boot sequence as a numbered list, and say which ones would be different on a phone.