av Simon Gustafsson, TE3EB
Ett praktiskt arbete som går ut på att programmera ett enkelt operativsystem. Operativsystemet ska innehålla de mest grundläggande funktionerna som behövs för att starta en kommandohanterare, som kan utföra enkla uppgifter samt ladda och köra små program direkt från disk.
Specialarbete
Älvkulle-gymnasiet
Vårterminen 1998
Inledning
Operativsystemet
Normal
uppbootning
bootsektorn uppgifter
startfilens uppgifter
Minneshantering
Filhantering
Fillistan
Filallokeringstabellen
Kommandohanteraren
Kommandon
Körbara filer
Interna kommandon
Tjänster
som nås via INT 20H
Målet med detta specialarbete är att designa ett enkelt operativsystem. Varför jag valde ett sånt stort arbete som detta vet jag nog inte riktigt, men jag har alltid tyckt om datorer. Förutom att programmera själva operativsystemet, så har jag tänkt mig att tillverka några applikationer. Applikationerna är till för att visa hur man använder operativsystemet. Jag har programmerat operativsystemet helt i assembler. För att inte tråka ut läsaren av detta arbete med långa assemblerlistningar (Startfilen är på över 1400 rader, c:a 25 sidor), så finns dessa med på diskett.
Här beskriver jag vad som ska hända efter att datorn slagits på. Beskrivningen börjar med det ögonblicket då biosen lämnar över kontrollen till bootblocket. Det kommer att hända lite olika saker beroende på om operativsystemet botas från diskett eller från hårddisk. Om man botar från hårddisken, så hamnar man på hårddiskens första sektor. Denna sektor innehåller "the Master Boot Record", som innehåller information om diskens partitionering, plus kod för att ladda in bootblocket från en av hårddiskens partition. Eftersom jag inte har så lång tid på mig att göra hela operativsystemet, så nöjer jag mig vid att köra operativsystemet på diskett, för då behöver jag inte skriva lika mycket kod.
Först en liten beskrivning av vad biosen gör när den bootar
upp.
Läser Sector 1, Track 0, Head 0 från boot-enheten till
absolut address 07C00h-07DFFh
Kollar om 16-bitars ordet på den absoluta addressen
07DFEh inehåller AA55h.
Detta är en signatur som talar om att sektorn innehåller en
giltig bootsector.
Laddar DL med
00h om bootsektorn laddades från enhet A
80h om bootsektorn laddades från enhet C
Hoppar till 0000:7C00h, som är början på bootsectorn.
När bootsektorn fått kontrollen av biosen, så har den egentligen bara en uppgift. Den ska ladda en startfil från disketten till minnet, och lämna över kontrollen till startfilen så att operativsystemet kan starta. Om det inte går så ska ett meddelande visas, som berättar hur det står till med datorn. Bootblocket är också viktigt, eftersom vissa uppgifter om hur data ligger på disken endast finns lagrade här.
Startfilen är den viktigaste filen i hela operativsystemet. Den innehåller all kod som behövs för att få igång en enkel kommandotolk. När startfilen börjar exekveras, börjar den med att kopiera sig själv så långt ner i minnet som det är möjligt. Efter det ändras interruptvektor 20H så att den pekar på en procedur, som låter program anropa funktioner i operativsystemet. Till sist får kommandohanteraren kontrollen, och man får en prompt som man använder för att köra program, somliga från diskett, och somliga från datorns minne
Minnsehanteringen i operativsystemet kan göras väldigt enkel. Eftersom det inte kommer att gå att köra mer än ett program i taget, behöver man bara hålla reda på vad som hör till programmet, och vad som hör till operativsystemet och eventuella drivrutiner. För att hålla reda på detta behövs det bara en enda variabel, som berättar var gränsen går mellan operativsystemet och programmet. Om man vill lägga till drivrutiner, startar man drivrutinen, så lägger den gränsen för var vanliga program kommer att köras efter sig själv innan kontrollen går tillbaka till operativsystemet.
Filhanteringen är mycket enkel. Grunden i filsystemet består av två delar, en filallokeringstabell, samt en lista med alla filer. Alla funktioner för filhantering finns med i tabellen Tjänster som nås via INT 20H. Ett program som vill använda andra filer får än så länge göra väldigt mycket själv.
Fillistan är en tabell som berättar var på disketten som varje fil startar. Fillistan kan också innehålla attribut, storlek, datum när filen skapats mm. I mitt operativsystem så kommer bara filnamn, attribut, samt startsektorn för filen att anges. Själva filsystemet ligger på en ganska låg nivå, och för att förstå det så är det enklast att titta på exempelfilerna som bifogas som bilaga.
Filallokeringstabellen är i grunden likadan som den i dos. Den skiljer sig genom att den är 16-bitars (dos använder bara 12 bitar på disketter), samt att vi inte har flera kopior av samma tabell. Grundprincipen är att man länkar ihop en fil genom att varje ord i listan pekar på nästa ord och nästa sektor. Sen använder man en speciell kod för att berätta när man nått sista ordet.
|
|
Startsektor: | Beskrivning: | |
---|---|---|
Sektor 0 | Bootblocket | Cylinder 0, Sektor 1, Huvud 0. Får kontrollen direkt från BIOSen. Skall ladda startfilen |
Kan variera | Startfil | Laddas in i minnet av bootblocket. Startfilen innehåller allt som behövs för att få igång operativsystemet och kommandohanteraren (som är inbygd i denna fil). |
Kan variera | Filallokeringstabell | Används för att hålla reda på vilka sektorer som hör till samma fil, samt vilka sektorer som är lediga |
Kan variera | Katalogpost för rotkatalogen | Håller reda på filnamn mm |
Anges i katalogposten | Vanliga filer | Kan vara program eller data |
Ev fortsättning av rot- katalogens katalogposter |
||
Sista sektorn | Ledigt utrymme |
Kommandohanteraren är gränssnittet som operativsystemet har mot användaren. Jag kommer att ha en enkel kommandohanterare. Den ska bara visa en prompt, och vänta på att man skriver något. När man skrivit klart, kollar kommandohanteraren om kommandot är internt, och i så fall hoppar den till den procedur i minnet som kommandot anger. Finns inte kommandot, så letar den efter en fil med samma namn som kommandot, och börjar exekvera filen. Om kommandot inte finns visar kommandohanteraren ett felmeddelande, och går tillbaka till sin vanliga prompt.
Kommandohanteraren är ganska "rå" när den laddar en fil för exekvering. Den läser in hela filen direkt till minnet utan att göra något med den. Sen sätter den CS:IP att peka till början av filen, och IP kommer alltid att vara 0000h. Kommandohanteraren sätter också DS:SI att peka på strängen som skrevs in för att starta filen, så att programmet kan kolla om den fick några extra parametrar på kommandolinjen.
Det finns vissa kommandon som ligger lagrade i
kommandohanteraren. För tillfället är det tre stycken sådana
- dir, mem och reg.
dir: Visar en lista med alla filer på disketten, tillsammans med
attributen. Det finns två attribut. E betyder att
filen är ett program, och att den kan startas genom att man
skriver dess namn.
mem: Visar hur mycket minne som är ledigt. Visar även en
variabel kallad USERBASE, som visar var gränsen kommer att gå
mellan användarprogram och operativsystem.
reg: Visar några register i datorn. Finns med i första hand
för att se om stackpekaren strular till sig, men vanliga
användare har egentligen ingen användning för detta kommando.
INST_DRIVER Används av program för att bli residenta.
AH = 00hBX = Antal paragrafer som ska bli residenta från början
av programmet
returnerar: AX = status
0000hFFFFh allt gick bradet gick inte att flytta upp gränsen BX
paragrafer
Programmet måste anropa EXITPROG efter att anropat INST_DRIVER.
EXITPROG Avslutar ett program som laddats från disk
AH = 01h
returnerar: Hoppar aldrig tillbaka till programmet
GET_KEY Läser in ett tecken från tangentbordet
AH = 03h
returnerar: AH = ScankodAL = ASCII tecken eller 00h för
specialtangenter
GET_KEY_ECHO Läser in ett tecken från tangentbordet, och
visar tecknet på skärmen
AH = 04h
returnerar: AH = ScankodAL = ASCII tecken eller 00h för
specialtangenter
PRINT_CHAR Skriver ut ett tecken på skärmen
AH = 05hAL = ASCII tecken
returnerar: ingenting
GET_STRING Läser in en hel sträng av tecken från
tangentbordet. Ekar till skärmen.
AH = 06hDS:SI ā pekare till utrymme för strängen[DS:SI] =
maxlängd för strängen
returnerar: strängutrymmet fylls med tecken.
<RETUR> samt specialtangenter avbryter inmatningen.
Inmatningen avbryts också om maxlängden för strängen
överskrids. Maxlängden är sparad i den första byten i
strängen. Strängen kommer alltid att avslutas med en nolla. Det
är möjligt att radera inskrivna tecken genom att trycka på
<backspace>.
PRINT_STRING Skriver ut en nollterminerad sträng på skärmen
AH = 07hDS:SI ā ASCIIZ sträng som skaskrivas ut
returnerar: ingenting
CHECK_FOR_INPUT Kollar vad som finns i tangentbordsbufferten
AH = 08h
returnerar: AX = 0000h om det inte finns någon scankod i
buffertenAH = scankodAL = ASCII tecken
READSECTOR Läser en 512 byte lång sektor från disk till minne
AH = 09hAL = enhet (00h=A, 01h=B)ESI = logisk sektor att
läsaES:BX = vart den ska läsas
returnerar: AX = status
0000hFFFFh allt gick branågonting gick snett
Man behöver inte bry sig om DMA-gränser, utan man kan läsa
sektorn vart man vill.
WRITESECTOR Skriver en sektor till disk
AH = 0AhAL = enhet (00h=A, 01h=B)ESI =logisk sektorES:BX =
varifrån den ska läsas
returnerar: AX = status
0000hFFFFh allt gick branågonting gick snett
Man behöver inte bry sig om DMA-gränser, utan man kan läsa
sektorn vart man vill.
CHECK_FAT_FOR_NEXT Letar upp nästa sektor som hänger ihop med
den i ESI
AH = 0BhESI = Sektor
returnerar: AX = nästa sektor.Undantag: AX = FFFFh Sektorn som
fanns i ESI var den sista i en kedja AX = 0 Sektorn i ESI hör
inte till någon fil
CHECK_FAT_FOR_FREE Letar upp en fri sektor i fatten
AH = 0Ch
returnerar: AX = första fria sektor enligt fattenUndantag: AX =
FFFFh Det finns inga lediga sektorer i fatten
WRITE_FAT Skriver i fatten
AH = 0DhBX = GrundsektorCX = Nästa sektor för sektorn BX
returnerar: AX = status
0000hFFFFh allt gick branågonting gick snett
Används av program tillsammans med CHECK_FAT_FOR_FREE för att
t.ex förlänga en fil, eller skriva en ny fil.
CREATE_FILE Skapar en ny fil
AH = 0EhBL = Filttribut (E = körbar fil,
D = fil med data)DS:SI = Pekare till ett 16 bytes
långt filnamn
returnerar: AX = Första sektor som allokerats till
filenUndantag: AX = 0h Det gick inte att skapa filen
Filnamnet måste vara 16 bytes långt. Är det kortare måste det
förlängas med spaces (20H). Funktionen allokerar alltid en
sektor för filen när den skapas. Använd CHECK_FAT_FOR_FREE och
WRITE_FAT för att förlänga filen.
DELETE_FILE Tar bort en redan existerande fil
AH = 0FhDS:SI = Pekare till ett 16 bytes långt filnamn
returnerar: AX = status
0000h Filen har tagits bort FFFFh Filen gick inte att ta bort
FIND Letar efter en fil
AH = 16hDS:SI pekar på filnamnet till filen som ska hittas
returnerar: AX = Första sektor för filen.BL = filattributAX =
0000h om det inte fungerar
Använd CHECK_FAT_FOR_NEXT och READSECTOR för att läsa in en
hel fil.
HELPPC - information om biosens interrupt. Finns på internet
INTERHELP - information om biosens interrupt. Finns på internet
Egenhändigt debuggade bootblock från DOS v3.3 och v5.0. Jag
bifogar ena på diskett.
Litteratur för den som vill fördjupa sig:
Operating System Concepts, Abraham Silberschatz, ISBN
0-201-54873-9