Synchonisation in Trustzone secure world by callbacks to non-secure world

@aggarg @OliM

One idea to allow FreeRTOS to validate interrupt priorities of secure interrupts would be to add secureportEND_SWITCHING_ISR() to secure_port_macros.h. This macro could validate the interrupt priorities because it would run on the secure side at the same interstating depth as the ISR itself (meaning IPSR is still valid).

Existing applications calling portEND_SWITCHING_ISR() (not the new secure version) from a secure ISR would be unaffected. Those applications would continue to function properly, but they would not magically gain validation of interrupt priorities from secure ISRs.

Obviously this is an API change, but so far I canā€™t think of a way around changing the API. In its own right itā€™s actually a good API change I think.

The secure ISR cannot call FreeRTOS APIs or portEND_SWITCHING_ISR directly as FreeRTOS runs in the non-secure world. The OP called a non-secure function from the secure ISR which called FreeRTOS APIs:

  Secure ISR         |         Non-Secure Function
                     |        called from secure ISR
                     |
+------------+       |      +------------+
|            |       |      |            |
| 1. Call Non-secure |      |  2. xSemaphoreGiveFromISR
|  function  |       |      |            |
|            |       |      |  3. portEND_SWITCHING_ISR
|            |       |      |            |
|            |       |      |            |
+------------+       |      +------------+
                     |
                     |

If we want to implement secureportEND_SWITCHING_ISR, the non-secure function should still do the same -

  Secure ISR                      |         Non-Secure Function
                                  |        called from secure ISR
                                  |
+------------+                    |      +------------+
|            |                    |      |            |
| 1. Call Non-secure              |      |  2. xSemaphoreGiveFromISR
|  function  |                    |      |            |
|            |                    |      |  3. portEND_SWITCHING_ISR
|            |                    |      |            |
| 4. secureportEND_SWITCHING_ISR  |      |            |
|            |                    |      |            |
+------------+                    |      +------------+
                                  |
                                  |

If secureportEND_SWITCHING_ISR only validates interrupt priorities, then all is good. If we also pend the non-secure PendSV from the secureportEND_SWITCHING_ISR, we do not need to worry whether the non-secure function called portEND_SWITCHING_ISR or not (Need to verify that pending PendSV twice does not make the PendSV handler run twice).

I donā€™t think such a function will help much. If someone is aware of the secure ISR breaking anything he will adapt the priority. If he isnā€™t, heā€™ll probably also not call the extra port function which would tell him that.
I think making securePort_DePrioritieNSExceptions()` a configuration option is the more straight forward solution.

For debugging, maybe a directly callable assert to ā€œcheck ISR pirorityā€, defined in both secure and unsecure world, could help, but thatā€™s probably not a FreeRTOS feature.

@OliM As Gaurav mentions, the developer cannot call portEND_SWITCHING_ISR() from the secure context of the secure ISR. But they definitely might try. If the developer attempts to call portEND_SWITCHING_ISR() from the secure context of the secure ISR, they will get an exception at runtime because that macro raises the current-security-context version of PendSV, which would be the secure PendSV, which has no handler. Can you confirm that? That error might guide the developer to find secureportEND_SWITCHING_ISR(), or it might guide the developer to write a nonsecure function that calls portEND_SWITCHING_ISR() (like the one in Gauravā€™s examples). Both are OK, but secureportEND_SWITCHING_ISR() would be preferred due to the priority checking.

Updated documentation and updated examples would also guide the developer toward secureportEND_SWITCHING_ISR().

@aggarg I agree on all points. If we decide secureportEND_SWITCHING_ISR() is the way to go, the nonsecure function called by the secure ISR would not need to call portEND_SWITCHING_ISR(). Instead, the nonsecure function would take parameter &xWasHigherPriorityTaskWoken as all the FromISR() functions already do. That pattern would be the same whether the secure ISR calls a custom nonsecure function or directly to a FreeRTOS nonsecure function.

  Secure ISR                      |         Non-Secure Function
                                  |        called from secure ISR
                                  |
+------------+                    |      +------------+
|            |                    |      |            |
| 1. Call Non-secure              |      |  2. xSemaphoreGiveFromISR
|  function  |                    |      |            |
|            |                    |      |            |
| 3. secureportEND_SWITCHING_ISR  |      |            |
|            |                    |      |            |
+------------+                    |      +------------+
                                  |
                                  |

And then the most familiar form of all becomes ideal:

  Secure ISR

+------------+
|            |
| 1. Call xSemaphoreGiveFromISR
|            |
| 2. secureportEND_SWITCHING_ISR
|            |
+------------+

(with xSemaphoreGiveFromISR running on the nonsecure side of course)

This works because secureportEND_SWITCHING_ISR() would raise the nonsecure PendSV. And if the developer provides a custom nonsecure function that also calls portEND_SWITCHING_ISR(), no harm done. PendSV wonā€™t run twice.

This is a piece I might be misunderstanding. Can you help me understand this better? How can the developer call their own non-secure function from the secure ISR, but they cannot call a non-secure FreeRTOS function from the secure ISR?

EDIT: I think Iā€™ve answered my own question. Passing &xWasHigherPriorityTaskWoken to the FreeRTOS API function wouldnā€™t work because it would refer to memory on the secure main stack. That memory should be marked as secure access only, thus preventing the non-secure API function from writing to it. I think Iā€™m ready to give up on the secureportEND_SWITCHING_ISR() idea because it really cannot fit the existing usage pattern for portEND_SWITCHING_ISR().

Yup, that is the reason!

What do you think about the above? In other words, have asecureportVALIDATE_INTERRUPT_PRIORITY which people can optionally call from secure ISR to incorrect secure interrupt priority configurations.

This would be OK, but looking ahead it would become deprecated in the future if the port ever facilitates access to the nonsecure FreeRTOS API functions from the secure side. That future seems likely to me. In that case, access to the nonsecure API would likely include interrupt-priority checks and eliminate the need for secureportVALIDATE_INTERRUPT_PRIORITY().