2

I have the following function which makes a supervisor call.

inline uint32_t os_SVC(uint32_t n, uint32_t pid, void* ptr1, void (*ptr2)()){
  __asm("svc #0");
  return;
}

By altering the stack during the SVC ISR I know R0 will contain the return argument from the SVC ISR. As I understand it, this is how the AAPCS returns values from functions. But how do I return the R0 register from os_SVC? Currently it gives me a warning because I am returning from the function without supplying a return value.

MHilton
  • 221
  • 2
  • 9

1 Answers1

4

Your compiler may have further extensions that allow you to pass data in and out of the assembly insert. You didn't tell us which compiler you're using, so I'm going to show you how to do it with GCC, which is the one whose extensions I remember without looking it up:

uint32_t os_SVC(uint32_t n, uint32_t pid, void *p1, void (*p2)(void))
{
    register uint32_t rv asm ("r0");
    asm ("svc #0" : "=r" (rv))
    return rv;
}

The register ... asm ("r0") annotations on the declaration of rv require the compiler to put it in r0, and the : "=r" (rv) annotation on the asm statement tells it that the assembly instruction writes to that variable. Then you can return rv as normal.

Also, notice how I removed the inline? That was intentional. If you inline this function, the arguments won't be neatly lined up on the stack where the system call expects to find them. If your operating system expects system call arguments in registers, you could annotate the assembly insert further and make an inline work, but if it expects them on the stack, leaving the function out-of-line is the best approach. (In production code I would put __attribute__((noinline)) on the function itself and __attribute__((used)) on each of its arguments, but that would be too much clutter for an example.)

The documentation for the extensions I'm using are in the "Using Assembly Language with C" section of the GCC manual. Read the entire thing very carefully.

If you are not using GCC, consult your compiler's manual to see if it has equivalent extensions. If it doesn't have equivalent extensions, your only option may be to write this function entirely in assembly language, in a separate .S file.

zwol
  • 135,547
  • 38
  • 252
  • 361
  • Thank you very much for your answer, and for warning me about the inline! I am indeed using the arm gcc compiler. When you say "the `: "=r" (rv)` annotation on the asm statement tells it that the assembly instruction writes to that variable", is it required that the instruction itself writes a register? Or is it sufficient that after ISR it triggers has ended, the register value has changed (changed due to popping an edited value off the stack on return)? – MHilton Aug 02 '19 at 13:52
  • @MHilton It should be sufficient for the value to have changed at the point when control reaches the first instruction _after_ the `svc`. – zwol Aug 02 '19 at 14:04
  • You might like to look into the generated machine code. For this you call GCC with the option `-S` and `-o output_file.s` to see this, or you use `objdump` to disassemble the object file. There are also options to be passed to the assembling pass to create a listing. – the busybee Aug 02 '19 at 20:25