Stapelfehler beim Springen vom Bootloader zur Anwendung

Ich versuche seit einiger Zeit, von meinem Bootloader zu einer Anwendung zu springen, aber ich kann nicht herausfinden, was schief läuft. Ich hoffe, dass mir hier vielleicht jemand helfen kann.
Ich verwende CC2652 von Texas Instruments und Code Composer Studio von Texas Instruments, um den Bootloader zu entwickeln und zu flashen. Der folgende Code ist der Code, den ich verwende, um zur Anwendung zu springen.

void startApp(uint32_t prgEntry) {
    static uint32_t temp;
    temp = prgEntry;
    // Reset the stack pointer,
    temp +=4;
    asm(" LDR SP, [R0, #0x0] ");
    ((void (*)(void))(*((uint32_t*)temp)))();
}

Wenn ich diesen Code ausführe, lande ich im FaultISR. Hier kann ich den Debugger verwenden, um mir die Register anzusehen. Im CFSR (Configurable Fault Status Register) sehe ich, dass die Bits STKERR und IUSERR gesetzt sind.

prgEntry ist in diesem Fall 0x2E000. Ich habe diese Adresse als Start der Anwendung in den Linker-Befehlsdateien sowohl des Bootloaders als auch der Anwendung definiert. Ich habe die Befehlsdateien weiter unten kopiert.

Die Anwendung, zu der ich zu springen versuche, wird zuerst im Intel-Hex-Format auf das Gerät hochgeladen und sieht so aus: https://pastebin.com/DAerFkXr . Texas Instruments hat eine Flash Programmer-Anwendung für Windows, mit der ich eine Reihe von Adressen aus dem internen Flash des Geräts lesen kann. Ich bin die Intel-Hex-Datei von Hand durchgegangen und habe sie mit dem verglichen, was ich in der Flash Programmer-Anwendung gesehen habe, und ich glaube, dass alles an der richtigen Stelle abgelegt ist. Ich habe einen Screenshot der Ausgabe des Flash-Programmierers unter den Befehlsdateien gepostet.

Wenn ich die Anwendung mit Code Composer Studio ohne meinen Bootloader auf das Gerät flashe, kann ich sehen, dass die Anwendung normal ausgeführt wird, sodass ich weiß, dass es kein Problem mit der Anwendung gibt.

Anwendungsbefehlsdatei:

--stack_size=1024   /* C stack is also used for ISR stack */

--heap_size=256

/* Retain interrupt vector table variable                                    */
--retain=g_pfnVectors
/* Override default entry point.                                             */
--entry_point resetISR
/* Allow main() to take args                                                 */
--args 0x8
/* Suppress warnings and errors:                                             */
/* - 10063: Warning about entry point not being _c_int00                     */
/* - 16011, 16012: 8-byte alignment errors. Observed when linking in object  */
/*   files compiled using Keil (ARM compiler)                                */
--diag_suppress=10063,16011,16012

#define BOOT_BASE               0x0
#define BOOT_SIZE               0x8000
#define FLASH_BASE              0x2E000
#define FLASH_SIZE              0x2A000
#define RAM_BASE                0x20000000
#define RAM_SIZE                0x14000
#define GPRAM_BASE              0x11000000
#define GPRAM_SIZE              0x2000


/* System memory map */

MEMORY
{
    /* Application stored in and executes from internal flash */
    FLASH (RX) : origin = FLASH_BASE, length = FLASH_SIZE
    /* Application uses internal RAM for data */
    SRAM (RWX) : origin = RAM_BASE, length = RAM_SIZE
    /* Application can use GPRAM region as RAM if cache is disabled in the CCFG
    (DEFAULT_CCFG_SIZE_AND_DIS_FLAGS.SET_CCFG_SIZE_AND_DIS_FLAGS_DIS_GPRAM = 0) */
    GPRAM (RWX): origin = GPRAM_BASE, length = GPRAM_SIZE
}

/* Section allocation in memory */

