Benutzung von resload_Protect#?
Theorie
Es gibt viele Situationen, bei denen es sehr hilfreich wäre informiert zu werden, wenn das installierte Programm auf bestimmte Speicherzellen zugreift. Mithilfe der resload_Protect#? Funktionen ist es möglich, bestimmte Speicherbereiche vor dem Lesen und/oder Schreiben durch den Prozessor zu schützen. Schützen meint dabei, dass jeder Zugriff auf ein solcherart markierten Bereich eine "Access Fault" Exception auslöst, die in einem Fehlerrequester von WHDLoad angezeigt wird. Wenn ein Speicherbereich durch resload_Protect#? geschützt wird, verändert WHDLoad die entsprechenden Kachel-Descriptoren im MMU-Übersetzungsbaum. Dadurch generiert jeder Zugriff auf eine geschützte Kachel durch den Prozessor eine "Access Fault" Exception. Der Exception-Handler im WHDLoad prüft den Grund für jede Exception. Wenn der Grund ein Zugriff auf eine geschützte Kachel war, aber die zugegriffene Adresse nicht in einem geschützten Bereich lag, wird der Zugriff emuliert und die normale Programmausführung fortgesetzt. Ansonsten wird das installierte Programm mit einem entsprechendem Fehlerrequester beendet. Zugriffe des Instruction-Stream (d.h. Zugriffe bei denen Prozessorcode geladen wird) werden immer emuliert, oder mit anderen Worten: die resload_Protect#? Funktionen überwachen nur das Schreiben und Lesen von Daten.
Dadurch, dass jeder Zugriff auf eine geschützte Kachel (Kachelgröße gegenwärtig $1000 Byte) ein "Access Fault" generiert auch wenn der geschützte Bereich nur eine Größe von einem Byte hat, bedingt eine starke Verlangsamung der Ablaufgeschwindigkeit des installierten Programmes. Insbesondere wenn sich Programmcode auf derselben Kachel befindet. Wenn das installierte Programm sehr von seiner Ausführungsgeschwindigkeit abhängt, können sich Unterschiede in der Ausführung ergeben. Es kann auch sein, dass einige Programme deshalb nicht mit resload_Protect zusammen arbeiten.
Beispiel: Codeprüfsummen
Wenn ein Spiel mit WHDLoad installiert werden soll, muss die original Laderoutine so verändert werden, dass sie nun WHDLoad nutzt um die Spieldaten zu laden. Einige Spiele verwenden Prüfsummen über Codebereiche um festzustellen, ob der ursprüngliche Code verändert worden ist. Solche Prüfsummenroutinen sind manchmal nicht leicht zu finden. Unter Verwendung der resload_Protect#? Funktionen in WHDLoad ist dies aber ganz einfach! Alles was man tun sollte, ist die veränderten Bytes mit Leseschutz zu versehen. Dadurch erzeugt jede Routine, die versucht eine Prüfsumme zu berechnen indem sie die geänderten Bytes liest, eine "Access Fault" Exception. Womit die entsprechende Routine identifiziert ist.
Einschränkungen
Die Kachel, auf den der SSP zeigt, darf nicht geschützt werden. Falls dies doch getan wird und eine Exception auftritt, führt dies zu einem "Double Bus Fault", weil der Prozessor nicht in der Lage ist das Exception Stackframe zu schreiben. Nach einem "Double Bus Fault" ist nur noch ein Hardwarereset möglich. WHDLoad prüft beim Setzen des geschützten Bereiches ob dieser sich mit dem aktuellen SSP überdeckt. Wenn dies der Fall ist, beendet es sich mit einer entsprechenden Fehlermeldung. Das hilft aber natürlich nicht wenn sich der SSP später ändert.
- 68020 + 68851
- diese Hardware wird gegenwärtig nicht unterstützt
- 68030
- 3-Byte Operationen werden nicht unterstützt und resultieren in einem "Access Fault", solche Operationen treten auf, wenn versucht wird auf ein Langwort an einer ungeraden Kachelgrenze zuzugreifen (z.B. "
tst.l ($fff)
", wenn die Kachel ab Adresse $1000 geschützt wurde), da dies auf einem 68000 nicht erlaubt ist, dürfte das kaum Praxisrelevant sein
- "locked" Operationen ausgelöst durch
tas
, cas
oder cas2
werden nicht unterstützt und resultieren in einem "Access Fault", dies ist kein Problem da "locked" Operationen von der Amiga-Hardware ohnehin nicht unterstützt werden
- 68040
- diese Hardware wird gegenwärtig nicht unterstützt
- 68060
- nicht ausgerichtete Datenzugriffe werden nicht unterstützt und resultieren in einem "Access Fault", ein nicht ausgerichteter Zugriff ist ein Zugriff welcher über zwei Kacheln reicht (und mindestens eine davon geschützt ist), zum Beispiel betrifft "
tst.l ($ffe)
" sowohl die Kachel $0..$fff als auch die Kachel $1000..$1fff, diese Einschränkung kann ein Problem sein und in bestimmten Fällen den Einsatz der resload_Protect Funktionen unmöglich machen, möglicherweise wird diese Einschränkung in einer späteren Version behoben
- nicht ausgerichtete Codezugriffe resultieren in einem "Access Fault", wenn beide betroffenen Kacheln geschützt sind, in der Regel sollten sich solche Konstellationen vermeiden lassen
- "locked" Operationen ausgelöst durch
tas
oder cas
werden nicht unterstützt und resultieren in einem "Access Fault", dies ist kein Problem da "locked" Operationen von der Amiga-Hardware ohnehin nicht unterstützt werden
- Instruktionen die auf einer geschützten Kachel liegen (und deshalb emuliert werden) und auf den Supervisor Teil des Status Registers zugreifen, werden abweichend ausgeführt, für diese Instruktionen ist das Trace-Bit immer 1 und die Interruptprioritätsmaske immer 7, falls die Instruktion versucht den Supervisor Teil des Status Registers zu verändern, bleibt das ohne Auswirkung (d.h. der Supervisor Teil bleibt unverändert)
movem
Instruktionen können auf einen geschützten Bereich zugreifen, ohne dass eine "Access Fault" Exception ausgelöst wird, dies ist möglich da nur der erste Speichertransfer (erstes Wort oder Langwort) auf Übereinstimmung mit dem geschützten Bereich überprüft wird
move16
und Operationen mit doppelter Genauigkeit (FPU) werden nicht unterstützt und resultieren in einem "Access Fault"
- ein "
move (mem),(mem)
" mit überlappender Quell- und Zieladresse, welcher eine Exception wegen nicht ausgerichteter Adresse erzeugt, wird fehlerhaft ausgeführt, zum Beispiel "move.l ($ffc),($ffe)
" mit der geschützten Kachel $1000..$1fff mit dem Speicher ($ffc)=$11112222, ($1000)=$33334444 vor der Ausführung enthält danach ($1000)=$11114444 und nicht $22224444