カーネル/VM Advent Calendar 16日目: USB/IPで遊んでみる

USB/IPはご存知ですか?

その名の通り、USBデバイスをIPネットワーク上で共有しようというプロジェクトです。 このプロジェクトはLinux 2.6.38でカーネルにマージされていて、遊んでみようと思いながらなかなか機会がなかったので、今回のネタにすることにしました。

1. USB/IPについて

USB/IPはもともとNAISTの研究がもとになって作られました。下のページに詳しい論文が掲載されています。

http://kawai.naist.jp/~eiji-ka/publications/remote-dev-j.html

仕組みとしては以下のようになっています。

A. クライアントがUSBデバイスにリクエストを投げる

B. クライアント側のVHCIドライバがホストコントローラーをエミュレーションして、リクエストを受け取る

C. VHCIドライバがリクエストをカプセル化してサーバーに送信する

D. サーバー側のスタブドライバがリクエストを受け取り、実際のデバイスにリクエストを投げる

E. スタブドライバがリクエストの結果をクライアント側に返す

 このVHCIドライバやStubドライバというのはすでにカーネルのstagingに入っています。また、VHCIドライバはWindows向けの実装も進んでいます。

2. サーバー側を準備する

サーバー側(デバイスを提供する側)は現在Linuxしか対応していません。なので、試して見る際はLinuxを用意しましょう。

まず、カーネルコンフィグで”USB/IP support”とその下にある”Host driver”を有効にしてカーネルをビルドしましょう。モジュールにしたならusbip-core.koとusbip-host.koをinsmodしておいてください。

つぎに、ユーザーランドのツールをビルドしましょう。これは上の図の”Device Control Manager”にあたるものです。カーネルのソースのdrivers/staging/usbip/userspaceにソースがおいてあるので、READMEを読みながらビルドしてください。

そして、デバイスマネージャとなるusbipdを起動しましょう。

# usbipd

それからbind_driverコマンドで共有するデバイスを設定してやります。

# bind_driver --list

で、USBデバイスとbusidの一覧がでてくるので、以下のようにしてデバイスを指定します。

# bind_driver --usbip <選択したデバイスのbusid>

3. クライアント側を準備する ーWindows編ー

クライアント側はWindowsも対応しているので、はじめにWindowsで試してみたいと思います。

まず、ここからWindows用のバイナリをダウンロードしてきて、展開します。

そして、デバイスマネージャーを開き、「操作」の「レガシハードウェアの追加」をクリックします。ヴィザードがはじまるので、「次へ」を押して、「一覧から選択したハードウェアをインストールする」を選択します。

ここで、「すべてのデバイスを表示」を選択したまま「次へ」進み、「ディスク使用」のボタンを押して、さきほど展開したディレクトリを選択します。

上のような画面になったら「次へ」を押してインストールを開始させます。 インストールが終われば準備は完了したので、実際に試しましょう。

コマンドプロンプトでさきほど展開したディレクトリに行って、以下のように実行します。

> usbip -l <サーバーのIPアドレス>

すると、サーバー側で共有しているデバイスのリストが出るはずです。

> usbip -a <サーバーのIPアドレス> <デバイスのbusid>

というふうにすると、ちゃんとデバイスが共有されます。

3. クライアント側を準備する ーLinux編ー

まず、カーネルコンフィグで”USB/IP support”とその下にある”VHCI hcd”を有効にしてカーネルをビルドしましょう。モジュールにしたならusbip-core.koとvhci-hcd.koをinsmodしておいてください。それから、先程と同じようにユーザーランドのツールをビルドしましょう。

これで使えるはずです。あと、3240番ポートをSSHポートフォワーディングしたりしても使えます。

# ほんとはscpとUSB/IP over SSHとかでスピードの差とか測ってみたかったんですが
# リモートの仮想マシンでのカーネルビルドが3時間かかっても終わらなかったので
# こんどちゃんと測って結果書きます

 

4. 感想など

すごく面白いです。

手前のノートパソコンにつないだマウスが奥のWindowsでうごいているっていうのはとっても奇妙で楽しかったです。

802.11nでマウスを使用しても気になる程度のタイムラグなどはなかったので、同じLAN内で使うには十分じゃないでしょうか?

ffmpegとopencvをいれる

ffmpegとopencvを連携させるのに結構手間取ったのでめも。

