The operating system, BIOS and device drivers
Hiding the hardware, managing resources, booting from the BIOS, and a driver table for the robot.
Do this lesson in the simulatorAt 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
printorledonce, 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")
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:
- runs the power-on self-test (POST), checking the processor, memory and essential hardware are present and working;
- sets up the hardware using settings kept in non-volatile memory, such as the date, time and the order of boot devices;
- finds a boot device and loads a small bootstrap loader (bootloader) from it into RAM;
- 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":valueis a colour name string; it sets the LED to that colour; - a driver for
"piezo":valueis a frequency in hertz (an integer from 100 to 10000); it plays that note for 0.2 seconds; - a driver for
"motor":valueis 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
- Add a driver for
"turn"that turns right byvaluedegrees, and a request that uses it. Which part of your program had to change, and which did not? - Make
syscallrefuse a"motor"request whendistance()shows a wall closer than the distance asked for. Is that check better in the driver or in the system call? Why? - Write the steps of the boot sequence as a numbered list, and say which ones would be different on a phone.