cancel
Showing results for 
Search instead for 
Did you mean: 

INVPC occurs when SVC Handler returns

Myasu.1
Senior

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?

1 ACCEPTED SOLUTION

Accepted Solutions

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
Up vote any posts that you find helpful, it shows what's working..

View solution in original post

4 REPLIES 4

>>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
Up vote any posts that you find helpful, it shows what's working..
Myasu.1
Senior

@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?

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
Up vote any posts that you find helpful, it shows what's working..

@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.