-1

I am using FreeRTOS on an ARM Cortex A9 CPU und I'm desperately trying to find out if it is possible to determin if the processor is executing a normal thread or an interrupt service routine. It is implemented in V7-a architecture.

I found some promising reference hinting the ICSR register (-> VECTACTIVE bits), but this only exist in the cortex M family. Is there a comparable register in the A family as well? I tried to read out the processor modes in the current processor status register (CPSR), but when read during an ISR I saw that the mode bits indicate supervisor mode rather than IRQ or FIQ mode.

Looks a lot like there is no way to determine in which state the processor is, but I wanted to ask anyway, maybe I missed something...

The processor has a pl390 General Interrupt Controller. Maybe it is possible to determine the if an interrupt has been triggered by reading some of it's registers?

If anybody can give me a clue I would be very greatfull!

Edit1: The IRQ Handler of FreeRTOS switches the processor to Superviser mode: enter image description here

And subsequently switches back to system mode: enter image description here

Can I just check if the processor is in supervisor mode and assume that this means that the execution takes place in an ISR, or are there other situations where the kernel may switches to supervisor mode, without being in an ISR?

Edit2: On request I'll add an overal background description of the solution that I want to achieve in the first place, by solving the problem of knowing the current execution context.

I'm writing a set of libraries for the CortexA9 and FreeRTOS that will access periphery. Amongst others I want to implement a library for the available HW timer from the processor's periphery.

In order to secure the access to the HW and to avoid multiple tasks trying to access the HW resource simultaneously I added Mutex Semaphores to the timer library implementation. The first thing the lib function does on call is to try to gain the Mutex. If it fails the function returns an error, otherwise it continouses its execution.

