Zopfcode

かつてない好奇心をあなたに。

電子辞書は組み込みLinuxの夢を見るか?

f:id:puhitaku:20200926011101j:plain

はじめに

去る2010年、津山高専の入学を間近に控えた puhitaku 少年は、とある SHARP の電子辞書を手にして震えていた。

SHARP Brain PW-GC610。Windows CE をプリインストールした、中学生から見ても一風変わった電子辞書。そんなものが津山高専の教科書販売で手に入るなんて…。

これは、そんな変わった電子辞書 Brain シリーズで Linux を動かすまでの記録だ。

(本記事は、第53回 情報科学若手の回で発表した以下のスライドを記事にしたものです)

speakerdeck.com

Brain ハックの隆盛と衰退

SHARP の電子辞書 Brain シリーズは、Windows が動くことによって外部アプリ ― 言い換えると、PE 実行可能ファイルそのもの ― が追加可能であることを売りにしている。自作ソフトの防止や対策は特にないので*1、Visual Studio で自作ソフトをビルドしたり、一部のCE向けソフトを追加したりすることで、電子辞書の枠を超えた使いみちを開拓できる。厨房からするとたまらない仕様だ。

2010年には既に、Brain で自作ソフトを動かす界隈が 2ch を中心に大いに盛り上がっていた。Brain で動くアプリ*2は両手では到底足りないくらいの数が出ていて、Newbie な僕でも授業中にいらんことして遊ぶ*3には十分すぎるガジェットになっていた。

f:id:puhitaku:20200925023631j:plain
かつての盟友 PW-GC610 は今も引き出しで眠っている

しかしながら、Windows CE といってもコア以外が削り取られていたり、USB ホストになれなかったり、インターネットに出られなかったりしたことが災いして、2012年を迎える頃にはネタ切れ感が漂い出していた。「自分も一発 Brain アプリを開発してブイブイいわすぞ〜w」と思っているうちに活発な開発者も離れ、Brain スレは急速にゴーストタウンと化していった。

さして技術力もなかった当時の僕には、ただ黙ってそれを見届けるしか選択肢がなかった。

Windows という「障壁」を越える

時は流れて2019年。僕は高専を卒業し、社会人となり、消防からの夢であったコンピューターで飯を食っていた。そんなある日のこと。

「…そういえば、2012年に発売された新機種の Brain は『性能が2倍に上がった』と公式が謳ってたな… あれなんだったんだろ?」

PW-GC610 は、界隈では「第一世代」と呼ばれる最初期のハード。そこから2倍にも性能が上がったのであれば、SoC は間違いなく変わっているはずだ。

調べてみるとやはり SoC のベンダーは変わっていて、その機種を見て思わず笑みがこぼれた。Freescale(現: NXP)i.MX シリーズ。組み込み Linux の生き証人*4とも言える有名 SoC だ。

f:id:puhitaku:20200925024908j:plain:right:w300

組み込み Linux とともに歩んだ歴史から、Freescale (NXP) は i.MX シリーズ向けの Linux ソースツリーを公開しているし、SoC のデータシート、評価ボードの回路図、ビルド方法といった情報がすべて無料で手に入る。

しかも幸いなことに、僕自身も i.MX シリーズが載ったボードに仕事でガッツリ関わっていたので、SoC の動作についてはかなり心得ていた。

10年前には到底持ち得なかった知識が、今ならたくさんある。

もしかすると Linux を移植できるのではないか?Windows という障壁を超え何でも出来るようになるのでは?といてもたってもいられなくなり、思わずメルカリで中古の Brain PW-SH1(第3世代)を購入。届くやいなや分解に取り掛かった。

第一の壁: 回路

Linux ポーティングで最初に立ちはだかる壁は、Linux ではない。回路そのものだ。

基板上のチップの型番を記録して、ヒートガンで部品を剥がして、ピンひとつひとつにテスターを当てて、基板上のどこに繋がっているかを探し回る。気の遠くなるような作業を黙々と進めた*5

f:id:puhitaku:20190713143907j:plain
中央左に並ぶピンが SoC。ほぼすべてのピンに何らかの機能がある。

i.MX シリーズには PSWITCH というピンがあり、ここに電圧を印加しながら電源を入れると USB からブートローダを流し込めるようになる。

程なくして、PSWITCH が eMMC のすぐそこにジャンパとして露出していることを発見し、USB Recovery が発動することも確認した。

まだ壁は乗り越えきっていない。i.MX にはピンの機能を変えられるマルチプレクサ*6があり、ピンの位置だけでは真の機能がわからない。ここは先人の力を借り、Windows CE 上で実メモリをダンプできるソフト*7でレジスタ値を直接読むことにより把握した。

第二の壁: ブートローダ

f:id:puhitaku:20190722222112j:plain:right:w300

次の壁は、まだ Linux ではない。ブートローダだ*8

