Skip to main content
Myasu.1
Associate III
March 6, 2022
Solved

INVPC occurs when SVC Handler returns

I use STM32F1 Value Line Discovery Kit.

​

I want to write SVC handler.

If I implement the following, invpc occurs when running 「POP PC�?in Line 38.

Caller
--------------------------------
 __asm volatile(" SVC %0 \n" : : "I" (2));
 __asm volatile(" NOP \n");
--------------------------------
 
Callee
--------------------------------
void SVC_Handler(void)
{
 __asm volatile(" TST LR, #0x4 \n"); /* Test EXC_RETURN number in LR bit 2 */
 __asm volatile(" ITE EQ \n"); /* if zero (equal) then */
 __asm volatile(" MRSEQ R1, MSP \n"); /* Main Stack was used, put MSP in R0 */
 __asm volatile(" MRSNE R1, PSP \n"); /* else, Process Stack was used, put MSP in R0 */
 __asm volatile(" LDR R0, [R1, #0] \n"); /* Get stacked R0 from stack */
 __asm volatile(" LDR R1, [R1, #24] \n"); /* Get stacked PC from stack */
 __asm volatile(" LDRB R1, [R1, #-2] \n"); /* Get the immidiate data from the instruction */
 __asm volatile(" PUSH {R7} \n");
 __asm volatile(" CBNZ R1, svc_handler_1 \n");
 __asm volatile(" BL tmp \n");
 __asm volatile(" B svc_handler_end \n");
 __asm volatile("svc_handler_1: \n");
 __asm volatile(" CMP R1, #1 \n");
 __asm volatile(" BNE svc_handler_2 \n");
 __asm volatile(" BL tmp \n");
 __asm volatile(" B svc_handler_end \n");
 __asm volatile("svc_handler_2: \n");
 __asm volatile(" CMP R1, #2 \n");
 __asm volatile(" BNE svc_handler_3 \n");
 __asm volatile(" BL tmp \n");
 __asm volatile(" B svc_handler_end \n");
 __asm volatile("svc_handler_3: \n");
 __asm volatile(" CMP R1, #3 \n");
 __asm volatile(" BNE svc_handler_end \n");
 __asm volatile(" BL tmp \n");
 __asm volatile(" B svc_handler_end \n");
 __asm volatile("svc_handler_end: \n");
 __asm volatile(" POP PC \n");
}
 
void tmp(void)
{
 
}
--------------------------------

​Could you please tell me the solution?

This topic has been closed for replies.
Tesla DeLorean
Tesla DeLoreanBest answer
Guru
March 7, 2022

Why are you even pushing R7? It's like you copied some other code.

Not sure I'd write in-line assembler this way.

Look at what code the compiler actually generates, and walk that, making sure it's doing what you actually expect/want. The MCU is just going to try and execute what it is encountering, and you get to be responsible for register usages, and bracketing push/pop usage on the stack.

Watch for what the compilers is doing for prologue/epilogue code for the function, or if you need more control of that via "naked" or equivalent directives.

Tips, Buy me a coffee, or three.. PayPal Venmo (See Profile) Up vote any posts that you find helpful, it shows what's working..

4 replies

Tesla DeLorean
Guru
March 6, 2022

>>If I implement the following, invpc occurs when running 「POP PC�?in Line 38.

No doubt

Perhaps you should push LR and not R7 ?

Tips, Buy me a coffee, or three.. PayPal Venmo (See Profile) Up vote any posts that you find helpful, it shows what's working..
Myasu.1
Myasu.1Author
Associate III
March 7, 2022

@Community member​ 

thank you for quick reply.

I changed it to PUSH LR as shown below, but the result is still the same and INVPC occurred.

void SVC_Handler(void)
{
 __asm volatile(" TST LR, #0x4 \n"); /* Test EXC_RETURN number in LR bit 2 */
 __asm volatile(" ITE EQ \n"); /* if zero (equal) then */
 __asm volatile(" MRSEQ R1, MSP \n"); /* Main Stack was used, put MSP in R0 */
 __asm volatile(" MRSNE R1, PSP \n"); /* else, Process Stack was used, put MSP in R0 */
 __asm volatile(" LDR R0, [R1, #0] \n"); /* Get stacked R0 from stack */
 __asm volatile(" LDR R1, [R1, #24] \n"); /* Get stacked PC from stack */
 __asm volatile(" LDRB R1, [R1, #-2] \n"); /* Get the immidiate data from the instruction */
 __asm volatile(" PUSH {LR} \n");
 __asm volatile(" CBNZ R1, svc_handler_1 \n");
 __asm volatile(" BL tmp \n");
 __asm volatile(" B svc_handler_end \n");
 __asm volatile("svc_handler_1: \n");
 __asm volatile(" CMP R1, #1 \n");
 __asm volatile(" BNE svc_handler_2 \n");
 __asm volatile(" BL tmp \n");
 __asm volatile(" B svc_handler_end \n");
 __asm volatile("svc_handler_2: \n");
 __asm volatile(" CMP R1, #2 \n");
 __asm volatile(" BNE svc_handler_3 \n");
 __asm volatile(" BL tmp \n");
 __asm volatile(" B svc_handler_end \n");
 __asm volatile("svc_handler_3: \n");
 __asm volatile(" CMP R1, #3 \n");
 __asm volatile(" BNE svc_handler_end \n");
 __asm volatile(" BL tmp \n");
 __asm volatile(" B svc_handler_end \n");
 __asm volatile("svc_handler_end: \n");
 __asm volatile(" POP {PC} \n");
}

Are there any other possible causes?

Tesla DeLorean
Tesla DeLoreanBest answer
Guru
March 7, 2022

Why are you even pushing R7? It's like you copied some other code.

Not sure I'd write in-line assembler this way.

Look at what code the compiler actually generates, and walk that, making sure it's doing what you actually expect/want. The MCU is just going to try and execute what it is encountering, and you get to be responsible for register usages, and bracketing push/pop usage on the stack.

Watch for what the compilers is doing for prologue/epilogue code for the function, or if you need more control of that via "naked" or equivalent directives.

Tips, Buy me a coffee, or three.. PayPal Venmo (See Profile) Up vote any posts that you find helpful, it shows what's working..
Myasu.1
Myasu.1Author
Associate III
March 8, 2022

@Community member​ 

thank you for quick reply.

​

As you said, I built with inline assembler and checked the actual output assembler. The assembler is shown below.

080014a0 <SVC_Handler>:
 80014a0:	b480 	push	{r7}
 80014a2:	af00 	add	r7, sp, #0
 80014a4:	f01e 0f04 	tst.w	lr, #4
 80014a8:	bf0c 	ite	eq
 80014aa:	f3ef 8108 	mrseq	r1, MSP
 80014ae:	f3ef 8109 	mrsne	r1, PSP
 80014b2:	6808 	ldr	r0, [r1, #0]
 80014b4:	6989 	ldr	r1, [r1, #24]
 80014b6:	f811 1c02 	ldrb.w	r1, [r1, #-2]
 80014ba:	b500 	push	{lr}
 80014bc:	b911 	cbnz	r1, 80014c4 <svc_handler_1>
…
080014de <svc_handler_end>:
 80014de:	bd00 	pop	{pc}

Immediately after entering the SVC_handler, an unintended push {r7} is added. I assume that the last pop stored the value of r7 in pc and invpc was happening.

I wrote the assembler directly and ran this and it worked correctly. Thank you for help.

​