Is it save to determine the execution mode (Thread mode or ISR) based on the ARM processor modes?

Hello,
I would like to be able to determine if my code is currently being executed from a task or an ISR. I need it decide during runtime if I should call SemaphoreTake() or SemaphoreTakeFromISR(). Some ports implement the function

“portFORCE_INLINE static BaseType_t xPortIsInsideInterrupt( void )”

for this purpose.

Unfortunately the ARM Cortex A9 does not.

As far as I know apparently there is no easy method to find out the currect execution state. I found some promising reference hinting the ICSR register (-> VECTACTIVE bits), but this only exist in the cortex M family.

But maybe it is enough to check the current ARM processor mode bits inside the CPSR. The FreeRTOS_IRQ_Handler() in the portASM.S switches to supervisor mode (SVC_MODE) before calling the ISR and back to system mode (SYS_MODE) on exit.

.align 4
.type FreeRTOS_IRQ_Handler, %function
FreeRTOS_IRQ_Handler:
	/* Return to the interrupted instruction. */
	SUB		lr, lr, #4

	/* Push the return address and SPSR. */
	PUSH	{lr}
	MRS		lr, SPSR
	PUSH	{lr}

	/* Change to supervisor mode to allow reentry. */
	CPS		#SVC_MODE
 
       (...)

.macro portSAVE_CONTEXT

	/* Save the LR and SPSR onto the system mode stack before switching to
	system mode to save the remaining system mode registers. */
	SRSDB	sp!, #SYS_MODE
	CPS		#SYS_MODE
        (...)

Using the function below one could determin if the processor is currently in supervisor mode and thus tell that the user code was called from an ISR if it is assured that the only time FreeRTOS executes user code in supervisor mode happens during an ISR.

portFORCE_INLINE static BaseType_t xPortIsInsideInterrupt( void )
{
	uint32_t ulCurrentInterrupt;
	BaseType_t xReturn;

	/* Obtain the number of the currently executing interrupt. */
	__asm volatile ( "MRS %0, CPSR"												
					: "=r" ( ulCurrentInterrupt )	
					:								
					:"memory" );					


	ulCurrentInterrupt &= 0b11111UL;

	if( (ulCurrentInterrupt == 10011)		//Supervisor Mode
	{
		xReturn = pdTRUE;
	}
	else
	{
		xReturn = pdFALSE;
	}

	return xReturn;
}

Therefore I wanted to ask if somebody can confirm to me that this is the case?
I did not find code that hints that the supervisor mode is used while a task is executed but maybe I overlooked something.

Thanks a lot for your time!

I wouldn’t rely on it; if for no other reason than the reason that future releases of the MCU may change their behavior as long as it’s not officially documented.

I ca see where you come from. It’s really helpful to be able to have abstractions for these kinds of things. Yet come to think of it: Aside from GIVING resources such as semaphores, there is not much semantically compatible behavior within FreeRTOS APIs that would benefit. In the example you provide above, for example (taking semaphores), the difference is far beyond simply calling one or the other: In tasks, you typically suspend yourself until the resource is available, whereas in ISRs, you can only check for semaphore availability and resume anyways. Thus, the code branch that is taken after the check for ISR is drastically different.

There is a function for this on the Cortex-M because that architecture includes the interrupt controller. Cortex-A on the other hand uses an external interrupt controller - so it is not the same from device to device. A lot of Cortex-A parts also separately use ARM’s interrupt controller (generic interrupt controller, or GIC), other use a proprietary interrupt controller. At least in the case of the GIC I think you can just read the interrupt priority level register to know if you are in an interrupt or not (from memory), and I assume proprietary interrupt controllers will have an equivalent.

1 Like

Can you not use ICC_RPR (Interrupt Controller Running Priority Register) in GIC?

Thanks.

1 Like

Thanks for the numerous replies. It sounds like a good possibility to read out the Running Priority Register. Altough the datasheet states that “If there is no active interrupt on the CPU interface, the value returned is the Idle priority.”
Is it possible to assign an interrupt the idle priority?
And wouldn’t this lead to failing to recognize if an interrupt is currently executed or not?

If you read the idle priority then an interrupt is not executing. If you read anything else then an interrupt is not executing.

1 Like

I guess you wanted to say that if I read anything else, then an interrupt is executing.
Thanks for your help!

No, it is not. The following is from the GIC architecture specification:

The idle priority, 0xFF, is the running priority read from ICC_RPR_EL1 on the CPU
interface when no interrupts are active on that interface.

The GIC always masks an interrupt that has the lowest supported priority.
1 Like

Great! Thanks for providing this coverage.