← ST-Computer 07 / 1991

Verbotene FrĂŒchte: Ein kritischer TOS-Hack zum Finden des MPB

Grundlagen

Es gibt Programme, die das TOS-Datum oder die TOS-Versionsnummer abfragen. Da möchte der Programmierer z.B. Funktionen nutzen, die erst von neueren Versionen des Betriebssystems zur VerfĂŒgung gestellt werden. Soll das Programm auch auf Ă€lteren, vielleicht noch weit verbreiteten OS-Versionen lauffĂ€hig sein, muß entsprechend verzweigt werden, um die nicht vorhandenen Features zu umgehen oder vielleicht sogar nachzubilden.

Jedenfalls sollte das Programm nicht etwa nur böse bombend abstĂŒrzen: Guter Stil erfordert zumindest eine Meldung der Art Prg. XYZ lĂ€uft erst ab OS-Version ABC!. Diese Art der TOS-Versionsabfrage ist völlig korrekt und entspricht guter Programmierpraxis.

Es gibt aber noch eine ganz andere Art der Versionsabfrage: Da hat ein pfiffiger Programmierer eine OS-interne Variable entdeckt, ĂŒber die sich Manipulationen vornehmen lassen, die seinem Programm ungeahnte Möglichkeiten eröffnen. Der einzige Nachteil ist, daß sich die Lage dieser Variablen von OS-Version zu OS-Version verĂ€ndert. Was tun? Der 'brave’ Programmierer stöhnt: „schade!“ und lĂ€ĂŸt die Finger davon. Vielleicht beginnt er auch eine Korrespondenz mit den Systemprogrammierern seines Rechners und versucht, sie davon zu ĂŒberzeugen, wie gut es wĂ€re, die bewußte Variable zu dokumentieren und damit zur Benutzung freizugeben.

Doch magisch lockt die Macht des Bösen, und das Fleisch ist schwach. So wird denn schließlich eine Tabelle installiert, in der die Lage der besagten Variablen fĂŒr alle relevanten, bis dato bekannten OS-Versionen festgelegt ist. Die Höflichkeitsmeldung - sofern implementiert mĂŒĂŸte hier lauten: Prg. XYZ lĂ€uft nur auf OS-Version(en) ABC! Bitte Update ordern! [1]

Nach dieser EinfĂŒhrung hoffentlich neugierig gemacht und entsprechend motiviert, lassen Sie uns zur Lösung eines bekannten praktischen Problems nun gemeinsam in die (Un-)Tiefen des TOS, seiner Dokumentation und speziell seiner internen Speicherverwaltung durch das GEMDOS hinabsteigen.

Ziel aller WĂŒnsche

Eine der am heißesten begehrten internen TOS-Variablen ist der sogenannte MPB (Memory Parameter Block): Er stellt nĂ€mlich den SchlĂŒssel fĂŒr die Speicherverwaltung des Betriebssystems (hier GEMDOS) dar und besteht aus drei Zeigern, angeordnet in folgender Struktur:

MPB: dc.l mpmfl ;Zeiger auf Beginn der 'mfl' (memory free list) dc.l mp_mal ;Zeiger auf Beginn der 'mal' (memory allocated list) dc. mp_rover ;nicht weiter definierter Zeiger (roving ptr)

Der roving ptr, ein intern verwendeter Zeiger auf den zuletzt bearbeiteten (oder den demnĂ€chst zu bearbeitenden?) Block, ist allerdings in seiner Funktion nicht weiter offiziell beschrieben. Bei meiner Konfiguration (TOS 1.4) zeigt er immer auf die mfl; wenn es keine mfl gibt (mp_mfl = 0), ist er auch Null. Man sollte sich allerdings hĂŒten, aus solchen Beobachtungen irgendwelche Annahmen fĂŒr die Zukunft abzuleiten, und siehe da, im TT-TOS 3.01 wird er anscheinend schon nicht mehr benutzt...

In den beiden Listen, der mfl und der mal, befinden sich die sog. MDs (Memory Descriptor), sie haben folgende Struktur:

MD: dc.l m_link ;Zeiger auf nÀchsten MD (0 = Ende der Liste) dc.l m_start ;Zeiger auf Beginn des Blocks dc.l m_length ;LÀnge des Blocks dc.l m_own ;Zeiger auf Besitzer des Blocks (die Basepage)

Beide Listen bestehen also aus diesen MDs, die mittels der m_link-Zeiger einfach miteinander verkettet sind, jeder allozierte (mit bestimmten Ausnahmen, s.u.) und jeder freie Block des Anwenderspeichers ist hier eingetragen. Der m_own-Zeiger ist allerdings bei den in der mfl befindlichen MDs bedeutungslos, wenn nicht schon Null. Diese Strukturen sind - Ă€ußerst sparsam - offiziell dokumentiert in [2], eine ausfĂŒhrliche Diskussion (inoffiziell) gibt ’s in den grundlegenden BeitrĂ€gen von Alex Esser [3]. Dabei sollte man aber bedenken, daß sich die nicht offiziell dokumentierten internen Strukturen des Betriebssystems des öfteren geĂ€ndert haben und auch weiterhin Ă€ndern werden, ja, daß sie gerade deshalb nicht dokumentiert werden, um die Möglichkeit ihrer Änderung - Optimierung oder Erweiterung - offenzuhalten.

Wenn man also ĂŒber die Kenntnis des leider nur strukturmĂ€ĂŸig wohldokumentierten Ankers, eben des MPB, Zugriff auf diese ebenfalls in ihrer Existenz und Struktur dokumentierten einfach verketteten Listen hĂ€tte, könnte man die Speicherverwaltung des GEMDOS allerliebst manipulieren. Dazu eröffnen sich folgende Perspektiven:

Ein sĂŒĂŸer Traum...

Atari dokumentiert endlich die Adresse des MPB als Systemvariable und gibt damit den Zugriff auf die schon lĂ€ngst publizierten MDs frei. DafĂŒr sollte man Allan Pratt und seinem Team von Systemprogrammierem den ‘Goldenen Jack am Band’ verleihen! Gewisse ‘trickreiche’ Programme könnten dann mit Tabellen fĂŒr Abfragen erster Art versehen werden und endlich in den Bereich der so lang ersehnten programmiertechnischen LegalitĂ€t ĂŒberwechseln.

...und die harte Wirklichkeit

Es gibt da die allgemein bekannte, dokumentierte [2] und vom Anwender tunlichst nicht aufzurufendc BIOS-Funktion Nr.0 getmpb, die vom GEMDOS wĂ€hrend des Systemstarts dazu benutzt wird, den MPB auszufĂŒllen und dabei gleichzeitig einen MD, nĂ€mlich den MD, das ist die Systemvariable themd $48E, zu initialisieren [2, 4].

