# System calls translation

The pipeline uses kernel as a source of truth. Unfortunately, all other options proved to be either
incomplete or imprecise.

System call names, numbers and entry points are extracted from kernel sources.

*TODO: consider extracting names, numbers and entry points from vmlinux!*

System call parameters are extracted from vmlinux DWARF.

Automatic translation happens between system calls with the same entry point if entry point
parameters are compatible.

### Checkout kernel

Assume the kernel checkout is at `$KERNEL_SRC`.

### Extract system calls names, numbers and entry points

This is specific for architectures. The script does extraction for `arm`, `arm64`, `x86`,
`x86_64` and `riscv64`.

In addition, the script checks entry point prototypes and marks those without parameters. System
calls without parameters do not need compatibility checking (and they don't have corresponding
`__do_sys_*` functions, see "Extract system calls parameters").

Unfortunately, extracting full info about parameters from prototypes is a bad idea. Most
architectures have specific calling conventions for system calls, so even the number of parameters
may vary. But, hopefully, "no parameters" means the same thing everywhere.

```./extract_syscalls_from_kernel_src.py $KERNEL_SRC/common > ./kernel_syscalls.json```

### Extract system calls parameters

Entry point `sys_foo` is a function that gets system call parameters in a form of `struct ptregs*`.
`SYSCALL_DEFINEx` macro unpacks parameters and calls implementation function `__do_sys_foo` which
receives parameters normally.

`__do_sys_foo` functions are usually inlined and do not exist in symbols table. However, DWARF
should still have these functions.

To get parameters info in our common .json API form, do:

Build kernel for arch with debug info. Assume this is `VMLINUX_RISCV64`.

Extract the list of `__do_sys_*` functions for arch:

```./gen_kernel_syscalls_symbols.py riscv64 ./kernel_syscalls.json > ./symbols_riscv64.txt```

Use `dwarf_reader` to get .json API info for these functions:

```dwarf_reader --filter=symbols_riscv64.txt VMLINUX_RISCV64 > ./kernel_api_riscv64.json```

### Generate system calls translation

Now there should be files like:

```
kernel_syscalls.json (common system calls info)
kernel_api_riscv64.json (src arch system calls API)
kernel_api_x86_64.json (dst arch system calls API)
custom_syscalls.json (translation exceptions)
```

Run the script to generate code for translation function:

```
gen_kernel_syscalls_translation.py riscv64 x86_64 \
> kernel_api/gen_syscall_emulation_riscv64_to_x86_64-inl.h
```

### Generate system call numbers

Each guest architecture must provide two files for system call numbers:
1. `gen_syscall_numbers_arch.h`, which contains constants for that guest architecture's syscall
   numbers. This file is generated by `gen_kernel_syscalls_numbers.py`.
2. `gen_syscall_numbers.cc`, which contains function definitions for mapping between host and guest
   syscall numbers. This file is generated by `gen_kernel_syscalls_mapping.py`.

Both of these files are generated from `kernel_syscalls.json` and should be regenerated whenever
that file changes. The command-line arguments for both scripts are `<src-arch> <dst-arch>
<path-to-kernel_syscalls.json>`:

```
./gen_kernel_syscalls_numbers.py riscv64 x86_64 ./kernel_syscalls.json \
> ../../guest_os_primitives/riscv64/include/berberis/guest_os_primitives/gen_syscall_numbers_arch.h
./gen_kernel_syscalls_mapping.py riscv64 x86_64 ./kernel_syscalls.json \
> ../../guest_os_primitives/riscv64/gen_syscall_numbers.cc
```
