Linux の移植方法まとめ
前回のエントリで書いたように、今まで自分で実装した独自の ARM システムシミュレータに Linux を移植していたわけですが、シリアルドライバ (8250 コンパチ) と NIC ドライバ (smc91x) が動き、rootfile system on NFS が可能になって、ようやく一段落しました。
全くの素人が 2 週間ぐらいでできたので、(優秀なデバッガさえあれば) 世間一般で思われているほど難しく無いんだな〜 というのが感想です (もちろん途中途中ではかなり悩みましたけど… しょーもないミスや誤解も無数にしました)。
難しいデバイスを動かそうと思ったらメチャクチャ大変なのだろうと思いますけど、今回は、全部自分で書いた仮想デバイスの上に移植したわけですから、動かし方などは完璧にわかりますし、いざとなったらハードウェアを printf デバッグして、ちゃんと I/O レジスタが叩けているかとかの確認までできるという (笑) シミュレータの上に Linux を移植するっていうのは、学習としても優れているのではないかと思います。
手順を簡単にまとめてみると。
(1) 移植済みのボードから、なるべく構成が近そうなものを探す。
今回は、とりあえず arch/arm/mach-versatile を使いました。
まぁ、全然構成は違うのですが、一番最初に参考にしたサイトが QEMU の上で versatile 向けに作った kernel を動かしていたので、そのまま惰性で。
どのみち、ARM に仮想的な PIC (IRR/IMR/ISR だけの単純化された割り込みコントローラ)が付いている変態的な構成ですし。
簡単のため、シミュレータのメモリマップを versatile と同じにしました。
(2) とりあえずいらない CONFIG を全て外してビルドしてみて、vmlinux ができることを確認。
仮想ボードにデバッガから直接ロードするので (PARTNER は ELF を解釈できる)、zImage とかは不要でした。
# ロードするとき、オフセット位置を適切にずらしたり、pc をセットしたり、r1 にマシン番号を入れておいたりとかいろいろやることはあるのですが、省略。
とりあえずロードして実行してみて、setup_arch() まで通過することを確認。
変な CONFIG が有効だと、途中でコケます。
あと物理メモリの設定を間違えたりして、メモリが足りないと、kmem_cache_init() で落ちたりします。
(3) IRQ の初期化
ここが一番大変ですが、これさえできればほぼできたようなものです。
arch/arm/kernel/entry-armv.S の __irq_svc/__irq_usr の irq_handler というアセンブラマクロが、VIC を前提にしたコードだったので、とりあえず全部捨てて、PIC の ISR レジスタを見て IRQ 番号を拾ってきて r0 に入れるようなルーチンと置き換えました。
これで、asm_do_IRQ() に IRQ 番号が渡るようになります。
versatile_init_irq() の実装を参考にしつつ、irq_chip 構造体を初期化します。
今回は PIC で、IRQ ハンドラの最後で EOI (End Of Interrupt) を発行する必要があるので、handle_fasteoi_irq というハンドラを使いました。このハンドラを使うためには、.eoi メンバを適切な EOI ルーチンへの関数ポインタで初期化しておく必要があります。.name や .mask .unmask なども必要だと思います。.name は /proc/interrupts などを見たときに表示されますし、mask/unmask で PIC の IRQ の有効/無効が制御される感じです。
また、set_irq_chip/set_irq_chip_data/set_irq_handler/set_irq_flags を使い、irq_desc 構造体配列の、使いたい IRQ 番号に対応する構造体を適切に初期化しておく必要があります。
ここで適切に IRQ を初期化しておかないと、デバイスドライバなどが request_irq() で IRQ ハンドラを登録しようとした時に失敗します。
最後までここらへんの設定が足りてなかったり間違っていたりで苦しめられました。IRQ ハンドラがちゃんと動くようにさえなれば、あとはデバイスドライバを適宜設定していけば、ちゃんと動かしてくれます。
(4) I/O メモリの初期化
versatile_io_desc[] を参考に、map_desc 構造体配列を初期化します。
ここで適切に I/O メモリのアドレスと範囲を登録しておかないと、ioremap() した時に死にます。
PIC の IMR (Interrupt Mask Register) の全ビットを立てて、全ての IRQ を disable にしておきます。
仮想ボードの方の元栓となる IRQ は開いておきました (有効ルーチンを登録するしくみが無さそうだったので)。
(3) タイマーの初期化
ここらへんは、versatile_timer_*() あたりのコードを少し変更しただけで済みました。
最初はタイマーは 1 つだったのですが、versatile は periodic と freerun のタイマーが 2 つ必要な感じだったので、とりあえずもう一つ freerun の仮想タイマーをでっちあげました。
タイマーの有効、無効、値の取得などの各ルーチンをボードに合わせて実装します。
(4) 8250 コンパチドライバの登録
CONFIG_SERIAL_8250=y
CONFIG_SERIAL_8250_CONSOLE=y
CONFIG_SERIAL_8250_NR_UARTS=2
CONFIG_SERIAL_8250_RUNTIME_UARTS=2
あたりを設定。ドライバは kernel に組み込みます。
plat_serial8250_port 構造体と platform_device 構造体を適切に初期化して、versatile_init() などで platform_device_register() 関数で登録します。
8250 ドライバを使っているボードは多いので、適宜参考にしていけば OK です。
(5) smc91x ドライバの登録
CONFIG_NETDEVICES=y
CONFIG_NET_ETHERNET=y
CONFIG_MII=y
CONFIG_SMC91X=y
あたりを設定。ドライバは組み込みます。
まぎらわしいですが、versatile のは smc911x なので、smc91x とは違います。smc91x_platdata 構造体を適切に初期化して、同じように登録します。
(6) initramfs でテスト
busybox をクロスコンパイルして簡単なルートファイルシステムを作り、kernel に組み込みます。
mem=256M console=ttyS0 root=/dev/ram0
みたいなカーネルコマンドラインで起動してみます。busybox の init が動けば OK。プロンプトが出るはずです。初めて ls や cd が動いた時は感動しました。もちろん Linus ほどではありませんが、光りあれ!という瞬間を感じられます。ようやくここまでこれたんだなぁとしみじみ。
DHCP が動いていれば、udhcp で IP が取れるか確認。
無かったら、ifconfig eth0 192.168.xxx.xxx netmask 255.255.255.0 broadcast 192.168.xxx.255 とか適当に静的に割り振って route add default gw 192.168.xxx.xxx でデフォルトゲートウェイを設定して、/etc/resolv.conf を適当に書いて DNS を指定して、どっか適当に ping して通るか確認してみます。
NFS が mount できれば準備 OK。
(実際はここらへんのユーザランドの構築だけで 3 日ぐらいいろいろ悩んだのですが…)
(7) NFS でブート
initramfs の中身を NFS サーバが export しているディレクトリに移動させて、
root=/dev/nfs nfsroot=192.168.xxx.xxx:/path/to/rootfs rw ip=dhcp
みたいな感じのカーネルコマンドラインで起動。
最初、途中まで上手く行ったけど、上手くプロンプトが /dev/ttyS0 に出てきてくれなかったので、
/etc/inittab を
::respawn:-/bin/sh -i < /dev/ttyS0 > /dev/ttyS0 2>/dev/ttyS0
みたいにして強引に解決。
と、こんな感じで。わかってしまえば簡単ですが、何もかも始めての経験だったので、ハマリそうなポイントにはだいたいはまった感じでけっこう大変でした。そのぶん勉強になって良かったと思います。
今は QEMU の CPU 部分だけを切り出してきて、QLeap さんが Android のためにやった仕事の成果をマージして、PARTNER とつなげて使っているのですが。
これを、完全に PARTNER の純正 CPU シミュレータ (自社開発品) と置き換えるのが、次の目標です。PARTNER シミュレータは、デバッガに直結なんですが、かなり面白い構造になっていて、1 つのシミュレータに対して複数の PARTNER がアタッチできるそうです。つまり、異なる階層や空間のプロセス、例えばカーネルと複数のアプリを、複数の PARTNER を同時起動して同時にデバッグとかが普通にできるらしい。
最終的には、マルチコア対応デバッガのデモが PARTNER デバッガだけでそのままできるように、マルチコアな PARTNER シミュレータの上で SMP 構成の Linux が動いてユーザプログラムの開発ができるところまで持っていくつもりです。より最新の ARM コアのサポートや、実行性能の向上など、やらなければいけないことはたくさんあります。
というわけで、今後はデバッガとシミュレータ (時にはその上で動く OS やアプリも) を同時に開発するという日々になりそうです。より汎用的で優れたソリューションをお客様に提供できるように、品質と機能の向上を目指して楽しみながら頑張って行きます!
全くの素人が 2 週間ぐらいでできたので、(優秀なデバッガさえあれば) 世間一般で思われているほど難しく無いんだな〜 というのが感想です (もちろん途中途中ではかなり悩みましたけど… しょーもないミスや誤解も無数にしました)。
難しいデバイスを動かそうと思ったらメチャクチャ大変なのだろうと思いますけど、今回は、全部自分で書いた仮想デバイスの上に移植したわけですから、動かし方などは完璧にわかりますし、いざとなったらハードウェアを printf デバッグして、ちゃんと I/O レジスタが叩けているかとかの確認までできるという (笑) シミュレータの上に Linux を移植するっていうのは、学習としても優れているのではないかと思います。
手順を簡単にまとめてみると。
(1) 移植済みのボードから、なるべく構成が近そうなものを探す。
今回は、とりあえず arch/arm/mach-versatile を使いました。
まぁ、全然構成は違うのですが、一番最初に参考にしたサイトが QEMU の上で versatile 向けに作った kernel を動かしていたので、そのまま惰性で。
どのみち、ARM に仮想的な PIC (IRR/IMR/ISR だけの単純化された割り込みコントローラ)が付いている変態的な構成ですし。
簡単のため、シミュレータのメモリマップを versatile と同じにしました。
(2) とりあえずいらない CONFIG を全て外してビルドしてみて、vmlinux ができることを確認。
仮想ボードにデバッガから直接ロードするので (PARTNER は ELF を解釈できる)、zImage とかは不要でした。
# ロードするとき、オフセット位置を適切にずらしたり、pc をセットしたり、r1 にマシン番号を入れておいたりとかいろいろやることはあるのですが、省略。
とりあえずロードして実行してみて、setup_arch() まで通過することを確認。
変な CONFIG が有効だと、途中でコケます。
あと物理メモリの設定を間違えたりして、メモリが足りないと、kmem_cache_init() で落ちたりします。
(3) IRQ の初期化
ここが一番大変ですが、これさえできればほぼできたようなものです。
arch/arm/kernel/entry-armv.S の __irq_svc/__irq_usr の irq_handler というアセンブラマクロが、VIC を前提にしたコードだったので、とりあえず全部捨てて、PIC の ISR レジスタを見て IRQ 番号を拾ってきて r0 に入れるようなルーチンと置き換えました。
これで、asm_do_IRQ() に IRQ 番号が渡るようになります。
versatile_init_irq() の実装を参考にしつつ、irq_chip 構造体を初期化します。
今回は PIC で、IRQ ハンドラの最後で EOI (End Of Interrupt) を発行する必要があるので、handle_fasteoi_irq というハンドラを使いました。このハンドラを使うためには、.eoi メンバを適切な EOI ルーチンへの関数ポインタで初期化しておく必要があります。.name や .mask .unmask なども必要だと思います。.name は /proc/interrupts などを見たときに表示されますし、mask/unmask で PIC の IRQ の有効/無効が制御される感じです。
また、set_irq_chip/set_irq_chip_data/set_irq_handler/set_irq_flags を使い、irq_desc 構造体配列の、使いたい IRQ 番号に対応する構造体を適切に初期化しておく必要があります。
ここで適切に IRQ を初期化しておかないと、デバイスドライバなどが request_irq() で IRQ ハンドラを登録しようとした時に失敗します。
最後までここらへんの設定が足りてなかったり間違っていたりで苦しめられました。IRQ ハンドラがちゃんと動くようにさえなれば、あとはデバイスドライバを適宜設定していけば、ちゃんと動かしてくれます。
(4) I/O メモリの初期化
versatile_io_desc[] を参考に、map_desc 構造体配列を初期化します。
ここで適切に I/O メモリのアドレスと範囲を登録しておかないと、ioremap() した時に死にます。
PIC の IMR (Interrupt Mask Register) の全ビットを立てて、全ての IRQ を disable にしておきます。
仮想ボードの方の元栓となる IRQ は開いておきました (有効ルーチンを登録するしくみが無さそうだったので)。
(3) タイマーの初期化
ここらへんは、versatile_timer_*() あたりのコードを少し変更しただけで済みました。
最初はタイマーは 1 つだったのですが、versatile は periodic と freerun のタイマーが 2 つ必要な感じだったので、とりあえずもう一つ freerun の仮想タイマーをでっちあげました。
タイマーの有効、無効、値の取得などの各ルーチンをボードに合わせて実装します。
(4) 8250 コンパチドライバの登録
CONFIG_SERIAL_8250=y
CONFIG_SERIAL_8250_CONSOLE=y
CONFIG_SERIAL_8250_NR_UARTS=2
CONFIG_SERIAL_8250_RUNTIME_UARTS=2
あたりを設定。ドライバは kernel に組み込みます。
plat_serial8250_port 構造体と platform_device 構造体を適切に初期化して、versatile_init() などで platform_device_register() 関数で登録します。
8250 ドライバを使っているボードは多いので、適宜参考にしていけば OK です。
(5) smc91x ドライバの登録
CONFIG_NETDEVICES=y
CONFIG_NET_ETHERNET=y
CONFIG_MII=y
CONFIG_SMC91X=y
あたりを設定。ドライバは組み込みます。
まぎらわしいですが、versatile のは smc911x なので、smc91x とは違います。smc91x_platdata 構造体を適切に初期化して、同じように登録します。
(6) initramfs でテスト
busybox をクロスコンパイルして簡単なルートファイルシステムを作り、kernel に組み込みます。
mem=256M console=ttyS0 root=/dev/ram0
みたいなカーネルコマンドラインで起動してみます。busybox の init が動けば OK。プロンプトが出るはずです。初めて ls や cd が動いた時は感動しました。もちろん Linus ほどではありませんが、光りあれ!という瞬間を感じられます。ようやくここまでこれたんだなぁとしみじみ。
DHCP が動いていれば、udhcp で IP が取れるか確認。
無かったら、ifconfig eth0 192.168.xxx.xxx netmask 255.255.255.0 broadcast 192.168.xxx.255 とか適当に静的に割り振って route add default gw 192.168.xxx.xxx でデフォルトゲートウェイを設定して、/etc/resolv.conf を適当に書いて DNS を指定して、どっか適当に ping して通るか確認してみます。
NFS が mount できれば準備 OK。
(実際はここらへんのユーザランドの構築だけで 3 日ぐらいいろいろ悩んだのですが…)
(7) NFS でブート
initramfs の中身を NFS サーバが export しているディレクトリに移動させて、
root=/dev/nfs nfsroot=192.168.xxx.xxx:/path/to/rootfs rw ip=dhcp
みたいな感じのカーネルコマンドラインで起動。
最初、途中まで上手く行ったけど、上手くプロンプトが /dev/ttyS0 に出てきてくれなかったので、
/etc/inittab を
::respawn:-/bin/sh -i < /dev/ttyS0 > /dev/ttyS0 2>/dev/ttyS0
みたいにして強引に解決。
と、こんな感じで。わかってしまえば簡単ですが、何もかも始めての経験だったので、ハマリそうなポイントにはだいたいはまった感じでけっこう大変でした。そのぶん勉強になって良かったと思います。
今は QEMU の CPU 部分だけを切り出してきて、QLeap さんが Android のためにやった仕事の成果をマージして、PARTNER とつなげて使っているのですが。
これを、完全に PARTNER の純正 CPU シミュレータ (自社開発品) と置き換えるのが、次の目標です。PARTNER シミュレータは、デバッガに直結なんですが、かなり面白い構造になっていて、1 つのシミュレータに対して複数の PARTNER がアタッチできるそうです。つまり、異なる階層や空間のプロセス、例えばカーネルと複数のアプリを、複数の PARTNER を同時起動して同時にデバッグとかが普通にできるらしい。
最終的には、マルチコア対応デバッガのデモが PARTNER デバッガだけでそのままできるように、マルチコアな PARTNER シミュレータの上で SMP 構成の Linux が動いてユーザプログラムの開発ができるところまで持っていくつもりです。より最新の ARM コアのサポートや、実行性能の向上など、やらなければいけないことはたくさんあります。
というわけで、今後はデバッガとシミュレータ (時にはその上で動く OS やアプリも) を同時に開発するという日々になりそうです。より汎用的で優れたソリューションをお客様に提供できるように、品質と機能の向上を目指して楽しみながら頑張って行きます!
Linux のポーティング
最近はずっとハードウェアシミュレータを開発していて (GCC x86/sh のバックエンドを hack したりもしてましたが),仮想 CPU エミュレータ (PARTNER デバッガと直結)/割り込みコントローラ (PIC)/シリアルコントローラ/ネットワークインタフェースカード (NIC) と一通り実装して,テストプログラムをそれぞれ書きました (NIC は ping サーバ,要するに ARP と ICMP に応答するプログラムを書いた).
そしたら社長が 「そんだけあれば Linux 動くやん.ほなら移植してみましょか.若槻さんのお勉強もかねて.良い経験になるで」 という展開に.
Linux とか全く開発したこと無いし,ましてや ARM のアーキテクチャ依存部なんて,いくら Linux の本は多いとはいえ資料全然無いし,ほんまにできるんかなと,ここ数日はけっこう暗中模索で大変でした.社長は 「一人でやってたら,詰まったら終わりやけどやな,この会社にはいっぱいできる人おるから大丈夫ですよ」 とさらっと言うのですが w
# ちなみに QLeap さんもいつも同じような感じで,「〜難しいです」 と僕が弱音を言うと 「そんなのアレしてコレするだけじゃん」 とさらっと言われます w その 「〜するだけ」 に苦労しているのに ww みんながこの調子の会社なので,知らず知らずのうちに感覚がマヒしてきて,何でもできるし,何でもできるようにならないといけない,できてあたりまえという感覚が当たり前になってくる,恐ろしい会社です (笑)
この会社に入ってから,良い感じに 「今の自分の実力よりも,ちょっと上の課題」 (もちろん勉強だけではなく,お客様がいる仕事の場合もあるのですが) を社長にもらっている気がします.趣味で遊んでいるだけだったら,もちろん PARTNER のような優秀なデバッガもありませんし,ちょっと大変だったり面倒だったりすると諦めてしまう場合が多いと思います.でも仕事ともなれば,やらないといけないし途中で投げ出すわけにはいかないので,プレッシャーや不安はすごく大きいですが,そのぶん上手く行ったときの達成感はすごいですし,自分の成長が実感できて達成感があります.今までの勉強,仕事させてもらったこと - (クロス)コンパイラ,組み込みプログラミング,JTAG デバッガの使い方,シミュレータの開発 - 全部繋がってきている感じがします.シミュレータの最高のテストにもなりますし,Linux ポーティングは,入社して半年の,一つの集大成ですね.
そんなこんなで,ここ 3 日間ぐらいひたすら悩みながら頑張ってました.最初の 2 日間は,そもそも Linux kernel のクロスコンパイル自体が初めてで,何をやったら良いのかすらさっぱりわからず,非常に暗中模索でした.
とりあえず QEMU (ARM) の上で,VMWare 上の Linux でクロスコンパイルした kernel 2.6.29 が動いた時はほっとしました.
qemu memo 2009年4月7日 kernel 2.6.29 と差し替えてみる (私が書いている別ブログ.他にも gccmemo というブログを blogspot に書いてます.ブログというか,作業メモのうち,外部に公開しても支障が無いものだけですが.支障があるものは,社内限定のログに書いてます)
動くものさえできてしまえば,デバッグ情報とソースがあるわけですから,PARTNER (QEMU に接続できる) で完璧に動きが追えますから.
「動いてるものだけが正義.デバッガを 2 台立ち上げて,動くものと動かないものを常に同時に動かして比較するのが一番確実で近道」 という鉄則を,何度も社長から聞かされました.いくらソース読んだりしても,それは想像にしか過ぎないわけで,実際に CPU の上で動いている機械語だけが信頼できる唯一のものです.
VMWare の中の Linux の中で samba を立ち上げて,ビルドした vmlinux をすぐに共有できるようにして,とりあえず不要なデバイスを全て外した kernel をビルドしました.デバッガからのロードのしかたも最初はわからなかったので,ここらへんは QLeap さんから教わりました(後述).とりあえず setup_arch() を超えるのが最初の関門.一番最初は,CPU 以外何もデバイスが動いてない状態なので,networking support から何から何まで,なるべくいらないものを外して絞り込む必要があります.あと,しょーもないミスですが,シミュレータのメモリ量の設定を間違えていて(kernel command に mem=32M とかでに渡した値よりも少なかった…),物理メモリが足りなくて kmem_cache_init() で死んだりとか,いろいろ罠がいっぱいでした.
次に,printk() を hack しました.シリアルコントローラの動かし方 (NS16550 互換) は,テストプログラムを書いたのでわかっています.出力するだけなら,割り込みさえ不要です.バッファの状態をポーリングで確認して,書き込み可能の状態で TX レジスタに書き込むだけでシリアルコンソールに文字は出ます.このルーチンを,printk() の最下層の __call_console_driver() のところにしこみました.log_buf[] という文字列バッファの,__call_console_driver() の引数の start から end までの部分を出力するようにしておけば,とりあえずこれで,コンソールドライバが動いてなくてもコンソールにログが出ます.
途中,BoGoMIPS のための calibration delay loop ... のところで止まってしまいます.これはタイマーが動いてないので,jiffies 変数がインクリメントされないからです.つまり,割り込みコントローラとタイマーを両方正しく動かす必要があります.
しかし,ARM の標準的な構成では,AVIC というベクター割り込みコントローラを使っているのですが,僕が作ったのはもっと素朴で簡単な PIC ですから,全然違います.というわけで,まだ IRQ が上手くハンドルできてません.
とりあえず __irq_svc というアセンブラで書かれたエントリーポイントまでは行くのですが,ここからちゃんと IRQ ハンドラの登録と呼び出しができてないので,またまた酷い hack で切り抜けました.とりあえず,このエントリーポイントの中に,直接 jiffies と PIC を操作するルーチンをアセンブラで書きました.これでとりあえず jiffies は進む…
そんなこんなで,なんとか init 直前の kernel panic までたどり着きました.これは,root ファイルシステムが無いので,当然のことです.しかし,root ファイルシステムを mount するためには,NFS のための NIC ドライバか,なんらかのブロックデバイスのドライバを動かさないといけない… 大変です.
というわけで,initramfs で切り抜けました.これは kernel の中に直接 ramfs を組み込むというもののようです.initrd を使っても良いのですが,僕は直接 PARTNER デバッガで ELF ファイル (vmlinux.圧縮された zImage ではなく) をロードして pc と r1 (machine number.これが正しく無いと起動しません) をセットして実行してるので,一つのバイナリにまとまってくれている方が楽なんです.
参考 : takinoya’s note on web 2009-03-04 Hello again, linux!
とりあえず 3 日間ぐらいで,全くの素人から init の起動までこぎつけることができました.こうなると楽しくなってくるし,やる気がどんどん出てきます.昨日まであんなに弱気で疲労していたのに,全部吹っ飛んでしまいます (笑)
まぁ,大変なのはこれからなんですが.mach-* と defconfig をちゃんと作って (今は mach-versatile と versatile_defconfig をベースに改造している.汚い hack だらけなので,きれいに作り直したい),IRQ 周りをちゃんとして,シリアルと SMSC LAN91C111 のドライバをちゃんと動かして,ユーザランドで printf ができるようにして,ramfs で busybox 動くことを確認して,最終的には root ファイルシステムを NFS でマウントできるようにして… 課題は山積みですが,一つ一つ確実に解決して,力を付けて行きたいですね.
そしたら社長が 「そんだけあれば Linux 動くやん.ほなら移植してみましょか.若槻さんのお勉強もかねて.良い経験になるで」 という展開に.
Linux とか全く開発したこと無いし,ましてや ARM のアーキテクチャ依存部なんて,いくら Linux の本は多いとはいえ資料全然無いし,ほんまにできるんかなと,ここ数日はけっこう暗中模索で大変でした.社長は 「一人でやってたら,詰まったら終わりやけどやな,この会社にはいっぱいできる人おるから大丈夫ですよ」 とさらっと言うのですが w
# ちなみに QLeap さんもいつも同じような感じで,「〜難しいです」 と僕が弱音を言うと 「そんなのアレしてコレするだけじゃん」 とさらっと言われます w その 「〜するだけ」 に苦労しているのに ww みんながこの調子の会社なので,知らず知らずのうちに感覚がマヒしてきて,何でもできるし,何でもできるようにならないといけない,できてあたりまえという感覚が当たり前になってくる,恐ろしい会社です (笑)
この会社に入ってから,良い感じに 「今の自分の実力よりも,ちょっと上の課題」 (もちろん勉強だけではなく,お客様がいる仕事の場合もあるのですが) を社長にもらっている気がします.趣味で遊んでいるだけだったら,もちろん PARTNER のような優秀なデバッガもありませんし,ちょっと大変だったり面倒だったりすると諦めてしまう場合が多いと思います.でも仕事ともなれば,やらないといけないし途中で投げ出すわけにはいかないので,プレッシャーや不安はすごく大きいですが,そのぶん上手く行ったときの達成感はすごいですし,自分の成長が実感できて達成感があります.今までの勉強,仕事させてもらったこと - (クロス)コンパイラ,組み込みプログラミング,JTAG デバッガの使い方,シミュレータの開発 - 全部繋がってきている感じがします.シミュレータの最高のテストにもなりますし,Linux ポーティングは,入社して半年の,一つの集大成ですね.
そんなこんなで,ここ 3 日間ぐらいひたすら悩みながら頑張ってました.最初の 2 日間は,そもそも Linux kernel のクロスコンパイル自体が初めてで,何をやったら良いのかすらさっぱりわからず,非常に暗中模索でした.
とりあえず QEMU (ARM) の上で,VMWare 上の Linux でクロスコンパイルした kernel 2.6.29 が動いた時はほっとしました.
qemu memo 2009年4月7日 kernel 2.6.29 と差し替えてみる (私が書いている別ブログ.他にも gccmemo というブログを blogspot に書いてます.ブログというか,作業メモのうち,外部に公開しても支障が無いものだけですが.支障があるものは,社内限定のログに書いてます)
動くものさえできてしまえば,デバッグ情報とソースがあるわけですから,PARTNER (QEMU に接続できる) で完璧に動きが追えますから.
「動いてるものだけが正義.デバッガを 2 台立ち上げて,動くものと動かないものを常に同時に動かして比較するのが一番確実で近道」 という鉄則を,何度も社長から聞かされました.いくらソース読んだりしても,それは想像にしか過ぎないわけで,実際に CPU の上で動いている機械語だけが信頼できる唯一のものです.
VMWare の中の Linux の中で samba を立ち上げて,ビルドした vmlinux をすぐに共有できるようにして,とりあえず不要なデバイスを全て外した kernel をビルドしました.デバッガからのロードのしかたも最初はわからなかったので,ここらへんは QLeap さんから教わりました(後述).とりあえず setup_arch() を超えるのが最初の関門.一番最初は,CPU 以外何もデバイスが動いてない状態なので,networking support から何から何まで,なるべくいらないものを外して絞り込む必要があります.あと,しょーもないミスですが,シミュレータのメモリ量の設定を間違えていて(kernel command に mem=32M とかでに渡した値よりも少なかった…),物理メモリが足りなくて kmem_cache_init() で死んだりとか,いろいろ罠がいっぱいでした.
次に,printk() を hack しました.シリアルコントローラの動かし方 (NS16550 互換) は,テストプログラムを書いたのでわかっています.出力するだけなら,割り込みさえ不要です.バッファの状態をポーリングで確認して,書き込み可能の状態で TX レジスタに書き込むだけでシリアルコンソールに文字は出ます.このルーチンを,printk() の最下層の __call_console_driver() のところにしこみました.log_buf[] という文字列バッファの,__call_console_driver() の引数の start から end までの部分を出力するようにしておけば,とりあえずこれで,コンソールドライバが動いてなくてもコンソールにログが出ます.
途中,BoGoMIPS のための calibration delay loop ... のところで止まってしまいます.これはタイマーが動いてないので,jiffies 変数がインクリメントされないからです.つまり,割り込みコントローラとタイマーを両方正しく動かす必要があります.
しかし,ARM の標準的な構成では,AVIC というベクター割り込みコントローラを使っているのですが,僕が作ったのはもっと素朴で簡単な PIC ですから,全然違います.というわけで,まだ IRQ が上手くハンドルできてません.
とりあえず __irq_svc というアセンブラで書かれたエントリーポイントまでは行くのですが,ここからちゃんと IRQ ハンドラの登録と呼び出しができてないので,またまた酷い hack で切り抜けました.とりあえず,このエントリーポイントの中に,直接 jiffies と PIC を操作するルーチンをアセンブラで書きました.これでとりあえず jiffies は進む…
そんなこんなで,なんとか init 直前の kernel panic までたどり着きました.これは,root ファイルシステムが無いので,当然のことです.しかし,root ファイルシステムを mount するためには,NFS のための NIC ドライバか,なんらかのブロックデバイスのドライバを動かさないといけない… 大変です.
というわけで,initramfs で切り抜けました.これは kernel の中に直接 ramfs を組み込むというもののようです.initrd を使っても良いのですが,僕は直接 PARTNER デバッガで ELF ファイル (vmlinux.圧縮された zImage ではなく) をロードして pc と r1 (machine number.これが正しく無いと起動しません) をセットして実行してるので,一つのバイナリにまとまってくれている方が楽なんです.
参考 : takinoya’s note on web 2009-03-04 Hello again, linux!
とりあえず 3 日間ぐらいで,全くの素人から init の起動までこぎつけることができました.こうなると楽しくなってくるし,やる気がどんどん出てきます.昨日まであんなに弱気で疲労していたのに,全部吹っ飛んでしまいます (笑)
まぁ,大変なのはこれからなんですが.mach-* と defconfig をちゃんと作って (今は mach-versatile と versatile_defconfig をベースに改造している.汚い hack だらけなので,きれいに作り直したい),IRQ 周りをちゃんとして,シリアルと SMSC LAN91C111 のドライバをちゃんと動かして,ユーザランドで printf ができるようにして,ramfs で busybox 動くことを確認して,最終的には root ファイルシステムを NFS でマウントできるようにして… 課題は山積みですが,一つ一つ確実に解決して,力を付けて行きたいですね.
andLinux 素晴らしい
windows 上で Linux 環境を使いたい場合,ユーザーモード OS として Linux kernel を Windows 上で実行できる coLinux が便利そう,というのは前から知っていたのですが.どうも coLinux は設定が面倒そうというイメージがあり,導入をためらっていました.
しかし,andLinux というのを知ったので試してみました.これは素晴らしいですね.ダウンロードしてインストーラを起動するだけでインストール終わりです.
日本語が使えないという意見がチラホラ見えますが,以下のサイトの通りにするだけで普通に使えました (要するに Ubuntu の初期設定と同じ ? Ubuntu は使ったことが無いのでよくわからないのですが)
ひゃまだのテキストで行こう - andLinuxのメモ
個人的にちょっと引っかかったのは,apt-get update した時に gpg エラーが出たことだけです.source.list に書いてあるのと同じようにして,エラーが出た時に出てくるキーを承認してあげればよいみたいです.
Start andLinux の他にも,Terminal のショートカットとかを作っておいた方が便利そうです.私は最初 vmware のように,箱庭環境 (?) の中でアプリを実行するものだと勘違いしていたので,どうせターミナルだけ上がれば良いやと思っていたのですが.
普通に,Windows の DOS 窓みたいに,いきなりターミナルが立ち上がります.そして,普通にターミナルから firefox を上げて Windows のネイティブアプリと同じようにシームレスに Linux アプリが全て使えます.Windows ⇔ Linux アプリ間でコピペも普通にできます (もちろん Windows と Linux では操作の作法は違いますが) Linux の方に Windows のファイルシステムがマウントされてるので,ファイル共有も簡単です.
とりあえずこれをインストールすれば,Windows 上に細々とした UNIX ツールを入れる必要性は少なくなりそうですね.apt でアプリがインストールできて,普通に Windows アプリとして使えるのはかなり大きいです.
しかし,andLinux というのを知ったので試してみました.これは素晴らしいですね.ダウンロードしてインストーラを起動するだけでインストール終わりです.
日本語が使えないという意見がチラホラ見えますが,以下のサイトの通りにするだけで普通に使えました (要するに Ubuntu の初期設定と同じ ? Ubuntu は使ったことが無いのでよくわからないのですが)
ひゃまだのテキストで行こう - andLinuxのメモ
個人的にちょっと引っかかったのは,apt-get update した時に gpg エラーが出たことだけです.source.list に書いてあるのと同じようにして,エラーが出た時に出てくるキーを承認してあげればよいみたいです.
# gpg --keyserver subkeys.pgp.net --recv 認証したいキー
# gpg --export --armor 認証したいキー | apt-key add -
Start andLinux の他にも,Terminal のショートカットとかを作っておいた方が便利そうです.私は最初 vmware のように,箱庭環境 (?) の中でアプリを実行するものだと勘違いしていたので,どうせターミナルだけ上がれば良いやと思っていたのですが.
普通に,Windows の DOS 窓みたいに,いきなりターミナルが立ち上がります.そして,普通にターミナルから firefox を上げて Windows のネイティブアプリと同じようにシームレスに Linux アプリが全て使えます.Windows ⇔ Linux アプリ間でコピペも普通にできます (もちろん Windows と Linux では操作の作法は違いますが) Linux の方に Windows のファイルシステムがマウントされてるので,ファイル共有も簡単です.
とりあえずこれをインストールすれば,Windows 上に細々とした UNIX ツールを入れる必要性は少なくなりそうですね.apt でアプリがインストールできて,普通に Windows アプリとして使えるのはかなり大きいです.
Damnsmall Linux 4.2 をインストールする
昨日 eco linux をインストールしたばかりですが,atptitude の罠によってうっかり大量のパッケージが削除されてしまったので,再びインストール.
eco は ubuntu ベースということで,微妙に debian と体系が異なりますし,けっこう重い気がしました.というわけで,今度は最軽量と名高い Damnsmall Linux を試してみます.
とりあえず,ライブ CD の部屋から Damnsmall Linux 4.2 日本語版 を持ってきて CD に焼きます.
そして昨日と同じように Thinkpad A21e に突っ込んで,F1 押して BIOS を CD ブートにして起動.
起動速っ !! 鬼のように速いです.これ,CD で常用できるんじゃないの ?
壁紙がカッコいいですね.シェルも透明だ.メモリを 50 M/256 M ぐらいしか使ってない.すごい.
とりあえずメニューから [DSL] > [アプリケーション] > [ツール] > [ハードディスクへインストール]
ここらへんを参考に.昨日 eco linux で作ったパーティションにそのまま Write して Quit.質問には全部 yes で OK.
5 分ぐらいでインストール完了 → reboot
root と dsl というユーザのパスワードを入力.dsl でログイン.
すごい,20 M ぐらいしか使ってない.su - して X の設定などする.
------------------- ここからは DSL 側でブログ書く (ルータ持って無いので…) ------------------
Knuppix ベースなのでハードウェア認識力が高く、設定ゼロで usb マウスが動き pppoeconf で普通にネットにつなげて、UIM + Anthy で日本語が読み書きできます (Ctrl+Space の他にも全角/半角キーでも切り替わる)。素晴らしい。firefox を立ち上げても 80 M 程度の消費で収まってます。eco で fc2 のブログエディタを使っていると、かなり遅延が酷くて、文字を打って変換する過程がスローモーションのようだったのですが、DSL は非常に軽いですね。最高です。これは良い。
とりあえず,句読点とスペースの設定.こんな感じの Scheme コードを置いておくと,句読点が,.になり,常に半角スペースを使用するようになります.
Ctrl と Swap を入れ換える.
apt-get をするまえには,[DSL] > [アプリケーション] > [ツール] > [APT 有効化] をしておく必要があるみたいです (これをやっておかないと以下のようなエラーが出る)
わりと DSL はいろいろ設定ツールとかゲームまで入ってる感じ (pppoeconf しなくても,ちゃんと GUI ツールがあったみたい [DSL] > [設定] > [ネットワーク] > [DSL/PPPoE] > [PPPoE 設定]) なので,本気出せばもっと軽量化できそうな気もしますね.
DSL,というか,たぶんライブCDの部屋の人が非常に素晴らしいのだと思いますが,非常に良いですね.JWM も普通に使えます.
eco は ubuntu ベースということで,微妙に debian と体系が異なりますし,けっこう重い気がしました.というわけで,今度は最軽量と名高い Damnsmall Linux を試してみます.
とりあえず,ライブ CD の部屋から Damnsmall Linux 4.2 日本語版 を持ってきて CD に焼きます.
$ du -h dsl-4.2-jp.iso
126M dsl-4.2-jp.iso
$ cat dsl-4.2-jp.iso.md5
f4f55a87140d0161c9832776dd622e9c
$ md5sum dsl-4.2-jp.iso
f4f55a87140d0161c9832776dd622e9c dsl-4.2-jp.iso
$ cdrecord dev=ATAPI -scanbus
WARNING: the ATAPI: method is considered deprecated on modern kernels!
Mapping device specification to ATA: method now.
To force the old ATAPI: method, replace ATAPI: with OLDATAPI:
scsibus0:
0,0,0 0) *
0,1,0 1) *
0,2,0 2) 'COMBO ' 'IDE4816CO ' '0037' Removable CD-ROM
0,3,0 3) *
0,4,0 4) *
0,5,0 5) *
0,6,0 6) *
0,7,0 7) *
$ cdrecord dev=ATAPI:0,2,0 -v -eject dsl-4.2-jp.iso
そして昨日と同じように Thinkpad A21e に突っ込んで,F1 押して BIOS を CD ブートにして起動.
起動速っ !! 鬼のように速いです.これ,CD で常用できるんじゃないの ?
壁紙がカッコいいですね.シェルも透明だ.メモリを 50 M/256 M ぐらいしか使ってない.すごい.
とりあえずメニューから [DSL] > [アプリケーション] > [ツール] > [ハードディスクへインストール]
ここらへんを参考に.昨日 eco linux で作ったパーティションにそのまま Write して Quit.質問には全部 yes で OK.
5 分ぐらいでインストール完了 → reboot
root と dsl というユーザのパスワードを入力.dsl でログイン.
すごい,20 M ぐらいしか使ってない.su - して X の設定などする.
------------------- ここからは DSL 側でブログ書く (ルータ持って無いので…) ------------------
Knuppix ベースなのでハードウェア認識力が高く、設定ゼロで usb マウスが動き pppoeconf で普通にネットにつなげて、UIM + Anthy で日本語が読み書きできます (Ctrl+Space の他にも全角/半角キーでも切り替わる)。素晴らしい。firefox を立ち上げても 80 M 程度の消費で収まってます。eco で fc2 のブログエディタを使っていると、かなり遅延が酷くて、文字を打って変換する過程がスローモーションのようだったのですが、DSL は非常に軽いですね。最高です。これは良い。
とりあえず,句読点とスペースの設定.こんな感じの Scheme コードを置いておくと,句読点が,.になり,常に半角スペースを使用するようになります.
$ cat ~/.uim
(require-module "anthy")
(define ja-rk-rule
(append '((((",") . ()) ("," "," ","))
(((".") . ()) ("." "." "."))) ja-rk-rule))
(require "japanese.scm")
(define ja-direct-rule '((" " " ")))
Ctrl と Swap を入れ換える.
$ cat .xmodmap
remove Lock = Caps_Lock
remove Control = Control_L
keysym Control_L = Caps_Lock
keysym Caps_Lock = Control_L
add Control = Control_L
add Lock = Caps_Lock
$ cat .xinitrc
...
xmodmap -e "keycode 49 = Zenkaku_Hankaku"
xmodmap .xmodmap
...
apt-get をするまえには,[DSL] > [アプリケーション] > [ツール] > [APT 有効化] をしておく必要があるみたいです (これをやっておかないと以下のようなエラーが出る)
# apt-get update
E: Could not open lock file /var/lib/apt/lists/lock - open (2 そのようなファイルやディレクトリはありません)
E: Unable to lock the list directory
わりと DSL はいろいろ設定ツールとかゲームまで入ってる感じ (pppoeconf しなくても,ちゃんと GUI ツールがあったみたい [DSL] > [設定] > [ネットワーク] > [DSL/PPPoE] > [PPPoE 設定]) なので,本気出せばもっと軽量化できそうな気もしますね.
DSL,というか,たぶんライブCDの部屋の人が非常に素晴らしいのだと思いますが,非常に良いですね.JWM も普通に使えます.
eco linux から記念カキコ
Thinkpad A21e (2655-CS5) に eco linux をインストールしてみました。
特に難しいところは何も無く、設定ゼロで X が立ち上がって、USB マウスが使えて、pppoeconf でフレッツ光に繋いで、Firefox を立ち上げて、SCIM + Anthy でいきなり日本語が使えて、ブログが書けます。素晴らしい。
root になれない (全部 sudo でやる) のは、Ubuntu の流儀なんですかね ? apt も vi も入ってないあたりが今風だなぁと。symaptic とか GUI ツールはイマイチ使い方がよくわからないです。まぁ、おいおいカスタマイズしていきます。基本的に Debian ベースなのだから、何とでもなるはず。
# 句読点のスタイルは良いとしても、全角スペースが混ざってしまうのが気持ち悪い…
なんと作者は現役高校1年生らしいです。すごい。高速道路世代ここに極まれりというか。2 ちゃんねるでの受け答えも堂々たるもので、いやはや、なんとも。
ところで、今年の後半に Debian の lenny が出るらしいんですが、kernel だけ linux から FreeBSD に変更したDebian GNU/kFreeBSD が公式サポートに追加されるそうです。これはかなり面白い上に、GNU プロジェクトが Linux kernel への依存を断ち切りつつあるという意味でも意義深いと思います (もともと FreeBSD の ports を意識したらしい Gentoo の FreeBSD 版、Gentoo GNU/kFreeBSD もあるみたい)。もともと Linux は Hurd の代用品に過ぎなかったわけで。自由で完全な UNIX システムをゼロから作る (GNU is NOT UNIX) という当初のプロジェクトの目的からすれば、UNIX の代用品の代用品なわけです。ユーザにとって、(現在のレベルの kernel では)、kernel 自体はどうでもいい。所詮どのスクリプト言語を選ぶのかといった言語マニアの論争と同レベル。ユーザが使いたいのは GNU Development Tools とその成果物であり、kernel に関係なく全ての自由な環境 (一応 Debian GNU/w32 なんてのもあるそうですが) で GNU ツールが動くようになれば、たいへんけっこうなことだと思います (ある意味では、MS の .NET 構想のような、プログラミング言語のコアとライブラリの関係に近い。言語が変わっても、ライブラリが同じならば移行は容易)。Debian GNU/OpenSolaris なども動きつつあるようですし、ぜひこの調子で、Debian GNU/Plan9 を開発してもらいたい (大変過ぎる)
西田さんが Linux のディレクトリ構成のいいかげんさを批判してましたが、これは Linux というよりもむしろ GNU プロジェクトの問題という気もするのですが。そういう意味では、むしろ kernel だけ linux に変更して、JVM や Linux パッケージやドライバがネイティブに動く (Linux バイナリエミュレータでない) FreeBSD や OpenBSD の方が欲しい気もします (とかうかつな発言をすると、あんな unk○ なカーネルなんて!と BSD の人たちに怒られそう…)
まぁ、Linux はダイナミックである意味では無節操な開発のおかげで、参加のハードルが低くなるためなのか、開発スピードは非常に速い気がするので、難しいところですね。BSD 系は少人数でひたすら正しい道を求めるので、成果物が高品質な反面、ハードルも高まるのでなかなか新機能の開発が進まないイメージがあります(伽藍とバザール)
うっかり aptitude 使ったら,大量のパッケージが remove されて大変なことになった… 削除するときは警告してくれよ.atptitude 怖すぎる.こりゃ,再インストールか,別のをインストールするしかないな.謎過ぎる
特に難しいところは何も無く、設定ゼロで X が立ち上がって、USB マウスが使えて、pppoeconf でフレッツ光に繋いで、Firefox を立ち上げて、SCIM + Anthy でいきなり日本語が使えて、ブログが書けます。素晴らしい。
root になれない (全部 sudo でやる) のは、Ubuntu の流儀なんですかね ? apt も vi も入ってないあたりが今風だなぁと。symaptic とか GUI ツールはイマイチ使い方がよくわからないです。まぁ、おいおいカスタマイズしていきます。基本的に Debian ベースなのだから、何とでもなるはず。
# 句読点のスタイルは良いとしても、全角スペースが混ざってしまうのが気持ち悪い…
なんと作者は現役高校1年生らしいです。すごい。高速道路世代ここに極まれりというか。2 ちゃんねるでの受け答えも堂々たるもので、いやはや、なんとも。
ところで、今年の後半に Debian の lenny が出るらしいんですが、kernel だけ linux から FreeBSD に変更したDebian GNU/kFreeBSD が公式サポートに追加されるそうです。これはかなり面白い上に、GNU プロジェクトが Linux kernel への依存を断ち切りつつあるという意味でも意義深いと思います (もともと FreeBSD の ports を意識したらしい Gentoo の FreeBSD 版、Gentoo GNU/kFreeBSD もあるみたい)。もともと Linux は Hurd の代用品に過ぎなかったわけで。自由で完全な UNIX システムをゼロから作る (GNU is NOT UNIX) という当初のプロジェクトの目的からすれば、UNIX の代用品の代用品なわけです。ユーザにとって、(現在のレベルの kernel では)、kernel 自体はどうでもいい。所詮どのスクリプト言語を選ぶのかといった言語マニアの論争と同レベル。ユーザが使いたいのは GNU Development Tools とその成果物であり、kernel に関係なく全ての自由な環境 (一応 Debian GNU/w32 なんてのもあるそうですが) で GNU ツールが動くようになれば、たいへんけっこうなことだと思います (ある意味では、MS の .NET 構想のような、プログラミング言語のコアとライブラリの関係に近い。言語が変わっても、ライブラリが同じならば移行は容易)。Debian GNU/OpenSolaris なども動きつつあるようですし、ぜひこの調子で、Debian GNU/Plan9 を開発してもらいたい (大変過ぎる)
西田さんが Linux のディレクトリ構成のいいかげんさを批判してましたが、これは Linux というよりもむしろ GNU プロジェクトの問題という気もするのですが。そういう意味では、むしろ kernel だけ linux に変更して、JVM や Linux パッケージやドライバがネイティブに動く (Linux バイナリエミュレータでない) FreeBSD や OpenBSD の方が欲しい気もします (とかうかつな発言をすると、あんな unk○ なカーネルなんて!と BSD の人たちに怒られそう…)
まぁ、Linux はダイナミックである意味では無節操な開発のおかげで、参加のハードルが低くなるためなのか、開発スピードは非常に速い気がするので、難しいところですね。BSD 系は少人数でひたすら正しい道を求めるので、成果物が高品質な反面、ハードルも高まるのでなかなか新機能の開発が進まないイメージがあります(伽藍とバザール)
うっかり aptitude 使ったら,大量のパッケージが remove されて大変なことになった… 削除するときは警告してくれよ.atptitude 怖すぎる.こりゃ,再インストールか,別のをインストールするしかないな.謎過ぎる




