|
|||||||||||
Technical Support Support Resources
Product Information |
ARM: How to Write an SVC FunctionInformation in this knowledgebase article applies to:
QUESTION
The Cortex-M cores support the SuperVisor Call (SVC) instruction,
with that the user can trigger an exception. This can become handy if
e. g. the core is in unprivileged mode and the program needs to
access special registers, that only can be accessed in privileged
mode. Exceptions run in privileged mode. ANSWERYes, but how it works depends on the used compiler version and if there is some other software component in use, that already implements an SVC handler, like the Keil RTX 4 or 5. Calling a SVCFor that, the program needs to insert the SVC instruction into the code. This instruction has a parameter (for Thumb code 0-255) to select different SVC functions. The example generates SVC 0. But also have in mind, that other software components in the project may use this already. Select another parameter value then. With Arm Compiler 5: This compiler knows the __svc keyword, which makes it simple to define a SVC function: void __svc( 0 ) EnablePrivilegedMode( void ) ; With Arm Compiler 6: With this compiler inline assembler needs to be used to generate something equivalent: #define EnablePrivilegedMode() __asm("SVC #0") Calling this function in the program will generate the required instruction at that location of the function call. Handling a SVC
When using a Keil RTX, then the RTX already implements its own SVC
handler, that also needs to remain in the image. See the RTX
documentation on how to add additional user SVC calls. With Arm Compiler 5: __asm void SVC_Handler(void) { IMPORT SVC_Handler_Main TST lr, #4 ITE EQ MRSEQ r0, MSP MRSNE r0, PSP B SVC_Handler_Main } With Arm Compiler 6: void SVC_Handler(void) { __asm( ".global SVC_Handler_Main\n" "TST lr, #4\n" "ITE EQ\n" "MRSEQ r0, MSP\n" "MRSNE r0, PSP\n" "B SVC_Handler_Main\n" ) ; } Both functions end in the SVC_Handler_Main(), which is a normal C function. This function looks at the instruction before the stacked return address to determine the SVC number. The SVC 0 in this case disables the privileged mode. void SVC_Handler_Main( unsigned int *svc_args ) { unsigned int svc_number; /* * Stack contains: * r0, r1, r2, r3, r12, r14, the return address and xPSR * First argument (r0) is svc_args[0] */ svc_number = ( ( char * )svc_args[ 6 ] )[ -2 ] ; switch( svc_number ) { case 0: /* EnablePrivilegedMode */ __set_CONTROL( __get_CONTROL( ) & ~CONTROL_nPRIV_Msk ) ; break; default: /* unknown SVC */ break; } } MORE INFORMATION
SEE ALSO
Last Reviewed: Thursday, November 12, 2020 | ||||||||||
|
Arm’s Privacy Policy has been updated. By continuing to use our site, you consent to Arm’s Privacy Policy. Please review our Privacy Policy to learn more about our collection, use and transfers
of your data.