組み込み Linux でよく使われるブートローダ "U-Boot" は、やはり NXP の fork が GitHub に公開されている。Brain に搭載されているものと同じ i.MX 28 の評価ボードがあるので、それ向けにコンパイルするのが足がかりとなる。

コンパイルはすぐできた。そしてドキドキの実機転送。これも難なく成功!さあシリアルポート*9からの出力は!!?!?

f:id:puhitaku:20200924221526p:plain

「は?」

思わず声が漏れた。高鳴る心臓も急速に静まっていった。

調べたところでは、 "HTLLCLLC" は Boot ROM*10 の出力らしい。 "Undefined Ins" は "Undefined instruction" のことで、原義は未定義命令だが、DRAM が初期化できていない時もこう表示されることがわかった。

さて、こうして次なる壁が現れた。

第三の壁: DRAM

次の壁は、まだまだ Linux ではない。DRAM だ。DRAM は初期化をしてあげないと読み書きすらできない。

i.MX 28 の評価ボードは DDR2 の DRAM を搭載している一方で、Brain は LPDDR を搭載しているので、そのままの実装では DRAM と話せない。初期化コードを手で書き換えるにしても、これまた気の遠くなる話だが、DRAM に関するレジスタは数にして 200 近いので対応が大変だ。Windows が動いている実機からレジスタをダンプするだけでは足りず、それを解析するスクリプトを Python で書き、刻印から機種とデータシートを探し当て、インターネットを訪ね歩き、試行錯誤を重ねていった。

幾度かの徹夜を経て、ついにその時は訪れた。

「ああ!!!よっしゃ!!!よっしゃ!!!」

プログラムが思ったように動いたときの、その何十倍にも思える達成感!Brain で Windows 以外のものが初めて動いた喜びに僕は酔いしれた。

第四の壁: microSD

次の壁は、まだまだまだ Linux ではない。microSD だ。

すごく地味な話だが、U-Boot から microSD を読むのにかなり難儀した。Linux kernel の本体とルートファイルシステム*11は microSD に置くのが自然だし、これから試行錯誤する上では絶対に必要になる。

オシロスコープで信号を見つつ*12、Windows との挙動の比較、microSD の電源を駆動する FET と GPIO の見直し、SoC のクロック設定見直しなどなど…途中で何度も諦めそうになりつつ、それらしい箇所の修正を繰り返した。

そしてやはり、その時はやってきた!

f:id:puhitaku:20200925001147p:plain

mmc dev 1 で microSD を選択し mmc info で情報を表示している。SD High Speed の表示からも eMMC ではなく SD であることがわかる。

かくして、興奮で震える手をなんとかいなしつつ、ようやく見えてきた Linux のコンパイルへと駒を進めた。

第五の壁: Linux kernel と Debian

ようやく、ついにようやく、Linux と戦う瞬間がやってきた。どんな苦労が待ち構えているだろうかと、武者震いする気分だった。

ところがどっこい、Linux のブートはあっさりと実現できた。

  • U-Boot から渡る cmdline
  • Device Tree に書かれたメモリサイズや I/O 設定

これらを直すだけで、kernel log 表示 → rootfs が見つからず panic(想定通り)まで到達できた。

以下のツイートで「deboostrap ポン付け」と言っているように、Linux からの microSD の読み書きも一瞬で実現し、Debian の移植がすぐに達成できた。前職で debootstrap と戯れた経験が大いに活きた。

第六の壁: LCD

もう Linux がブートしてログインシェルが出るところまでは到達できたものの、「やっぱ本体の LCD が映らないことにはなぁ」という気持ちが残り続けていた。そこで、次は画面表示の実現に向けてハックを進めた。

f:id:puhitaku:20200925070646j:plain
この時点では、Linux がブートしても画面が灯りすらしなかった

LCD すら特殊なパーツを使っているのがこの Brain というデバイスで、一般的なものと違い、画面に変更が生じた時だけ信号を送る特殊な規格を使用している*13。この特殊さ故に、Linux に既に入っているドライバは使えないこともすぐに判明した。

LCD はただ映像信号を送ればいいわけではなく、初期設定をしてやる必要がある*14。信号線を全部引き出す道具を作ったのでロジックアナライザで信号は読み取れるが、初期化の信号が何を意味するのか当初はまったくわからなかった。

ドライバが使えず、信号の意味も不明確。かなり厳しい状況だった。

f:id:puhitaku:20200925011340j:plain
LCD の信号を引き出すやつ。メイン基板と LCD フレキの間の基板から取り出している。

f:id:puhitaku:20200925010731p:plain
デコード結果の FF FF 98 05 は 「拡張コマンドセットの有効化」を意味する

ブレイクスルーは突然にやってきた。LCD ドライバの型番を Windows が奇跡的にログへ出力していたのだ。

"ILI" は、SPI 液晶のドライバでメジャーな ILITEK 社の製品を表す。この ILI9805 は、ILI9806 に特定顧客向けのカスタマイズを加えたものと推測される*15。ILI9806 (ILI9806G) のデータシートは普通に手に入るので、さながらロゼッタストーンのように命令列を類推し解読することに成功した。

