_bios_disk()
« | 19 Feb 2023 | »Der Zugriff auf Disketten
(und die ersten Festplatten) war bereits mit dem originalen IBM
BIOS möglich, denn der
INT 13h bot einige Dienste,
wie etwas das Lesen und Schreiben einzelner Sektoren.
Das brauchte das BIOS auch selbst, um das OS booten zu können.
Watcom (und andere historische Compiler)
stellen für diesen Systemaufruf die C-Funktion _bios_disk()
zur Verfügung.
Grundsätzlich funktionieren alle BIOS und
DOS Systemaufrufe recht ähnlich.
Man schreibt in das A
Register (AH
, AL
oder AX
) eine Aufrufnummer,
setzt weitere Register auf diverse Parameter und springt zu einem der
Interrupts:
int 10h
für Text- und Grafikint 13h
für Disketten und Festplattenzugriffeint 21h
für MS-DOS Funktionen- und viele mehr
(Hmm … an welchen Unix Klon erinnert uns das jetzt?)
Um das zu vereinfachen, haben die Compiler von damals einige häufig benutzte
Assembler Interrupt-Aufrufe
in C Funktionen gekapselt.
Watcom stellt auch heute noch in dos.h
viele DOS-Aufrufe direkt als
unsigend _dos_*(...);
zur Verfügung.
Tatsächlich gibt es auch den Header bios.h
, der einige häufig genutzte
BIOS Funktionen kapselt:
_bios_disk
_bios_equiplist
_bios_keybrd
_bios_memsize
_bios_printer
_bios_serialcom
_bios_timeofday
Disketten auslesen
Wozu sollte man heute Disketten per BIOS-Aufruf auslesen?
Tja, wenn man einen Toshiba T300 hat, der ein 640 KB-Spezialdiskettenformat unterstützt, das kein anderes 5.25 Zoll Laufwerk lesen kann, und wenn man von einer solchen Diskette ein Image ziehen will … dann braucht man das.
Der T300 kann zum Glück auch normale IBM/DOS 360 KB Diskettenformate lesen und schreiben. Doch Booten kann er offenbar nur von seinem Spezialformat.
Meine Idee war daher die Sektoren der Spuren auszulesen und in Dateien auf dem zweiten Laufwerk zu schreiben. So kann man eine “große” Diskette in zwei kleine teilen, die dann ein neuerer PC wieder lesen kann.
Man befüllt also eine struct _ibm_diskinfo_t
mit den Laufwerksparametern
und ruft
_bios_disk(_DISK_READ, &diskinfo);
auf.
Ein paar Details über den Aufruf musste ich mir von den alten Interrupt-Listen zusammensuchen, die ich zum Glück online finden konnte.
Dass drive
mit 0
Laufwerk A
und mit 1
dann B
meint, ist logisch.
Der Kopf kann mit 0
und 1
die obere untere Seite ansprechen.
track
geht von 0
bis einschließlich 79
auf meiner Spezialdiskette.
Und sector
, tja der tanzt mit der Nummerierung von 1
bis 8
aus der Reihe.
Doch so konnte ich dann den ersten 512-Bytes Puffer befüllen und freute mich, dass die Daten auch tatsächlich einem FAT12 Format entsprachen. Zumindest einige der Felder konnte ich klar zuordnen und sie stimmten mit den Laufwerksparametern überein.
Leider schlug mein erster Versuch die Sektoren in einer Schleife auszulesen
fehl, denn ich erhielt von den Folgesektoren immer leere Puffer zurück.
Vielleicht hat DOS auch etwas dagegen, wenn man im Hintergrund per
int 13h
das Laufwerk fernsteuert, oder der Aufruf in der Schleife klappt
nicht wie erwartet.
Fazit
Zumindest kann ich eines feststellen:
OpenWATCOM erstellt 16-Bit DOS-EXE Programme, die auch auf dem Toshiba T300 lauffähig sind.
Ich war leider zu kurz am Zweitwohnsitz und konnte keine weiteren Tests machen, warum das weitere Auslesen fehlschlug.
Leider ist von vielen BIOS-Varianten bekannt, dass sie Bugs haben und z.B.
Registerwerte zerstören. Wann das hier der Fall ist und die _bios_disk
Funktion nicht ausreichend abgesichert ist, dann müsste man den Aufruf
in Assembler neu schreiben und alles doppelt und dreifach absichern.
Wie dem auch sei … zumindest ein Teilschritt ist erreicht und beim nächsten Mal komme ich hoffentlich wieder ein Stück weiter.