Ich habe eine PIC32MX-Bootloader-Anwendung geschrieben. Ich möchte dem Linker mitteilen, dass er es vollständig in den Startspeicher legen soll, damit der gesamte Programmspeicher für die endgültige Anwendung erhalten bleibt.
Derzeit sehen die meiner Meinung nach relevanten Teile meiner .ld
Datei so aus:
_RESET_ADDR = 0xBFC00000;
_BEV_EXCPT_ADDR = (0xBFC00000 + 0x380);
_DBG_EXCPT_ADDR = (0xBFC00000 + 0x480);
_DBG_CODE_ADDR = 0xBFC02000;
_DBG_CODE_SIZE = 0xFF0 ;
_GEN_EXCPT_ADDR = _ebase_address + 0x180;
MEMORY
{
kseg0_program_mem (rx) : ORIGIN = 0x9D000000, LENGTH = 0x10000 /* All C Files will be located here */
kseg0_boot_mem : ORIGIN = 0x9FC00000, LENGTH = 0x1000 /* This memory region is dummy */
exception_mem : ORIGIN = 0x9FC01000, LENGTH = 0x200 /* Interrupt vector table */
config3 : ORIGIN = 0xBFC02FF0, LENGTH = 0x4
config2 : ORIGIN = 0xBFC02FF4, LENGTH = 0x4
config1 : ORIGIN = 0xBFC02FF8, LENGTH = 0x4
config0 : ORIGIN = 0xBFC02FFC, LENGTH = 0x4
kseg1_boot_mem : ORIGIN = 0xBFC00000, LENGTH = 0x2FF0 /* C Startup code */
kseg1_data_mem (w!x) : ORIGIN = 0xA0000000, LENGTH = 0x8000
sfrs : ORIGIN = 0xBF800000, LENGTH = 0x100000
debug_exec_mem : ORIGIN = 0xBFC02000, LENGTH = 0xFF0
configsfrs : ORIGIN = 0xBFC02FF0, LENGTH = 0x10
}
Dies ist das standardmäßig generierte Linker-Skript für einen PIC32MX695F512H , obwohl sich die Länge einiger Abschnitte möglicherweise geändert hat - das Speicherlayout des Chips befindet sich auf Seite 61 des Datenblatts.
ORIGIN
Soll ich einfach das and LENGTH
of kseg0_program_mem
in die Werte von ändern kseg0_boot_mem
und dem Linker mitteilen, dass er überlappende Abschnitte zulassen soll? Das fühlt sich nicht so sauber an. Gibt es eine Möglichkeit, dem Linker mitzuteilen, dass er den Anwendungscode nicht in, kseg0_program_mem
sondern in einfügen soll kseg0_boot_mem
?
Der C-Compiler platziert den Startcode der C-Laufzeit in der kseg0_boot_mem
, die den Stack, Heap und die allgemeine Prozessorinitialisierung einrichtet. Die Menge des eingefügten Codes kseg0_boot_mem
variiert zwischen einem Debug- und einem Release-Build. Wenn ich mich richtig erinnere, nahm der Debug-Build bei der Arbeit an einem Bootloader für einen PIC32MX250F ~ 70 % der kseg0_boot_mem
, was für meinen Bootloader nicht ausreichte.
Wenn Ihr Bootloader klein genug ist, um kseg0_boot_mem
zusammen mit dem C-Startcode in die zu passen, reduzieren Sie die Größe der kseg0_boot_mem
, und verschieben Sie kseg0_program_mem
sie dann über den neuen boot_mem
Platz. Beachten Sie, dass Sie die Startposition des kseg0_boot_mem
Raums nicht verschieben können. Die Codeausführung beginnt auf 0xBFC00000
dem PIC32, und Sie können nichts tun, um dies zu ändern. Wenn Sie den gesamten Bootloader verschieben möchten , müssen Sie auch die ISR-Tabelle verschieben. Zum Beispiel:
MEMORY
{
kseg0_program_mem (rx) : ORIGIN = 0xBFC01200, LENGTH = 0x1DF0 /* kseg1_boot is 2FF0 long.*/
kseg0_boot_mem : ORIGIN = 0x9FC00000, LENGTH = 0x1000 /* This memory region is dummy */
exception_mem : ORIGIN = 0xBFC01000, LENGTH = 0x200 /* Relocated ISR table. */
config3 : ORIGIN = 0xBFC02FF0, LENGTH = 0x4
config2 : ORIGIN = 0xBFC02FF4, LENGTH = 0x4
config1 : ORIGIN = 0xBFC02FF8, LENGTH = 0x4
config0 : ORIGIN = 0xBFC02FFC, LENGTH = 0x4
kseg1_boot_mem : ORIGIN = 0xBFC00000, LENGTH = 0x1000 /*This has been reduced in size. Was 0x2FF0*/
kseg1_data_mem (w!x) : ORIGIN = 0xA0000000, LENGTH = 0x8000
sfrs : ORIGIN = 0xBF800000, LENGTH = 0x100000
debug_exec_mem : ORIGIN = 0xBFC02000, LENGTH = 0xFF0
configsfrs : ORIGIN = 0xBFC02FF0, LENGTH = 0x10
}
HINWEIS: Dies ist nur ein Beispiel-Bootloader-Skript und sollte auf keinen Fall in die Produktion kopiert werden!
Vor diesem Hintergrund kann ich aus Erfahrung sagen, dass der Versuch, einen nicht trivialen Bootloader in den boot_mem
Programmbereich zu stopfen, nicht funktioniert. Der Platz, der vom C-Startcode übrig bleibt, reicht normalerweise nicht aus, insbesondere wenn Sie eine umfassende Fehlerbehandlung und Validierung wünschen (und ja, Sie wollen das!). Es ist auch nicht gut, die Debug-Builds aus dem sehr begrenzten Arsenal eingebetteter Debug-Tools zu entfernen. Sie müssen irgendwann in der Zukunft in der Lage sein, Hardware zu debuggen. Ich habe diese Lektion auf die harte Tour gelernt.
Meine Empfehlung ist, den kseg0_boot_mem
Codeabschnitt in Ruhe zu lassen und nur mit dem kseg0_program_mem
Leerzeichen zu arbeiten. Schnappen Sie sich ein Stück kseg0_program_mem
oben oder unten (egal) und verwenden Sie es für Ihren Bootloader-Code und Ihre ISR-Tabelle. Lassen Sie sich auch etwas Platz für das Wachstum des Bootloader-Codes. Der Umgang mit mehreren Linker-Skripten ist ein bisschen mühsam.
Anstatt das alles im Linker zu tun, können Sie es auch ähnlich machen
MEMORY
{
kseg0_program_mem (rx) : ORIGIN = 0x9D000000, LENGTH = 0x5000
bootverify_mem (rx) : ORIGIN = 0x9D03FFAC, LENGTH = 0x50
kseg0_boot_mem : ORIGIN = 0x9FC00490, LENGTH = 0xB70
exception_mem : ORIGIN = 0x9FC01000, LENGTH = 0x300
kseg2_boot_mem : ORIGIN = 0x9FC01380, LENGTH = 0xC80
kseg1_boot_mem : ORIGIN = 0xBFC00000, LENGTH = 0x490
debug_exec_mem : ORIGIN = 0xBFC02000, LENGTH = 0xFF0
config3 : ORIGIN = 0xBFC02FF0, LENGTH = 0x4
config2 : ORIGIN = 0xBFC02FF4, LENGTH = 0x4
config1 : ORIGIN = 0xBFC02FF8, LENGTH = 0x4
config0 : ORIGIN = 0xBFC02FFC, LENGTH = 0x4
kseg1_data_mem (w!x) : ORIGIN = 0xA0000000, LENGTH = 0x10000
sfrs : ORIGIN = 0xBF800000, LENGTH = 0x100000
configsfrs : ORIGIN = 0xBFC02FF0, LENGTH = 0x10
}
SECTIONS
{
.config_BFC02FF0 0xBFC02FF0 : {
KEEP(*(.config_BFC02FF0))
} > config3
.config_BFC02FF4 : {
KEEP(*(.config_BFC02FF4))
} > config2
.config_BFC02FF8 : {
KEEP(*(.config_BFC02FF8))
} > config1
.config_BFC02FFC : {
KEEP(*(.config_BFC02FFC))
} > config0
}
PROVIDE(_DBG_CODE_ADDR = 0xBFC02000) ;
PROVIDE(_DBG_CODE_SIZE = 0xFF0) ;
SECTIONS
{
.extra_prgm_mem :
{
*(extra_prgm_mem)
} >kseg0_boot_mem
.extra_prgm_mem2 :
{
KEEP(*(extra_prgm_mem2))
} >kseg2_boot_mem
/*Linker continued*/
Dann können Sie in Ihrem Code jede Funktion an die gewünschte Stelle setzen.
int __attribute__ ((section ("extra_prgm_mem2")))GetVersion(char * Info){
int Result = (Info[4] - '0') * 1000;
Result += ((Info[5] - '0') * 100);
Result += ((Info[6] - '0') * 10);
Result += Info[7] - '0';
}
BOOL __attribute__ ((section ("extra_prgm_mem")))BLMedia_LoadEncryptedFile(char *file_name) {
//Function info
}
Beachten Sie auch, dass Sie weitere 0x1000 im Raum gewinnen können, wenn Sie keine Interrupts verwenden. Übrigens, wenn dies kein serieller Bootloader ist, sehe ich es nicht passend.
Roger Rowland
brhans
Erik Friesen