SECTIONS
{
    .intvecs        :   > FLASH_BASE
    .text           :   > FLASH
    .TI.ramfunc     : {} load=FLASH, run=SRAM, table(BINIT)
    .const          :   > FLASH
    .constdata      :   > FLASH
    .rodata         :   > FLASH
    .binit          :   > FLASH
    .cinit          :   > FLASH
    .pinit          :   > FLASH
    .init_array     :   > FLASH
    .emb_text       :   > FLASH
    .ccfg           :   > FLASH (HIGH)

    .vtable         :   > SRAM
    .vtable_ram     :   > SRAM
     vtable_ram     :   > SRAM
    .data           :   > SRAM
    .bss            :   > SRAM
    .sysmem         :   > SRAM
    .stack          :   > SRAM (HIGH)
    .nonretenvar    :   > SRAM

    .gpram          :   > GPRAM
}

Bootloader-Befehlsdatei:

--stack_size=1024   /* C stack is also used for ISR stack */

--heap_size=256

/* Retain interrupt vector table variable                                    */
--retain=g_pfnVectors
/* Override default entry point.                                             */
--entry_point resetISR
/* Allow main() to take args                                                 */
--args 0x8
/* Suppress warnings and errors:                                             */
/* - 10063: Warning about entry point not being _c_int00                     */
/* - 16011, 16012: 8-byte alignment errors. Observed when linking in object  */
/*   files compiled using Keil (ARM compiler)                                */
--diag_suppress=10063,16011,16012

#define BOOT_BASE               0x0
#define BOOT_SIZE               0x8000
#define FLASH_BASE              0x2E000
#define FLASH_SIZE              0x2A000
#define RAM_BASE                0x20000000
#define RAM_SIZE                0x14000
#define GPRAM_BASE              0x11000000
#define GPRAM_SIZE              0x2000


/* System memory map */

MEMORY
{
    /* The bootloader will be stored and executed from this location in internal flash */
    BOOT (RX)  : origin = BOOT_BASE, length = BOOT_SIZE
    /* Application stored in and executes from internal flash */
    FLASH (RX) : origin = FLASH_BASE, length = FLASH_SIZE
    /* Application uses internal RAM for data */
    SRAM (RWX) : origin = RAM_BASE, length = RAM_SIZE
    /* Application can use GPRAM region as RAM if cache is disabled in the CCFG
    (DEFAULT_CCFG_SIZE_AND_DIS_FLAGS.SET_CCFG_SIZE_AND_DIS_FLAGS_DIS_GPRAM = 0) */
    GPRAM (RWX): origin = GPRAM_BASE, length = GPRAM_SIZE
}


/* Section allocation in memory */

SECTIONS
{
    .intvecs        :   > BOOT_BASE
    .text           :   > BOOT
    .TI.ramfunc     : {} load=BOOT, run=SRAM, table(BINIT)
    .const          :   > BOOT
    .constdata      :   > BOOT
    .rodata         :   > BOOT
    .binit          :   > BOOT
    .cinit          :   > BOOT
    .pinit          :   > BOOT
    .init_array     :   > BOOT
    .emb_text       :   > BOOT
    .ccfg           :   > BOOT (HIGH)

    .vtable         :   > SRAM
    .vtable_ram     :   > SRAM
     vtable_ram     :   > SRAM
    .data           :   > SRAM
    .bss            :   > SRAM
    .sysmem         :   > SRAM
    .stack          :   > SRAM (HIGH)
    .nonretenvar    :   > SRAM

    .gpram          :   > GPRAM
}

Screenshot vom Flash-Programmierer:

Beschreibung von STKERR: Stacking von Ausnahme hat einen oder mehrere Busfehler verursacht. Der SP wird immer noch angepasst und die Werte im Kontextbereich auf dem Stack sind möglicherweise falsch. BFAR wird nicht geschrieben.

Beschreibung von IBUSERR: Befehlsbus-Fehlerflag. Dieses Flag wird durch einen Prefetch-Fehler gesetzt. Der Fehler stoppt bei der Anweisung, sodass kein Fehler auftritt, wenn der Fehler unter einem Zweigschatten auftritt. BFAR wird nicht geschrieben.

Bearbeiten:
Dies ist die Disassemblierung der startApp-Funktion:

