Why to jump to _port_exit_from_isr from _port_irq_epilogue?

Discussions and support about ChibiOS/RT, the free embedded RTOS.
Post Reply
ceisendle
Posts: 2
Joined: Tue Nov 01, 2016 7:01 pm

Why to jump to _port_exit_from_isr from _port_irq_epilogue?

Post by ceisendle »

Hi,

maybe a stupid question but during review of the irq_epilogue code (for ARM v6m - chcore_v6m.c) I recognized that even in case no rescheduling is required (chSchIsPreemptionRequired() returns false) the artificial return from ISR is used, so in fact on exit of an ISR and even if no rescheduling is required, the CPU enters _port_exit_from_isr when leaving the ISR. In _port_exit_from_isr the only thing which is done is to enter exception mode again (via NMI or PendSV) to re-adjust the context. Why is this done, i don't really see a need? Why not directly returning back to the interrupted task? So the code i'm thinking of would be:

Code: Select all

void _port_irq_epilogue(regarm_t lr) {

  if (lr != (regarm_t)0xFFFFFFF1U) {
    struct port_extctx *ctxp;

    port_lock_from_isr();
    if (chSchIsPreemptionRequired()) {
      /* Preemption is required we need to enforce a context switch.*/
      /* The extctx structure is pointed by the PSP register.*/
      ctxp = (struct port_extctx *)__get_PSP();

      /* Adding an artificial exception return context, there is no need to
      populate it fully.*/
      ctxp--;

      /* Writing back the modified PSP value.*/
      __set_PSP((uint32_t)ctxp);

      /* Setting up a fake XPSR register value.*/
      ctxp->xpsr = (regarm_t)0x01000000;
      ctxp->pc = (regarm_t)_port_switch_from_isr;
      /* Note, returning without unlocking is intentional, this is done in
         order to keep the rest of the context switch atomic.*/
    }
    else {
      /* Preemption not required, we use normal ISR return.*/
         port_unlock_from_isr();
    }
  }
}


This would make exit from ISR faster in case no re-scheduling is required.

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

Re: Why to jump to _port_exit_from_isr from _port_irq_epilogue?

Post by Giovanni »

Hi,

Not a stupid question, it is something that caused a lot of problems before I found a reliable solution.

You could be preempted by another, higher priority, IRQ after unlocking and before exception return. The reschedule check would not be performed for the preempting IRQ. This is why we perform the whole sequence anyway.

The problem is that Cortex-M has no way to atomically return form an exception AND re-enable IRQs. I wish they thought about this.

Giovanni
ceisendle
Posts: 2
Joined: Tue Nov 01, 2016 7:01 pm

Re: Why to jump to _port_exit_from_isr from _port_irq_epilogue?

Post by ceisendle »

Wow.. tricky race-condition. But couldn't this be solved by removing the

Code: Select all

 if (lr != (regarm_t)0xFFFFFFF1U) 
check? Ok, this might create problems when chSchIsPreemptionRequired() returns true, then ctxp is decremented two times - it would require another state variable in the task context to avoid this - also not really nice..

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

Re: Why to jump to _port_exit_from_isr from _port_irq_epilogue?

Post by Giovanni »

Hi,

The switch must happen only when returning from the outer exception frame when the exception stack is empty, failing to do that would cause the system to switch to another thread while the stack is not empty and not all exception-return operations performed.

On a side note, the port originally did just return after re-enabling interrupts, when we implemented the IRQ-storm test the bug become evident, not even a rare occurrence.

Giovanni
Post Reply