# それにしても動画系はライセンスがいろいろややこしくて難儀

1. ffmpegをいれる

まずgitから最新のソースを落としてくる。

$ git clone git clone git://source.ffmpeg.org/ffmpeg.git

configureする。

$ ./configure --arch=core2 --enable-avconv --enable-gpl \
  --enable-libfaac --enable-libmp3lame --enable-libpulse \
  --enable-libtheora --enable-libv4l2 --enable-libx264 \
  --enable-libxvid --enable-nonfree --enable-openal --enable-pic \
  --enable-shared --enable-version3 --enable-x11grab \
  --enable-zlib --prefix=/usr/local

ここで重要なのは、”–enable-ffmpeg”, “–enable-ffmpeg”, “–enable-pic”, “–enable-shared”。あとはライセンスとかの問題でデフォルトで無効になってるものだったり、追加のコーデックだったりするので、きちんとライセンスやコーデックを使うかを検討してから必要なものだけenableにするとよい。

あと、途中でいろいろlibraryが足りないと言われるので適宜install。ぜんぶapt-getで事足りた。

$ make

で、ビルド開始。すごく時間がかかります。

それで、インストール

# make install

2. OpenCVをいれる

まず、SVNで最新ソースを落としてくる

$ svn co https://code.ros.org/svn/opencv/trunk/opencv

それから、cmakeでconfigureする。

$ cmake .

このとき肝要なのが、以下の項目。

-- FFMPEG: YES
-- codec: YES
-- format: YES
-- util: YES
-- swscale: YES
-- gentoo-style: YES

ffmpegが有効になっていることを確認する。

そして、ビルド。

$ make

最後にインストール。

# make install

これで、OpenCVから動画とかを扱い易くなるはずです。

Esolang Advent Calender 8日目: Esolang on Linux kernel

みなさん、Esolangはご存知ですよね?

Esoteric Language = 奇妙な言語ということで、(難解|難読)プログラミング言語などを意味しています。そのEsolangをカーネルに載せるという話について書きたいと思います。

1.システムコールって?

Linuxカーネルにはシステムコールという機能があります。

システムコールとはカーネルがユーザーランドに対して提供するAPIのようなもので、例えばC言語のfopen()はシステムコールのopen()を裏で呼び出すことによってファイルを開いています。Linuxならカーネルのソースコードをkernel.orgから自由にダウンロードできるので、それを改造すればシステムコールを自前で追加することもできます。

なので、今回はLinuxカーネルにEsolangのインタープリタのシステムコールを追加してみました。

2.システムコールの追加方法

システムコールは、いくつかのファイルをいじって、本体となるファイルを追加するだけで作ることができます。どのようにして追加すればいいのか、例としてBrainfuckのインタープリタのシステムコール、sys_brainfuck()を追加する手順を解説してみます。

A. unistd.h

unistd.hはPOSIX環境でのOSが提供するAPIが定義されているヘッダーファイルです。ここにはシステムコールとそれに割り当てられた通し番号が書かれています。

まず、include/asm-generic/unistd.hに以下のように追記します。

#define __NR_brainfuck <通し番号>
__SYSCALL(__NR_brainfuck, sys_brainfuck)

通し番号は他のと被らないように一番最後の番号+1(バージョン3.2.0-rc4では244)を使用してください。

そして、以下の部分も変更します。

#define __NR_arch_specific_syscall <今までの番号+1>

これは、システムコールの総数を意味しているので、追加した分インクリメントしましょう。

続いて、各アーキテクチャに用意されたunistd.hを編集します。これは、アーキテクチャによって用意されているシステムコールが異なることから、動かしたいアーキテクチャ向けにunistd.hを変更する必要があります。

    • ARMならarch/arm/include/asm/unistd.h
    • x86ならarch/x86/include/asm/unistd_32.h
    • amd64ならarch/x86/include/asm/unistd_64.h

それぞれ表記方法が違ってややこしいのですが、だいたい見れば分かると思います。詳しくは、下に貼ってあるpatchをお読みください。

B.エントリファイル

それぞれのアーキテクチャに対して、アセンブリでシステムコールの一覧が書かれたファイルがあります。

    • ARMならarch/arm/kernel/calls.S
    • x86ならarch/x86/kernel/syscall_table_32.S
    • amd64はなし

