0から作るソフトウェア開発

日々勉強中。。。

Tips
リンク

システムコール >

0から作るLinuxプログラム システムコールその2 カーネル内のシステムコール

システムコール

Linuxのシステムコールについて見ていきます。


それでは、順番に見ていきます。

  1. ユーザープログラムからのシステムコールの呼び出し


  2. カーネル内のシステムコール


  3. (現在のページ) 簡単なシステムコールの作成




開発環境のインストール

ここではUbuntuの64ビット版を例に作っていきたいと思います。

それでは、まずはカーネルをビルドするためのツールをインストールしていきましょう。



Ubuntuでカーネルをビルドするためには以下のパッケージが必要となります。

  1. libncurses-dev

  2. ncursesの開発用ライブラリーです。テキスト形式のAPIを提供してくれます。カーネルの

    menuconfigに使用します。



  3. build-essential

  4. Debianパッケージを構築するのに必要なツール群です。カーネルのDebianパッケージを

    作成するのに使用します。



  5. fakeroot

  6. ファイル操作を行うときにルート権限で行ったようにするツールです。パッケージ作成に

    使用します。

  7. kernel-package

  8. カーネルのパッケージを構築するためのスクリプトツール群です。



  9. linux-source

  10. カーネルのソースです。



これらをインストールしていきます。

				
$ sudo apt-get -y update
[パスワード入力]
$ sudo apt-get -y install libncurses-dev
$ sudo apt-get -y install build-essential
$ sudo apt-get -y install fakeroot
$ sudo apt-get -y install kernel-package
$ sudo apt-get -y install linux-source



linux-sourceをインストールすると/usr/srcに圧縮されたカーネルのソースが格納されています。

次のようなファイル名となります。ここで(kernel version)はその時の最新バージョンとなります。

				
linux-source-(kernel version).tar.bz2



ここでは、カーネルのバージョン3.17.1を例にします。

カーネルのバージョンは次のコマンドで確認することができます。

				
$ uname -r



この場合の圧縮されたソースは次のようになります。

				
linux-source-3.17.1.tar.bz2



カーネルのビルド

圧縮されたソースを展開します。

				
$ cd /usr/src
$ sudo -s
[パスワード入力]
# tar xf linux-source-3.17.1.tar.bz2



ソースコードディレクトリに移動して.configファイルを作ります。

				
# make oldconfig



カーネルの設定を変えたいときにはmenuconfigで設定を変更できます。

今回はシステムコールを作成するだけとなりますので、必要ありません。

				
# make menuconfig



カーネルをビルドしていきます。

				
# make-kpkg clean
# make-kpkg --rootcmd fakeroot kernel_image kernel_headers



そして、ビルドしたカーネルをインストールしていきます。

カーネルのパッケージは/usr/src/にあります。次のパッケージとなります。

				
linux-image-(kernel version and arch).deb
linux-header-(kernel version and arch).deb



kernel version and archはそれぞれの環境で違います。

kernel-imageとkernel-headerをインストールします。

(下記例とは違ったファイルかと思いますが.debパッケージができていれば成功です。)

				
# dpkg -i linux-image-3.17.1_amd64.deb
# dpkg -i linux-header-3.17.1_amd64.deb



後はリブートしてインストールしたカーネルで起動できているか確認します。

				
# reboot



カーネルのバージョンを確認します。

				
$ uname -r



これでカーネルをビルドしてインストールできるようになりました。

それでは、簡単なシステムコールを実装していきましょう。

簡単なシステムコールの実装

システムコールを実装するには以下のファイルを編集します。

この例では、Linuxのソースが置いてあるディレクトリにmy_syscallディレクトリを作って

fsディレクトリと同じ階層のディレクトリです)そこに今回実装する簡単なシステムコールの中身を

置きます。また開発環境は64ビットのLinuxです。

64ビットLinuxでシステムコールを実装するときに編集するファイル
ファイルパス 説明
my_syscall/my_syscall.c 今回実装するシステムコールの処理実体です。
my_syscall/Makefile 今回実装するシステムコールのmakeファイルです。
arch/x86/syscalls/syscall_64.tbl システムコールテーブルが定義さされているファイルです。
include/linux/syscalls.h システムコール処理関数のプロトタイプ宣言を追加するファイルです。
Makefile my_syscallディレクトリを追加します。


それではそれぞれのファイルについて実装または編集してきます。

my_syscall/my_syscall.cの実装

まずはLinuxソースルートディレクトリに移動してmy_syscallディレクトリを作成します。

				
$ cd /usr/src/linux-source-3.17.1/linux-source-3.17.1
$ sudo -s
[パスワード入力]
# mkdir my_syscall
# ce my_syscall



推奨
ここでは/usr/src配下のLinuxソースディレクトリを作業ディレクトリにして

していますが、先にバックアップをとっておくか別の作業ディレクトリにコピーしてから

一般ユーザーで作業することをおすすめします。



それでは、my_syscallディレクトリに今回作成するシンプルなシステムコール処理を

作っていきます。ここではファイル名をmy_syscall.cとしました。

[my_syscall.c]
				
#include <linux/kernel.h>
#include <linux/syscalls.h>

