Hi,
was macht eigentlich ein ARM-Prozessor, wenn er den Opcode 0xFFFFFFFF im
Flash findet? Und was bei 0x00000000?
Macht es einen Unterschied, ob der ARM im Thumb Modus ist oder nicht?
Was sollte man sinnvollerweise ins Flash schreiben, wenn man einen
(Soft-) Reset auslösen möchte, falls der Programm Counter (warum auch
immer) in einen "leeren" Flash-Bereich springt?
Thumb:
0000 left shift by R0 into R0 -> NOP -> Bus-/Hardfault am
FlashEnde
FFFF der 2. Teil einer Befehlssequenz "Branch mit 23Bit offset"
vermutlich per Hardfault beende.
ARM:
00000000 illegale Bitkombination -> Hardfault
FFFFFFFF SWI Never -> NOP -> Bus-/Hardfault am FlashEnde
-> endet immer in einer Exception und scheint vorher höchsten Zyklen zu
verbrauchen, aber nichts Böses anzustellen.
Ok, danke. Naja, das durch den Flash durch-"NOPpen" will ich genau
vermeiden. Könnte ja gut sein, dass da noch Code oder Daten kommen.
Damit wäre das Verhalten dann komplett undefiniert.
Ich würde den Linker gerne anleiten, die leeren Flash-Bereiche mit etwas
sinnvollem vollzuschreiben, das am besten direkt einen Reset auslöst
oder zumindest auf Adresse 0 springt. Eine Sequenz scheidet aus, falls
der Controller da mittenrein springt.
Was wäre da geeignet?
Na bei Thumb einfach "leeren Flash" oder FF.
Bei ARM wird das schwieriger, weil F in den obersten 4 Bit (condition
code) immer "Never" bedeutet. Aber in μC-Umfeld ist ARM-Code im Flash ja
eher selten.
Du gehst also davon aus, daß der an beliebige Stellen des Flashes
springt, und da soll dann hinterher etwas definiertes wie z.B. ein
Reset ausgeführt werden, korrekt?
Ich würde sagen das ist ein Fall für einen Watchdog.
Denn wenn Du schon davon ausgehst, daß der an beliebige Stellen im
unbenutzten Teil des Flash springen kann, was soll ihn dann davon
abhalten stattdessen an die von Deinem Code verwendeten Stelle zu
springen? Ich sehe da keinen Unterschied. In Deinem normalen Code wirst
Du nicht ständig Resets ausführen wollen.
Nimm einen Watchdog und bau um den Rücksetzmechanismus dafür enge
Plausibilitätstests ein.
Wenn Du wirklich von beliebigen Sprüngen im Code ausgehst, könnte der
theoretisch direkt an die Stelle mit dem Zurücksetzen des Watchdogs
springen. Vermutlich könntest Du das mit der Memory Protection Unit
nochmal extra sichern. Ich hab mich damit aber noch nicht im Detail
beschäftigt. Evtl. hilft auch ein externer Watchdog oder 2 die sich
gegenseitig überwachen.
Gerhard schrieb:> Was sollte man sinnvollerweise ins Flash schreiben, wenn man einen> (Soft-) Reset auslösen möchte, falls der Programm Counter (warum auch> immer) in einen "leeren" Flash-Bereich springt?
Ich muß mich zurückhalten!
Er macht nur das, was du ihm befiehlst.
Also mach es.
Wenn der Programmzeiger in den luftleeren Raum springt, crasht das
Programm sowieso. Es ist völlig egal was der Prozessor damit macht. Sei
froh, wenn Du eine Exception bekommst, damit kannst Du immerhin einen
Reset auslösen oder die gesteuerte Schaltung in einen sicheren Zustand
versetzen. Unter Windoofs ist das diese berühmte allgemeine
Schutzverletzung.
Gerhard schrieb:> Ich würde den Linker gerne anleiten, die leeren Flash-Bereiche mit etwas> sinnvollem vollzuschreiben, das am besten direkt einen Reset auslöst> oder zumindest auf Adresse 0 springt.> ...> Was wäre da geeignet?
Warum fragst du dann, was der Prozessor bei 0xFFFFFFFF oder 0x00000000
anstellt, wenn du ganz was anderes wissen möchtest?
Gerhard schrieb:> Was sollte man sinnvollerweise ins Flash schreiben, wenn man einen> (Soft-) Reset auslösen möchte, falls der Programm Counter (warum auch> immer) in einen "leeren" Flash-Bereich springt?
Nett wäre ein Breakpoint-Befehl. Normalerweise ergibt das eine Exception
oder man landet im Debigger (jedenfalls beim Cortex M3). Angeblich gibt
es auch offiziell undefinierte Opcodes:
https://stackoverflow.com/questions/16081618/programmatically-cause-undefined-instruction-exception
Carl D. schrieb:> FFFFFFFF SWI Never -> NOP -> Bus-/Hardfault am FlashEnde
In ARMv3 und ARMv4 steht cond=1111 nicht mehr für NEVER, sondern für
UNPREDICTABLE. Ab ARMv5 werden damit Befehle ohne Bedingung codiert
(z.B. VFP), wobei der Code 0xFFFFFFFF UNDEFINED ist.
Sapperlot W. schrieb:> Eine rhetorische Frage : Wie macht man das, dass der Controller in einen> unprogrammierten Bereich springt ?
Man zerlegt sich die auf dem Stack gesicherte Return-Adresse durch
Pufferüberlauf.
Markus F. schrieb:> Ich würde mein Hirnschmalz lieber in ein stabiles, verlässliches> Programm stecken als in die smarte Rettung aus einem schampig> hingerotzten.
Genau, und wenn man niemals Fehler macht, braucht man auch keine
zeitraubenden Tests.
Wie man das hinkriegt?
push müll
ret
oder
function crash
push a
push b
[..]
pop c
pop b
pop a
ret
Das war's dann.
Oder es führt zum Festhängen des Controllers falls der Watchdog
deaktiviert ist. Aber hast trotzdem Recht, insofern nichts an der
Schaltung Schaden nimmt, gibts dann einen User-getriggerten Reset.
Das Problem ist ja auch, daß der Controller irgendwann den Stack am Ende
des RAM ausführen möchte wenn keine exception ausgelöst wird. Das führt
dann wieder zu undefiniertem Verhalten.
Man könnte sich behelfen, wenn man den kompletten freien Flash mit
jmp reset oder jmp what_to_do_if_program_crashed
oder so vollschreibt. Dann bewirkt ein Einspringen in freie
Flash-Bereiche z.B. einen sofortigen Reset.
Wie wahrscheinlich ist es denn, daß die CPU bei einem Sprung an eine
zufällige Adresse überhaupt im Programmflash landet? Das Flash mit
seinen paar (hundert) kB ist doch verschwindend klein gegenüber dem
4GB-Adressraum.
Hm die Frage wäre ob Du dann eine Exception bekommst weil die CPU weiß,
daß an dieser Stelle "nicht angeschlossen" ist... Ansonsten sind das
einfach unbelegte Adressleitungen, sprich Du landest wieder irgendwo im
vorhandenen Speicher, der durch die belegten Adressleitungen
angesprochen wird.
Natürlich wird die Software ordentlich entwickelt und getestet. Und es
gibt auch einen Watchdog. Aber es verstößt gegen die Grundregeln der
Kunst, eine (fast) kostenlose Maßnahme NICHT zu treffen.
Ich habe beim Reverse-Engineering auch schon 0xDEADCODE oder 0xDEADBEEF
in unbenutzten Blöcken gefunden statt 0xFFFFFF. Ohne zu wissen, zu
welchen Instruktionen das jetzt disassemblieren würde und ob es eine
gute Wahl war. Es zeigt aber, dass jemand das Linker-File angefasst und
sich Gedanken gemacht hat.