これも、アーキテクチャによって微妙に表記方法が違いますが、基本的には順番にならべているだけです。なので、他のところを編集して順番変えてしまったりしないように注意してください!

x86の場合は一番下に以下のように追記すると大丈夫です。

.long sys_brainfuck

C. syscalls.h

これはシステムコールのプロトタイプ宣言が書かれているヘッダーファイルです。

普通と同じようにプロトタイプ宣言を書けばいいのですが、最初にasmlinkageとつける必要があります。要はinclude/linux/syscalls.hに以下のように書けば大丈夫です。

asmlinkage long sys_brainfuck(char *source_user, char *input_user,
                       char *output_user, unsigned int source_len,
                  unsigned int input_len, unsigned int output_len);

D. システムコール本体

今回はkernel/brainfuck.cに本体を書いてみました。

大体は普通にC言語のプログラムと同じように書けばいいのですが、stdio.hなどの標準ライブラリは使えません(カーネルランドで動くので、ユーザーランドのIOなどを使えるはずがありません)。ですが、大抵の関数はインクルードしなくても使えたりします。

また、main関数というものもありません。main関数に当たる部分にはSYSCALL_DEFINEというマクロを使用します。

sys_brainfuckでは以下のような形になります。

SYSCALL_DEFINE6(brainfuck, char *, source_user, char *, input_user,
               char *, output_user, unsigned int, source_len,
               unsigned int input_len, unsigned int, output_len)

簡単に表記すると以下のような仕組みです。

SYSCALL_DEFINE<引数の個数> (<システムコール名>, <引数1の型>, <変数1の名前>...)

また、malloc()やfree()も使えないので、代わりにkmalloc(), kfree()といった関数を使用します。

文字を表示したい場合は、printk()を使用しましょう。printk()はカーネルのログに文字列を出力することができます。

このような簡単な手順でLinuxカーネルのシステムコールを自由にいじることができるのです。

3. 実際にやってみた

とりあえずBrainfuckとLazy Kのインタープリタを作ってみたので、それぞれ、カーネルに当てられるpatchとしてgistにアップロードしました。

このpatchはx86, amd64, armのアーキテクチャに対応しています。Androidのカーネルにこれをあてて、実機で動かすことも可能です。(IS01でやったこともありますが….

あと、システムコールを呼び出す見本プログラムもおいときます。

ちゃんと動くので試してみてください!

4. さいごに

なぜかEsolang Advent Calenderのはずが、Linuxカーネルの記事になってました….

申し訳ありません….

あと、要望があれば別の言語でも作ってみますが?

桜花あどべんとかれんだぁ 4日目 おーかちゃんかわいいよ

おーかちゃんかわいいよ


おーかちゃんかわいいです!

しりあったきっかけ


セキュリティ&プログラミング2011で、はじめて会いましたっ!

僕はLinuxカーネル組で、おーかちゃんがソフトウェアセキュリティ組だったので

おーかちゃんとあんまりはなせませんでした…

でもその時にもらった名刺はちゃんといつでも眺められるように保管してますっ

おーかちゃんのようじょりょくをしる


そのあと、Twitterでふぉろーさせてもらいました

おーかちゃんかわいい!!

しまぱんようじょのかわいさに圧倒されました

Twitterでずっとしゃべってることもしばしば

よく2:00頃とかにおしゃべりさせてもらいました>ω<

おーかちゃんのこわさをしる


それから、関西の勉強会で何度か会うことになります

で、おーかちゃんのこわさをしりました

そのうちのひとつが、カーネル/VM勉強会@関西です

そのときの発表が円周率プログラミングです…

おーかちゃんやっぱりこわいです

あと、おーかちゃんが懇親会でメイド服を着てました

かわいかったです(^ω^)

気になる人は検索してみれば….(/ω・\)

おーかちゃんのきょうぎぷろぐぷろぐらみんぐ


おーかちゃんとの共通点のひとつに競技プログラミングがあります

おーかちゃんつよいです><

いつまでたっても追いつける気がしません

あと、コンテストがだいたい2:00~3:00くらいに終わるので、

それから朝までしゃべってることもけっこうあります

さいごに


おーかちゃんのいえにおじゃまさせてもらったり

なんかいろんなところでお世話になってます

おーかちゃんだいすき!

こんどあえるのはいつかな~?