CMD + K

OperativsystemerIntroduksjon til operativsystemerBegreper & formler19
6 min lesing1 video

Introduksjon til operativsystemer

Operativsystemet er laget som får maskinvaren til å se brukbar ut for programmer. Det skjuler rå kompleksitet bak abstraksjoner som prosesser, virtuelle adresser, filer og sockets, og balanserer hele tiden mellom ytelse, beskyttelse, rettferdighet og enkel bruk.

Læringsmål
  • 01Forklare hva et operativsystem gjør, og hvorfor virtualisering og abstraksjon er bærende ideer
  • 02Beskrive bootsekvensen fra POST til init/systemd, og hvilken rolle bootloaderen spiller
  • 03Sammenligne monolitisk, microkjerne og hybrid arkitektur — hva de optimaliserer for og hva de ofrer
  • 04Forklare overgangen mellom brukermodus og kjernemodus via systemkall, og hvorfor det er nødvendig

Maskinen er rotete; OS-et rydder

En moderne datamaskin er en kaotisk samling deler — flere CPU-kjerner, hierarkisk minne, disker, nettverkskort og periferi. Hver enhet krever sin egen drivlogikk, sine egne register og sine egne sekvenser av "skriv X til adresse Y for å starte ny overføring". Et operativsystem er programvarelaget som rydder opp i dette og lar programmer bruke maskinen uten å vite hvor knappene sitter.

operativsystem (os) er altså ikke en applikasjon du starter — det er det som starter alt annet. Det skjuler rå kompleksitet bak vennlige grensesnitt, fordeler maskinen mellom programmer som tror de har den for seg selv, og passer på at ingen ødelegger for noen.

Virtualisering og abstraksjon — de to store triksene

To begreper bærer mye av forklaringen. virtualisering betyr at OS-et får én fysisk ressurs til å framstå som flere logiske ressurser. CPU-en blir til mange "virtuelle CPU-er" — én per prosess. Det fysiske RAM-et blir til private adresserom for hver prosess. Disken blir til filer og kataloger. Nettverkskortet blir til sockets. Alle disse virtualiseringene finnes ikke i maskinvaren; de er løgner OS-et forteller, og holder konsistent.

abstraksjon er det å skjule detaljer bak et grensesnitt. Når et program skriver til en fil, vet det ikke hvilke sektorer på SSD-en som faktisk endres, ikke om filen ligger i cache, ikke om filsystemet er ext4 eller NTFS. Det kjenner bare grensesnittet — open, read, write, close. Programmet trenger ikke å være portabelt på tvers av maskinvare; OS-et tar støyten.

De to triksene henger sammen. Virtualisering uten abstraksjon ville vært ubrukelig — du måtte fortsatt vite hva som lå under den virtuelle laget. Abstraksjon uten virtualisering ville vært snillere, men du kunne fortsatt bare ha ett program av gangen. Kombinasjonen er det som lar en moderne maskin kjøre hundrevis av prosesser samtidig.

Tre store hensyn

Nesten alle designvalg i OS-et kan forstås som balansering mellom tre hensyn: ƒtre sentrale os-mål.

Ytelse dreier seg om hvor mye CPU, minne og I/O som faktisk blir nyttig arbeid. ƒcpu-utnyttelse måler hvor stor andel av tida CPU-en jobber, og ƒthroughput sier hvor mange jobber systemet får unna per sekund. Ineffektive overganger eller for mye låsing eter raskt av disse målene. En batch-prosess vil typisk ha 95 % CPU-utnyttelse; en interaktiv desktop kanskje 5 % — fordi den bruker mesteparten av tida på å vente på brukeren.

Beskyttelse betyr at programmer ikke skal kunne ødelegge for hverandre — eller for OS-et. Én buggy nettleser skal ikke kunne korrumpere minnet til tekstbehandleren, og slett ikke kunne overskrive kjernen. Det krever maskinvarestøtte: separate adresserom, ulike CPU-modi og kontrollerte overganger.

Deling er ressursfordeling: ingen prosess skal sulte, og alle skal få nok CPU og minne til å gjøre jobben sin. Her dukker design tradeoff alltid opp — gir du en prosess mer respons, gir du den ofte mindre throughput. Optimaliserer du for snitt-svartid, kan haleresponsen lide. Hele kap 4 handler om akkurat slike avveininger.

Bootsekvensen — fra strøm til kjørende kjerne

Hvordan starter dette i det hele tatt? Når du trykker på strømknappen er det ingen kjerne, ingen prosesser, ingenting kjørende — bare maskinvare og noen byte med fastvare. ƒbootsekvensen oppsummerer rekkefølgen i fire-fem trinn.

0255075100POST · t=0 · 10 enheterPOSTBIOS/UEFI · t=10 · 25 enheterBIOS/UEFIbootloader · t=35 · 20 enheterbootloaderkjerne · t=55 · 25 enheterkjerneinit · t=80 · 20 enheterinitfire fem trinn fra strøm på til brukerrom
FIGBootsekvens: fra POST til init

Først kjører POST (Power-On Self Test). Maskinvaren tester seg selv, finner ut hvilken RAM som finnes og hvilke disker som er tilkoblet. Deretter overtar BIOS eller UEFI og leter etter en boot-enhet. Den finner bootloader på den enheten — typisk i MBR-sektoren eller EFI-partisjonen — og laster den inn i RAM.

