Real mode, monolitiska och mikrokärnor
För länge, länge sedan, som du säkert har sett på bild, bestod datorer av stoora transistorer (vakumrör) och sladdar som gick hit och dit. De hade inget operativsystem, utan hur man kopplade sladdarna avgjorde vad datorerna utförde. Sen kom minidatorerna. En minidator är (mot vanlig tro) en dator som är ungefär stor som en bokhylla, fast lite djupare. Minidatorerna var mycket mer high-tech, och hade ett faktiskt maskinspråk. Olika bitar i minnet representerade olika instruktioner och så vidare.
Fördelen med det systemet är att det nu går att ladda in program externt. De två vanligaste metoderna var probably antingen genom strömbrytare (tänk åtta strömbrytare för en octet, och sen en "spara"-switch för att spara octeten i minnet och gå vidare till nästa minnescell.) Eller, så kunde man ladda in hålremsor. Hålremsor är lite som hålkort, fast med en remsa. Ett hål stod för en binär etta, och inget hål stod för en binär nolla. Remsan var ungefär åtta hål i bredd. Först switchade man in en bootloader med strömbrytarna, och sen kunde den läsa hålremsor.
Det här var väldigt tidskrävande, mind you. Och dyrt. Då fanns det kanske en minidator per forskningsinstitut, och alla professorer ville få sina beräkningar utförda. Professorerna lämnade sina hålremsor i en låda, och sen kom datorpersonalen och plockade upp en remsa i taget när datorn var ledig, exekverade den, och lämnade utskriften i en annan låda. Den arbetscykeln är ganska lång. Även om professorns uträkning bara tar 15 minuter att köra, så kanske han lämnar remsan klockan 12 på dagen när han är klar med programmet och går och tar lunch. Han kan komma tillbaka efter lunchen och hoppas att de har kört hans program, men nope. Sen innan han går hem klockan 17, hittar han äntligen sin utskrift i lådan.
Då har han väntat i fem timmar på att få veta att det var något fel i programmet, och så måste han göra om samma sak igen nästa dag.
När datorer blev lite mer tillgängliga, och man hade uppfunnit magnetband, så fanns det lite fler alternativ. Nu kunde datorerna allt som oftast läsa från magnetband av sig själva, och arbetscykeln ändrades drastiskt. Datorlabbet hade tre datorer: Två som var specialiserade på in- och utmatning, och en som var specialiserad på beräkning. Professorn kunde nu själv mata in hålkortet i dator A, som producerade ett magnetband med professorns program.
Datorpersonalen hämtade upp magnetbandet så fort dator B (beräkningsdatorn) var ledig, och exekverade programmet. Dator B tryckte ut resultatet till ett annat magnetband. Personalen bar magnetbandet till dator C, som skrev ut resultatet till ett papper. Fördelen med denna metod är att även om beräkningsdatorn, dator B, fortfarande är dyr, så är dator A och C mycket billigare. Är det stort tryck så kan man köpa två stycken av dator A, eller två stycken av dator C, eller av båda. Man avlastar beräkningsdatorn så att den kan jobba med det den ska, och hela processen snabbas up.
Allt som finns i datorerna är fortfarande en bootloader. I dator A finns ett operativsystem som konverterar information på hålremsa till magnetband. I dator B finns programmet som professorn har skrivit, och i dator C finns ett operativsystem som konverterar informationen på ett magnetband till en utskrift på papper.
Men det är här det tar vid. Den fundamentala idén kring hur datorer fungerar har inte ändrats så värst mycket sen dess. En processor tar emot instruktioner från ett program i RAM-minnet. Det blir inte enklare än så. Den enklaste formen av operativsystem som nästan fortfarande finns i dag är såna som på intel-språk körs i real mode. Real mode är ett gammalt läge i intel-processorer* som är jättesimpelt. Processorn exekverar helt enkelt det som finns i RAM-minnet. Om nuvarande instruktionen i RAM-minnet är att tömma hela RAM-minnet, så gör processorn det, laglydigt.
DOS fungerar på det här sättet, till exempel. När du startar ett program i DOS så tar det över kontrollen över datorn helt tills du stänger det, då det rensar ut sig själv från RAM-minnet och släpper tillbaka kontrollen till DOS igen. Det innebär att programmet också har full tillgång till hela (max 1 Mo†) RAM-minnet. Det är förstås ganska osäkert. Om man har bara en pytteliten bugg i programmet så kan man krascha hela systemet, för när DOS får tillbaka kontrollen kan man ha råkat ändra lite för mycket i RAM-minnet. (Finns förstås inget minnesskydd.)
Drivrutiner till DOS lägger sig i minnet, och registrerar sig också direkt hos processorn, så att processorn anropar dem när det sker en interrupt (en (hårdvaru-)händelse.) Sedan ger de tillbaka kontrollen till DOS, som alla andra program. Skillnaden är att drivrutinen hänger kvar i minnet, och väntar på att bli anropad. Alla program, varenda ett, har här potential att krascha ditt system. Eftersom de har full kontroll över datorn medan de körs.
Motsatsen till real mode är, vad som på intel-språk kallas, protected mode (skyddat läge). Det ger minnesskydd, möjlighet till mer än 16 bitar (32 och 64 är vanligt) vilket i sin tur ger tillgång till mer än 1 Mo RAM-minne och lite annat gott. Allt jag pratar om i fortsättningen är i pmode.‡
En monolitisk kärna (monolithic kernel) påminner om den i DOS, fast är ändå långt därifrån. Eftersom man har minnesskydd och icke-linjär exekvering finns även stöd för multitasking på ett säkert sätt. Det innebär att flera program kan köras »samtidigt.« Det som egentligen händer är att processorn kör ett program i taget, men växlar så snabbt mellan program att det verkar som att de körs samtidigt. Åh, flera program! F1 nice! Då borde man väl typ kunna göra operativsystemet till en kärna, och så körs alla program utanför den, och båda lever samtidigt? Yup. Så gör man också. Windows (versioner större än 95, dock inte NT) gör så. BSD gör så. Linux gör så. OS X gör så.
Skillnaden är nu alltså att programmen körs övervakade i user space. Att de är övervakade betyder att om de försöker komma åt och/eller ändra en minnesaddress de inte har rätt till, så säger systemet till. I *nix-system så skickar kärnan en signal som heter SIGSEGV, och eftersom programmet inte svarar på den dödas det (älskar att *nix dödar program som inte svarar,) och oftast får man utskriften »Segmentation fault.« På Windows får man en pop-up (ofc) med text i stil med, »has encountered a problem and needs to close.«
This is all nice. Men drivrutiner då? Det är en annan historia. De kan fortfarande vara kompilerade in i kärnan. Då laddas de in samtidigt som kärnan. En annan modell för monolitiska system är att drivrutiner kan i efterhand laddas in som moduler in i kärnan. Denna modell har *nix använt sig av ganska friskt, och Windows gör det också, till viss del. Den stora skillnaden är att Windows bara kan ladda in drivrutiner när man startar datorn. Detta är en av anledningarna att man måste starta om Windows så ofta. Med *nix kan man ladda in drivrutiner under drift (kommandot modprobe kanske känns igen.)
Fördelar? Att ha drivrutiner som en del av kärnan gav en ganska rejäl prestandaskjuts för 20-30 år sedan. Eftersom kärnan kan anropa drivrutiner lite hipp som happ utan att behöva tänka på något går det rätt snabbt.
Nackdelar? Drivrutiner är fortfarande en del av kärnan, och en bugg i en drivrutin kan krascha hela ditt system. (Varit med om blue screens i Windows? That's right, det är troligtvis en drivrutin som har segfaultat.)
Windows NT och högre (XP, Vista, 7) tar en intressant ståndpunkt här. De har många punkter som är karaktäristiska för en monolitisk kärna, som att drivrutiner, nätverk och så vidare körs i kärnan. Däremot finns det vissa saker hos operativsystemet som inte gör det. Till exempel filsystemet. Däremot är det en hel del som vanligtvis körs i user space (grafiska delen) som Microsoft har lagt in i kärnan i Windows på grund av prestandaskäl.
Att Windows NT inte riktigt är en monolitisk kärna, men nästan, har fått den att anta etiketten hybridkärna eller makrokärna. Det innebär helt enkelt att de har ungefär lika mycket saker i kärnan som monolitiska operativsystem, men somliga saker som traditionellt ligger i kärnan har de lagt i user space.
Ett alternativ till den monolitiska kärnan är mikrokärnan (micro kernel.) Nackdelen med den är att man kan få en prestandaminskning på kanske 10% (frisk gissning, för 20 år sedan var det 20%. Nu är det antagligen en hel del mindre.)
Hur kommer det sig? Vad gör mikrokärnan som är långsammare?
Minns du att i en monolitisk kärna körs programmen i user space? I en mikrokärna körs allt i user space. Allt som kan köras i user space i alla fall. Det inkluderar drivrutiner, filsystem, nätverkssystem och så vidare. Minns du fördelen med att programmen kördes i user space? Just det, de var övervakade. Med en mikrokärna kan även drivrutiner övervakas, eftersom de också körs i user space.
Detta är ganska tydligt stabilt. I ett experiment provade man att föra över en stor fil mellan två datorer. På ena datorn körde man ett operativsystem med en mikrokärna (Minix). På det systemet simulerade man krascher av nätverks- och filsystemet genom att döda respektive drivrutin massor av gånger. Övervakningen kunde lugnt starta om dem och fortsätta filöverföringen. Filen var inte korrupt när den kom fram, trots att grundläggande, vitala delar av systemet blev avstängda flertalet gånger under överföringen.
Det är kraften hos en mikrokärna. Även om något så vitalt som filsystemet i din dator dör, så kommer:
Det inte direkt påverka något annat program (jämför med blue screen eller kernel panic som tvingar dig att stänga av hela datorn)
Det kunna startas om så fort systemet märker att det har dött
Betänk även en lite sällsyntare händelse som att en drivrutin fastnar i en oändlig loop. Det skulle med en monolitisk kärna innebära att hela systemet hänger sig. Med en mikrokärna så kan systemet ge drivrutinen lägre och lägre prioritet (tona ut hur stor effekt oändliga loopen har på resten av systemet) och till sist starta om drivrutinen om den inte kommer loss.
Nackdelen var som jag redan nämnt, att det här kräver lite mer prestanda. Eftersom drivrutiner och sånt körs som i program i user space så kan kärnan bara kontakta dem genom att skicka runt meddelanden till deras processer. Detta kräver lite mer kraft än vad som krävs för att bara anropa en modul i kärnan. Det är även jobbigare att implementera en mikrokärna (i alla fall enligt folk som kan sånt där) från början. Fun fact: Torvalds skrev Linux inspirerad av Tanenbaums bok om Minix. Minix är baserat på en microkernel, och Linux är en monolitisk kärna. Hur gick det till? Torvalds har mig veterligen inte svarat på det. Kanske var han lat, kanske missförstod han Tanenbaum på en av de viktigaste punkterna. :)
Varför kör vi fortfarande med monolitiska kärnor överallt? Fråga inte mig.
* När jag skriver »intel-processorer« menar jag »processorer som är kompatibla med intels 8086-processor.« Det innefattar alla intels och AMD:s nuvarande modeller, så vitt jag vet.
För övrigt är intel-processorer retarderade. Varför de har bestämt sig för att alla splitter nya processorer som säljs ska vara kompatibla med DOS 1.0 är bortom min förståelse. Att de dessutom kör en CISC-tolk på en RISC-kärna för att RISC visade sig vara snabbare är bara helt otroligt. Envisa jävlar. Intel och alla som följer i deras spår är urmammorna till alla hårdvarufulhakk. (Sa någon gate A20?)
† Mo står för megaoctet. När jag pratar om 8 bitar föredrar jag termen octet, eftersom en byte kan vara olika stor. Dessutom är byte förvirrande, eftersom det förkortas med samma bokstav som bit. Jag rekommenderar er att börja använda octet när ni pratar om 8 bitar också. En byte står bara för minsta addresserbara enheten, och är i de flesta PC:s lika med en octet. Dock är så inte alltid fallet.
‡ Protected mode. Eller som vanligt folk (som inte har med intel att göra) skulle säga: NORMALT JÄVLA LÄGE. Det är ganska bra om du förstår att real mode inte har rätt att existera i dag. Det finns ingen vettig användning för det och det är helt sjukt att de har behållt det.