You are on page 1of 11

Understanding FreeRTOS SVC_Handler

In this article Let me explain the SVC Handler of FreeRTOS. The SVC Handler is
used to launch the first task on to the CPU.

The SVC Handler is triggered due to the execution of SVC instruction.

The SVC instruction will be executed when you call xTaskStartScheduler()


Function .

The xTaskStartScheduler() finally ends up in executing SVC instruction and as


a result SVC handler will be called and there we schedule the very first task
on to the CPU.

After that SVC is not used at all. Because after that, Task Switching in and
switching out, that is context switching is carried out by the PendSV handler,
which you already studied in the previous article.

Alright, this is the SVC handler code you will find in port.c
Let’s understand this function line by line.

" ldr R3, pxCurrentTCB \n"

" ldr R1, [R3] \n"

As you already know from the previous article on PendSV handler,


pxCurrentTCB is a global TCB pointer which points to the TCB of the Currently
selected Task to run.

Let’s assume as shown in the image below.

So, R3 = 0x20000000 and R1 = 0x20001108

" ldr R0, [R1] \n"

Here, we are de-referencing the TCB and storing the first element that is
nothing but top of the stack to R0.

So, RO = an address which is nothing but top of current Task's stack memory.

" ldmia R0!, {r4-R11, R14} \n"

Alright, now we know that, RO contains top of the stack address isn’t it ?

Now, using that stack address pop out R4 to R11.

You may have the doubt, why are we popping first?

Where did we do push first?

To understand this you have to go through another function in port.c . i. e the


below one .
This function says that,” Simulate the stack frame as it would be created by a
context switch interrupt“.

Not very clear ? Don’t worry let me explain.

When the task is created using xTaskCreate() API, you know that both TCB
and stack space is allocated for that tasks.

And xTaskCreate() later calls this function pxPortInitialiseStack()

What this function does is, it will add a dummy stack frame to the stack
memory of the created Task.

But, what’s a stack frame?

First let’s understand that, please check the image below,


When processor hits with an interrupt or internal system exception like SVC,
PendSV,etc, the processor's operation mode is changed to "handler " mode
in ARM cortex M processor.

And processor automatically pushes all the above registers on to the stack ,
pointed by SP.

And remember that by default SP is nothing but MSP and after that processor
will enter in to the interrupt or exception handler.

When processor is done with the exception handler, it will pop back this stack
frame from stack and resumes from the point where it left , before coming in
to the handler.

Students who are enrolled to my first course may already know these
concepts because i covered it in my first course i.e "Embedded systems
programming on ARM cortex M3/M4 processor"

If you have not enrolled for that course, then don’t worry, if you have any
doubt on these concepts, please reach out to me, because i cannot cover
all those concepts in this article.

Now, let’s apply this concept to our situation.

In our case processor is hit with SVC, that’s a system exception right?

So, before processor coming to SVC handler, it must have pushed the above
shown stack frame on to the stack pointed by MSP .

Correct?? Great !!!

Now, let’s say, our SVC_handler is just an empty handler like below, just
instructions, then processor will come and execute some NOP instructions,
then it exits from the handler, right ? Great!
Now, Ask yourself! Processor exits to resume where?

Yes! Of course, it will exit and resume from the point where it got interrupted
right? That is nothing but instruction after the SVC .

That address is already saved in the stack frame.

But, now our requirement is when this SVC handler returns/exits , it should
execute our task function , it should not go to the above mentioned Return
address.

How to do that? That is how we can go to our task function, once we exit
from this handler. ???

For that a dummy stack frame “trick” is being used to confuse the processor!

The dummy stack frame will be added to the stack in the below function!!!
This function puts the dummy stack frame on to the stack of the task, pointed
by TCB’s first member.

Remember?? TCBs fist member contains an address which is top of the stack
of the task.

Observe the above line in the function, pxCode is nothing but address of the
Task function. That means, this stack frame contains Task’s Task Function as
the Return address.

Great !!!

So, when the task is created its stack is already will be having a dummy stack
frame.
So, finally, when the function pxPortInitialiseStack() returns , this is how stack
of that Task looks.

That’s why we use the below instruction, to pop from R4 to R11 and also R14.

ldmia R0!, {r4-R11, R14}

Great, so this is the kernel stack as well as Task’s stack state at this point

Before ldmia R0!, {r4-R11, R14}


After ldmia R0!, {r4-R11, R14}
Now, did you observe on thing here?, LR(R14) value is 0Xfffffff9 in kernel stack
space but it is 0xFFFFFFFD in Task’s stack space.

The reason our dummy stack frame contains the value 0Xfffffffd is because,

"When this SVC handler exits, the processor will be forced to use PSP to POP
out the stack frame”.

So, before exiting this handler, we need to initialize the PSP. Right ?

That’s why the next instruction !!!.

" msr psp, R0 \n"

So, now PSP is holding the address of top of the stack. (That is nothing but
address of the last item on the stack)

Let’s move a head!

" mov R0, #0 \n"

" msr basepri, R0 \n"

Here, we are disabling all the exceptions!


" bx R14 \n"

Return from the SVC handler, the processor will now end up in executing our
task function! That’s how you just made Processor landing in to your Task
Function! During and after return, processor will use PSP as the SP.

Great!! That’s how the SVC handler launches our first tasks.

Note 1: I have omitted explaining “ISB” instruction. Please read


from here

http://infocenter.arm.com/help/index.jsp?topic=/com.arm.doc.d
ui0552a/CHDEBIEG.html

Note 2: I have omitted explaining BASEPRI register. Please read


from here

http://infocenter.arm.com/help/index.jsp?topic=/com.arm.doc.d
ui0553a/CHDBIBGJ.html

Note 3: If you have any doubts or if you find any mistakes in the
article, kindly report it to me.

You might also like