4.3 Code: Calling system calls
Chapter 2 ended with
initcode.S
invoking the exec system call
(user/initcode.S:11).
Let’s look at how the user call
makes its way to the exec system call’s
implementation in the kernel.
initcode.S
places the arguments for
exec
in registers a0 and a1, and puts the
system call number in
a7.
System call numbers match the entries in the syscalls array,
a table of function pointers
(kernel/syscall.c:107).
The ecall
instruction traps into the kernel
and causes
uservec,
usertrap, and then syscall to execute, as we saw above.
syscall
(kernel/syscall.c:132)
retrieves the system call number from the saved
a7 in the trapframe
and uses it to index into syscalls.
For the first system call,
a7
contains
SYS_exec
(kernel/syscall.h:8),
resulting in a call to the system call implementation function
sys_exec
.
When sys_exec
returns,
syscall
records its return value in
p->trapframe->a0
.
This will cause the original user-space call to
exec() to return that value, since the C
calling convention on RISC-V places return values in a0.
System calls conventionally return negative numbers to indicate
errors, and zero or positive numbers for success.
If the system call number is invalid,
syscall
prints an error and returns .