What an operating system does

An operating system (OS) is the software between your programs and the hardware. Windows, Linux, macOS, Android and iOS are operating systems. It has two jobs:

  1. Manage the hardware: share the CPU, memory, disks and devices among many programs, fairly and safely.
  2. Give programs simple abstractions: a program sees processes, files and network connections, never the details of a particular disk or network card.

The part of the OS that is always in memory, with full control of the hardware, is the kernel.

User mode and kernel mode

The CPU has (at least) two modes, kept in a mode bit:

  • In user mode, ordinary programs run. Instructions that touch hardware directly, change memory protection or turn interrupts off are privileged: trying one causes a trap to the kernel.
  • In kernel mode, the kernel runs, and every instruction is allowed.

So one buggy or hostile program cannot wipe the disk or read another program's memory: only the kernel can, and it checks every request.

System calls

A program that needs the hardware asks the kernel with a system call: read, write, open, fork, exit and a few hundred more. Your printf is a library function; in the end it calls write(1, text, length). A system call:

  1. puts a number (which service) and the arguments in registers,
  2. runs a special instruction (syscall on x86-64) that traps into kernel mode,
  3. the kernel looks the number up in its system-call table, checks the arguments, does the work,
  4. and returns to user mode with the result.
#include <stdio.h>

enum cpu_mode { USER, KERNEL };
enum cpu_mode mode = USER;     /* the CPU's mode bit */
int blocks_read = 0;

/* Two kernel services */
int sys_getpid(int arg) { return 1234; }
int sys_read_block(int block) { blocks_read++; return block * 512; }

/* The system-call table: call number -> handler */
int (*syscall_table[2])(int) = { sys_getpid, sys_read_block };

int syscall(int number, int arg) {
    mode = KERNEL;                      /* the trap enters kernel mode */
    int result = -1;
    if (number >= 0 && number < 2)      /* the kernel checks every request */
        result = syscall_table[number](arg);
    mode = USER;                        /* back to the program, in user mode */
    return result;
}

int main(void) {
    int pid = syscall(0, 0);
    int offset = syscall(1, 7);
    int bad = syscall(9, 0);
    printf("pid %d, byte offset %d, bad call %d\n", pid, offset, bad);
    return 0;
}
Open in compiler

This program acts it out: an array of function pointers is the system-call table, and the mode variable is the mode bit. Step through and watch mode change around each call, and the kernel refuse call number 9.

Interrupts

An interrupt is a signal that makes the CPU stop what it is doing and run a kernel handler.

  • Hardware interrupts: a key was pressed, a disk finished a read, a network packet arrived.
  • The timer interrupt fires every few milliseconds. It is how the OS takes the CPU back from a program that would otherwise run forever.
  • Traps (software interrupts) come from the running program: a system call, a division by zero, a bad memory access.

Booting

Power on → the firmware (BIOS or UEFI) tests the hardware and loads a boot loader (such as GRUB) → the boot loader loads the kernel → the kernel starts the first process (init, or systemd on most Linux systems) → that starts the services and the login screen.

Kinds of kernel

DesignIdeaExamples
Monolithicthe whole OS runs in kernel mode as one program: fastLinux
Microkernelonly the essentials in kernel mode; drivers and file systems run as user programs: saferMinix, QNX
Hybrida mix of the twoWindows, macOS

Quick check

1. Why can a normal program not erase the whole disk directly?
2. What lets the OS take the CPU back from a program stuck in an endless loop?
3. What does printf finally use to show its text?
My notes

Write down what you want to remember from this lesson. Notes are saved on this device as you type, and appear on your dashboard.