Page 1 of 1

Why to jump to _port_exit_from_isr from _port_irq_epilogue?

Posted: Tue Nov 01, 2016 7:13 pm
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.

Re: Why to jump to _port_exit_from_isr from _port_irq_epilogue?

Posted: Tue Nov 01, 2016 10:16 pm
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

Re: Why to jump to _port_exit_from_isr from _port_irq_epilogue?

Posted: Wed Nov 02, 2016 11:02 am
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.

Re: Why to jump to _port_exit_from_isr from _port_irq_epilogue?

Posted: Wed Nov 02, 2016 11:10 am
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