intctx and extctx

ChibiOS public support forum for topics related to the STMicroelectronics STM32 family of micro-controllers.

Moderator: RoccoMarco

Post Reply
swinchen
Posts: 18
Joined: Tue May 15, 2012 8:44 pm

intctx and extctx

Post by swinchen »

Hi everyone,

So I have spent the last few evenings really trying to learn how the ARM port of ChibiOS works. I am a bit hung up on the use of extctx. Here is my understanding of the two ctx structures:

extctx (External Context?): The are the registers a function is allowed to clobber. After a call to a function or method they may be different so the compiler is in charge of adding the correct prologue and epilogue to save these registers in use (hence it's name.. external). In order for all of these registers to be saved by the prologue all of them would have to be in use so this structure is really a worst-case representation of the stack.

intctx (Internal Context?): These are the registers that are expected to be the same after a function call. ChibiOS saves these internally in the port_switch function (hence the name Internal). These registers are ALWAYS saved during a contect switch, therefore the number of registers and their order is fixed.

Does that sound correct? If so this is the problem I have(the wording is a bit tricky... sorry): SVCallVector and PendSVVector both increment the PSP by the size of an extctx, and seem to use a value (the FPU Condition Code Register) from the structure. How is it known that those values were actually stored at that location on the stack? I am not really sure what the SVC and PendSV vectors are for, but this is seems strange to me. I have included the code that is giving me trouble:

Code: Select all

#if !CORTEX_SIMPLIFIED_PRIORITY || defined(__DOXYGEN__)
/**
 * @brief   SVC vector.
 * @details The SVC vector is used for exception mode re-entering after a
 *          context switch.
 * @note    The PendSV vector is only used in advanced kernel mode.
 */
void SVCallVector(void) {
  struct extctx *ctxp;

  /* Current PSP value.*/
  asm volatile ("mrs     %0, PSP" : "=r" (ctxp) : : "memory");

  /* Discarding the current exception context and positioning the stack to
     point to the real one.*/
  ctxp++;

#if CORTEX_USE_FPU
  /* Restoring the special register SCB_FPCCR.*/
  SCB_FPCCR = (uint32_t)ctxp->fpccr;
  SCB_FPCAR = SCB_FPCAR + sizeof (struct extctx);
#endif
  asm volatile ("msr     PSP, %0" : : "r" (ctxp) : "memory");
  port_unlock_from_isr();
}
#endif /* !CORTEX_SIMPLIFIED_PRIORITY */

#if CORTEX_SIMPLIFIED_PRIORITY || defined(__DOXYGEN__)
/**
 * @brief   PendSV vector.
 * @details The PendSV vector is used for exception mode re-entering after a
 *          context switch.
 * @note    The PendSV vector is only used in compact kernel mode.
 */
void PendSVVector(void) {
  struct extctx *ctxp;

  /* Current PSP value.*/
  asm volatile ("mrs     %0, PSP" : "=r" (ctxp) : : "memory");

  /* Discarding the current exception context and positioning the stack to
     point to the real one.*/
  ctxp++;

#if CORTEX_USE_FPU
  /* Restoring the special register SCB_FPCCR.*/
  SCB_FPCCR = (uint32_t)ctxp->fpccr;
  SCB_FPCAR = SCB_FPCAR + sizeof (struct extctx);
#endif
  asm volatile ("msr     PSP, %0" : : "r" (ctxp) : "memory");
}
#endif /* CORTEX_SIMPLIFIED_PRIORITY */


Thanks for your time!
Sam
User avatar
Giovanni
Site Admin
Posts: 14891
Joined: Wed May 27, 2009 8:48 am
Has thanked: 1202 times
Been thanked: 996 times

Re: intctx and extctx

Post by Giovanni »

Hi,

It is correct, extctx is also the stack frame that ISRs push on the stack, this is done in HW in the Cortex-M architecture.

The code you posted is the most complex bit in the ARMCMx port, it implements a way to perform the context switching out of exception context so, when exiting the last ISR of an ISR chain:

- On ISR exit a fake extctx context is pushed in order to make the ISR return on a specific bit of code where context switch is performed.
- A SVC exception is triggered, in the handler the SVC exception context is removed, the SVC will never return.
- The SVC exception returns where the original exception was meant to return.

Other ports are way more simple than this one.

Giovanni
swinchen
Posts: 18
Joined: Tue May 15, 2012 8:44 pm

Re: intctx and extctx

Post by swinchen »

I believe you that this is the most complicated part!

So this is what I see from the code:

At the end of an interrupt PORT_IRQ_EPILOGUE() creates a space for an ISR stack frame (the "fake" frame) and makes sure the bit to indicate Thumb execution is set. It then checks to see another thread has higher priority and if so sets the pc in the "fake" context to _port_switch_from_isr() and save some FPU stuff (I haven't really looked at the FPU stuff), otherwise set the pc in the "fake" context to _port_exit_from_isr() and returns to one of these function. So if a preemption was required it does the rescheduling then executes the SVC instructions (or not, depending on CORTEX_SIMPLIFIED_PRIORITY) And forces PendSV to pending. If the svc instruction was executed then SVCallVector interrupts the current ISR (creating a new extctx). SVCallVector removes that context, leaving the PSP pointing to the fake frame created earlier. This function returns to the current thread (ISR is over).

UGH!? Am I even close?

I am a little confused on PendSV executes. If CORTEX_SIMPLIFIED_PRIORITY is not set then SVCallVector is executed... does this prevent PendSV from occurring?

Boy, I sure hope I am close... that is really hard to wrap your mind around. Especially with preemption a possibility.

Thanks,
Sam
User avatar
Giovanni
Site Admin
Posts: 14891
Joined: Wed May 27, 2009 8:48 am
Has thanked: 1202 times
Been thanked: 996 times

Re: intctx and extctx

Post by Giovanni »

Hi,

You are correct, it is the single piece of code that I have rewritten most times too because it is very critical for the overall RTOS performance, the FPU bits made it even more complex...

About CORTEX_SIMPLIFIED_PRIORITY, when this mode is enabled SVC is not used for reentering the exception mode, PENDSV is used to do exactly the same thing.
The reason is that SVC can have a priority that goes from 0 to N-1, when interrupts are disabled (CORTEX_SIMPLIFIED_PRIORITY does exactly that, disables all interrupts rather than partially masking them which is the normal mode) the priority mask level is zero so attempting to execute SVC would result in a priority violation, PENDSV has a priority of -1 so can be used in that context.

Giovanni
Post Reply