Da wir wissen, daß das GEMDOS nur einmal die Funktion BIOS (0) getmpb aufruft, mĂŒssen wir uns zu einem Zeitpunkt in der Systeminitialisierung, zu dem der BIOS-Trap schon eingerichtet ist, aber vor der Initialisierung des GEMDOS, in den Trap hĂ€ngen und warten, bis getmpb aufgerufen wird. Dabei wird p_mpb als Zeiger auf den MPB auf dem Stack ĂŒbergeben, wir brauchen ihn uns nur zu merken und können ihn in einer dokumentierten und deshalb fĂŒr andere Programme zugĂ€nglichen Form ablegen, z.B. als cookie im cookie jar, um gleich einmal diese mit TOS 1.6 eingefĂŒhrte, aber auch bei frĂŒheren TOS-Versionen nachrĂŒstbare Informationsstruktur zu nĂŒtzen.

Leider stellt sich bei Untersuchung der im schon zitierten HHG [2] sehr ausfĂŒhrlich dokumentierten Startup-Sequenz heraus, das nur eine ROM-Port-Cartridge dort hineinkommen kann, und zwar in unserem Falle am besten eine Anwendung vom Typ L direkt vor der Initialisierung des GEMDOS. Nun haben aber Cartridges, auch ROM-Module genannt, einen Nachteil: Sie sind ziemlich hart und lassen sich weder auf Diskette ziehen noch ĂŒber ein elektronisches Medium schicken, was ihrer Verbreitung natĂŒrlich im Wege steht - zumal dies ja eine der wenigen echten ROM-Modul-Anwendungen wĂ€re. Na, zumindest den Code kann man ja veröffentlichen. Leider ist diese harte Tour bis dato der einzige Weg, dem MPB auf völlig legale - und damit 100%ig und fĂŒr alle Zeiten (...solange das TOS noch von Belang ist und Atari sich an seine eigene Dokumentation hĂ€lt...) sichere - Weise beizukommen.

Weichere Möglichkeiten

Der Anker der MD-Listen ist also der MPB. Nur, was macht man, wenn man seine Adresse nicht kennt? Das einzige, worauf man seine Hand legen kann, ist themd ($48E), eine ‘garantierte’ Systemvariable zwar, aber leider nicht sehr von Nutzen. Das war und ist der bisherige Stand der (recht kĂ€rglichen) Dokumentationen und die generelle Meinung der Fachautoren. Das soll sich nun Ă€ndern, denn genau hier setze ich den Hebel an!

