Forzar xc32-ld para colocar todo el código de la aplicación en kseg0_boot_mem

He escrito una aplicación de cargador de arranque PIC32MX. Me gustaría decirle al enlazador que lo coloque completamente en la memoria de arranque, de modo que todo el espacio del programa se mantenga para la aplicación final.

Actualmente, lo que creo que son las partes relevantes de mi .ldarchivo se ven así:

_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
}

Esta es la secuencia de comandos del enlazador generada por defecto, para un PIC32MX695F512H , aunque la longitud de algunas secciones puede haber cambiado; el diseño de la memoria del chip se encuentra en la página 61 de la hoja de datos.

¿Debería simplemente cambiar el ORIGINy LENGTHde kseg0_program_mema los valores de kseg0_boot_memy decirle al enlazador que permita secciones superpuestas? Eso no se siente tan limpio. ¿Hay alguna manera de decirle al enlazador que no coloque el código de la aplicación en kseg0_program_memsino en kseg0_boot_mem?

Acabo de leer sobre esto en este libro electrónico ; no puedo responderme a mí mismo, pero eche un vistazo a la página 44 y puede haber información útil.
Justo debajo de eso, probablemente tenga algo como ".text ORIGIN(kseg0_program_mem) :" que le dice al enlazador que cualquier cosa en la sección .text debe ubicarse en el segmento kseg0_program_mem. Esto no es algo que haya intentado, pero probablemente podría cambiarlo a kseg0_boot_mem en su lugar...
Entiendo preguntar aquí, pero hay algunas personas bastante decentes en el foro pic32 que entienden bien los enlazadores.

Respuestas (2)

El compilador de C colocará el código de inicio de tiempo de ejecución de C en el kseg0_boot_mem, que configura la pila, el montón y la inicialización general del procesador. La cantidad de código colocado kseg0_boot_memvariará entre una compilación de depuración y una de lanzamiento. Si no recuerdo mal, cuando estaba trabajando en un cargador de arranque para un PIC32MX250F, la compilación de depuración ocupaba ~70 % del kseg0_boot_mem, lo que no era suficiente para mi cargador de arranque.

Si su cargador de arranque es lo suficientemente pequeño como para caber junto kseg0_boot_memcon el código de inicio de C, reduzca el tamaño de kseg0_boot_memy luego muévalo kseg0_program_mema la parte superior del nuevo boot_memespacio. Tenga en cuenta que no puede mover la ubicación inicial del kseg0_boot_memespacio. La ejecución del código comienza en 0xBFC00000el PIC32 y no hay nada que pueda hacer para cambiar eso. Si desea mover todo el cargador de arranque, también deberá mover la tabla ISR. Por ejemplo:

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
}

NOTA: ¡este es solo un ejemplo de secuencia de comandos del cargador de arranque y de ninguna manera debe copiarse y pegarse en producción!

Dicho esto, puedo decir por experiencia que tratar de incluir un cargador de arranque no trivial en el boot_memespacio del programa no funciona. El espacio que queda del código de inicio de C generalmente no es suficiente, especialmente si desea un manejo y validación de errores pesados ​​(¡y sí, SI desea esto!). Eliminar las compilaciones de depuración del arsenal muy limitado de herramientas de depuración integradas tampoco es bueno. Deberá poder depurar en el hardware en algún momento en el futuro. Aprendí esa lección de la manera difícil.

Mi recomendación es dejar la kseg0_boot_memsección de código en paz y simplemente trabajar con el kseg0_program_memespacio. Tome una porción de la kseg0_program_memparte superior o inferior (no importa) y utilícela para el código del gestor de arranque y la tabla ISR. Deje algo de espacio para el crecimiento del código del gestor de arranque también. Tratar con múltiples secuencias de comandos de vinculación es un poco doloroso.

En lugar de hacerlo todo en el enlazador, también puede hacerlo de manera similar a esto

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*/

Luego, en su código, puede colocar cada función donde desee.

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
}

Además, tenga en cuenta que si no usa ninguna interrupción, puede ganar otro 0x1000 en el espacio. Por cierto, si esto no es un gestor de arranque en serie, no lo veo adecuado.