Hallo,
ich stehe gerade vor folgendem Problem und würde mich über einige
Anregungen freuen und zwar entwickle ich gerade auf einem ARM Cortex M3,
und zwar ein STM32 und bin gerade dabei einen schon vorhandenen
Bootloader auf eine kryptographisch gesicherte Version umzubauen also
AES256 und HMAC mit SHA1, der Krypto Code und alles laufen auch aber
jetzt würde ich das ganze gerne dahingehend optmieren, dass Applikation
und Bootloader die Kryptofunktionen gemeinsam nutzen und in Zukunft
vielleicht auch noch SPI oder sonst was von der Treiberschicht. Denn die
Krypto Funktionen sind ca 6KB groß und die will ich nur ungern doppelt
hineinkompilieren weil sie die Applikation auch braucht und die sich eh
nicht mehr ändern werden.
Soweit so gut, nur wie geht das am einfachsten? Was mir mal so einfallen
würde:
1) Beides gemeinsam kompilieren, Sections für Bootloader+Lib und
Hauptapplikation, könnte dann auch den NVIC Table sharen. Gefällt mir
recht gut, aber wie mach ich das mit den Sections für initialisierte
Variablen, nicht initialisierten Variablen, globalen Variablen, die
müssen ja für den Bootloader+Libs teil auch wenn ich an der Applikation
schraube immer unverändert bleiben. Für den Code geht das ja einfach,
aber globale Variablen und der Initialisierungsteil machen mir da
Sorgen?
2) getrennt kompilieren, so ca wie ich es jetzt mache, dann müsste ich
aber auch irgendwie schauen, dass sich globale Variablen nicht
überschneiden, die Initialisierung könnt ich mir sparen weil beim
Bootloader teil die globalen Sachen eh immer neu initialisiert werden,
vielleicht wärs auch eine Optione alle globalen Variablen bei der Krypto
Lib zu vermeiden, macht vieles einfacher. Aber wie sag ich dann meiner
Hauptapplikation beim Linken wo sie die Funktionen findet?
würde mich über einige Anregungen dazu freuen,
mfg
thomas
Ich würde einen festen Einsprungvektor bauen, der immer auf die
gleiche Adresse geladen wird. Von dort wird im Bootloader auf die
eigentliche Funktion gesprungen. Globale Variablen sollten diese
Funktionen komplett meiden, dann bist du das Problem ebenfalls los.
(Der Bootloader selbst kann natürlich globale Variablen benutzen,
wenn er läuft, läuft ja die Applikation nicht.)
Die Adressen des Einsprungvektors kannst du über passend zurecht
gebogene Zeiger in einer Headerdatei deiner Applikation zur
Verfügung stellen, ungefähr so:
1
typedefint(*foo_t)(constchar*);
2
staticconstfoo_tfoo=(foo_t)0x1234;
Die Applikation kann dann daher kommen und foo() wie eine ganz
normale Funktion behandeln:
danke erstmal für die Anregung. Ich glaub ich werde es so machen:
Bootloader+Lib und Applikation+Lib getrennt kompilieren.
Alles was gemeinsam verwendet wird werde ich als statische Lib
kompilieren und mittels Linker Script in eine eigene Section legen, hier
muss ich nur noch schauen, dass auch alle Teile der Lib gelinkt werden
bzw dass nur ein *.o in der Lib ist, sollte soweit ich gesehen habe aber
mit dem use Attribut bei Funktionen gehen. Bei der Hauptapplikation werd
ich dann beim erstellen wieder die section mit ojb-copy aus dem Hex/Bin
file rauslöschen.
Sollte das so funktionieren?
Weiß nicht, ich find's reichlich umständlich und fehleranfälliger
als die Sache mit dem Einsprungvektor. Spätestens, wenn du nach
einiger Zeit die nächste Version des Bootloaders implementieren
musst und dann "im Feld" zwei verschiedene Versionen mit verschiedenen
Adressen für die Bibliotheksfunktionen hast, wirst du mächtig ins
Rudern kommen.
Hmm, naja das mit den verschiedenen Adressen, wenn sich der Bootloader
ändert kann ich ja so oder so nicht beeinflussen, da muss ich die
Vektoren auch anpassen. Aber wenn ich Applikation und Bootloader immer
gegen die selbe Lib linke, muss ich mir die Vektoren nicht aus dem Map
File saugen. Sondern ich bekomm sie beim Linken automatisch.
Man kann Bootloader und Applikation nicht zusammen manschen, das geht in
die Hose.
Der Bootloader könnte einen SW-Interrupt benutzen und dort nen API-Call
eintragen.
Und die Applikation ruft dann mit Funktionsnummer das API auf und kriegt
nen Returnwert über den Erfolg.
Dazu müssen aber die API-Funktionen so geschrieben werden, daß sie
keinen RAM belegen.
Alle temporären Variablen müssen auf dem Stack abgelegt werden.
Benötigt das API statische Variablen, müssen die von der Applikation mit
einen API-Init Call angelegt werden. Z.B. es wird der Pointer auf malloc
übergeben damit das API es aufrufen kann.
Peter
Thomas H schrieb:
> aber>> jetzt würde ich das ganze gerne dahingehend optmieren, dass Applikation>> und Bootloader die Kryptofunktionen gemeinsam nutzen und in Zukunft>> vielleicht auch noch SPI oder sonst was von der Treiberschicht.
Man kann sowas gut via Software Interrupt lösen. Der Bootloader
installiert entsprechende Crypto-Funktionen über den Software Interrupt
Handler, die Anwendung erzeugt dann einfach einen Software Interrupt zum
Ausführen dieser Funktionen. Bin mir aber nur nicht sicher ob ARM Cortex
M3 sowas bietet
Thomas H schrieb:
> Hmm, naja das mit den verschiedenen Adressen, wenn sich der Bootloader> ändert kann ich ja so oder so nicht beeinflussen
Du hast das immer noch nicht verstanden.
Du baust einen Einsprungvektor auf eine feste Adresse (bspw. ganz
an den Anfang oder kurz vor das Ende des Bootloaders). Dessen
Adresse ändert sich nie wieder und die Reihenfolge seiner Einträge
auch nicht. Die Applikation kennt damit ausschließlich diese
Adressen.
Dieser Vektor wiederum verzweigt auf die tatsächlichen Adressen im
Bootloader, mit einfachen Sprüngen. Die werden dann vom Linker
aufgelöst (beim Linken des Bootloaders). Wenn sich in einer nächsten
Version des Bootloaders diese Sprünge ändern, interessiert das die
Applikation kein bisschen.
klaus schrieb:
> Man kann sowas gut via Software Interrupt lösen. Der Bootloader> installiert entsprechende Crypto-Funktionen über den Software Interrupt> Handler, die Anwendung erzeugt dann einfach einen Software Interrupt zum> Ausführen dieser Funktionen. Bin mir aber nur nicht sicher ob ARM Cortex> M3 sowas bietet
Natürlich gibt es beim Cortex-M3 auch Software Interrupts, die bei ARM
jetzt generell SuperVisor Call (SVC) genannt werden. Die alte
Bezeichnung führte wahrscheinlich zu Verwechslungen mit Software
Triggered Interrupts (STI), die einen ganz anderen Mechanismus
verwenden.
Die Frage ist, was die Applikation machen soll. Soll sie eventuell
eigene SVC bereitstellen? Dann wird das mit den SVC im boot loader
schwierig (man könnte auf STI ausweichen, falls vorhanden). Ansonsten
ist das mit SVC eine saubere Sache.
Ein anderer Ansatz wäre es, die API Funktionen mit dem boot loader in
einen definierten Speicherbereich zu linken, und deren Adressen beim
späteren Linken der Applikation zu laden (--just_symbols)
Gruß
Marcus