MIPS architecture 'syscall' instruction
Asked Answered
R

2

15

What is the role of syscall instruction in MIPS?

Royster answered 9/5, 2011 at 15:9 Comment(0)
S
15

The syscall is used to request a service from the kernel. For MIPS, the service number/code must be passed in $v0 and arguments are passed in a few of the other designated registers. For example, to print we might do:

li $v0, 1
add $a0, $t0, $zero
syscall

In this case, 1 is the service code for print integer. The second instruction effectively performs a copy from $t0 to $a0 which is the designated register where the argument is held ( in this case, the integer to be printed ). A list of the services and corresponding arguments is given in SYSCALL functions available in MARS.

Stupor answered 9/5, 2011 at 15:15 Comment(2)
What happens if the syscall instruction is used when the current program is already in kernel-mode? Does MIPS have any other modes besides user-mode and kernel-mode?Katheryn
The MARS/SPIM set of system calls isn't fundamental to the MIPS ISA, it's just a set of simplistic "toy" system calls that a couple emulators choose to provide. Linux on MIPS provides POSIX and Linux-specific system calls, and none of then convert integers to/from text; that's what libc functions are for. The MARS/SPIM system calls provide a very limited subset of the functionality of scanf and printf (with a different ABI), among other things.Whispering
R
8

It becomes a lot more obvious when you step outside the context of an emulator like MARS or SPIM where the system calls are somewhat artificial. On a real MIPS machine, you would use it transfer control the kernel to invoke a specific function.

For example, this is a basic Hello, World! program in MIPS 32-bit assembly for a Linux machine (I'm 95% sure this was on a mipsel install, though not that it matters much for this question):

# CS341L Fall 2008
# Lab Exercise #1
# Matthew J. Barrick <[email protected]>

#include <asm/regdef.h>
#include <sys/syscall.h>

.data
    hello:  .asciz    "Hello World\n"
    length: .word    12
.text
    .globl  main
    .ent    main
main:
    li      a0, 1
    la      a1, hello
    lw      a2, length
    li      v0, SYS_write
    syscall
    move    v0, zero
    jr      ra
    .end    main

This corresponds very closely to the C code (if you have trouble following the MIPS assembly).

#include <stdio.h>

int main(int argc, char** argv) {
    char* hello = "Hello, World\n";
    write(STDOUT_FILENO, hello, 12);
    return 0;
}

First note that headers are included to give the registers symbolic names (asm/regdef.h) and a header that will pull in symbolic names for the system calls (sys/syscall.h), so we don't have to refer to the system calls by number. The conventions for making a system call here are pretty much the same as calling a function, load the a# register with arguments, and then we load which system call we want into $v0 and invoke syscall. SYS_write corresponds to the basic write(2) function for Linux/Unix (1 being standard output).

ssize_t write(int fd, const void *buf, size_t count);

So we're telling the kernel to write to the file handle 1 (standard output), the string Hello, using length bytes. On Linux you can see syscalls(2) for all the different system calls available, but they pretty much correspond the core functions that the kernel provides and that (g)libc either wraps or builds upon for C/C++ programs.

Linux (and most Unix-like systems, going back to the 4BSD route) have a function syscall(2) which is effectively the same thing.

Once you start doing more complex stuff, you'll either find yourself wrapping the syscall invoking into handy functions, or better yet just calling the corresponding libc versions (surprisingly easy to do, but another discussion).

Repeated answered 23/4, 2012 at 19:0 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.