void startApp(uint32_t prgEntry) {
startApp():
    push       {r3, r14}
    str        r0, [r13]
temp = prgEntry;
    ldr        r1, [pc, #0x18]
    ldr        r0, [r13]
    str        r0, [r1]
temp +=4;
    ldr        r1, [pc, #0x14]
    ldr        r0, [r1]
    adds       r0, r0, #4
    str        r0, [r1]
asm(" LDR SP, [R0, #0x0] ");
    ldr.w      r13, [r0]
((void (*)(void))(*((uint32_t*)temp)))();
    ldr        r0, [pc, #8]
    ldr        r0, [r0]
    ldr        r0, [r0]
    blx        r0
}
Sie müssen zerlegen startAppund sehen, was los ist, und dann sehen, ob der generierte Maschinencode mit der Aufrufkonvention Ihres speziellen Compilers übereinstimmt. Im Allgemeinen existiert C-Code nicht in einem vorhersagbaren Zustand, bis der SP initialisiert ist, noch existiert er in derselben Funktion wie der Code, der den SP manuell einstellt.
@lundin Ich habe die Disassemblierung der startApp-Funktion hinzugefügt. Sehen Sie, ob etwas daran nicht stimmt? Ich bin neu in diesem Bereich und habe keine Ahnung von Montage.
Ich kenne diese Anrufkonvention nicht. Wenn Sie das auch nicht wissen, geht nichts - das müssen Sie in der Compiler-Dokumentation studieren. Sie können nicht einfach eine ganze Zahl in einen Funktionszeiger umwandeln und ihn aufrufen.
@lundin Diese Funktion wurde direkt aus dem Boot Image Manager-Beispiel übernommen, das von Texas Instruments für dieses Board bereitgestellt wurde. Ich denke also, diese Funktion sollte einfach funktionieren, oder? Ich habe den prgEntry natürlich so geändert, dass er auf die erste Adresse der Firmware zeigt.

Antworten (1)

Ich denke, Sie sollten diesen Code in Einzelschritten durchlaufen, um zu sehen, was R0direkt vor der LDR SP, [R0]. Denken Sie daran, dass der Wert in R0als Adresse interpretiert wird und die Anweisung holt, was auch immer an dieser Adresse ist, und es in den Stapelzeiger schiebt.

Es scheint mir, dass Ihr Code den Wert 0x0002E004 nimmt und als Adresse verwendet. Welcher Wert auch immer bei 0x0002E004 gespeichert ist, wird dann im Stapelzeiger gespeichert. Ist das so beabsichtigt?

Je nach Endianess sieht es so aus, als ob der SP 0x1F1F1F00 oder 0x001F1F1F bekommt.

Das ist in der Tat so, aber nicht das, was ich beabsichtigt habe. Können Sie mir sagen, wie ich es so ändern kann, dass es auf die Adresse zeigt und nicht auf den an der Adresse gespeicherten Wert? Ich bin ziemlich neu in der Montage.
Der übliche Vorgang zum Abrufen eines Werts, der an einer beliebigen Adresse im Speicher gespeichert ist, erfordert zwei LDR-Befehle. Der erste LDR verwendet den wörtlichen Adressierungsmodus, um die Adresse der Daten abzurufen. Die Adresse würde im Programmspeicher zwischen Funktionen irgendwo in der Nähe des LDR-Befehls gespeichert werden. Die wörtliche Adressierung wird dann zur PC-relativen Adressierung. Sobald Sie die Adresse der Daten abgerufen haben, ruft ein zweiter LDR, der diese Adresse verwendet, den tatsächlichen Wert der Daten ab.
Ich konnte es stattdessen mit "mov SP, R0" beheben und das auch für den PC verwenden. Dies scheint das Problem STKERR und IBUSERR zu beheben, und mit dem Debugger kann ich jetzt alle Schritte in der Anwendung, die ich lade, durchgehen, aber ich lande immer noch in FaultISR(), schließlich mit einem PRECISERR und mit 0xFFFFFFE0 in BFAR. Es ist also nicht ganz behoben, aber es hat mir geholfen.