f:id:puhitaku:20200925183232p:plain
デコード結果(下)の FF FF 98 05 は、データシート(上)の FF FF 98 06 と似ていて、FF FF に続いて型番が16進で入っていると推測できる

そういった努力の結果、まず U-Boot で LCD の初期化と映像伝送を実装できた。簡単そうに書いているが、ほんまめっちゃくそ大変だった。作業してて何度朝を迎えたかわからんくらい。

できた瞬間は友達と作業通話していて、思わず「キタキタキタキタ!来た!やった!!」と興奮してしまった。

そう来れば次は Linux だ。今までのキャリアで得た Linux のグラフィックドライバ、もとい DRM の知識を再結集し、数日後には実装が完了した。フレームバッファがあると、できる事が一気に増える。思いつくソフトを動かしては、喜びを噛み締めた。

次なる壁は?

やるべきことはまだまだ残っている。キーボードのドライバ。音。開閉検知。バッテリ管理。パフォーマンスチューニングと安定性向上。課題は山積しているが、まだ触れたことのない領域を掘るワクワクは途絶える兆しがない。自分の技術力を高める意味でも楽しく続けられるだろうと思っている。

分解なしで Linux をブートするために、Windows から microSD ブートさせるアプリも実現したい。これはリセットを工夫すればできるはずなので*16実現は難しくないだろう。Windows プログラミングはからっきしなので、知識のある協力者がいればより早いかもしれない。分解なしの Linux ブートが実現した暁には、Rasbperry Pi のごとく SD カードのイメージデータにまとめて公開したり、OSのビルド方法について文章化したりしたい。

まとめ

時々、人からこう聞かれることがある。「なんで Linux とか低レイヤーが好きなんですか?」と。この記事を読んでもらえれば(多少引かれるかもしれないが)きっと理由は理解してもらえることだろう。

Linux は、「コンピューターを使っている」という実感を力強く得ることができる素晴らしい趣味だ。10年前の僕が Brain ハックに心を躍らせたように、この記事が世の中の知的好奇心をくすぐり、ハッカーの卵たち、そして読んでくれたあなたを鼓舞できるならとても嬉しい。

*1:2017年以降に発売された機種では、EXEに細工を加えると起動できる・あるいはそのテクニックも塞がれるといったイタチゴッコ状態になっている。

*2:例えば、キーボードをそれなりに使えるようにするソフト、ランチャー、オフラインで Wikipedia を閲覧するソフト、テキストエディタ、matplotlib、ノベルゲーのエンジン、ソフトウェア3D、ピアノ音源、エミュなど。

*3:10年も経てば時効だよね…。

*4:MMU を搭載しない SoC で動く Linux "uCLinux" は、世界で最初に Freescale Dragonball プロセッサへと移植された。i.MX はその Dragonball の直系の子孫。組み込み Linux の歴史について詳しくは弊ブログの翻訳記事を参照。なお、uCLinux は現在は mainline に merge されている。

*5:元々自作ソフトが動くのだから、昔の Windows Embedded のスマホのように Windows から直接 Linux をブートするソフト的手法もあるだろう。しかし周辺回路を知らないことには結局何もすることができないので、チップ剥がしはいずれ必須となる。

*6:IOMUXと呼ばれる。

*7:Nexhawks 氏作の Scalpel 。氏は Brain 開発を引退し別名義で活動している。

*8:プリインストールされているブートローダは Windows 専用なので Linux のブートはできない。

*9:ところでブートローダ以前はIOMUXも初期状態なので、入出力の配置が奇想天外なことになっている。例えばシリアルポートは「SoC に接続されたマイコンの足」から引き出す必要がある。

*10:現代の SoC のブートは多段構造が普通で、Boot ROM は本当に一番最初の段階を指す。

*11:Linux ディストリビューションをなすソフトウェアなどを含むファイルシステムのこと。今回は利便性を優先し Debian 10 を採用。

*12:Sparkfun の Sniffer board が超便利だったのでオススメ。

*13:RGB の信号を水平同期 (HSYNC) と垂直同期 (VSYNC) に合わせてずっと送り続けるパラレル伝送が一番王道で、近年のデバイスではフットプリントの小さい MIPI DSI というシリアルI/Fが一般的。Brain の規格は極めて古典的なバス方式で、MIPI DBI として一応 MIPI には含まれているが、Linux ですら MIPI DBI の実装は存在しない。それくらいマイナーだ。

*14:例えば、伝送規格、ガンマ曲線、リセットの解除、などなど。

*15:ある筋によれば、パブリックな製品の型番から1引いてカスタム品を出すというのはよくある手法らしい。実際、Nintendo Switch の サウンドチップも似たルールで採番されている

*16:Brain を意図的にリセットするツールというのも Nexhawks 氏の手によって実装されているのでそれがベースになるだろう。