![f:id:puhitaku:20160118225834j:plain f:id:puhitaku:20160118225834j:plain](https://cdn-ak.f.st-hatena.com/images/fotolife/p/puhitaku/20160118/20160118225834.jpg)
TOC
●Introduction ルータとLinuxとOpenWrt ●1. 前例を調べる ●2. OpenWrtをビルドする ●3. 悪戦苦闘・一旦諦める ●4. 再開 ●5. Linuxを学ぶ ●6. 成功 ●7. 今後Introduction 1. ルータとLinuxとOpenWrt
家電量販店に並ぶ無線ルータ。あなたは、ルータの中身に興味を持ったことがあるだろうか? 実は、あれらはほとんどが組み込みLinuxで動いている。 私はRaspberry Piが発売された時に初めて、世の中にRISC CPUの Linuxが浸透していくのを感じたのだが、 実はそれより遥か昔から組み込みLinuxマシンは一般家庭に浸透していた。それがルータである。 ﹁昔からMIPS含め組み込みLinuxは一般的だから﹂というツッコミもあると思うが、私に言わせればそれはギークの世界だけの話である。 極端な話、昨日初めてパソコンを買ったような人でも多少の手助けですぐ組み込みLinuxの世界に入れるようになったのは、 Raspberry Piが出てからである。x86とのアーキテクチャの違いをほとんど意識しなくてもよくなったのが大きい。 話を戻す。ルータでLinuxが動いているとわかれば、次に興味が湧いてくるのは﹁ルータを好きなようにいじって遊ぶことができるか﹂ ということだ。PS3のような極めて特殊な環境下でも、その上で動くLinuxさえ手に入れば後は遊び放題であるはずだ。 答えはYES。ルータには幸い、OpenWrtをはじめとするディストリビューションが存在する。 ルータは本来ユーザによる改造を意図しないハードだが、製造側でデバッグや修理ができないと色々と困ることから どのようなルータであっても必ずシリアルポートが用意してある。スルーホールやピンヘッダがなくても、プローブを押し当てるランドは絶対にある。 シリアルポートは最も低レベルなアクセスができるため、ブートローダが起きてからLinuxのブートが完全に起動するまで、 すべてのログを読みだすことができる。 また同時にほぼすべてのルータが、LAN越しのファームウェア書き込みの手段を提供している。改造対策のあるなしはあるにしても、 tftpでバイナリを投げればホイホイとファームウェアをFlashに書き込んでくれる。 たったこれだけで、超安くてハイパーお手軽な組み込みLinuxマシンが手に入るのだ。 費用対効果で言えば、Raspberry Pi Zeroが発売されるまではこれに勝るLinuxマシンは無かったし、 今現在も入手性やNICの多さでは負けていない。 私は、ルータ芸人を自称するほどにはこの世界に心酔している。 初めて改造ファーム︵DD-WRT︶をルータに書き込んだのは中3の夏だが、 ルータハックもとい﹁ルータ芸﹂を行うようになったのは高専4年、つまり2年ほど前である。 当初はルータに付いているUSBコネクタにはDACやUSBメモリ・マウス・キーボードなどそれらしいハードを繋いで遊んでいたのだが、ある日 ﹁ルータにPCのディスプレイを接続し、スタンドアロンなLinuxマシンとして使えないか﹂ と思い、実行に移すことにした。1. 前例を調べる
前例を調べると、同様の事例が3つあった。それぞれ、 ●キーイベントの獲得から画面出力までひたすらコードを書いて力技で解決したもの ●カーネルの機能だけで済ませようとしたもののうまくいったかよくわからないもの ●BuffaloのNASにDebianを入れXまで動作させたもの といった顔ぶれで、NASの例に関しては本当に驚いた。 ただ、ルータに限ればどちらもしっくり来るとは言えなかった。 ただどれも共通していたのは、DisplayLink社のUSBアダプタ︵IC︶を使っていることだった。さらに調べてみるとLinuxのソースツリーにDL社のICを駆動するドライバ udlfb がマージされていることも判明した。 直後にFULLER株式会社に入社しアメリカに行く機会を得たため、アメリカにて$15で販売されていたDL-165搭載のアダプタを購入した。2. OpenWrtをビルドする
日本に帰ってきて早速とりかかった。 まずは前例に従いudlfbの導入を行った。Ubuntu TrustyのVMを用意しOpenWrtのBuildrootをインストール、make kernel_menuconfig
でDisplayLink関連のconfigをModuleにした。
![f:id:puhitaku:20160201235328p:plain f:id:puhitaku:20160201235328p:plain](https://cdn-ak.f.st-hatena.com/images/fotolife/p/puhitaku/20160201/20160201235328.png)
scp ./ko/* root@192.168.1.1:/lib/modules/3.xx.xx/
modprobeでkoをロードしてみたら、
![f:id:puhitaku:20151211031823j:plain f:id:puhitaku:20151211031823j:plain](https://cdn-ak.f.st-hatena.com/images/fotolife/p/puhitaku/20151211/20151211031823.jpg)
/dev/fb0
︵Framebuffer, ここに絵を描くことによって画面にそれが描画される。いわばキャンバスのようなもの︶が生成され、dmesgにEDID情報などが出力される。
実際、dmesgやFramebufferの所在を確認してみたらどれも正常だった。でもshellが表示されないのはおかしい。
よく考えたら、Raspberry Piは起動した瞬間からshellが表示される。あれは何なんだろう?と思い調べてみたところ、Framebuffer用のコンソールであるfbcon
(FrameBuffer CONsole) があれであることが判明した。本当に何も入っていないのがルータのLinuxである。
ここでfbconを導入する。もう一度ビルド。
![f:id:puhitaku:20160202002453p:plain f:id:puhitaku:20160202002453p:plain](https://cdn-ak.f.st-hatena.com/images/fotolife/p/puhitaku/20160202/20160202002453.png)
3. 悪戦苦闘・一旦諦める
画面の電源は切れないので正常に認識してはいるようだが、どういうわけか何ら反応がない。キーボードをつないで色々押してもなしのつぶてである。ここから設定を少しずつ変えつつ何度となくカーネルのビルドを繰り返したものの、全く変化はなかった。 どうしてうまく動かないんだ… dmesgは正常、echo 1 > /sys/class/gra
phics/fb0/blank
や、busyboxのアプレットに追加したfbset
を使うなどして画面が変化することも確認した。しかし文字は出ない。
キーボードのKernel Moduleを忘れたか?いやそれも入っているし/dev/input
にもデバイスファイルがある。vtconsoleもある。
結局何度か徹夜したものの全く進展がなく疲れたので、このネタはお蔵入りとなった。
4. 再開
お蔵入りになって2ヶ月経った2016年1月、会社でエンジニアミートアップを行うとの連絡があった。弊社CTOが﹁ルータの発表聞かせて﹂と私に言ったところでお蔵入りになったこのネタを思い出した。 今やるしか無い… そして死闘が始まった。 OpenWrtはtrunkのバージョンが上がっていたので、新しいLinux 4.xの方がコードも新しいだろうと思いtrunkを更新した。2ヶ月前はChaos Chalmerがリリースされてそんなに経っていなかったのに、trunkはいつのまにかDesignated Driverという次世代のコードネームに変わっていた。 画面が真っ暗になるところまで再現した。さてここからどうするか… 結局、前回と同じところを試行錯誤しても全く進展はなかった。 ここで再びRasPiを思い出す。RasPiでもPCでも﹁起動した瞬間に画面に文字が出て、キーを押すと反応する﹂ことが当たり前すぎて気づかなかったのだが、 何でPCを起動したら画面にshellが出て、何でキーを押したら画面に反映されるんだろう という、根本的な事を今まで考えていなかった事に気づいた。 つまり、RasPiでは﹁入出力を司る何か﹂があると気づいた。 RasPiのLinuxにはこの﹁何か﹂を窓口に待ち受けるshellが最初からいて、キーイベントが何らかのルートでこの﹁何か﹂を通り、さらにそれに対してshellが受け答えているのではないか…加えて、この﹁何か﹂を通じる入出力を傍受してPCモニタに出力しているプログラムがRasPiでは動いているのではないか…という所まで考察が進んだところで、Linuxの動作原理について調べることにした。5. Linuxを学ぶ
Linuxにおいて入出力といえば…なんだろう…と考え始めて浮かぶのにそう時間はかからなかった。 ●Arduinoにプログラムを送信したり通信したりするときは/
dev/ttyUSB*
を使う
●シリアルコンソール一般は /dev/ttyS*
で通信できる
●UbuntuでCtrl+Alt+F1を押すと以下の様にtty1
と表示される
![f:id:puhitaku:20160202002402p:plain f:id:puhitaku:20160202002402p:plain](https://cdn-ak.f.st-hatena.com/images/fotolife/p/puhitaku/20160202/20160202002402.png)
echo "Hello World!" > /dev/tty1
すると…
![f:id:puhitaku:20160130105223j:plain f:id:puhitaku:20160130105223j:plain](https://cdn-ak.f.st-hatena.com/images/fotolife/p/puhitaku/20160130/20160130105223.jpg)
6. 成功
色々なものが動作していない可能性を考えていたが、文字が表示されたことを考えるとゴールは近いと確信した。あと一息だ!! ttyに書き込まれた文字はfbconへ出力された。この書き込まれた文字を受け取り、応答を返すshellがいないので調べてみると、/etc/inittab
がこのあたりの動作を定義していることがわかった。
www.atmarkit.co.jp
inittabには、﹁カーネルが起きた後initがどうすればよいか﹂や、﹁TTYへの着信があった際にどんなプロセスを呼べばよいか﹂が書いてある。前者についてはお馴染みのrcSスクリプトの実行が関係していて、後者はgettyに代表されるような、シリアルポートの初期化を行い、着信のあったTTYへログインスクリプトを実行させるプログラムを呼び出す設定である。
なるほど、じゃあtty1に対して/bin/sh --login
を割り当てればいいじゃないか。
tty1::askfirst:/bin/sh --login
と書き加えて再起動した…すると…!!
![f:id:puhitaku:20160118225834j:plain f:id:puhitaku:20160118225834j:plain](https://cdn-ak.f.st-hatena.com/images/fotolife/p/puhitaku/20160118/20160118225834.jpg)
![f:id:puhitaku:20160118220148j:plain f:id:puhitaku:20160118220148j:plain](https://cdn-ak.f.st-hatena.com/images/fotolife/p/puhitaku/20160118/20160118220148.jpg)
![f:id:puhitaku:20160118232539j:plain f:id:puhitaku:20160118232539j:plain](https://cdn-ak.f.st-hatena.com/images/fotolife/p/puhitaku/20160118/20160118232539.jpg)
7. 今後
今後やりたいことはわんさかあるのだが、メモリ容量の限られたルータにおいて︵ZRAMやSwapは使うにせよ︶Xを動かすのは荷が重い。しかしながらウインドウ表示の夢は全く諦めていない。考えていることを雑にまとめると以下のようになる。 ●Xなしでウインドウマネージャとして振る舞えるソフトを使う︵例: Qt︶ ●Wayland / Weston にアプローチする ●USB 3.0に対応したルータで、3.0対応の最新DLチップを使う︵mesaにも期待できる︶ ●DirectFB ちなみに、今回の成果を元にルータでプレゼンを行うためのコードをPythonで書き、実際にプレゼンを行った。このことについては後日別記事で書くことにする。![f:id:puhitaku:20160117094731j:plain f:id:puhitaku:20160117094731j:plain](https://cdn-ak.f.st-hatena.com/images/fotolife/p/puhitaku/20160117/20160117094731.jpg)
![f:id:puhitaku:20160202012811j:plain f:id:puhitaku:20160202012811j:plain](https://cdn-ak.f.st-hatena.com/images/fotolife/p/puhitaku/20160202/20160202012811.jpg)