Lets focus on the function that starts the timer:

   static ret_val_e TmrStart(tmr_ctrl_t * pCtrl)
   {
   ret_val_e retVal = RET_ERR_DEF;
   BaseType_t  retVal_os = pdFAIL;
   XTtcPs * pHwTmrInstance = (XTtcPs *) pCtrl->pHwTmrInstance;

   //Check status of driver
   if(pCtrl == NULL)
   {
       return RET_ERR_TMR_CTRL_REF;
   }else if(!pCtrl->bInitialized )
   {
       return RET_ERR_TMR_UNINITIALIZED;
   }else
   {
       retVal_os = xSemaphoreTake(pCtrl->osSemMux_Tmr, INSTANCE_BUSY_ACCESS_DELAY_TICKS);

       if(retVal_os != pdPASS)
       {
           return RET_ERR_OS_SEM_MUX;
       }
   }

   //This function starts the timer
   XTtcPs_Start(pHwTmrInstance);

   (...)

Sometimes it can be helpful to start the timer directly inside an ISR. The problem that appears is that while the rest of function would support it, the SemaphoreTake() call MUST be changed to SemaphoreTakeFromISR() - moreover no wait ticks are supported when called from ISR in order to avoid a blocking ISR.

In order to achieve code that is suitable for both execution modes (thread mode and IRQ mode) we would need to change the function to first check the execution state and based on that invokes either SemaphoreTake() or SemaphoreTakeFromISR() before proceeding to access the HW.

That's the context of my question. As mentioned in the comments I do not want to implement this by adding a parameter that must be supplied by the user on every call which tells the function if it's been called from a thread or an ISR, as I want to keep the API as slim as possible.

I could take FreeRTOS approch and implement a copy of the TmrStart() function with the name TmrStartFromISR() which contains the the ISR specific calls to FreeRTOS's system resources. But I rather avoid that either as duplicating all my functions makes the code overall harder to maintain.

So determining the execution state by reading out some processor registers would be the only way that I can think of. But apparently the A9 does not supply this information easily unfortunately, unlike the M3 for example.

Another approch that just came to my mind could be to set a global variable in the assembler code of FreeRTOS that handles exeptions. In the portSAVE_CONTEXT it could be set and in the portRESTORE_CONTEXT it could be reset. The downside of this solution is that the library then would not work with the official A9 port of FreeRTOS which does not sound good either. Moreover you could get problems with race conditions if the variable is changed right after it has been checked by the lib function, but I guess this would also be a problem when reading the state from a processor registers directly... Probably one would need to enclose this check in a critical section that prevents interrupts for a short period of time.

If somebody sees some other solutions that I did not think of please do not hesitate to bring them up.

Also please feel free to discuss the solutions I brought up so far. I'd just like to find the best way to do it.

Thanks!

Stone
  • 33
  • 6
  • Take a look at the ARM architectural manual. You will be able to query the CPU state – doron Nov 15 '21 at 12:41
  • Your problem is a little unclear. The Mode bits [4:0] of the CPSR should identify the mode just fine. If you're using an operating system that causes user code to run unprivileged, you should expect 0x10 in those bits. Most other things indicate privilege. 0x12 and 0x11 indicate IRQ and FIQ respectively. – cooperised Nov 15 '21 at 14:33
  • I am already looking at the armv7-a architecture reference manual. It provides a table with the user modes, and I was expecting to see the user mode turn to IRQ or FIQ when in an ISR. But it was in Superviser mode instead. – Stone Nov 16 '21 at 14:11
  • Supervisor mode is an exception mode. Normally entered via an SVC call (which I think is only used to start the scheduler in your port). So I think as long as you check you are not in User or System mode you should be good (unless you are in a fault mode). – Realtime Rik Nov 16 '21 at 16:05

1 Answers1

0

On a Cortex-A processor, when an interrupt handler is triggered, the processor enters IRQ mode, with interrupts disabled. This is reflected in the state field of CPSR. IRQ mode is not suitable to receive nested interrupts, because if a second interrupt happened, the return address for the first interrupt would be overwritten. So, if an interrupt handler ever needs to re-enable interrupts, it must switch to supervisor mode first.

Generally, one of the first thing that an operating system's interrupt handler does is to switch to supervisor mode. By the time the code reaches a particular driver, the processor is in supervisor mode. So the behavior you're observing is perfectly normal.

A FreeRTOS interrupt handler is a C function. It runs with interrupts enabled, in supervisor mode. If you want to know whether your code is running in the context of an interrupt handler, never call the interrupt handler function directly, and when it calls auxiliary functions that care, pass a variable that indicates who the caller is.

void code_that_wants_to_know_who_called_it(int context) {
    if (context != 0)
        // called from an interrupt handler
    else
        // called from outside an interrupt handler
}

void my_handler1(void) {
    code_that_wants_to_know_who_called_it(1);
}
void my_handler2(void) {
    code_that_wants_to_know_who_called_it(1);
}

int main(void) {
    Install_Interrupt(EVENT1, my_handler1);
    Install_Interrupt(EVENT2, my_handler1);
    code_that_wants_to_know_who_called_it(0);
}
Gilles 'SO- stop being evil'
  • 104,111
  • 38
  • 209
  • 254
  • Thanks for your detailed response. I looked through the FreeRTOS IRQ Handler in assembler and found the line that switches the processor into supervisor mode! Please refer to the edit of my question for more details. – Stone Nov 16 '21 at 14:17
  • The problem regarding your suggested solution, is that I need to know the execution mode whilst executing inside a library function called by the user. And I really would like to avoid to have to trust the user to supply this context inside the ISR if possible. Therefore I would greatly prefer a solution that can determine the current execution mode on its own. – Stone Nov 16 '21 at 14:31
  • @Stone I'm familiar with arm processor modes but not with FreeRTOS. Normally system mode is only used for a short time when kernel code is accessing user data. However, FreeRTOS on Cortex-A always runs in privileged mode, and uses system mode to have a separate set of registers from SVC/IRQ/FIQ modes. So maybe system vs supervisor mode will give you what you want. I can't tell because I don't know FreeRTOS well enough and you haven't explained precisely what you want. “Currently servicing an interrupt” is an ambiguous concept and [you may be asking the wrong question](https://xyproblem.info/). – Gilles 'SO- stop being evil' Nov 16 '21 at 15:10
  • Okay, I'll step back and try to give a larger picture of the whole problem. I just did not want to blow-up the whole question in the first place, but maybe I'm really trying to solve a problem that won't help me with my first problem. Please refer to Edit2 in the original question. – Stone Nov 17 '21 at 10:10
  • @Stone I don't know for sure because you haven't updated the question yet as I write this, but I suspect this should be a different question. – Gilles 'SO- stop being evil' Nov 17 '21 at 10:45