システムコールを追加してみる

Linux 3.16.3 に自作のシステムコールを追加してみました。

システムコールといっても、printk()を使用してコンソールログに文字列を出力するだけの簡単なものです。

1. システムコール番号を定義する

"include/asm/unistd.h"とか、色々な情報があったのですが、"arch/x86/syscalls/syscall_32.tbl"で定義されているようです。

#
# 32-bit system call numbers and entry vectors
#
# The format is:
# <number> <abi> <name> <entry point> <compat entry point>
#
# The abi is always "i386" for this file.
#
0       i386    restart_syscall         sys_restart_syscall
1       i386    exit                    sys_exit
2       i386    fork                    sys_fork                        stub32_fork
3       i386    read                    sys_read
4       i386    write                   sys_write
5       i386    open                    sys_open                        compat_sys_open
6       i386    close                   sys_close
7       i386    waitpid                 sys_waitpid                     sys32_waitpid
8       i386    creat                   sys_creat
9       i386    link                    sys_link
... 以下略 ...

ここで、"ABI"というのは、"Application Binary Interface"の略で、アプリケーションの実行ファイルとカーネルがやりとりするインターフェースのことだそうです。

この"syscall_32.tbl"に今回するシステムコールの番号を追加します。

... 略 ...
348     i386    process_vm_writev       sys_process_vm_writev           compat_sys_process_vm_writev
349     i386    kcmp                    sys_kcmp
350     i386    finit_module            sys_finit_module
351     i386    sched_setattr           sys_sched_setattr
352     i386    sched_getattr           sys_sched_getattr
353     i386    renameat2               sys_renameat2
354     i386    get_xtime               sys_get_xtime   <---- この行を追加

2. syscalls.hの編集

"syscalls.h"には以下のように、システムコールのプロトタイプ宣言がまとめられているので、追加するシステムコールの宣言もここで行います。

... 略 ...
asmlinkage long sys_creat(const char __user *pathname, umode_t mode);
asmlinkage long sys_open(const char __user *filename,
                                int flags, umode_t mode);
asmlinkage long sys_close(unsigned int fd);
asmlinkage long sys_access(const char __user *filename, int mode);
asmlinkage long sys_vhangup(void);
asmlinkage long sys_chown(const char __user *filename,
... 略 ...
asmlinkage long sys_helloworld(void); <- 追加
#endif

3. システムコールの実装

次にシステムコールを実装していきます。今回は、"kernel/helloworld.c"というファイルを作成して、そこに実装していきます。

#include <linux/kernel.h>
#include <linux/syscalls.h>

asmlinkage long sys_helloworld(void) {
    printk(KERN_INFO "This is helloworld()\n");

    return 0;
}

ここで、"asmlinkage"というのは、コンパイラに関数の引数をスタックで渡すように指示するためのものだそうです。

"printk()"というのはコンソールにログを出すために使われています。

4. Makefileの編集

次に追加した"kernel/helloworld.c"がコンパイルされるように、"kernel/Makefile"を編集します。

#
# Makefile for the linux kernel.
#

obj-y     = fork.o exec_domain.o panic.o \
            cpu.o exit.o itimer.o time.o softirq.o resource.o \
            sysctl.o sysctl_binary.o capability.o ptrace.o timer.o user.o \
            signal.o sys.o kmod.o workqueue.o pid.o task_work.o \
            extable.o params.o posix-timers.o \
            kthread.o sys_ni.o posix-cpu-timers.o \
            hrtimer.o nsproxy.o \
            notifier.o ksysfs.o cred.o reboot.o \
            async.o range.o groups.o smpboot.o helloworld.o <<-- 追加

5. ビルドと実行

カーネルをビルドします。

そして、追加したシステムコールを使用するためのプログラムも作成します。

普通システムコールは標準ライブラリ(glibcなど)経由で呼ばれるそうです。ただ、今回はsyscall(2)を使用して、システムコールを呼び出します。

#include <stdio.h>
#include <unistd.h>
#include <sys/types.h>

#define SYS_HELLOWORLD 354

int main(void) {
    syscall(SYS_HELLOWORLD);
    return 0;
}

見てもわかるように、syscall(2)は、"arch/x86/syscalls/syscall_32.tbl"で定義したシステムコール番号を引数に取ります。

このプログラムをコンパイルして、試してみます。

今回はqemu上でカーネルを動かし、システムコールが無事追加されているか確認してみました。

$ qemu-system-i386 -kernel ~/build/mykernel-3.16.3/arch/x86/boot/bzImage -hda ./disk.img -initrd ./my-initramfs -nographic -append "console=ttyS0"

f:id:ryouta768:20141001112404p:plain

システムコールが無事呼び出されています。

参考にしたページ