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

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
Aus: ST-Computer 07 / 1991, Seite 132

Links

Copyright-Bestimmungen: siehe Über diese Seite