xc32-ld zwingen, den gesamten Anwendungscode in kseg0_boot_mem zu platzieren

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 .ldDatei 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.

ORIGINSoll ich einfach das and LENGTHof kseg0_program_memin die Werte von ändern kseg0_boot_memund 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_memsondern in einfügen soll kseg0_boot_mem?

Ich habe gerade darüber in diesem E-Book gelesen – ich kann es mir nicht selbst beantworten, aber schau dich auf Seite 44 um und es könnte nützliche Informationen geben.
Direkt darunter haben Sie wahrscheinlich so etwas wie ".text ORIGIN(kseg0_program_mem) :", das dem Linker mitteilt, dass sich alles im Abschnitt .text im Segment kseg0_program_mem befinden sollte. Das habe ich nicht versucht, aber Sie könnten das wahrscheinlich stattdessen in kseg0_boot_mem ändern ...
Ich verstehe, hier zu fragen, aber es gibt einige ziemlich anständige Leute im pic32-Forum, die Linker gut verstehen.

Antworten (2)

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_memvariiert 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_memzusammen mit dem C-Startcode in die zu passen, reduzieren Sie die Größe der kseg0_boot_mem, und verschieben Sie kseg0_program_memsie dann über den neuen boot_memPlatz. Beachten Sie, dass Sie die Startposition des kseg0_boot_memRaums nicht verschieben können. Die Codeausführung beginnt auf 0xBFC00000dem 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_memProgrammbereich 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_memCodeabschnitt in Ruhe zu lassen und nur mit dem kseg0_program_memLeerzeichen zu arbeiten. Schnappen Sie sich ein Stück kseg0_program_memoben 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.