Diesmal widmen wir uns der Verwaltung der Laufwerke unter GEMDOS. Dabei wird, wie versprochen, der Drive-Media-Descriptor erklĂ€rt. AuĂerdem ist das Thema âCluster- und Sektornumerierungâ vom letzten Mal auch noch nicht ausgeschöpft.
Nachtrag
Doch zuerst noch ein kleiner Nachtrag zur FAT-Verwaltung. Es ist vielleicht noch ganz interessant, den Algorithmus zu kennen, mit dem ein freier Sektor in der FAT ausgewÀhlt wird, wenn eine Datei verlÀngert wird.
Die Strategie ist eigentlich sehr einfach. Beim letzten Cluster der Datei beginnend, wird einfach der erste freie Cluster gesucht. Wenn dabei der letzte Cluster (nach Meinung des GEMDOS der letzte, eigentlich der drittletzte) erreicht wird, setzt man die Suche beim ersten Cluster (der Nummer 2) fort. Wenn ânumclâ- EintrĂ€ge erfolglos untersucht wurden, ist das Speichermedium voll, und die Funktion bricht ab.
Nach dem Kreieren einer Datei beginnt die Suche fĂŒr den ersten Cluster von vorne.
Anmeldung von Laufwerken
Damit GEMDOS mit den verschiedenen Massenspeicher-Laufwerken Zusammenarbeiten kann, mĂŒssen diese bei ihm âangemeldetâ sein. Dies geschieht aber nicht explizit dadurch, daĂ ein Treiberprogramm eine spezielle Funktion aufruft oder irgendwelche Systemvariablen manipuliert, sondern wird von GEMDOS automatisch durchgefĂŒhrt, wenn das Laufwerk zum ersten Mal mittels einer GEMDOS-Funktion angesprochen wird.
GEMDOS fĂŒhrt Buch darĂŒber, welche Laufwerke ihm schon bekannt sind. Dazu dient eine Bit-Maske (âdrvmapâ), wobei ein gesetztes Bit bedeutet, daĂ das Laufwerk angemeldet ist. Bit 0 ist dabei Laufwerk A: zugeordnet, Bit 1 gehört zu Laufwerk B:, usw.
Bei jeder GEMDOS-Funktion, die auf ein Laufwerk zugreifen muĂ (insbesondere also die Datei- und Disk-Funktionen F... bzw. D...), wird von einer Routine ĂŒberprĂŒft, ob der Zugriff auf das gewĂŒnschte Laufwerk möglich ist. Diese Routine wird im folgenden âd_chkdrvâ genannt.
Wenn das Laufwerk schon bekannt ist, also das zugehörige Bit in âdrvmapâ gesetzt ist, geht man davon aus, daĂ es auch ansprechbar ist. Man ĂŒberprĂŒft nur noch, ob fĂŒr das Laufwerk schon ein Standardpfad existiert. Ist dies nicht der Fall, wird das Root Directory als aktuelles Directory festgelegt (dazu kommen wir noch einmal in einer spĂ€teren Folge). Ist das Laufwerk dagegen GEMDOS noch unbekannt, wird das BIOS mit âGetbpbâ um Hilfe gefragt. Wenn hier ein Fehler zurĂŒckgeliefert wird, ist entweder kein Treiber fĂŒr das Laufwerk installiert oder es kann nicht an-, gesprochen werden (z.B. wenn der Boot-Sektor der Diskette einen Lesefehler hat).
Im Normalfall gibt âGetbpbâ die Adresse des âBIOS-Parameter-Blocksâ (BPB) zurĂŒck, an dessen Aufbau Sie sich vielleicht noch aus der letzten Folge erinnern. Der BPB wird nun ausgewertet und der âDrive Media Descriptorâ aufgebaut (siehe nĂ€chsten Abschnitt).
AnschlieĂend definiert wie oben beschrieben, das Root-Directory als aktueller Pfad.
Interessant ist in diesem Zusammenhang noch, daĂ âd_chkdrvâ, wenn alles geklappt hat, die Laufwerkskennung an den Aufrufer zurĂŒckgibt. ERROR (-1L) zeigt einen eventuellen Fehler an. Wenn die aufrufenden Routinen diese Kennung und nicht die, die sie âd_chkdrvâ ĂŒbergeben haben, fĂŒr die eigentlichen Operationen benutzen wĂŒrden, könnten in âd_chkdrvâ Laufwerke auf andere umgeleitet werden, bzw. es könnten âvirtuelle Laufwerkeâ verwaltet werden.
An der Verwendung des Konjunktivs merken Sie schon, daĂ dies ein Wunschtraum bleibt, denn die RĂŒckgabe von âd_chkdrvâ wird nicht weiter beachtet (auĂer daĂ die Fehlermeldung abgefragt wird).
Dieser in âd_chkdrvâ auftretende interne Fehler, nĂ€mlich daĂ ein Laufwerk nicht angesprochen werden kann, ist die in der Januar-Folge als âLaufwerk unbekanntâ bezeichnete Ursache von GEMDOS-Fehlermel-dungen (am besten nochmal nachlesen).
Jeder eifrige Leser von Original ATARI-Dokumentationen ist schon ĂŒber die Bezeichnung âDrive Media Descriptorâ gestolpert: Bei der Angabe (von Dokumentation kann man hier wohl kaum sprechen) des âBuffer Control Blocksâ (BCB) taucht dieser Begriff auf, ohne daĂ ein weiteres Wort ĂŒber ihn verloren wird. Hier soll nun sein Geheimnis, das eigentlich gar keins ist, gelĂŒftet werden.
Sein Aufbau ist in Abb. 1 dargestellt. Die Komponenten lassen sich am besten erlÀutern, indem man die Initialisierung des DMD bei der Anmeldung eines Laufwerks betrachtet.
Wie der Name schon sagt, beschreibt der DMD ein Laufwerk bzw. das damit verbundene Speichermedium. Er erlaubt GEMDOS, die Kommunikation mit den unterschiedlichsten Laufwerken und Medien, da er recht flexibel ist. Wie letzten Monat schon deutlich wurde, ist dies aber alles nur graue Theorie, da hier so manches nicht funktioniert.
âd_driveâ enthĂ€lt, wie man sich beinahe denken kann, die Kennung des Laufwerks, das der DMD beschreibt. Einige Werte im DMD werden direkt aus dem BPB ĂŒbernommen, was durch die Ă€hnliche Namensgebung angedeutet werden soll. So ist âd_clsizâ die Cluster-GröĂe in Sektoren (wie âb_clsizâ), âd_clsizbâ gibt die Cluster-GröĂe in Bytes an (wie âb_clsizbâ), âd_recsizâ ist die Sektor-GröĂe in Bytes (wie âb_recsizâ), âd_fsizâ ist die FAT-GröĂe in Sektoren (wie âb_fsizâ) und âd_numclâ ist die Anzahl der Daten-Cluster (wie âb_numclâ). âd_flag' enthĂ€lt eine Kopie des Bit 0 von âb_flags[0]\ gibt also Auskunft, ob eine 12-oder 16-Bit-FAT vorliegt. Die anderen Bits von âd_flagâ sind immer Null, unabhĂ€ngig von âb_flags[0]'
Bei der Berechnung von Datei-Positionen, Sektor-Nummern, usw. rechnet GEMDOS fleiĂig mit diesen Werten herum. Dabei ist es oft notwendig, durch sie zu dividieren bzw. bestimmte Bits auszublenden. Dies wird mit Shift-Operationen und Logisch-AND-Befehlen erreicht. Damit man die hierbei benötigten Shift-Operanden (Zweierlogarithmen) und Bit-Masken nicht jedesmal neu berechnen muĂ, merkt sich GEMDOS einige davon im DMD.
In âdjclsizâ wird der Zweierlogarithmus von âd_clsizâ gespeichert, âd_mclsizâ ist eine Bit-Maske zum Ausblenden niederwertiger Bits (Tab. 1). Die entsprechenden Werte fĂŒr âd_recsizâ sind in âdjrecsizâ und âd_mrecsizâ abgelegt (wer hĂ€tte das gedacht?). Die Bit-Masken sind zwar gerade die um eins verminderten Werte selbst, aber GEMDOS holt sie sich extra aus einer Tabelle ('f_masksâ, s.u.)!
'clsiz' âlclsiz' 'mclsiz'
bzw. bzw. bzw.
'recsiz' âlrecsiz' 'mrecsiz'
1 0 $0000
2 1 $0001
4 2 $0003
: : :
512 9 $01FF
1024 10 $03FF
: : :
Tab. 1: Shift- und Maskier-Werte
typedef struct
{ int d_roff[3]; /* Sektornummer-Offsets fĂŒr FAT,DIR,DATA */
int d_drive; /* Laufwerkskennung 0..15 */
int d_fsiz; /* FAT-GröĂe in Sektoren */
int d_clsiz; /* Cluster-GröĂe in Sektoren */
int d_clsizb; /* Cluster-GröĂe in Bytes */
int d_recsiz; /* Sektor-GröĂe in Bytes */
int d_numcl; /* Zahl der Datencluster */
int d_lclsiz; /* 2er-Logarithmus von clsiz * */
int d_mclsiz; /* Bit-Maske fĂŒr clsiz */
int d_lrecsiz; /* 2er-Logarithmus von recsiz */
int d_mrecsiz; /* Bit-Maske fĂŒr recsiz */
int d_lclsizb; /* 2er-Logarithmus von clsizb */
FD *d_fatfd; /* Zeiger auf FD der FAT */
long d_dummy; /* unbenutzt */
DD *d_rdd; /* Zeiger auf DD des Root Directorys */
int d_flag; /* FAT-Typ: 0: 12-Bit, 1: 16-Bit */
} DMD;
Abb. 1 : Drive Media Descriptor (DMD)
- | Standard-Diskette | fiktiv | fiktiv
------- | ---------- | ------- | -------
CLSIZ | 2 | 1 |4
datrec | 18 | 11 | 50
fatrec | 16 | 13 | 21
d_roff[2] | 14 | 9 | 42
RDLEN | 7 | 5 | 9 |
RDCL | 4 | 5 |3 |
RD-Clusternr. | -5.. -2 | -6.. -2 | -4.. -2
RD-Sektornr. | -10.. -4 | -6.. -2 | -16.. -6
d_roff[1] | 21 | 12 | 57
FSIZ | 5 | 3 | 20
FCL | 3 | 3 | 5
FAT-Clusternr. | -8.. -6 | -9.. -7 | -9.. -5
FAT-Sektornr. | -16..-12 | -9.. -7 | -36..-17
d_roff[0] | 22 | 12 | 57
Tab. 2 : Beispiele zur GEMDOS-Sektor-ZĂ€hlung
Zur Verwaltung von Dateien (einschl. Directories und FAT) gibt es weitere Strukturen (âFile Descriptorenâ und âDirectory Descriptorenâ), um die wir uns ein andermal kĂŒmmern. Hier sei nur erwĂ€hnt, daĂ sie zusammen mit dem DMD ein kompliziertes Netz bilden, welches vom DMD aus gut âaufgerolltâ werden kann.
Beim Einrichten des DMD werden die File Descriptoren fĂŒr das Root Directory und die FAT sowie der Directory Descriptor des Root Directories ebenfalls initialisiert.
Ăbrig bleiben nun noch die "d_roff[0..2]â-Werte. Dabei handelt es sich um die letzten Monat erwĂ€hnen Sektornummer-Offsets fĂŒr FAT-, DIR- und DATA-Sektoren. Die GEMDOS-Sektornummer plus entsprechendem Offset ergibt die BIOS-Sektornummer.
In der letzten Folge waren die beiden ZĂ€hlweisen einander gegenĂŒbergestellt, wobei auffiel, daĂ die GEMDOS-Sektornummern nicht durchgehend waren, sondern daĂ es merkwĂŒrdige LĂŒcken in der Numerierung gab. Heute soll der Algorithmus erklĂ€rt werden, mit dem diese ZĂ€hlweise festgelegt wird.
Bisher habe ich Ihnen eine weitere Komplikation noch verschwiegen. Obwohl eigentlich nur Daten-Sektoren zu Clustern zusammengefaĂt werden, gibt es auch Cluster-Nummern fĂŒr Root Directory (RD) und FAT. Das liegt daran, daĂ RD und FAT intern wie Dateien behandelt und daher bei der Berechnung von Dateipositionen (Seek-Funktion) wie bei Dateien Cluster in Sektoren umgerechnet werden. Da es in Wirklichkeit aber gar keine Cluster gibt, mĂŒssen Cluster- und Sektornumerierung so angelegt sein, daĂ die Pseudo-Cluster-Nummern eindeutig auf GEMDOS-Sektornummem abgebildet werden.
Zum besseren VerstĂ€ndnis der etwas komplizierten ZusammenhĂ€nge dient Tab. 2, wo Beispiele fĂŒr die nun folgenden ErklĂ€rungen angegeben sind. Aus der LĂ€nge des RD in Sektoren (âb_rdlenâ) errechnet sich seine LĂ€nge in Clustern (ârdclâ). Da die Zahl der RD-Sektoren kein Vielfaches der ClustergröĂe sein muĂ, wird diese Clusterzahl aufgerundet. Die genaue Formel lautet:
rclcl_rdlen + clsiz - 1 clsiz
(Der bei der Division auftretende Rest wird ignoriert). Der erste âClusterâ des RD ist ârdsf:
rdst = - 1 - rdcl
Das RD belegt damit die Clusternummern ârdstâ bis -2; die Clusternummer -1 existiert nicht, ebenso die Cluster 0 und 1. Die erste GEMDOS-Sektornummer ergibt sich durch Multiplikation mit der Anzahl der Sektoren pro Cluster. Durch die Aufrundung bei der Berechnung von ârdclâ ergeben sich in der âAusnutzungâ der GEMDOS-Sektornummern LĂŒcken (s. Beispiele in Tab. 2).
Entsprechend verfÀhrt man mit der FAT:
fl_fsiz + clsiz - 1 clsiz
fst = rdst - fcl
Die FAT-Cluster liegen unmittelbar vor den RD-Clustem, denn sie haben die Nummern âfstâ bis ârdstâ-1. Auch hier ergibt sich die erste GEMDOS-Sektornummer durch Multiplikation von âfstâ mit âclsizâ.
Nachdem nun festgelegt wurde, welchen Pseudo-Clustern die RD- und FAT-Sektoren zugeordnet werden, kann GEMDOS die gesamte Verwaltung wie bei User-Dateien erledigen. Beim tatsĂ€chlichen Zugriff werden nun die GEMDOS-Sektornummern, mit denen sich die Sektorpuffer-Verwaltung herumschlagen muĂ, mit den âd_roffâ-Offsets zu BIOS-Nummern zurĂŒckgerechnet. Diese Offsets mĂŒssen nun so berechnet werden, daĂ diese RĂŒcktransformation klappt.
FĂŒr Daten-Sektoren:
d_roff[2] = datrec - (2 * clsiz)
âdatrecâ ist die aus dem BPB entnommene BIOS-Nummer des ersten Da-ten-Sektors. Da der erste Cluster immer die Nummer 2 hat, ergeben sich fĂŒr Daten-Sektoren die Nummern ab âdatrecâ aufwĂ€rts.
FĂŒr FAT-Sektoren:
d_roff[0] = fatrec - (fst * clsiz)
âfatrecâ ist die ebenfalls im BPB gefundene BIOS-Nummer des ersten Sektors der zweiten FAT, die, wie Sie seit einem Monat wissen, eigentlich die erste FAT ist. Zu beachten ist, daĂ âfstâ negativ ist, und damit âd_roff[0]â gröĂer als âfatrecâ wird. Dies ist aber korrekt, da die bei der Umrechnung addierten GEMDOS-Sektornummern negativ sind, so daĂ sich BIOS-Nummern ab âfatrecâ aufwĂ€rts ergeben.
FĂŒr RD-Sektoren:
d_roff[1] = fatrec + fsiz - (rdst * clsiz)
Das RD muĂ unmittelbar nach der zweiten FAT liegen, beginnt also bei âfatrecâ plus âfsizâ (âfsizâ ist die Zahl der Sektoren pro FAT, zu finden im BPB - wo wohl sonst?). Der Rest ist wie bei der FAT.
So, nun wissen Sie hoffentlich alles, was man ĂŒber Sektor- und Clusternummern wissen muĂ. Bei den bisherigen Erfahrungen mit GEMDOS muĂ man sich wundern, daĂ das ganze Hin- und Hergerechne so reibungslos funktioniert; zumindest ist mir in dieser Hinsicht noch kein Fehler bekannt.
Noch eine ErgĂ€nzung fĂŒr diejenigen, die den Artikel ĂŒber die Speicherverwaltung kennen:
Die DMDs werden im âinternen GEMDOS-Speicherâ abgelegt. Da es hiervon aber nur relativ wenige gibt, ist die Anzahl der Laufwerke selbst nicht so entscheidend. Allerdings wird man bei vielen Laufwerken auch viele Ordner ansprechen, so daĂ die Chance, daĂ einem der GEMDOS-Speicher ausgeht, bei jedem neuen Laufwerk steigt (eine zweite Floppy wirkt hier schon Wunder).
Da ein DMD 42 Byte groĂ ist, was aufgerundet drei 8-Wort-Einheiten (382 = 48) sind, finden sich freigegebene DMDs in der âmiflâ-Liste 3. Der DMD ist ĂŒbrigens die einzige Struktur, die ĂŒber die â3er-Listeâ verwaltet wird.
Abmelden von Laufwerken
GEMDOS erkennt zwar selbstĂ€ndig neue Laufwerke und richtet dafĂŒr die internen Datenstrukturen ein, doch ist die Anmeldung eines Laufwerks nicht vorgesehen.
Aber auch hierfĂŒr gibt es einen âautomatischenâ Mechanismus, nĂ€mlich den Mediumwechsel. Bei einem durch das BIOS gemeldeten Mediumwechsel werden zuerst alle Datenstrukturen des betroffenen Laufwerks freigegeben. Dies sind der DMD, die File und die Directory-Descriptoren. Weiterhin werden alle Pfade zu Directories sowie die Sektor-Puffer fĂŒr ungĂŒltig erklĂ€rt (siehe hierzu auch die erste und zweite Folge).
AnschlieĂend wird mit der BIOS-Funktion âGetbpbâ ĂŒberprĂŒft, ob das Laufwerk (mit einem anderen Medium) ĂŒberhaupt noch verfĂŒgbar ist. Ist dies der Fall, werden die Strukturen zur Disk-Verwaltung neu initialisiert, so daĂ das Laufwerk GEMDOS wieder bekannt ist.
Wenn das Laufwerk nicht mein ansprechbar ist, wird es fĂŒr GEMDOS abgemeldet, indem das entsprechende Bit von âdrvmapâ gelöscht wird. Einer erneuten Anmeldung durch Zugriff steht nichts im Wege.
Dieses Verfahren kann man sich zu Nutze machen, wenn man gezielt einzelne Laufwerke abmelden will. Dies kann sinnvoll sein, wenn das Laufwerk unter verschiedenen Kennungen angesprochen werden soll. WĂŒrde die Abmeldung nicht erfolgen und der Treiber einfach auf seine alte Kennung nicht mehr reagieren, wĂŒrden die Datenstrukturen als âLeichenâ im Speicher herumliegen und kostbaren internen Speicher verbrauchen.
AuĂerdem kann ein simulierter Mediumwechsel bei allen Laufwerken einfach dazu dienen, internen Speicher freizugeben, was nach ausgiebigem Ăffnen von vielen Ordnern empfehlenswert ist. Dazu lĂ€Ăt sich eine solche Routine leicht in ein Accessory einbauen.
Listing 1 zeigt nun, wie manâs macht. In der Funktion âfree=drvâ werden zunĂ€chst die Vektoren der elementaren Disk-Routinen âMediachâ, âGetbpbâ und âRwabsâ auf eigene Routinen umgesetzt. Durch den Aufruf der GEMDOS-Funktion âDffeeâ (andere tunâs auch) wird GEMDOS zu einem Zugriff auf das Laufwerk gezwungen. Die eigenen Disk-Routinen geben nun Meldungen zurĂŒck, wie sie bei einem Diskettenwechsel auftreten.
Die Funktion âfree_allâ generiert Diskettenwechsel fĂŒr alle 16 möglichen Laufwerke.
Da die Disk-Vektoren im geschĂŒtzten Speicherbereich liegen, darf auf sie nur im Supervisor-Mode zugegriffen werden. Da man dieses Problem als âBetriebssystem-Hackerâ öfter hat, sind die allgemeinen "Peek & Pokeâ-Routinen fĂŒr solche Dinge ganz brauchbar. Wer erinnert sich hier nicht an seine alten 8-Bitter, bei denen die Kenntnis geheimnisvoller âPoke-Befehleâ unerlĂ€Ălich war?
Bei der Anwendung dieses kleinen Programms sollten Sie darauf achten, daĂ auf den betroffenen Laufwerken keine Dateien mehr geöffnet sind, da diese bei dem âMediumwechselâ nicht mehr ordnungsgemÀà geschlossen werden können, und daher Datenverlust droht. Ferner gehen alle Standardpfad-Einstellungen verloren.
Systemvariable âdrvbitsâ
Wie wir nun wissen, steht in der GEMDOS-Variablen âdrvmapâ, welche Laufwerke bekannt sind. Andererseits gibt es noch die BlOS-Systemvariable âdrvbitsâ ($4C2). âdrvbitsâ ist ebenfalls eine Bit-Maske fĂŒr vorhandene Laufwerke (sogar 32 Bit!), hat aber nichts mit GEMDOS zu tun.
WĂ€hrend âdrvmapâ angibt, welche Laufwerke schon einmal angesprochen wurden, steht in âdrvbitsâ, ob das Laufwerk ĂŒberhaupt verfĂŒgbar ist. Massenspeicher-Treiber sollten allerdings die von ihnen belegten Laufwerkskennungen hier eintragen, âdrvbitsâ wird nĂ€mlich von der BIOS-Funktion âDrvmapâ zurĂŒckgeliefert, damit Anwenderprogramme feststellen können, welche Laufwerke ansprechbar sind. Vom AES wird diese Möglichkeit wĂ€hrend der Reset-Phase auch ausgiebig genutzt.
GEMDOS-Variablen fĂŒr Disk-Verwaltung
Die globalen GEMDOS-Variablen fĂŒr die Disk-Verwaltung sind in Abb. 2 dargestellt, zusammen mit denen fĂŒr die Sektor-Pufferung, die ich letztes Mal vergessen habe. Die erste Adresse gilt fĂŒr das alte TOS (6.2.1986), die zweite fĂŒr das Blitter-TOS. ĂberflĂŒssig zu erwĂ€hnen, daĂ diese Adressen nicht dokumentiert sind und nicht in Programmen verwendet werden sollten.
BCB bcbx[4]; /* $60a4/ $8846: BIOS: 4-Standard-BCBs */
char secbuf [4][512]; /* $4e22/ $75c4: BIOS: 4 Puffer fĂŒr je 1 Sektor */
int drvmap; /* $5fe2/ $8784: Bit-Map fĂŒr angemeldete Drives */
DMD *dmdx[16]; /* $5bde/ $8780: DMD-Zeiger fĂŒr alle Drives */
int f_masks[] /* $fd1bf6/$fd3022: Masken fĂŒr Datei-Operationen */
= { 0x0000, 0x0001, 0x0003, 0x0007,
0x000f, 0x001f, 0x003f, 0x007f,
0x00ff, 0x01ff, 0x03ff, 0x07ff,
0xffff, 0x1fff, 0x3fff, 0x7fff };
Abb. 2 : GEMDOS-Variablen zur Puffer- und Disk-Verwaltung
âbcbxâ und âsecbufâ sind die vom BIOS eingerichteten 4 BCBs mit den dazugehörigen Sektor-Puffern. Sie sind legal ĂŒber die Pufferlisten (âbufl[]â) zugĂ€nglich.
âdrvmapâ wurde oben schon erlĂ€utert. GEMDOS hat eine Tabelle (âdmdxâ), in der fĂŒr jedes Laufwerk der Zeiger auf den DMD steht. Wenn ein Laufwerk unbekannt ist, enthĂ€lt die Tabelle einen Nullzeiger (OL). Gesetzt bzw. gelöscht werden diese Zeiger bei der automatischen An- und Abmeldung der Laufwerke.
âf_masksâ ist eine Tabelle mit Bit-Masken, die fĂŒr Berechnungen verschiedenster Art benötigt werden. Bei der Anmeldung von Laufwerken ergeben sich die Werte fĂŒr âb_mrecsizâ und âb_mclsizâ aus dieser Tabelle durch Indizierung mit den log2-Werten (âb_lrecsizâ, âbjclsizâ).
Im folgenden wird die Struktur des ProzeĂdescriptors noch gebraucht werden, daher ist sie fĂŒr diejenigen unter Ihnen, die den Artikel âProgrammverwaltungâ nicht gelesen haben, in Abb. 3 noch einmal dargestellt. FĂŒr die genaue ErklĂ€rung muĂ ich jedoch leider wieder auf das ST-Extra-Heft verweisen.
Mehr als 16 Laufwerke?
GEMDOS kann in seiner derzeitigen Version entgegen sĂ€mtlicher GerĂŒchte maximal 16 Laufwerke verwalten. Dies scheint viel zu sein, doch gibt es Leute, denen das noch zu wenig ist. Die GrĂŒnde fĂŒr die BeschrĂ€nkung auf 16 Laufwerke sind die folgenden:
âdrvmapâ ist nur eine âintâ-Variable (16 Bit). Durch eine einfache Ănderung im GEMDOS-Quelltext könnte dies auf Tongâ (32 Bit) geĂ€ndert werden.
Das âdmdxâ-Feld mĂŒĂte fĂŒr 32 Laufwerke erweitert werden (fĂŒr die Atari-Entwickler ebenfalls kein Problem). Das âp_drvxâ-Feld im ProzeĂdeskriptor (PD), in dem Handles fĂŒr die Standardpfade abgelegt sind (dazu kommen wir in einer spĂ€teren Folge), ist fĂŒr 16 Laufwerke dimensioniert. Da danach aber noch Platz im PD ist, wĂ€re eine Erweiterung auf 32 Laufwerke ohne Ănderungen möglich. Allerdings gibt es Routinen, die alle Laufwerke aus âp_drvxâ in einer Schleife durchgehen (z.B. bei der Vererbung an Tochterprozesse). Hier mĂŒĂte ĂŒberall der Schleifenendwert auf 32 statt 16 gesetzt werden.
Bei Benutzung so vieler Laufwerke mĂŒĂte aber auch der interne Speicher nochmals vergröĂert werden, da GEMDOS hier ganz schön zuschlĂ€gt.
GEMDOS-Funktionen (TRAP #1)
Hier möchte ich noch kurz auf die GEMDOS-Funktionen eingehen, die mit der Disk-Verwaltung ZusammenhÀngen.
Funktion $0e Dsetdrv
long Dsetdrv(int drv)
Das Default-Laufwerk wird auf âdrvâ gesetzt (0,1.. fĂŒr A:, B:, usw.). Dieses Laufwerk wird angesprochen, wenn in Pfadnamen keine Laufwerkskennung explizit angegeben ist.
RĂŒckgabewert
Es wird eine 32-Bit-Maske der angemeldeten Laufwerke zurĂŒckgegeben (Bit 0,1,.. fĂŒr A:,B:,..). Dabei handelt es sich jedoch nicht um die GEMDOS-Variable âdrvmapâ, sondern um die oben erwĂ€hnte BlOS-Systemvariable âdrvbitsâ.
typedef struct
{ char *p_lowtpa; /* Zeiger auf Beginn des reservierten Bereichs */
char *p_hitpa; /* Zeiger auf Ende des reservierten Bereichs */
char *p_tbase; /* Zeiger auf TEXT-Segment */
long p_tlen; /* LĂ€nge TEXT-Segment */
char *p_dbase; /* Zeiger auf DATA-Segment */
long p_dlen; /* LĂ€nge DATA-Segment */
char *p_bbase; /* Zeiger auf BSS-Segment */
long p_blen; /* LĂ€nge BSS-Segment */
DTA *p_dta; /* Zeiger auf DTA-Puffer */
PD *p_parent; /* Zeiger auf PD des Parent-Prozesses */
long resl; /* nicht benutzt */
char *p_env; /* Zeiger auf Environment-String */
char p_devx[6]; /* Handles fĂŒr Standard-Devices */
char res2; /* nicht benutzt */
char p_defdrv; /* aktuelles Laufwerk (Default-Laufwerk) */
char res3[8]; /* nicht benutzt */
char p_drvx[16); /* Pfad_Handles fĂŒr alle Laufwerke */
char res4[0xl8]; /* nicht benutzt */
long p_d0; /* Prozessorregister DO */
long p_a3; /* Prozessorregister A3 */
long p_a4; /* Prozessorregister A4 */
long p_a5; /* Prozessorregister A5 */
long p_a6; /* Prozessorregister A6 */
long *p_reg; /* Zeiger auf restliche Prozessor-Register */
char p_cmdlin[128]; /* Kommando-Zeile (ĂŒbergebener Parameter) */
} PD;
Abb. 3: Der ProzeĂdescriptor (PD)
typedef struct
{ long b_free; /* freie Cluster */
long b_total; /* Gesamtzahl der Cluster */
long b_secsiz; /* Sektor-GröĂe in Byte */
long b_clsiz; /* Cluster-GröĂe in Sektoren */
} DISKINFO;
Abb. 4: DISKINFO-Struktur
Arbeitsweise
GEMDOS merkt sich das aktuelle Laufwerk im PD als âp_defdrvâ. Dies bedeutet, daĂ jeder ProzeĂ sein eigenes aktuelles Laufwerk hat.
Die Funktion âDsetdrvâ besteht nur aus zwei âCâ-Befehlen. âdrvâ wird direkt nach âp_defdrvâ des PD kopiert. Dabei erfolgen keinerlei Kontrollen. Wenn das Laufwerk gar nicht existiert, wird dies frĂŒhestens beim versuchten Zugriff bemerkt (in der oben erlĂ€uterten Routine âd_chkdrvâ). Als zweites wird die BIOS-Funktion âDrvmapâ aufgerufen, deren Ergebnis direkt an den Aufrufer von âDsetdrvâ zurĂŒckgegeben wird.
Bei der Gelegenheit gleich noch ein Wort zu unerlaubten Laufwerkskennungen: GEMDOS bemerkt zwar frĂŒher oder spĂ€ter, wenn ein Laufwerk nicht ansprechbar ist. Es reagiert allerdings ausgesprochen allergisch auf Kennungen, die nicht zwischen 0 und 15 liegen. Da keine ĂberprĂŒfungen erfolgen, können unvorhersehbare Zugriffe erfolgen (durch Index-Ăberlauf in âp_drvxâ). NatĂŒrlich gibt es auch Schwierigkeiten beim Abfragen des Laufwerk-Bits in âdrvmapâ.
Die GEMDOS-Programmierer waren sicherlich der Ansicht, daĂ es in Anwenderprogrammen keine Programmierfehler gibt, die illegale Kennungen erzeugen. Wie ĂŒblich muĂ der Anwender selbst nach den Bombenlegern im GEMDOS suchen. Bei Accessories ist wieder einmal zu beachten, daĂ diese unter dem PD der Hauptapplikation, also unter AES/ Desktop, laufen, wodurch sich Konflikte ergeben können.
Funktion $19 Degetdrv
int Dgetdrv()
Hiermit erhĂ€lt man die Kennung des fĂŒr den aktiven ProzeĂ gĂŒltigen aktuellen Laufwerks. Dies kann entweder die zuletzt mit âDsetdrv* gesetzte oder die vom Parent-ProzeĂ âgeerbteâ Kennung sein.
Arbeitsweise
âDgetdrvâ ist ein Einzeiler. Es erfolgt direkt die RĂŒckgabe von âp_defdrvâ aus dem PD.
Funktion $36 Dfree
void Dfree
(DISKINFO *info, int drv)
Diese Funktion gibt Auskunft ĂŒber den freien Speicherplatz auf dem Laufwerk âdrvâ (OfĂŒr aktuelles Laufwerk; 1,2,... fĂŒr A:,B:,..). âinfoâ muĂ dabei auf freien Speicherplatz zeigen, der von âDfreeâ mit einer DISKINFO-Struktur (Abb. 4) gefĂŒllt wird. Daraus kann der belegte und noch freie Speicherplatz in Bytes berechnet werden:
free = b_free * b_clsiz * b_secsiz
used =(b_total - b_free)*b_clsiz *b_secsiz
Dabei ist zu berĂŒcksichtigen, daĂâDfreeâ nur die Informationen der FAT berĂŒcksichtigt, wo der Speicherplatz nach Clustern verbucht wird.
Arbeitsweise
Nach der Ermittlung des gewĂŒnschten Laufwerks (BerĂŒcksichtigung des aktuellen Laufwerks) und der ĂberprĂŒfung mit âd_chkdrvâ werden alle FAT-EintrĂ€ge (von 2 bisânumclâ) gelesen. Alle EintrĂ€ge gleich Null werden als frei gezĂ€hlt (dies ergibt âb_freeâ).
Dann wird die DISKINFO-Struktur erzeugt. Die Werte âb_total\ âb_secsizâ und âb_clsizâ entnimmt man dabei dem DMD (âd_numd\ 'd_recsiz\ âd_clsizâ).
FĂŒr das Lesen der FAT wurde keine groĂe, programmtechnische MĂŒhe âvergeudetâ. Dies erledigt nĂ€mlich die allgemeine FAT-Lese-Routine, die mit âf_seekâ (der internen Version von GEMDOS-Tseekâ) und âf_readâ jeden Eintrag einzeln liest und auch noch gleich den Folge-Cluster bestimmt, was hier ja ĂŒberflĂŒssig ist. Dieser enorme Overhead erklĂ€rt, warum âDfreeâ so berĂŒchtigt langsam ist (gar nicht zu reden vom DESK-
TOP-âDisk-Infoâ, das auch noch sĂ€mtliche Directories liest!). Eine auf âDfreeâ zugeschnittene Routine, die effektiver arbeitet, wĂŒrde hier schon Wunder wirken.
Vorausschau
Das nĂ€chste Mal kehren wir wieder zur Dateiverwaltung zurĂŒck. Dabei geht es um die nĂ€chsthöhere Ebene -die Ebene der File-Descriptoren.
/* Routinen zum Abmelden von Laufwerken
bzw. zur Freigabe internen GEMDOS-Speichers
by A. Esser, Juni 1987
entwickelt mit MEGAMAX C
*/
#define pokeb(a,b) poke(0,(long)a,(int)b)
#define pokew(a,b) poke(1, (long)a,(int)b)
#define pokel(a,b) poke(3,(long)a,(long)b)
#define peekb(a) ((int)peek(0,(long)a))
#define peekw(a) ((int)peek(1,(long)a))
#define peekl(a) peek(3,(long)a)
/* allgemeine Funktionen zum Speicherzugriff
ermöglicht Zugriff auf geschĂŒtzte Bereiche
und auf ungerade Adressen */
asm
{
poke:
pea spoke
move.w #38,-(A7) ;XBIOS-Supexec
trap #14
addq.w #6,A7
rts
spoke:
move.l 14(A7),A0 ;Poke-Adresse
lea 18(A7),a1 ;Adresse des zu schreibenden Wertes
move.w 12(A7),d1 ;Zahl der Bytes -1 (0,1,3)
bne.s spokel ;-> int oder long
addq.w #1,A1 ;char wurde als int ĂŒbergeben
spokel:
move.b (A1)+,(A0)+
dbf D1,spokel
rts
;
peek:
pea speek
move.w #38,-(A7) ;XBIOS-Supexec
trap #14
addq.l #6,A7
rts
speek:
move.l 14(A7),A0 ;Peek-Adresse
moveq #0,D0
move.w 12(A7),D1 ;Zahl der Bytes -1 (0,1,3)
speekl:
asl.l #8,D0
move.b (A0)+,D0
dbf D1,speekl
rts
}
/* gesamten internen Speicher eines Laufwerks freigeben */
void free_drv(drive)
register int drive; /* Laufwerks-Kennung 0..15 */
{ long dummy[4]; /* Dfree-Puffer */
long old_bpb; /* Zwischenspeicher fĂŒr alte Vektoren */
long old_rw;
long old_med;
extern free_bpb(),free_rw(),free_med();
old_bpb = peekl(hdv_bpb); /* alte Vektoren merken */
old_rw = peekl(hdv_rw);
old_med = peekl(hdv_mediach);
pokel(hdv_bpb,free_bpb); /* auf Spezial-Routinen setzen */
pokel(hdv_rw,free_rw);
pokel(hdv_mediach,free_med);
Dfree(dummy, drive+1); /* Disk-Zugriff gibt Speicher frei */
pokel(hdv_bpb,old_bpb); /* Vektoren wieder zurĂŒckholen */
pokel(hdv_rw,old_rw);
pokel(hdv_mediach,old_med);
return;
/* folgende hdv-Routinen sorgen indirekt
fĂŒr Speicher-Freigabe */
asm
{ free_med:
moveq #2,D0 ;"sicherer Medium-Wechsel"
rts
free_rw:
moveq #-14,D0 ;"Medium-Wechsel"
rts
free_bpb:
moveq #0,D0 ;Medium nicht vorhanden
rts
}
}
/* internen Speicher aller Laufwerke freigeben */
void free_all()
{ register int drive;
/* ohne RĂŒcksicht auf Existenz */
for (drive = 0; drive < 16; drive++)
free_drv(drive);
}