themd ist gleich nach der GEMDOS-Initialisierung ein (der einzige) Eintrag der mfl und weist damit den gesamten Anwenderspeicher - auch TPA (Transient Program Area; genannt - von membot bis memtop als frei aus, so ist’s dokumentiert in [2]. Die mal ist zu diesem Zeitpunkt leer (mp_mal=0), mp_mfl (und bis TOS 1.6 auch mp_rover) zeigt auf themd. Dies Ă€ndert sich, sobald die erste Speicherreservierung (z.B. zum Starten eines Prozesses) vorgenommen wird. Nun ist themd der letzte MD der mal: m link=0, m_own = Urprozeß (seit TOS 1.4, frĂŒher Null), m_start = membot, m_length enthĂ€lt die GrĂ¶ĂŸe des ersten reservierten Blocks. Die Möglichkeit zu einer solchen â€˜Ă¶ffentlichen’ Reservierung - mit Malloc() - besteht bei ausfĂŒhrbaren Boot-Sektoren (Floppy- und DMA-Boot) und PĂ€ckchen, in dieser Reihenfolge. Danach ist dann wieder das ROM dran, und hier geschehen auf jeden Fall die ersten Reservierungen fĂŒr Environment-String und Basepage, die fĂŒr den sog. AUTOEXEC-Prozeß eingerichtet werden (nicht dokumentiert), der dann, falls vorhanden, die AUTO-Ordner-Programme und anschließend das AES (oder das COMMAND.PRG) startet (das ist wieder dokumentiert!).

Fallunterscheidung

  1. Wir haben in themd eine Struktur, auf die zu einem Zeitpunkt, zu dem noch kein Speicher reserviert wurde (Boot-Sektorprogramme und PĂ€ckchen), ein oder zwei Zeiger (mp_mfl und mp_rover) zeigen. Die mĂŒĂŸten sich doch finden lassen, und damit wĂ€re dann der ach so heißbegehrte MPB lokalisiert [5].

Äußerst kritisch ist hier, daß noch kein Speicher reserviert worden sein darf, im Falle des PĂ€ckchens könnte z.B. ein Harddisk-Treiber aus dem Boot-Sektor von Laufwerk C: dazwischen gekommen sein, so daß eine gewisse Sicherheit fĂŒr diese Methode nur dann besteht, wenn das Programm aus dem Boot-Sektor von Laufwerk A: startet und damit garantiert als allererstes ausgefĂŒhrt wird. Die UnberĂŒhrtheit des Speichers lĂ€ĂŸt sich recht einfach nachprĂŒfen. Um dem Problem mit der Benutzung des mp_rover aus dem Wege zu gehen, empfiehlt sich hier die Suche von unten nach oben. Die verbleibende Unsicherheit resultiert aus der nicht ganz dokumentenechten Annahme, daß es im durchsuchten Bereich nur einen solchen Zeiger gibt, und daß das dann der gesuchte mp_mfl ist (ich wĂŒĂŸte allerdings nicht, was das GEMDOS mit mehr als einem solchen Zeiger auf die mfl anfangen sollte!).

  1. Wir haben in themd das letzte Glied einer Kette, auf deren Beginn mp_mal zeigt. Dies ist zu allen spĂ€teren Zeiten so, gleich, ob aus dem AUTO-Ordner oder vom Desktop aus. Dieser Fall ist etwas kniffliger: Zeiger suchen, der auf themd zeigt; prĂŒfen, ob’s ein m_link eines MD sein könnte; prĂŒfen, ob m_own Null ist; wenn ja, ist es vermutlich der mp mal; sonst: Zeiger suchen, der auf diesen MD zeigt...

Hier gibt es zwei kritische Punkte, den einen allerdings erst seit TOS 1.4. Die von residenten Programmen belegten MDs werden nĂ€mlich wie schon zuvor ĂŒblich aus der mal ausgehĂ€ngt und sind damit dem GEMDOS unbekannt. [6] Leider werden die von ihnen belegten ‘Slots’ aber nicht freigegeben, d.h. der Inhalt gelöscht oder zumindest ihr m_own ungĂŒltig gemacht. Bei z.B. 10 residenten AUTO-Ordner-Programmen sind dann 20 MD-Slots völlig unnötigerweise belegt (je 10 fĂŒr die Environment-Strings, 10 fĂŒr die residenten Programmteile inklusive Basepage), ein weiterer Bug im neuen GEMDOS-Poolmanager (POOLFIX3 hilft da leider auch nicht weiter)! Unser Suchprogramm könnte somit auf die Adressen zwar formal gĂŒltiger, aber fĂŒr uns wertloser MDs stoßen, die als ‘Leichen’ im GEMDOS-Pool liegen. Ein Test auf die GĂŒltigkeit von m_own (muß auf gĂŒltige Basepage zeigen [7]) nĂŒtzt in diesem Falle auch nichts. Der Referenzierungsalgorithmus, der die verkettete Liste von hinten aufrollen soll, muß also durch einen entsprechenden Dereferenzierungsalgorithmus ergĂ€nzt werden, damit sich die Routine sozusagen wieder rĂŒckwĂ€rts aus der Sackgasse - Stufe fĂŒr Stufe - heraushangeln kann, um dann jeweils neue Versuche nach vom zu starten. Damit das Programm bei etwaigem Versagen nicht hĂ€ngenbleibt, sollte die maximal mögliche Anzahl der ‘Backtracking’-Versuche auf einen vernĂŒnftigen Wert begrenzt werden. Das alles hört sich zwar furchtbar kompliziert an, der Code ist jedoch recht kurz und klar!

Der zweite kritische Punkt ist die Abbruchbedingung, nĂ€mlich m_own=0. So etwas darf es allerdings in der mal nicht geben: einen herrenlosen Block. Dann hĂ€tten wir also hoffentlich den mp mal selbst erwischt. Das wĂ€re dann aber kein Element eines MD mehr, und die Tatsache, daß an diesem Offset eine Null steht, haben wir nur dem glĂŒcklichen Umstand zu verdanken, daß der MPB (zumindest zur Zeit des AUTO-Ordners und meist auch des Desktops) allein auf weiter Flur in einem sonst leeren Datenbereich steht. Dies ist natĂŒrlich logisch ĂŒberhaupt nicht zwingend. Und das muß auch nicht so bleiben, selbst wenn es schon seit Uralt-Rauchpilz-TOS-Zeiten so war und auch im STE-TOS 1.6 sowie im TT-TOS 3.01 noch immer so ist. Die Methode funktioniert prĂ€chtig, wie der geneigte Leser sicher schon erraten hat, und wird es wohl auch weiterhin, doch kann man dies weder 100%ig noch fĂŒr alle Zeiten garantieren.

Lösungsvorschlag

Die erste Methode bietet mehr Sicherheit, eignet sich aber nicht fĂŒr Programme, die, wie das nun vorgestellte MAL_FIND oder GET_MPB, lediglich eine darstellende Funktion haben. Um nicht umstĂ€ndlich mit Boot-Sektor-Installationen herumbasteln zu mĂŒssen, könnte man auch ein PĂ€ckchen installieren (ein Bonus fĂŒr Programme, die sowieso auf einem resetfesten PĂ€ckchen laufen sollen!), evtl. gleich einen Warmstart veranstalten und aus dem PĂ€ckchen heraus den MPB ermitteln. Da man hier immer damit rechnen muß, daß ein selbstbootender Harddisk-Treiber von Laufwerk C: dazwischenfunkt, empfiehlt sich eine Kombination der beiden Methoden, wie es in dem als Link-Modul ausgelegten _GET_MPB implementiert wurde.

Gesucht wird jeweils von membot nach unten bis $2000 (willkĂŒrlich, auch bei Uralt- TOS-Versionen findet sich nichts darunter). Hierbei wird vorausgesetzt, daß die Liste komplett im ursprĂŒnglichen OS-Pool liegt und dieser nicht etwa schon erweitert wurde (z.B. durch FOLDRXXX.PRG). Ferner ist denkbar, daß Pool-Manipulationen residenter Programme, z.B. Monitore, den Suchalgorithmus blockieren könnten, die Reihenfolge der Programme wĂ€re hier zu beachten: Je frĂŒher der Start, desto höher die Erfolgswahrscheinlichkeit! Die Suchrichtung von oben nach unten ist zwar um einiges langsamer, hat sich aber als stabiler erwiesen. Das Problem der ‘Sackgassen durch Geister-MDs’ wird zwar in beiden Suchrichtungen von der Routine gleich gut bewĂ€ltigt, auch wenn man ihnen bei der Suche von unten nach oben natĂŒrlich öfter begegnet, zuweilen tauchen jedoch kurzfristig (!) ‘verstĂŒmmelte’ MDs auf, die mit ausgenulltem m_own vorzeitig die Abbruchbedingung erfĂŒllen. Diese Gefahr hat sich bei der Suche von oben nach unten nicht ergeben.

Einbruchsgefahr!

Wie man sieht, bewegen wir uns hier auf ziemlich dĂŒnnem Eis. Sinnvolle PlausibilitĂ€tstests, in der richtigen Kombination, sind demnach das A und O solcher Routinen, da ließe sich evtl. noch einiges verfeinern. Das war auch mit der schwierigste Teil beim Entwurf der Routine, denn hier spiegeln sich ja alle Annahmen, die man so macht. Der Test auf 24-Bit-Adressen mußte dem TT zuliebe z.B. wieder gestrichen werden, ebenso die Annahmen ĂŒber das Verhalten des mp_rover. Andere Tests erwiesen sich als nicht stabil: der ‘Ad-hockery’ sind bei solchen Problemen ja TĂŒr und Tor geöffnet, und man muß schon sehr aufpassen, was fĂŒr Annahmen man macht und was sie implizieren. Man darf sich auch nicht von SpeicherabbiIdern, sog. Dumps, zu generalisierenden Annahmen verleiten lassen. Wenn ich vorhin sagte, daß der Bereich um den MPB so schön leer sei, so gilt das durchaus nicht immer. Beim Nachladen anderer Programme werden u.U. direkt anschließend Tabellen mit Deskriptoren angelegt. Das bedeutet, daß die Abbruchbedingung der Routine z.B. unter auf dem AES laufenden Debuggern oder bestimmten Shells (u.a. Gulam, Gemini 1.2) nicht erfĂŒllt werden kann. So etwas ist aber nun gerade nicht die Umgebung, unter der die Routine nachher laufen soll, und ich habe mich daher gehĂŒtet, hier ad hoc Abhilfe zu schaffen!

Weitere Einzelheiten zu erklĂ€ren, erspare ich mir, und lasse dafĂŒr lieber den Code sprechen: Er ist ja kurz genug und, wie ich hoffe, ausreichend kommentiert. Also, immer die Zeiger suchen oder den Zeigern folgen! GlĂŒcklicherweise lĂ€ĂŸt sich dieses ganze Zeigergewurstel in Assembler nicht nur einigermaßen elegant programmieren, sondern der Code ist auch entsprechend schnell in der AusfĂŒhrung, so daß selbst bei RAM-TOS, wo membot ja ziemlich hoch liegt und sich der Algorithmus erst durch das ganze TOS.IMG wĂŒhlen muß, passable AusfĂŒhrungszeiten erreicht werden.

Die Programme

MAL_FIND gibt die ganze mal entsprechend dem Algorithmus von hinten nach vom aus, wobei ungĂŒltige MDs mit <invalid! gekennzeichnet werden. Weitere solche Markierungen hintereinander bedeuten, daß entsprechend viele Zeilen darĂŒber als ungĂŒltig zu betrachten sind, wie schon oben erklĂ€rt. Dann wird der MPB ausgegeben und anschließend die mfl[8] von vorn nach hinten, den m_link-Zeigern folgend. Falls der Suchalgorithmus bei Ausgabe der mal steckenbleiben sollte, gibt es eine entsprechende Fehlermeldung.

GET_MPB gibt bei Erfolg nur den MPB aus, sonst eine Fehlermeldung. Der Code entspricht MAL_FIND bis auf die MD-Listenausgabe.

GET_MPB ist ein Modul, das zur Einbindung in Hochsprachen gedacht ist. In D0 wird bei Erfolg die Adresse des MPB zurĂŒckgeliefert, sonst eine Null. Man bedenke allerdings, daß so ein Modul wirklich nur zur Vewendung in ganz speziellen (meist resetfesten) Utilities geeignet ist und nicht etwa fĂŒr Standard TOS- oder gar AES-Applikationen. Dort gibt es schließlich genug bekannte und gut dokumentierte Methoden, sich Speicher zu besorgen.

CART_MPB und BOOT_MPB sind die Implementationen der Routine fĂŒr Cartridge bzw. Boot-Sektor. Sie installieren ein Cookie namens MPB* im Cookie Jar, auf das andere Programme dann zu greifen können. Falls das Cookie Jar erst eingerichtet werden muß (<TOS 1.6), wird auch ein Resethandler installiert, der die Systemvariable _p_cookies $5A0 bei einem allfĂ€lligen Warmstart wieder löscht, wie von Atari in [0] vorgeschrieben. Speicher fĂŒr das Cookie Jar besorgen sich beide Programme in einer Art, die ich ‘stille Reservierung’ nennen möchte - also ohne Benutzung von Malloc(). Das ist, wie man sieht, sehr einfach - wir sitzen ja schließlich an der Quelle! Im Falle der Cartridge ist es noch einfacher und zudem die einzig mögliche Methode, da ja noch keine GEMDOS-Aufrufe gemacht werden dĂŒrfen.

Probe aufs Exempel

Spott erntet, wer sich darĂŒber beklagt, daß sein wunderbares XYZ-Programm nicht auf der neuen OS-Version lĂ€uft. Neulich hatte ein (registrierter!) User endlich sein Update eines bekannten biegsamen Programms fĂŒr TOS 1.4 erhalten und strahlte ĂŒbers ganze Gesicht. Der STE stand auf dem Tisch. Ich sagte nur: ‘Nimm doch mal diesen hier... 4Unbekannte TOS-Version ’, das war’s! Betretenes Schweigen...

Bei aller Begeisterung fĂŒr den wunderbar ‘tight & clean’ geschriebenen Code des Luftschlosses [10] aus Scheibenkleister II habe ich es wegen der dort enthaltenen Versionsabfragen zweiter Art nicht gustiert. RRN2500F wurde nach kurzem Test wieder gelöscht: Aus den Augen, aus dem Sinn! Doch nun her damit und neu ausgepackt! Das StĂŒckchen Code schnell ersetzt, assembliert und gleich mal auf dem STE gestartet: lĂ€uft! Desgleichen auf diversen modernen RAM-TOS-Versionen, Blitter TOS, KAOS, RAM/ROM-TOS 1.0, Very OLD RAM-TOS 1.0 vom 20.11.85. LĂ€uft nicht auf Rauchpilz-TOS, scheitert dort aber an act_pd (nicht in der Liste). Eine Abfrage erster Art wĂ€re hier natĂŒrlich möglich, wird jedoch nicht eingearbeitet, da unwichtig!. Wer noch auf so einer alten Gurke hackt, muß wohl irgendwie von der Zivilisation abgeschnitten sein, vielleicht auf Expedition am Amazonas...

P.S. Nach nunmehr ĂŒber einem Jahr stabilen Dauerbetriebs des mit der hier vorgestellten MPB Suchroutine ausgerĂŒsteten ‘Luftschlosses’ auf meinem und einigen anderen Systemen unter wechselnden Konfigurationen, konnte es dank der NachrĂŒstung des stufen weisen Dereferenzierungsalgorithmus’ nun auch erfolgreich auf dem TT030 (32 MHz, TOS 3.01) getestet werden, so daß ich, von der relativen (Beachtung der Caveats) Robustheit des Algorithmus’ ĂŒberzeugt, diesen einer grĂ¶ĂŸeren Öffentlichkeit nicht lĂ€nger vorenthalten möchte. Eigentlich schön, daß Atari zur Zeit so aktiv ist: Die nĂ€chste Probe aufs Exempel wĂ€re, ob’s auch auf TOS 2.05 des neuen Mega STE lĂ€uft.

Anmerkungen und Referenzen:

  1. Leider sind diese Methoden selbst bei Leuten, die ansonsten etwas anderes ‘predigen’, noch immer nicht ganz aus der Mode gekommen. Hat’s doch subjektiv auch manches fĂŒr sich: Das anhĂ€ngige Problem ist gelöst, und wenn’s dann spĂ€testens bei Erscheinen der nĂ€chsten OS-Version nicht mehr funktioniert, muß der Programmierer eben das Programm anpassen (Auftrag) und der Kunde halt zahlen (fĂŒrs Update). So steigert man das Bruttosozialprodukt!

  2. Landon Dyer: A Hitchhiker’s Guide to the BIOS (HHG), 1985, Atari Corp
    Unter ‘themd’ heißt es: „Filled in by the BIOS on a ‘getmpb’ call; indicates to GEMDOS the limits of the TPA. ...(you can’t use the m_link field in the first MD). Someday (with a better GEMDOS) these limitations may be lifted.“ ...und stellt somit die Freigabe des MPB in Aussicht.

  3. Alex Esser: TOS intern, ST-Computer 1987, Sonderheft Nr.2, S.35 ff.:
    Umfassende Analyse der GEMDOS-Speicherverwaltung, mit Programmen zur Erforschung der interessierenden Strukturen, basierend auf TOS 1.0. Siehe ebenfalls den 1. Teil des zweiteiligen Beitrags ‘Systemvariablen des TOS’, ST-Computer 11/88, sowie zu TOS 1.4 ‘Somewhere over the Rainbow’, 2 und 3, ST-Computer 5-6/90, vom gleichen Autor. In letzterem Beitrag ĂŒbrigens auch die Beschreibung des oben genannten Pool-Bugs.

  4. Allan Pratt. UUCP Message-ID: < 2737@atari.UUCP >, 12 Nov 90 20:03:26 GMT „...Getmpb is a BIOS call which is used by GEMDOS to find out the lay of the land at the beginning of the world: it is the BIOS’s way of telling GEMDOS what memory it found and where. It should not be used by user programs.

  5. Zu diesem Zeitpunkt könnten wir ĂŒbrigens auch, ohne den MPB zu ermitteln und damit dann die ‘mfl’ wie gehabt zu bearbeiten, völlig simpel gleich ‘themd’ manipulieren. Das ist es nĂ€mlich, was in Wirklichkeit geschieht, wenn man zu eben der Zeit ĂŒber den MPB auf die ‘mfl’ zugreift: Sie besteht dann ja nur aus ‘themd’!

  6. Allan Pratt, UUCP Message-ID: < 2756@atari.UUCP >, 30 Nov 90 02:03:15 GMT „...You can’t free memory which has stayed resident as a result of a TSR. It’s not even accounted for in the system as „allocated“ memory - it’s been UNHOOKED from the memory management lists. It’s GONE.“

  7. B. Rosenlecher, ‘XBRA? XNAM?? BASEFIND!!!’, ST Computer 9/90, S.147 ff.

  8. Bei meiner Standardkonfiguration (TOS 1.4 mit geladenem POOLFIX3 sowie weiteren fĂŒnf residenten und einem nicht residenten AUTO-Ordner-Programm und sechs Accessories) habe ich immer nur einen MD in der ‘ mfl ’ gesehen, auf den regelmĂ€ĂŸig beide Zeiger mp_mfl und mp rover zeigten, bei anderen Konfigurationen auch schon mal 2 oder 3, und manchal sogar, daß der mp_rover nicht auf das gleiche Ziel zeigte wie der mp _mfl. Nur einen MD in der ‘mfl’ zu haben, bedeutet natĂŒrlich, daß der als frei ausgewiesene Speicher nur aus einem großen Block besteht und nicht etwa zersplittert ist, eine wirklich erfreuliche Tatsache also!

  9. Atari Corp., STE TOS Release Notes, Jan 12, 1990, Sunnyvale, CA 94086

  10. Claus Brod, Anton Stepper: Scheibenkleister II, MAXON Computer GmbH, Eschborn 1989. Das ‘Luftschloß’ ist eine ĂŒber den Dateinamen konfigurierbare, superschnelle, resetfeste, autobootfĂ€hige, winzigkleine (mit eigener Optimierung unter 2 kB) RAM-Disk, die nach Einbau der hier vorgeschlagenen ‘ _geMnpb’-Routine auf allen relevanten TOS-Versionen lĂ€uft (hoffentlich zur Freude der Autoren wie auch der Anwender!).

* ------------------------------------------------------- * mal_find.s lists MD's of mal MPB & MD's of mfl br 2/90 * 1st revision: multiple tries in backtracing thru dead MD links * br 1/91 * 2nd revision: reverse scan direction br 2/91 * ------------------------------------------------------- action: move.l 4(sp),a0 ;basepage addr lea mystk,a1 ;end of code move.l a1,sp ;new sp suba.l a0,a1 ;prog length move.l a1,-(sp) ;newsize move.l a0,-(sp) ;block clr -(sp) ;filler move.w #$4A,-(sp) ;Mshrink trap #1 ;GEMDOS lea $C(sp),sp start: dc.w $A000 ;line_a init cmpi #79,-$2C(a0) ;v_cel_mx: minimum #columns = 80 blt sorry ;schade! cmpi #24,$2A(a0) ;v_cel_my: minimum #lines = 25 blt sorry ;traurig! lea title1(pc),a0 ;Titelzeile bsr conws ;ausgeben lea subtit(pc),a0 ;Untertitel bsr conws ;ausgeben pea main(pc) move #$26,-(sp) ;Supexec trap #14 ;XBIOS addq #6,sp term: bsr cnecin ;warte auf Taste clr -(sp) ;Pterm0 trap #1 ;GEMDOS * -------------------------------------------------- main: lea $48E,a3 ;themd — letzter MD der mal lea $2000,a5 ;Startadresse movea.l $432,a4 ;Endadresse = membot bsr show_md ;zum Display (a3 - > MD) loop_0: movea.l a5,a0 ;Startadresse laden moveq #0,d6 ;VersuchszĂ€hler loop_1: addq #2,a0 ;nur gerade Adressen cmpa.l a0,a4 ;Endadresse erreicht ? bls stuck ;war nichts cmpa.l (a0),a3 ;Zeiger da? bne loop_1 ;weiter testen * PlausibilitĂ€ts-Tests fĂŒr MD’s, falls (a0) = mp_mal - kritisch! btst #0,15(a0) ;m_own gerade? (!) bne loop_1 ;weiter testen btst #0,7(a0) ;m_start gerade? (!) bne loop1 ;weiter testen btst #0,11(a0) ;m_length gerade? (!) bne loop_1 ;weiter testen move.l a0,a3 ;neuer MD? bsr show_md ;als Eintrag der 'mal' ausgeben weiter: tst.l 12(a3) ;m_own =0? (!!!) bne loop_0 ;nĂ€chsten Zeiger suchen thats_it: lea marker(pc),a0 ;als ungĂŒltig bsr conws ;markieren lea title3(pc),a0 ;neue Überschrift bsr conws ;ausgeben subq #4,a3 ;Adresse mpb move.l a3, d3 ;umrechnen und bsr prt_hex ;ausgeben moveq #5,d4 sp_loop: bsr.s space ;Zwischenraum dbf d4,sp_loop move.l (a3),d3 ;mp_mf1 bsr prt_hex ;ausgeben bsr.s space ;Zwischenraum move.l 4(a3),d3 ;mp_mal bsr prt_hex ;ausgeben bsr.s space ;Zwischenraum move.l 8(a3),d3 ;mp_rover bsr prt_hex ;ausgeben lea crlf2(pc),a0 ;2 * CR LF bsr.s conws ;ausgeben lea title2(pc),a0 ;letzte Titelzeile bsr.s conws ;ausgeben lea subtit(pc),a0 ;Untertitel bsr.s conws ;ausgeben loop_2: tst.l (a3) ;und jetzt beq.s return ;schön move.l (a3),a3 ;einfach bsr.s show_md ;die 'mfl' ausgeben bra loop_2 return: rts stuck: lea marker(pc),a0 ;als ungĂŒltig bsr.s conws ;markieren addq #1,d6 ;# Versuche hochzĂ€hlen move.l a3,a0 ;ab hier weiter suchen move.l (a3),a3 ;wieder alten Zeiger nehmen cmp #10,d6 ;max. Anzahl der Versuche = 11 bls loop_1 ;nochmal versuchen! lea sticky(pc),a0 ;leider bsr.s conws ;steckengeblieben! rts * -------------------------------------------------- show_md: lea crlf(pc),a0 ;CR LF bsr.s conws ;ausgeben move.l a3,d3 ;md_addr bsr.s prt_hex ;ausgeben bsr.s space ;Zwischenraum ausgeben moveq #3,d5 ;4 Werte next_1: move.l (a3)+,d3 ;Wert holen bsr.s prt_hex ;ausgeben bsr.s space ;Zwischenraum dbf d5,next_1 ;um durchzuschaun lea -16(a3),a3 ;a3 restaurieren rts * -------------------------------------------------- space: lea space_1(pc),a0 ;Zwischenraum conws: pea (a0) ;Stringadresse move #9,-(sp) ;Cconws trap #1 ;GEMDOS addq #6,sp ;SP restaurieren rts * -------------------------------------------------- cnecin: move #7,-(sp) ;Cnecin trap #1 ;GEMDOS addq #2,sp rts * -------------------------------------------------- cconout: move d0,-(sp) ;char move #2,-(sp) ;Cconout trap #1 ;GEMDOS addq #4,sp rts * -------------------------------------------------- * Langwort in d3 in Hex (als Text) auf Konsole ausgeben prt_hex: moveq #7,d7 ;8 mal nibble: rol.l #4,d3 ;jeweils ein Nibble move d3,d0 ;ans Ende rollen andi #$000f,d0 ;isolieren lea hextab(pc),a0 ;Hextabelle holen move.b 0(a0,d0.w),d0 ;und Zeichen " bsr cconout ;ausgeben dbf d7,nibble ;weiter rts * -------------------------------------------------- sorry: lea lorez(pc),a0 ;'sorry, min screen size 80 * 25!' bsr conws ;ausgeben bra term ;das war's * -------------------------------------------------- hextab: dc.b '0123456789ABCDEF' title1: dc.b 13,'mal: memory allocated list (c) br 90,91',13,10,0 subtit: dc.b 'md_addr m_link m_start mlength m_own',13,10 dc.b '--------------------------------------------',13,0 title2: dc.b 13,'mfl: memory free list (c) br 90 91',13,10,0 title3: dc.b 13,10,10,'mpb: memory parameter block (c) br 90,91',13,10 dc.b 'mpb_addr mp_mfl mp_mal mp_rover',13,10 dc.b '------------------------------------------',13,10,0 sticky: dc.b 13,10,'* * * * * * sorry, got stuck! * * * * * *',13,10,0 space_1: dc.b ' ',0 crlf2: dc.b 10 crlf: dc.b 13,10,0 marker: dc.b '<invalid! ',0 lorez: dc.b 13,10,'sorry, min screen size 80 * 25!',13,10,0 * -------------------------------------------------- even bss ds.l 100 mystk: * -------------------------------------------------- * get_mpb.s (the real one!) br 2/90 * 1st revision: multiple tries in backtracking * thru dead MD links br 1/91 * 2nd revision: reverse scan direction br 2/91 * -------------------------------------------------- action: move.l 4(sp),a0 ;basepage addr lea stack+$400(pc),a1 ;end of code + $100 longs move.l a1,d0 andi.b #$FC,d0 ;long align move.l d0,sp ;new sp suba.l a0,a1 ;prog length pea (a1) ;newsize pea (a0) ;block clr -(sp) ;filler move #$4A,-(sp) ;Mshrink trap #1 ;GEMDOS lea $C(sp),sp lea title(pc),a0 ;Titelzeile bsr conws ;ausgeben pea main(pc) ;get_mpb move #$26,-(sp) ;Supexec trap #14 ;XBIOS addq #6,sp tst.l d0 ;na? beq.s error ;schade! move.l d0,a3 ;Adresse mpb move.l a3,d3 bsr prt_hex ;ausgeben moveq #2,d5 ;3 mal loop_2: bsr.s space ;Zwischenraum move.l (a3)+,d3 ;mp_mfl, mp_mal, mp_rover bsr prt_hex ;ausgeben dbf d5,loop_2 lea bye(pc),a0 ;'Taste drĂŒcken!' bsr.s conws ;ausgeben term: move #7,-(sp) ;Cnecin trap #1 ;GEMDOS clr (sp) ;Pterm0 trap #1 ;GEMDOS error: lea err_l(pc),a0 ;Fehlermeldung bsr.s conws ;ausgeben bra term * -------------------------------------------------- main: lea $48E,a3 ;themd = letzter MD der mal lea $2000,a4 ;Startadresse movea.l $432,a5 ;Endadresse = membot loop_0: movea.l a4,a0 ;Startadresse moveq #0,d6 ;VersuchszĂ€hler loop_1: addq #2,a0 ;nur gerade Adressen cmpa.l a0,a5 ;Endadresse erreicht? bls.s stuck ;war nichts cmpa.l (a0),a3 ;Zeiger? bne loop_1 ;weiter testen btst #0,15(a0) ;m_own gerade? bne loop_1 ;weiter testen btst #0,7(a0) ;m_start gerade? bne loop_1 ;weiter testen btst #0,11(a0) ;m_length gerade? bne loop_1 ;weiter testen move.l a0,a3 ;neuer MD? tst.l 12(a3) ;m_own = 0 Besitzer? (!!!) bne loop_0 ;nĂ€chster Zeiger subq #4,a3 ;Adresse des MPB move.l a3,d0 ;RĂŒckgabewert rts stuck: addq #1,d6 ;# Versuche hochzĂ€hlen move.l a3,a0 ;ab hier weitersuchen move.l (a3),a3 ;wieder alten Zeiger nehmen cmp #10,d6 ;max. Anzahl der Versuche = 11 bls loop_1 ;nochmal versuchen! moveq #0,d0 ;Fehler rts * -------------------------------------------------- space: lea space_1(pc),a0 ;Zwischenraum conws: pea (a0) ;Stringadresse move #9,-(sp) ;Cconws trap #1 ;GEMDOS addq #6,sp ;SP restaurieren rts * -------------------------------------------------- cconout: move d0,-(sp) ;char move #2,-(sp) ;Cconout trap #1 ;GEMDOS addq #4,sp rts * -------------------------------------------------- * Langwort in d3 in Hex (als Text) auf Konsole ausgeben prt_hex: moveq #7,d7 ;8 mal jeweils nibble: rol.l #4,d3 ;ein Nibble move d3,d0 ;ans Ende rollen andi #$000f,d0 ;isolieren lea hextab(pc),a0 ;Hextabelle holen move.b 0(a0,d0.w),d0 ;und Zeichen bsr cconout ;ausgeben dbf d7,nibble ;weiter rts * -------------------------------------------------- hextab: dc.b '0123456789ABCDEF' title: dc.b 13,'get mpb (the real one!) (c) br 90,91',13,10,10 dc.b 'mpb_addr mp_mfl mp_mal mp_rover',13,10 dc.b '---------------------------------------',13,10,0 space_1: dc.b ' ',0 bye: dc.b 13,10,10,"* * * press any key! * * *",13,10,0 err_1: dc.b "* * * sorry, couldn't get mpb! * * *",13,10,0 even stack: * -------------------------------------------------- bss ds.l 100 * -------------------------------------------------- * _get_mpb.s link module dev1d from get_mpb (the * real one!) br 2/90 * -------------------------------------------------- * 1st revision: multiple tries in backtracking * thru dead MD links br 1/91 * 2nd revision: split mfl/mal search, reverse * first scan direction br 2/91 * -------------------------------------------------- * long _get_mpb(void); IN: nothing, * OUT: address of MPB or NULL in D0.L * -------------------------------------------------- themd = $48E membot = $432 memtop = $436 MAX = 10 ;max # Versuche = 11 * -------------------------------------------------- globl _get_mpb ;C & assembly language entry globl GETMPB ;FORTRAN & Pascal entry GETMPB: * -------------------------------------------------- _get_mpb: movem.l d1-d2/a0-a2,-(sp) ;Register retten pea get_mpb(pc) ;Routine move #$26,-(sp) ;Supexec trap #14 ;XBIOS addq #6,sp movem.l (sp)+,d1-d2/a0-a2 ;Register zurĂŒck rts * -------------------------------------------------- get_mpb: lea themd,a1 ;Ausgangspunkt movea.l membot,a2 ;Suchende move.l memtop,d0 sub.l a2,d0 ;freien Speicher berechnen cmp.l 8(a1),d0 ;m_length = memtop - membot? bne.s loop_0 ;fehlt schon etwas lea $4000,a0 ;Suchbeginn t_loop: addq #2,a0 ;nur gerade Adressen cmpa.l a0,a2 ;Endadresse erreicht? bls.s error ;fertig cmpa.l (a0),a1 ;Zeiger auf themd? bne t_loop ;weiter suchen bra.s fini ;das war's loop_0: move.l a2,a0 ;Suchbeginn = membot moveq #0,d2 ;VersuchszĂ€hler loop_1: subq #2,a0 ;nur gerade Adressen cmpa.l #$2000,a0 ;Endadresse erreicht? bls.s stuck ;war nichts cmpa.l (a0),a1 ;Zeiger da? bne loop_1 ;weiter testen * PlausibilitĂ€ts-Tests fĂŒr MD's, falls mp mal gefunden wurde, kritisch! btst #0,15(a0) ;m_own gerade? bne loop_1 ;weiter testen btst #0,7(a0) ;m_start gerade? bne loop_1 ;weiter testen btst #0,11(a0) ;m_length gerade? bne loop_1 ;weiter testen move.l a0,a1 ;evtl. neuer MD tst.l 12(a0) ;Besitzer = 0? bne loop_0 subq #4,a0 ;Adresse des MPB fini: move.l a0,d0 ;RĂŒckgabewert rts stuck: addq #1,d2 ;# Versuche hochzĂ€hlen move.l a1,a0 ;war kein gĂŒltiger m_link move.l (a1),a1 ;alten Zeiger nehmen cmp #MAX,d6 ;max. Anzahl der Versuche bne loop_1 ;nochmal versuchen! error: moveq #0,d0 ;Fehler rts * ---------------------------------------------- * cart_mpb.s install 'MPB*' cookie from type #1 * cartridge br 1/91 * ---------------------------------------------- p_cookie = $5A0 longfram = $59E resvalid = $426 resvecto = $42A RESMAGIC = $31415926 membot = $432 trap13 = $B4 COOKIE = 'MPB*' * -------------------------------------------------- ca_magic: dc.l $ABCDEF42 ca_next: dc.l 0 ca_init: dc.l $02FA0026 ca_run: dc.l $00FA0026 ca_time: dc.w 0 ca_date: dc.w 0 ca_size: dc.l ende-start ca_name: dc.b 'CART_MPB.003',0,0 * -------------------------------------------------- start: move.l membot,a0 ;erstmal Platz besorgen move.l trap13,d0 move.l d0,(a0)+ ;alten BIOS-Vektor retten move.l a0,membot lea get_mpb(pc),a0 ;neuen BIOS-Vektor move.l a0,trap13 ;installieren rts * -------------------------------------------------- get_mpb: move.l sp,a0 ;OS ist immer im Super tst longfram ;Prozessor? beq.s weiter addq #2,a0 weiter: tst 6(a0) ;Getmpb? beq.s do_it move.l membot,a0 ;dort ist subq #4,a0 ;alter Vektor jmp (a0) * -------------------------------------------------- * Here's where the action is: IN: p_mpb @ 8(a0), * OUT: entry in cookie jar * -------------------------------------------------- do_it: move.l 8(a0),a0 ;p_mpb movem.l d3-d7/a3-a7,-(sp) ; retten move.l membot,a6 ;altes membot retten move.l a0,a5 ;MPB merken move.l #COOKIE,d3 ;'MPB*' movea.l p_cookie,a0 ;*p_cookie move.l a0,d0 ;NULL = TOS <1.6? beq.s make_jar ;cookie jar nicht vorhanden moveq #0,d1 ;ZĂ€hler jarscan:addq #1,d1 ;Eintrag zĂ€hlen cmp.l (a0),d3 ;cookie schon da? move.l (a0)+,d0 ;cookie beq.s put_cook ;eintragen addq #4,a0 ;nĂ€chstes cookie bra jarscan ;prĂŒfen put_cook:cmp.l (a0),d1 ;noch Platz? beq.s mak_spc ;nein move.l (a0)+,d0 ;#d.EintrĂ€ge clr.l (a0)+ ;Endeintrag move.l d0,(a0) ;verschieben subq #8,a0 ;zurĂŒckpositionieren move.l a5,(a0) ;Adresse des MPB eintragen move.l d3,-(a0) ;cookie eintragen bra.s return ;unlink from trap etc. mak_spc:movea.l p_cookie,a1 ;*p_cookie move.l a6,a0 ;Adresse = membot move.l d1,d2 ;ZĂ€hler add.l d2,d2 ;fĂŒr je 2 longs subq.l #3,d2 ;prĂ€parieren j_loop: move.l (a1)+,(a0)+ ;altes cookie jar dbf d2,j_loop ;umkopieren move.l d1,d0 ;minus Endeintrag addq.l #7,d0 ;und um 8 erweitern bra.s _injar make_jar:move.l a6,a0 ;Adresse = membot moveq #8,d0 ;# EintrĂ€ge _injar: move.l d3,(a0)+ ;cookie move.l a5,(a0)+ ;Adresse des MPB clr.l (a0)+ ;Endeintrag move.l d0,(a0)+ ;Anzahl eintragen move.l a6,p_cookie ;cookie jar eintragen lea 48(a0),a0 ;+6*8 position. _unjar: move.l resvecto,(a0)+ ;Reihenfolge move.l resvalid,(a0)+ ;und Lage wie unten! movea.l a0,a2 ;Position merken lea reshand(pc),a1 ;Resethandler moveq #copy_cnt,d0 c_loop: move.l (a1)+,(a0)+ ;kopieren dbf d0,c_loop move.l a0,membot ;neues membot move.l a2,resvecto move.l #RESMAGIC,resvalid return: lea -4(a6),a0 ;alten trap13 Vektor move.l (a0),trapl3 ;restaurieren movem.l (sp)+,d3-d7/a3-a7 ;restaur. jmp (a0) * -------------------------------------------------- vecsave: dc.l 0 ;Reihenfolge valsave: dc.l 0 ;und Lage beachten! reshand: clr.l p_cookie;fĂŒr < TOS 1.6 move.l valsave(pc),resvalid move.l vecsave(pc),resvecto jmp (a6) cpy_cnt = (* - reshand)/4 * -------------------------------------------------- ende: * -------------------------------------------------- * boot_mpb.s install 'pMPB' cookie from * bootsector of drive A: br 1/91 * -------------------------------------------------- * Bedingungen: Laufwerk A:, Speicher in * Originalkonfiguration, sonst raus. * Annahme: Es gebe zur Zeit der AusfĂŒhrung des * Bootsektors A: einen Zeiger * auf 'themd' zwischen SRCHBG und membot * (Suchrichtung!), den 'MPB.mp_mfl'. * -------------------------------------------------- p_cookie = $5A0 resvalid = $426 resvecto = $42A RESMAGIC = $31415926 themd = $48E membot = $432 memtop = $436 bootdev = $446 COOKIE = 'MPB*' SRCHBG = $4000 * -------------------------------------------------- bra.s start dcb.w 16,'**' msg_1: dc.b ' MPB Ox',0 msg_2: dc.b ' cookie in jar br91’,13,10,0 dcb.w 16,'**' * -------------------------------------------------- start: move #$19,-(sp) ;Dgetdrv trap #1 ;GEMDOS addq #2,sp tst d0 ;Laufwerk A:? bne.s getout ;nein get_mpb: movea.l membot,a6 ;merken move.l memtop,d0 ;freien Speicher sub.l a6,d0 ;berechnen lea themd,a3 ;themd sei einziger MD der mfl cmp.l 8(a3),d0 ;m_length = memtop - membot ? bne.s getout ;Speicher schon manipuliert, von wem??? lea SRCHBG,a0 ;willkĂŒrliche Startadresse fĂŒr Suche movea.l a6,a1 ;Endadresse = membot t_loop: addq #2,a0 ;nur gerade Adressen cmpa.l a0,a1 ;Endadresse erreicht? bls.s getout ;fertig cmpa.l (a0),a3 ;Zeiger da? bne t_loop ;weiter suchen movea.l a0,a5 ;Adresse des MPB merken move.l #COOKIE,d7 ;'MPB*' movea.l p_cookie,a0 ;*p_cookie move.l a0,d0 ;NULL = TOS <1.6? beq.s make_jar ;cookie jar nicht vorhanden moveq #0,d1 ;ZĂ€hler jarscan: addq #1,d1 ;Eintrag zĂ€hlen cmp.l (a0),d7 ;cookie schon da? beq tell_it ;das war's schon move.l (a0)+,d0 ;cookie beq.s put_cook ;hier eintragen addq #4,a0 ;nĂ€chstes cookie bra jarscan ;prĂŒfen put_cook:cmp.l (a0),d1 ;noch Platz? beq.s mak_spc ;nein move.l (a0)+,d0 ;Zahl der EintrĂ€ge clr.l (a0)+ ;Endeintrag move.l d0,(a0) ;verschieben subq #8,a0 ;zurĂŒckpositionieren move.l a5,(a0) ;Adresse des MPB move.l d7,-(a0) ;cookie eintragen bsr.s tell_it ;Meldung ausgeben getout: rts ;fertig mak_spc: movea.l p_cookie,a1 ;*p_cookie move.l a6,a0 ;Adresse = membot move.l d1,d2 ;ZĂ€hler add.l d2,d2 ;fĂŒr je 2 longs subq.l #3,d2 ;prĂ€parieren j_loop: move.l (a1)+,(a0)+ ;altes cookie jar dbf d2,j_loop ;umkopieren move.l d1,d0 ;minus Endeintrag addq.l #7,d0 ;und um 8 erweitern bra.s _injar make_jar:move.l a6,a0 ;Adresse - membot moveq #8,d0 ;# EintrĂ€ge _injar: move.l d7,(a0)+ ;cookie move.l a5,(a0)+ ;Adresse des MPB clr.l (a0)+ ;Endeintrag move.l d0,(a0)+ ;Anzahl eintragen move.l a6,p_cookie ;cookie jar eintragen lea 48(a0),a0 ;+6*8 positionieren _unjar: move.l resvecto,(a0)+ ;Reihenfolge move.l resvalid,(a0)+ ;und Lage wie unten! movea.l a0,a2 ;Position merken lea reshand(pc),a1 ;Resethandler moveq #copy_cnt,d0 c_loop: move.l (a1)+,(a0)+ ;kopieren dbf d0,c_loop move.l a0,membot ;neues membot addq #4,a3 ;m_start move.l a0,(a3)+ ;eintragen suba.l a6,a0 ;Platz move.l a0,d0 ;besorgen sub.l d0,(a3) ;neues m_length move.l a2,resvecto move.l #RESMAGIC,resvalid tell_it: lea msg_1(pc),a0 ;string bsr.s message move.l a5,d3 ;MPB bsr.s prt_hex lea msg_2(pc),a0 ;string message: pea (a0) ;string move #9,-(sp) ;Cconws trap #1 ;GEMDOS addq #6,sp rts * -------------------------------------------------- cconout: move d0,-(sp) ;char move #2,-(sp) ;Cconout trap #1 ;GEMDOS addq #4,sp rts * -------------------------------------------------- * Wort in d3 in Hex (als Text) auf Konsole ausgeben prt_hex: moveq #3,d7 ;4 mal nibble: rol #4,d3 ;jeweils ein Nibble move d3,d0 ;ans Ende rollen andi #$000f,d0 ;isolieren lea hextab(pc),a0 ;Hextabelle holen move.b 0(a0,d0.w),d0 ;und Zeichen bsr cconout ;ausgeben dbf d7,nibble ;weiter rts * -------------------------------------------------- vecsave: dc.l 0 ;Reihenfolge valsave: dc.l 0 ;und Lage beachten! reshand: clr.l p_cookie ;fĂŒr < TOS 1.6 clr bootdev ;von Floppy booten bei < TOS 1.6 move.l valsave(pc),resvalid move.l vecsave(pc),resvecto jmp (a6) copy_cnt = (* - reshand)/4 ;1 added in loop * -------------------------------------------------- hextab: dc.b '0123456789ABCDEF'
Bernd Rosenlecher