6.6.6. Calling SVCs dynamically from an application

In some circumstances it might be necessary to call an SVC whose number is not known until runtime. This situation might occur, for example, when there are a number of related operations that can be performed on an object, and each operation has its own SVC. In this case, the methods described in the previous sections are not appropriate.

There are several ways of dealing with this, for example:

The second mechanism can be implemented in assembly language by passing the required operation number in a register, typically r0 or r12. You can then rewrite the SVC handler to act on the value in the appropriate register.

Because some value has to be passed to the SVC in the comment field, it is possible for a combination of these two methods to be used.

For example, an operating system might make use of only a single SVC instruction and employ a register to pass the number of the required operation. This leaves the rest of the SVC space available for application-specific SVCs. You can use this method if the overhead of extracting the SVC number from the instruction is too great in a particular application. This is how the ARM (0x123456) and Thumb (0xAB) semihosted SVCs are implemented.

Example 6.12 shows how __svc can be used to map a C function call onto a semihosting SVC. It is derived from retarget.c in the main examples directory, in ...\emb_sw_dev\source\retarget.c.

Example 6.12. Mapping a C function onto a semihosting SVC

#ifdef __thumb
/* Thumb Semihosting */
#define SemiSVC 0xAB
/* ARM Semihosting */
#define SemiSVC 0x123456

/* Semihosting SVC to write a character */ 
__svc(SemiSVC) void Semihosting(unsigned op, char *c);
#define WriteC(c) Semihosting (0x3,c)

void write_a_character(int ch)
    char tempch = ch;
    WriteC( &tempch );

The compiler includes a mechanism to support the use of r12 to pass the value of the required operation. Under the AAPCS, r12 is the ip register and has a dedicated role only during function calls. At other times, you can use it as a scratch register. The arguments to the generic SVC are passed in registers r0-r3 and values are optionally returned in r0-r3 as described earlier (see Calling SVCs from an application). The operation number passed in r12 can be the number of the SVC to be called by the generic SVC. However, this is not required.

Example 6.13 shows a C fragment that uses a generic, or indirect SVC.

Example 6.13. 

    unsigned SVC_ManipulateObject(unsigned operationNumber,
                                  unsigned object,unsigned parameter);

unsigned DoSelectedManipulation(unsigned object,
                                unsigned parameter, unsigned operation)
{ return SVC_ManipulateObject(operation, object, parameter);

This produces the following code:

DoSelectedManipulation PROC
        STMFD    sp!,{r3,lr}
        MOV      r12,r2
        SVC      0x80
        LDMFD    sp!,{r3,pc}

It is also possible to pass the SVC number in r0 from C using the __svc mechanism. For example, if SVC 0x0 is used as the generic SVC and operation 0 is a character read and operation 1 a character write, you can set up the following:

__svc (0) char __ReadCharacter (unsigned op);
__svc (0) void __WriteCharacter (unsigned op, char c);

These can be used in a more reader-friendly way by defining the following:

#define ReadCharacter () __ReadCharacter (0);
#define WriteCharacter (c) __WriteCharacter (1, c);

However, if you use r0 in this way, then only three registers are available for passing parameters to the SVC. Usually, if you have to pass more parameters to a subroutine in addition to r0-r3, you can do this using the stack. However, stacked parameters are not easily accessible to an SVC handler, because they typically exist on the User mode stack rather than the supervisor stack employed by the SVC handler.

Alternatively, one of the registers (typically r1) can be used to point to a block of memory storing the other parameters.

Copyright © 2002-2006 ARM Limited. All rights reserved.ARM DUI 0203G