Conmutador de contexto FreeRTOS ARM Cortex-M4

0

Estoy examinando el procedimiento de cambio de contexto en un procesador basado en ARM Cortex-M4 que ejecuta FreeRTOS. En port.c tenemos:

void xPortPendSVHandler( void )
{
    /* This is a naked function. */

    __asm volatile
    (
    "   mrs r0, psp                         \n"
    "   isb                                 \n"
    "                                       \n"
    "   ldr r3, pxCurrentTCBConst           \n" /* Get the location of the current TCB. */
    "   ldr r2, [r3]                        \n"
    "                                       \n"
    "   tst r14, #0x10                      \n" /* Is the task using the FPU context?  If so, push high vfp registers. */
    "   it eq                               \n"
    "   vstmdbeq r0!, {s16-s31}             \n"
    "                                       \n"
    "   stmdb r0!, {r4-r11, r14}            \n" /* Save the core registers. */
    "   str r0, [r2]                        \n" /* Save the new top of stack into the first member of the TCB. */
    "                                       \n"
    "   stmdb sp!, {r0, r3}                 \n"
    "   mov r0, %0                          \n"
    "   msr basepri, r0                     \n"
    "   dsb                                 \n"
    "   isb                                 \n"
    "   bl vTaskSwitchContext               \n"
    "   mov r0, #0                          \n"
    "   msr basepri, r0                     \n"
    "   ldmia sp!, {r0, r3}                 \n"
    "                                       \n"
    "   ldr r1, [r3]                        \n" /* The first item in pxCurrentTCB is the task top of stack. */
    "   ldr r0, [r1]                        \n"
    "                                       \n"
    "   ldmia r0!, {r4-r11, r14}            \n" /* Pop the core registers. */
    "                                       \n"
    "   tst r14, #0x10                      \n" /* Is the task using the FPU context?  If so, pop the high vfp registers too. */
    "   it eq                               \n"
    "   vldmiaeq r0!, {s16-s31}             \n"
    "                                       \n"
    "   msr psp, r0                         \n"
    "   isb                                 \n"
    "                                       \n"
    #ifdef WORKAROUND_PMU_CM001 /* XMC4000 specific errata workaround. */
        #if WORKAROUND_PMU_CM001 == 1
    "           push { r14 }                \n"
    "           pop { pc }                  \n"
        #endif
    #endif
    "                                       \n"
    "   bx r14                              \n"
    "                                       \n"
    "   .align 4                            \n"
    "pxCurrentTCBConst: .word pxCurrentTCB  \n"
    ::"i"(configMAX_SYSCALL_INTERRUPT_PRIORITY)
    );
}

En la primera mitad del código, el estado de la tarea actual se transfiere a su pila, luego se llama a vTaskSwitchContext. Aquí, el sistema decide si se necesita un cambio de contexto y obtiene el TCB de la siguiente tarea. Luego, el contexto se restaura cargando el valor de la pila. Según tengo entendido, el registro LR ahora debe contener el contador del programa de la nueva tarea. Con bx r14, este valor se carga en el contador del programa real. Cuando se tienen dos tareas A y B, el cambio de contexto está funcionando. Sin embargo, cuando examino el código utilizando GDB y salto a xPortPendSVHandler cuando se produce el cambio de A a B, el valor de R14 (LR) es 0xfffffffd, y no 0x8008700 (PC cuando se interrumpió la tarea). ¿En qué me estoy equivocando?

    
pregunta who93

1 respuesta

3

R14 (LR) no contiene la dirección a la que volver cuando se sale de una excepción (como lo ha encontrado), sino que contiene información sobre si se debe regresar al modo de controlador o subproceso, qué puntero de pila usar (msp o psp) , y si es un contexto de punto flotante.

Esto se detalla en la sección sobre Entrada y salida de excepciones en la guía del usuario genérica de Arm Cortex M4, página 2-28.

El contador del programa (entre otros) se colocó en la pila durante la entrada de excepciones, cuando el procesador deja el controlador de excepciones, saca la PC de la pila y continúa. En este caso, el puntero de pila utilizado se cambia durante la excepción, lo que permite que la tarea cambie.

    
respondido por el Colin

Lea otras preguntas en las etiquetas