Bootloaderen er liten av en grunn: den må passe i en sektor (eller noen få). Dens jobb er bare å finne kjernen på filsystemet, lese den inn i minnet, og hoppe til den. Moderne bootloadere som GRUB støtter også flere kjerneversjoner og kjernemoduler, men kjernen er fortsatt det som tar over.

Kjernen initialiserer drivere, monterer rotfilsystemet, og starter brukerrommet. Den siste handlingen er typisk å starte init eller systemd som PID 1. Det er PID 1 som leser systemets konfigurasjon, starter login-prompter, nettverkstjenester og alt det andre du forbinder med "datamaskinen er klar".

Eksamensvennlig formulering: maskinvare-init → fastvaren finner boot-enhet → bootloader laster kjernen → kjernen starter brukerrom.

To CPU-modi

Når kjernen først kjører, er den i kjernemodus (kernel mode) — full tilgang til alt. Det er kraftig, men også farlig: en bug her kan ta ned hele systemet. Derfor lar OS-et vanlige programmer kjøre i brukermodus, der privilegerte instruksjoner ikke er lov.

ƒto-modus-overgang oppsummerer hvordan en prosess pendler mellom de to. Når den trenger noe OS-et må gjøre — lese fra disk, allokere minne, sende på nettet — gjør den et systemkall, en kontrollert overgang inn i kjernen. Kjernen gjør jobben, og en iret-instruksjon overgir kontrollen tilbake til brukermodus.

Dette skjer mange ganger per sekund. En typisk webserver-prosess kan gjøre titusenvis av systemkall per request — accept, read, epoll_wait, write, close. Hver overgang koster et par hundre nanosekunder, men prisen er at programmet aldri kan røre maskinvaren direkte. CPU-en bestemmer hvor trap-en lander; ikke programmet. Det er hardware-mekanismene som gjør beskyttelse mulig.

Tre kjernearkitekturer

Hvordan organiseres koden inne i kjernen? Det finnes tre store tradisjoner.

Hva som ligger i kjernemodus (farget) vs. brukermodus (lyst)MonolitiskDrivere · FS · Net · Sched · VMalt i kjernemodusMicrokjernekjernenDrivereuserFSuserNetuserHybridKjerne + krit. driverekjernemodusUI · noen tjenesterusermonolitisk er rask men bredt angripbar; micro er trygg men koster IPC
FIGTre kjernearkitekturer: hva som kjører i kjernemodus vs. brukermodus

I en monolitisk kjerne kjerne bor alt i kjernemodus: drivere, filsystem, scheduler, nettverkstack, virtuelt minne. Linux er det klassiske eksempelet. Fordelen er fart — kallene mellom delene er bare vanlige funksjonskall, ingen kontekstbytte mellom subsystemer. Ulempen er at angrepsflaten er stor, og at en buggy driver kan krasje hele systemet.

I en microkjerne ligger bare kjernekjernen i kjernemodus — IPC (inter-process communication), scheduling og grunnleggende minnehåndtering. Drivere og tjenester kjører som vanlige prosesser i brukermodus og snakker sammen via meldinger. Det gjør systemet langt mer robust og isolert, men koster IPC-overhead på hver eneste systemtjeneste. Eksempler: QNX, seL4.

En hybrid kjerne kjerne er kompromisset. Windows NT og macOS XNU har visse tjenester i kjernen og andre i brukermodus, avhengig av hva som krever ytelse. I praksis er de fleste store moderne OS-er hybrider med monolittisk slagside — Linux i det ekstreme, Windows og macOS et stykke nærmere mikrokjerne-idealet.

Ressurshåndtering og enkel bruk

Når alt det andre er på plass gjenstår ressurshåndtering: hvilken prosess får CPU-en nå, hvor mye RAM kan denne få, hvilke I/O-operasjoner skal serveres først? Det er et eget kapittel i seg selv (kap 3 og 4), men husk at det er her design tradeoff blir konkret. Maksimerer du throughput? Da kan respons lide. Maksimerer du fairness? Da kan throughput lide. Det finnes ingen scheduler som er best på alle mål samtidig.

I praksis må OS-et også fordele minne — hvor mange sider får hver prosess, hvilken prosess sin minne kan vi paginere ut til disk hvis vi går tom, hvor stor cache reserverer vi for filsystemet? Og det må fordele I/O-båndbredde — hvilken request på SSD-en skal serveres først når køen er full? Hver av disse avgjørelsene har en algoritme bak seg, og hver algoritme bærer i seg et bestemt verdivalg.

OS-et lykkes når brukeren ikke trenger å tenke på noe av dette. Du åpner en terminal, kjører ls, ser filene. Det enkle grensesnittet er produktet av tiår med abstraksjoner, virtualiseringer og forsiktige avveininger — og en bootloader som først måtte lese kjernen inn i RAM mens du satt og ventet på at skjermen skulle slå seg på. I de neste kapitlene tar vi fatt på CPU-virtualiseringen og prosessene, fordi det er der både ytelsen og beskyttelsen ofte står på spill, og fordi alle de andre abstraksjonene henger sammen med dem.