SYSCALL_DEFINE2( my_syscall, char __user *, buf, int, count )
{
	long err;
    char text[ ] = "my syscall!";

    printk( "<MY_SYSCALL>%s\n", text );

    if( count < sizeof( text ) )
    {
        return( -ENOMEM );
    }

    /* copy untill null terminator */
    err = copy_to_user( buf, text, sizeof( text ) );
    	
    return( err );
}



関数宣言の引数に注意してください。SYSCALL_DEFINEを使用する場合には、型と変数名の

間に゛,”を入れます。処理内容は非常にシンプルです。printkでデバッグ情報をログに書き出して、

ユーザーが指定したバッファーにテキストを書き込むだけの処理となります。ユーザーが指定した

バッファーの大きさが十分でない場合にエラーを返します。

my_syscall/Makefileの実装

次に同じディレクトにMakefileを作っていきます。次の一行だけです。

[Makefile]
				
obj-y := my_syscall.o



arch/x86/syscalls/syscall_64.tbl

sys_call_tablesys_my_syscallシステムコールを追加します。

この例では、arch/x86/syscalls/に移動してファイルを編集します。

				
# cd ../arch/x86/syscalls/



次のようにsys_my_syscallsyscall_64.tblに追加します。

[syscall_64.tbl]
				
310     64      process_vm_readv        sys_process_vm_readv
311     64      process_vm_writev       sys_process_vm_writev
312     common  kcmp                    sys_kcmp
313     common  finit_module            sys_finit_module
314     common  sys_my_syscall          sys_my_syscall



今回はテーブルの最後に追加しました。この例ではmy_syscallシステムコールの番号は

314となります。

include/linux/syscalls.hの編集

syscalls.hヘッダーファイルに追加したシステムコールのプロトタイプ宣言を追加します。

この例ではinclude/linux/に移動して作業を行います。

				
# cd ../../../include/linux



次のようにsys_my_syscallのプロトタイプ宣言を追加します。

[syscalls.h]
			
asmlinkage long sys_kcmp(pid_t pid1, pid_t pid2, int type,
                         unsigned long idx1, unsigned long idx2);
asmlinkage long sys_finit_module(int fd, const char __user *uargs, int flags);

asmlinkage long sys_my_syscall( char __user *buf, int count );



ここではSYSCALL_DEFINEで展開された後の記述を行います。

asmlinkageを付けただけの普通の関数としてプロトタイプ宣言します。

Makefileの編集

最後にLinuxソースのルートディレクトリに移動してMakefileを編集します。

最初に作業ディレクトリを移動します。

				
# cd ../../



そして、Makefileを開きcore-yで検索します。下記のように最後にmy_syscall

ディレクトリを追記します。これにより、カーネルのビルドを行うとmy_syscallディレクトリで

makeコマンドを実行してくれます。

[Makefile]

ifeq ($(KBUILD_EXTMOD),)
core-y          += kernel/ mm/ fs/ ipc/ security/ crypto/ block/ my_syscall/



後は先ほどまで見てきました、カーネルのビルドを参照しながらカーネルを

ビルド・インストール・再起動してください。



結構簡単だったかと思います。では、次にmy_syscallシステムコールを呼び出すユーザー

プログラムを作っていきます。

追加したシステムコールを呼び出すユーザープログラムの実装

追加実装したシステムコールは、たったいま自分で作ったので、もちろんライブラリーには

APIがありません。ですので、 ユーザープログラムからのシステムコールの呼び出し で見てきましたsyscallを使って呼び出します。

この例では適当なディレクトリにファイルcall_my_syscall.cを作成しました。

[call_my_syscall.c]
				
#include <stdio.h>
#include <unistd.h>
#include <sys/syscall.h>

#define SYS_my_syscall  314

int main( int argc, char *argv[ ] )
{
        char    buf[ 256 ];
        long    ret;

        ret = syscall( SYS_my_syscall, buf, sizeof( buf ) );

        if( ret < 0 )
        {
                fprintf( stderr, "erro : %ld\n", ret );
        }
        else
        {
                printf( "buf = %s\n", buf );
        }

        return( 0 );
}



syscall関数で314番目のシステムコールを呼び出しを行っています。



コンパイルします。

				
$ gcc -o call_my_syscall call_my_syscall.c
$ ./call_my_syscall
my syscall!



実行すると、my_syscallシステムコールがバッファーを書き換えます。

そしてその内容が表示されるかと思います。



次のようにdemsgコマンドを実行すると、システムコールの呼び出しがログに記録されていることを

確認できます。

				
$ dmesg
<MY_SYSCALL>my syscall!





PR 説明

ディベロッパー・エクスペリエンス Linux Ext2ファイルシステム
0から作るLinuxプログラム Linux Ext2ファイルシステムの完全説明版(Kindleのみ)となります。実装するステップ数は36ステップあります。少しずつステップを実装して、実際に動かして学習していきます。ファイルシステムの機能を呼び出すシステムコールの実装から、仮想ファイルシステムが呼び出すExt2ファイルシステムの実装を行っていきます。ファイルシステムの開発体験を通すことで、実際にカーネルが行っているファイルシステムの基礎的な動作を理解することができます。ぜひお試しください!

inserted by FC2 system