#Klooienmetcomputers

IBM-pc en MS-DOS

Arnout van Kempen over rommelen in een digitale wereld.

Met de IBM-pc werd de basis voor de hegemonie van de 8086 gelegd. Wat maakte de IBM-pc nu precies zo bijzonder? Tenminste één van de dingen die IBM goed deed, was proberen een machine te maken die zoveel mogelijk leek op een CP/M machine. Want wat maakte CP/M tamelijk uniek? Het systeem kon overweg met heel veel verschillende computers, zonder grote aanpassingen in het operating system zelf. De truc die daarvoor werd gebruikt, was een BIOS. Het Basic Input/Output System was het onderdeel van CP/M dat machinespecifiek was. De rest van CP/M en de applicaties die werkten met CP/M hoefden zich daardoor niet bezig te houden met de machine zelf. Of je nu met diskdrive A, B of C werkte, dat werd door het BIOS geregeld. Applicaties en CP/M zelf maakten een call naar het BIOS. En het BIOS zorgde voor de vertaalslag naar de onderliggende hardware.

IBM paste precies diezelfde methode toe. Wat standaard was, was de manier van aanroepen van dat BIOS en niet het aanroepen van de onderliggende hardware. En wat was die methode? De interruptcall. Als je nu maar zorgde dat jouw machine achter, bijvoorbeeld, vector 10h de video-aansturing had zitten en achter vector 13h de diskdrives, dan kon je zelf je hardware kiezen, zelf de software voor de ISR's of interruptserviveroutines schrijven, zonder inbreuk te maken op de rechten van IBM en toch een computer bouwen die op BIOS-niveau IBM-compatible was.

De manier waarop je zo'n interrupt moest aanroepen stond vast. Met enkele waarden in vastgestelde registers gaf je het interruptcommando en de computer voerde de bijbehorende opdracht uit. Bijvoorbeeld, de volgende code leest 1 sector van het begin van een floppy disk in de eerste floppy drive:

MOV AH, 02h             ; Functie: lees sectoren
MOV AL, 01h             ; Aantal sectoren om te lezen (1 sector)
MOV CH, 0               ; Track/Cylinder nummer (0)
MOV CL, 1               ; Sector nummer (1, sectoren beginnen bij 1)
MOV DH, 0               ; Head nummer (0)
MOV DL, 0               ; Diskette station (0 = A:)
MOV BX, 0x8000          ; Adres in geheugen om de sector te laden
MOV ES, BX              ; Segmentadres (0x8000)
MOV BX, 0x0000          ; Offset binnen segment

INT 13h                 ; BIOS disk-service aanroepen

Hoe die interrupt wordt afgehandeld, geen idee. Waar de code om dat te doen staat, hoeven we niet te weten. Zolang we er maar op kunnen rekenen dat achter vector 13h een ISR staat die volgens de IBM-standaarden een diskdrive zal uitlezen.

Nu is dit nog dichtbij de hardware, het Operating System voegt daar nog een laag aan toe. Voor de eerste pc was dat vooral MS-DOS. Dit systeem maakt maximaal gebruik van het BIOS en is daardoor onafhankelijk van de exacte hardware. Zo kon MS-DOS prima werken op PC’s van de concurrentie, mits die maar BIOS-compatible waren. Voor de programmeur voegt MS-DOS een hoop zaken toe. Waar je met INT 13h individuele velden, of sectoren, van een diskdrive kan lezen, kan je met MS-DOS een abstractielaag hoger gaan en bestanden lezen. Alle MS-DOS opdrachten geef je via vector 21h. En dan krijg je zoiets, dit keer een volledig bruikbaar programma in MS-DOS:

org 0x100                   ; Startadres voor COM-programma's

; Stap 1: Bestand openen
    MOV AH, 3Dh             ; Functie: Bestand openen
    MOV AL, 0               ; Open alleen-lezen modus
    MOV DX, OFFSET FILENAME ; Laad adres van bestandsnaam in DX
    INT 21h                 ; DOS-functie aanroepen 

    JC FILE_ERROR           ; Spring naar foutafhandeling als Carry Flag is gezet
    MOV BX, AX              ; Bestandshandle opslaan in BX

; Stap 2: Bestand lezen
    MOV AH, 3Fh             ; Functie: Bestand lezen
    MOV CX, 16              ; Aantal bytes om te lezen (16 bytes)
    MOV DX, OFFSET BUFFER   ; Adres waar de data moet worden opgeslagen
    INT 21h                 ; DOS-functie aanroepen

    JC FILE_ERROR           ; Spring naar foutafhandeling als Carry Flag is gezet

; Stap 3: Gelezen data weergeven
PRINT_DATA:
    MOV SI, OFFSET BUFFER   ; Zet begin van buffer in SI

PRINT_LOOP:
    LODSB                   ; Lees byte uit buffer in AL
    CMP AL, 0               ; Controleer op null-byte (einde buffer)
    JE CLOSE_FILE           ; Spring naar CLOSE_FILE als AL = 0
    MOV AH, 0Eh             ; BIOS-functie om een karakter te printen
    INT 10h                 ; Print karakter
    JMP PRINT_LOOP          ; Herhaal voor volgende byte

; Stap 4: Bestand sluiten
CLOSE_FILE:
    MOV AH, 3Eh             ; Functie: Bestand sluiten
    MOV BX, AX              ; Bestandshandle in BX
    INT 21h                 ; DOS-functie aanroepen
    JMP END_PROGRAM         ; Spring naar einde

; Foutafhandeling
FILE_ERROR:
    MOV AH, 0Eh             ; BIOS-functie om een foutmelding te printen
    MOV AL, 'E'             ; Print 'E' voor error
    INT 10h
    JMP END_PROGRAM         ; Spring naar einde

END_PROGRAM:
    HLT                     ; Stop programma

; Gegevens
FILENAME DB 'TESTFILE.TXT', 0 ; Bestandsnaam (null-terminated string)
BUFFER   DB 16 DUP (?)        ; Buffer om de gelezen data op te slaan

Wie mee wil doen met #klooienmetcomputers kan dat doen via GitHub. Maak een account op github.com en zoek naar Abmvk/kmc. Het account Abmvk volgen kan ook. Lezers zijn vrij te gebruiken wat ze willen en om zelf zaken toe te voegen of aan te passen, vragen te stellen of commentaar te leveren.

Arnout van Kempen di CCO CISA is directeur compliance & risk bij aaff, de fusieorganisatie van Alfa en ABAB. Hij schrijft op persoonlijke titel.

Gerelateerd

reacties

Reageer op dit artikel

Spelregels debat

    Aanmelden nieuwsbrief

    Ontvang elke werkdag (maandag t/m vrijdag) de laatste nieuwsberichten, opinies en artikelen in uw mailbox.

    Bent u NBA-lid? Dan kunt u zich ook aanmelden via uw ledenprofiel op MijnNBA.nl.