I. Linux kernel articles
3. Syscall
Here is a very interesting part of the linux kernel programming! You always wondered "how can I add a syscall in my linux ?"? Here is the answer!
Go to your module folder and create a new one in it:
mkdir syscall
Good. Now add its path to the current Makefile (the one in linux_test/linux/my_module/):
obj-y += syscall/
And you should also move your hello.c in a subfolder (it will get dirty very quickly otherwise).
Now go in your syscall folder and create a syscall.c file. Put in it:
#include <linux/init.h>
#include <linux/module.h>
#include <linux/syscalls.h>
#include <linux/kernel.h>
SYSCALL_DEFINE0(hello)
{
usleep_range(1000, 100000);
return 0;
}
Very easy isn't it ? But that's not all ! You have to do one more thing (or two, depending on how we look at it...) ! You have to go the file(s) where syscalls are declared. Where ?
cd ~/linux_test/linux/arch/x86/syscalls/
# on more recent linux versions:
cd ~/linux_test/linux/arch/x86/entry/syscalls/
We are interested here by syscall_32.tbl and syscall_64.tbl. To add a syscall, go to the end of a file and add this line in (the first line is just an example):
356 i386 memfd_create sys_memfd_create
357 i386 hello sys_hello
Be very careful in the syscall_64.tbl file ! If there is a "x32" in the line:
544 x32 io_submit compat_sys_io_submit
You're not in the good place. Try to search the end of lines like this:
320 common kexec_file_load sys_kexec_file_load
Now you just have to add your syscall:
321 common hello sys_hello
You can now build but if you want to test your syscall, just modify or create a new module and put in it:
syscall(_NR_hello, 0);
If it says _NR_hello
isn't defined, replace it with your syscall number:
syscall(357, 0);
Everything's good ? Cool ! Now if you want to add parameter to your syscall:
SYSCALL_DEFINE2(hello, unsigned int, begin, unsigned int, end)
{
usleep_range(begin, end);
return 0;
}
You will notice that SYSCALL_DEFINE0 is now SYSCALL_DEFINE2. I'm sure you already guessed but I say it: the number at the end is the number of parameter that your syscall needs.
Precision
If you want your syscall to take a pointer as parameter, just know that you can't use "just like that". You're in kernel space, so you have to "import" (I simplify a lot) the pointer. Example:
SYSCALL_DEFINE3(hello, unsigned int, begin, unsigned int, end, unsigned int*, ptr)
{
usleep_range(begin, end);
copy_to_user(ptr, &end, sizeof(ptr));
return 0;
}
You're welcome !
More ?
If you want more information about syscalls, here is a little article very interesting which speak about it.