Neo Slim 3000 or A-41 で Linux を動かすつもりなのだが、全然進んでいない。
理由は面倒だから。動いたときの満足感がイメージできていなくて面倒だとばかり感じてしまう。
ここで、なにが一体面倒なのか書いて(そうすることで実は面倒じゃないじゃないかと思える場合が多々ある)、 実現できると何が嬉しいのかについても書いてみる(動機の強化)ことにする。
なにが面倒なのか?Linux は既にあるのだ。コンパイルもできている。面倒なのは、シリアルコンソール。これがないと動作の確認も最初のオペレーションもできない。だが、0.4mm ピッチの IC から線を引き出さなくてはならず、自分のスキルでは実現ができない。
そうなると、シリアルコンソールに代わるものを用意しないといけない。で、usbboot のプロトコルを改造して メッセージのやりとりが出来るようにしようと考えている。
こうなると u-boot - linux の通常起動は無視して、usbboot - linux の直接boot をすることになる。
面倒1: メモリマップ
どこにロードしてどうやってパラメータを渡すのかをちゃんと設計しなければならない。そして障害になるのが、xburst_stage2 ブートローダの ロード場所と 使用しているバッファ(1MB もある)
さて、メッセージのやりとりは、PC 側のプログラム(usbboot) がポーリングすることで 行うことになりそうだ。
面倒2:ポーリングの方法
普通ポーリングする場合 select システムコールを使ったりするのだが、USB を使うための ライブラリ libusb には select を支援するための機能がない。
timeout を使ってビジーループにすれば実現できるのだが、作法的にどうか? というのがあって躊躇している。マルチスレッドにするのも手なのだが、Windows でも動かしたいし OS の違いを吸収するのもまた面倒だったりする。
面倒3:Linux のシリアルコンソール代替ドライバ
いま考えている方式だと、xburst_stage2 で usbboot が動いている状況を USB をリセットすることなく Linux に引き継いでもらわないと うまくいかない。
なので、xburst_stage2 相当をつくり直して Linux に組み込むことになる。これが面倒で面倒で。
xburst_stage2 を破壊しないようにして、 xburst_stage2 に callback のエントリーを加えたほうが楽でスマートなように思えてきた。
メモリは無駄に使うことになりそうだが、ここは目をつぶろう。
ちなみに、Linux のメッセージの出力は、メモリに書いて callback を呼び出すことになりそう。入力は ポーリングになると思う。シリアルドライバもポーリングできるようになっていたと思うので、たぶんあまり悩まずに作れる。
これができると何が出来るようになるのか?まず、シリアルコンソールだけが使える Linux が出来るわけだ。
これで何ができるかというと 立ち上げメッセージが見える。だが、root を mount するところで panic することになる。
panic するところまで確認できたら、initrd を作って root にして いくつかのコマンドを用意すれば、デバッグができるようになる。
SD カードは ドライバが動くと思うので、次の段階では SD カードを mount して ストレージが使えるようにする。
次に LCD のドライバ。LCD の初期化の問題さえクリアすれば、LCD もまた動かせるはず。LCD が動けば、シリアルコンソール以外にメッセージを見る手段ができたことになるから、xburst_stage2 を開放して、usg-gadget で Network を通す。
詳しく書くと、
1) Linux から callback しないようにする。
2) xburst_stage2 が使っていたメモリを linux が使うように組み込む。
3) usg-gadget ドライバを組み込む。
- 1) - 3) を連続実行する手続き(スクリプト?)を シリアルコンソールから実行するとともに usbboot を 終了する。(切り替えに失敗するとなにも出来ないので shutdown か?)
- Jz47xx 側で dhcpd を動かすと PC 側の設定なしで、(ローカル IP を使った)Network の接続はできる。
ここまでくると普通に Linux が動いているのに近くなる。login もできるだろうし、nfs を使ったりもできる。
で、このあたりから始めるのが、Neo Slim 3000/A-41 固有のドライバの作成。.. といってもボタンぐらいのはず。
装置固有のドライバが捗らなくても、やれることは多い。システムをつくり上げるために色々ビルドしなくてはならないし、サスベンドとかもある。
それに、正規の boot も やらないと。u-boot についても 同じように シリアルコンソールの代替をすることからやれば良い。
これができると何が嬉しいのか?とりあえず最終形態ではなく、usbboot から Network が使える前後まで来たらなにが嬉しいか。
まず嬉しいのは、開発できるものが複数になること。あきたり、行き詰まったりしたら別のことをやれば良い。
性能を調べても良いし、オリジナル ファームウェアがどう FLASH を使っているのか調べたりしても良い。u-boot の移植でも良いし。
あと、ここまで来れば立派な開発環境になるというのも嬉しい。メモリを付け替えて 64MB にして ビルド三昧とか。-- 64MB でも全然足りなさそうだが、足りないのは gcc の CPU パワーと ld(リンカ)のメモリが第一。これを 外の IA マシンにやらせればなんとかなるはず。(ただ、それの前提として nfs でファイル共有が必要なはず)
あと、USB-gadget での Network は Windows でも出来る。SD が使えさえすれば、PC でも動かすことは出来るようになる。cifs を入れれば PC との共有(PCがサーバ)もできるし 箱庭のようなシステムを構築することも出来る。
SDL 1.2を使えば Windows でも グラフィックの表示は簡単にできそうだ。
Jz47xx のフレームバッファを抜いてきて Windows で表示させれば、LCD が動かない場合でもデバッグは出来そうだ。こういったのは機種依存がないので、意外と便利かも知れない。
あと SDL は、スレッドを提供している。SDL に全面依存して作ると楽かも知れない。-- Jz47xx 自体も SDL つかうことになりそうだし。
では最終形態ではなにが嬉しい?
まぁものを作るネタがあればそれだけで嬉しいのだが、どういうものにつながっていくかイメージしておけないと ..
デバイスを追加したりする改造をしない前提ならば、入力は マイクと USB device しかないのだ。マイクを無視すると、PC と接続してデータを取り込むような使い方が第一。PC と接続している間は PC を使えばよいわけで、持ち歩く前提なら、データを見ることしかできない。動画や音楽はそれなりのレベルになっているわけで、嬉しい点を見つけるとすれば、がんばって不満な点をなくせるということになる。
あと、中華PMP の EBOOK 機能は貧弱なので、それが充実すると 嬉しいかも知れない。
PDF viewer とか その他 viewer を充実できると まぁ嬉しいから そのあたりが嬉しい点。
あと、PC と接続して PC だけではできないことをする という可能性が残っている。
追加ディスプレーというのが そのひとつ。嬉しくないかも知れないが要素の1つ。
あと、セキュリティーの理由などで PC ではできないことをできるようにする観点がある。PC のセキュリティーをすり抜けるとかそういうことではなく、共用PC におきたくないデータを置くとか .. 共用PC にはインストールしなくないアプリケーションを動かすとか ... まぁそういうもの。Linux を動かすこと自体も この範疇かも知れない。こういう使い方では、PC でできることをあえて PMP 上で動かす必要はない。また、画面を PC に出すなど、PC のリソースを利用できる。
マイクも なにか利用できるアプリケーションがあるかも知れない。音声認識するには十分なパワーがあるはず。音紋とかで誰と会っていたか/何をしていたか記録するとか .. で、秘書ソフトと連携させて ... なんてのは難しいだろうか。
もし、Jz4755 などで カメラが利用できるなら、スタンドアロンでできることが増えるかもしれない。マイクよりカメラはさらに難しいと思うので、マイクさえ十分な利用ができないなら、なくても別にかまわないかも知れない。
追記: メモリマップについて
0x80000000
割り込みベクタとか
0x80002000
(8KB) xburst_stage1
(stack)
0x80004000
0x80010000
0x80100000 (offset 1MB) :
u-boot : kernel(vmlinux.bin)
: + initrd
0x80600000 (offset 6MB) 0x80600000(max)
kernel (zImage)
0x81c00000
(4MB) xburst_stage2
(stack)
0x82000000 (32MB の場合)
xburst_stage1 は、0x80002000 (先頭 +8KB) にロードされ、xburst_stage2 は、後ろ 4MB にロードされる。メモリのサイズは、SDRAM の設定情報から計算している。
xburst_stage2 のスタックは、start address + 0x3ffff0 (4MB の終わり) に設定。1MB のバッファ(Bulk_buf) は、配列で 普通に BSS 上に取られる。
ちなみに、xburst_stage1/stage2 共に 先頭は jump命令 + nop。
その後の 32バイトにパラメータが設定される。
こういう構造をしているので、Linux は 先頭の方にロード可能。usbboot のプロトコルでシリアルコンソールを使う場合は、後ろの 4MB は使わないようにする。
使わない場合は、全部のメモリを使えるが HOST側 が usbboot 使えなくなったことを知っていないと まずい。
あとは、linux に対するパラメータを (u-boot が)どのように渡すのか調べないと。
これは、普通の関数呼び出しと同じで a0-a3 にパラメータをいれて jump する。文字列を渡すからその領域は 割り当てておかないといけないが。
prom_argc = (int) fw_arg0; // a0
prom_argv = (char **) fw_arg1; // a1
prom_envp = (char **) fw_arg2; // a2
だそうだ。envp は jz47xx では未サポート。prom_init_cmdline() で argc,argv を元に、arcs_cmdline に cmdline を再構築する。スペースでくっつけていくだけだから アーギュメントは command_line のイメージ 1 個でも良い。
なお COMMAND_LINE の最大サイズは 256 バイト。
ロードするアドレスは、ビルドするときに決まる。
dingoo-linux だとどうも 0x80600000 らしい。
zImage は、0x80600000 にロードされ、先頭アドレスから実行する。実行すると、0x80010000 〜のアドレスに vmlinux.bin と initrd を展開して制御を渡す。パラメータは、セーブしておいて、同じパラメータを vmlinux.bin に渡している。
ちなみに u-boot は 0x80100000 。
ところで、xburst_stage2 とかのメモリを Linux に渡して使えるようにするには、どうしたら良いのだろう。
initrd のメモリを開放するとかは出来るから、方法はあるはずだが、スマートな方法を取りたい。
reserve_bootmem(__pa(initrd_start), size, BOOTMEM_DEFAULT);
free_bootmem(__pa(initrd_start), size);
こういう使い方をするらしいのだが、
void __init free_bootmem(...
と __init 属性が付いているから 初期化終了後は、free_bootmem は使えない。まぁ initrd も後で開放できるからなにか方法があるのだろう。
重要なのは、usbboot のときは、後ろの 4MB について reserve_bootmem しておくこと。メモリーサイズ自体を -4MB とすると再利用するとき困る。
追記: シリアル コンソールドライバ
多くの SoC の シリアルは、8250 の拡張の 16550A と互換性を持っている。linux では、8250 ドライバが一手に引き受けているようだ。
Jz47xx でも
CONFIG_SERIAL_8250=y
CONFIG_SERIAL_8250_CONSOLE=y
CONFIG_SERIAL_8250_NR_UARTS=2
CONFIG_SERIAL_8250_RUNTIME_UARTS=2
なんて定義をして、汎用ドライバを使っている。
さて、シリアルのふりをして CONSOLE にも登録できるドライバを用意しないといけないわけだがどうしよう。
とりあえず drivers/char/Kconfig を見て CONSOLE になれる変なドライバをさがしたところ bfin_jtag_comm.c というのを見つけた。どうも kthread を作ってポーリングしているようだし、マネして作れば良さそうに思える。ライン数は 365 行であまり規模が大きくなさそうだし、いけそうだ。
これを drivers/char/jz_char に移し、jz_usbboot_comm.c とかにして 変更していけば、良さそう。
ところで、コールバックのエントリをどこに置くか?
stage2 の先頭 の jmp 命令の次に 4x8 のエリアをパラメータエリアとして使用している。ここには、fw_args 構造体をコピーするのだが、fw_args 構造体のサイズは 4x7 分。もう 1 エントリ付け加えることができる。また、start, size というメンバがあって、これは未使用。-- すくなくとも 初期化は不必要にできる。
このあたりに callback 関数のアドレスを入れておけばよさそう。
追記: SDL 1.2
ソースコードをダウンロードして configure するだけで MinGW 版はビルドできた。
これが、libusb と MSYS コンソールの stdout をスレッド環境で使えるなら言うことはないのだが...
ちなみに SDL 自体は グラフィックを提供するだけで、メニュー 、ダイアログなどは提供しない。それどころか フォントの描画すら提供していない。
でも Jz47xx のフレームバッファを表示するだけならそれで十分。
メッセージは出力したいが、MSYS コンソールに出力できるなら、それでもいいかと思う。log とか取るの楽だし。
もし、フォントを表示するなら、DINGUX と 互換になるようにしたほうが良さそう。これは別途考える。
試してみると全然だめ。
gcc -o testkeys.exe testkeys.c -g -O2 -I/usr/local/include/SDL -D_GNU_SOURCE=1 -Dmain=SDL_main -DHAVE_OPENGL -L/usr/local/lib -lmingw32 -lSDLmain -lSDL -mwindows
こんな風に testkeys はビルドされるのだが、なにもメッセージがでない。
... 調べてみると Windows は、stdout.txt , stderr.txt に出力されるものらしい。で、環境変数を SDL_STDIO_REDIRECT=0 としておくと reopen されないみたいに見える。
あ、できた。環境変数設定することで MSYS コンソールでも コマンドプロンプトでもちゃんと stdout が出力された。
あとは、スレッド使って usbboot と SDL 画面の 両立ができればいけるか。
- ちなみに、使用している qi-hardware 版 usbboot は、Linux 以外で コンパイルできることを考慮していないから 先に移植しないと。
さらに、ちょっと面倒なことに confuse も 入れないといけない。
mingw での confuse の ビルドは、ここ参照。
とりあえず ... ここまでの環境を usbboot-wk4.tar.gz に置いておく。
Linux だと動くけれども MinGW だとビルドできるものの usb_claim_interface で エラーになったりするのが現状。
( ちなみに inf ファイルは 0x4750 も通すように修正)
追記: ちょっとメモ
Linux 2.6.30 あたりのカーネルは、mm/migrate.c が含まれている。なにをするものかというと、ページを動かして連続領域を確保しようとするもの。今までは 4KB のページの数倍 -- 16KB でも厳しい状況があったのが、取れるようになる。ただ、128KB とか 数MB (システムの 10% とか) とかの連続領域を作ってくれるのかどうか? ちょっとわからない。目的が違うから厳しいような気もする。
MB クラスの 連続ページが取れると、IPU用メモリの動的アロケートができるのだが ... そうすると動画を使わない場合は メモリが多少増えて嬉しいのだ。 360p -- 仮に 640x360 だとすると IPU を使うには たぶん 256KB/64KB/64KB の 3 つの連続領域が 取れる必要がある。720p なら 1280x720 として 1MB/256KB/256KB が必要そう。PMPみたいなシングルタスクに近い使い方なら取れるような気もするし無理なような気もする。--- うーんわからない。
最後の 4MB を HIGHMEM にできないかな。HIGHMEM だと slab 置けないから 確実にメモリを追い出せるような気がする。
ちなみに、オリジナルの処理は、初期化時に __get_free_pages() を使って 4MB を予約している。予約したエリアは jz_imem_base に保存される。
ここから メモリ領域を 割り当てるのは proc を使って行う。
... usbboot を使ったときは、当初は使えず Network でつないだ後に 使えるようになる ... といった仕様で十分そうな感じ。
そういうふうにすれば、jz_imem_base の設定ぐらいで事足りる。
こういう風に しておいて、後で migrate の機能を使って動的に確保できないか試す ... のほうが手順的に楽そう。
usbboot (stage2) → Linux への制御の渡し方
どうやって Linux に制御を渡すのか について整理しておく。
stage2 は初期化が終わると 無限ループで udc4740Proc() を実行する。その延長で いろんなコマンドの処理を行う。コマンドの中には VR_PROGRAM_START1(未実装) と VR_PROGRAM_START2 がある。
VR_PROGRAM_START2 は、渡ってきたコマンドパケットに含まれる アドレスを パラメータなしで call する。( アドレスは USB の wValue , wIndex を使っていて パラメータを入れる余裕はない )。
もしリターンしてきたら、処理を続行する。Linux に処理を渡したとすれば、もちろんリターンせず Linux がスタートすることになる。
で、Linux のドライバで (USB Device ドライバを 使うことなく) udc4740Proc() をポーリングしてやれば、Linux が動作しながらも USBBOOT のプロトコルを受けられることになる。
Linux のカーネルは 仮想アドレス を使う。stage2 の アドレスが変わってしまうと 暴走する。.. のだがたぶん大丈夫だろう。(未確認)
udc4740Proc() は、再帰的に call されることになる。再帰自体は問題ないが、一回リターンして 再度 call されるのと比べると いくつか実行されない処理が出る。
両方 2 度 同じ処理をしても問題なさそうなので、処理をする前に 実行しておいたほうが良いかもしれない。( 不要かも知れないのだが、面倒なので調べていない )
さて、ポーリングするだけだと、メッセージをやりとりすることはできない。メッセージがどこに置いてあるか の情報を Linux が知る必要がある。それも登録しておけば ... Linux から メッセージの送受信のコードが書ける。
ついでなので、パラメータとして渡すコマンドラインも 同じように登録しておいて あらかじめ送り込んでおき、a0,a1 に常に設定するようにしたら良いかも知れない。(ただし、登録エリアが少ないので、メッセージの置き場所を構造体にしておく)
追記:を !
Subject: [PATCH v2 00/26] Add support for the Ingenic JZ4740 System-on-a-Chip
Date: Sat, 19 Jun 2010 07:08:05 +0200
(中略)
This patch series adds support for the Ingenic JZ4740 System-on-a-Chip.
The JZ4740 has a mostly MIPS32 compatible core (no on cpu timers) and many on
chip peripherals like RTC, NAND, MMC, OHCI, UDC, ADC, I2C, SPI, AC97, I2S, I2S
Codec, UART and LCD controller.
The JZ4740 is mostly used in eBooks, PMPs and hand-held consoles.
This series contains patches for the Qi Ben NanoNote clamshell device as the
inital supported device.
(後略)
こんなメールを見つけた。JZ4740 用のコードを メインストリームにマージしようとしているのか?
Ben NanoNote とか の名前が出ているし ingenic 版から jz4750系とかをザックリ切り捨てた qi-hardware 版みたいだ。(dingoo-linux とも違う)
まぁベースとして入ってくれると 差分が分かるから jz4740 は今のところ 関係なくても 嬉しいかも。
MIPS のマシンについて
ARMと比べて MIPS のマシンは種類が圧倒的に少ない。安価でLinux を動かすのに向いているものは、さらに少ない。
Jz47xx の 中華PMP と比べてどうなのか..ちょっとチェックしてみた。
- linkstation HD-HLANv2
バッファローのNAS 。CPU IDT 79RC32H434-400BC (MIPS32 4Kcコア, 400MHz)、メモリ 64MB (DDR, 16bit)。
玄箱でNetBSDを動かす Linkstation-mipsel に情報がある。ブートログをみると キャッシュは、8KB/8KB で小さい。
total memory = 65536 KB
avail memory = 60584 KB
mainbus0 (root)
cpu0 at mainbus0: 400.00MHz (hz cycles = 2000000, delay divisor = 200)
cpu0: MIPS 4Kc (0x1800a) Rev. 10 with software emulated floating point
cpu0: 8KB/16B 4-way set-associative L1 Instruction cache, 16 TLB entries
cpu0: 8KB/16B 4-way set-associative write-back L1 Data cache
La Fonera
La Fonera wiki に機種の情報がある。
FON2100E/FON2200/FON2201
Atheros AR2315 183 MHz , Memory 16MB (SDRAM 16bit)
FON2202
Atheros AR5315 183 MHz , Memory 32MB
FON2305E/FON2405E(FONERA SIMPL) -- iphone のおまけ(非売品)
RT3050(24KEcコア,320MHz), Memory 32MB(SDRAM 16bit), FLASH 2MB(SPI-FLASH mx25l1605d)
-- Hot Tuna Labsでは、FON2405E を解析しているようだ。
-- FON2405Eの中身
シリアルが付いているのがいいな。FLASH は裏の 16pin っぽい。.. 見覚えがあるマーク -- シリアルFLASH じゃないか?
シリアルFLASH なら 8pin-DIP ソケット付けて差し替えなんてのが可能かも。
FON2202 もシリアルFLASH だった。裏の 16pin の IC
ETHERNET はあるけど ストレージ がないのは厳しいな。FON2305E だと USB のパターンがあるらしいけど。
FON2305E の写真を見たら... USB 以外に NAND FLASH のパターンもある。載せ替えできる シリアル FLASH/NAND FLASH/SDRAM 全部持っている。これも楽しいかも。
これで遊ぶなら SeevaPlug のほうがはるかに良さそう。
U-Boot 1.1.3 (Jan 6 2010 - 07:10:30)
Board: Fonera
DRAM: 32 MB
relocate_code Pointer at: 81fac000
spi_wait_nsec: 3e
spi deice id: c2 20 15 c2 20 (2015c220)
find flash: mx25l1605d
raspi_read: from:41030000 len:1000
Using default environment
##### The CPU freq = 320 MHZ ####
SDRAM bus set to 16 bit
SDRAM size =32 Mbytes
Please choose the operation:
1: Boot system code via Flash (default).
2: Load system code then write to Flash via TFTP.
3: Entr boot command line interface.
booting from flash
## Booting image at bf020000 ...
:
:
mx25l3205d(c2 20160000) (4096 Kbytes)
mtd .name = raspi, .size = 0x00400000 (4M) .erasesize = 0x00010000 (64K) .numeraseregions = 0
ramips_mtd: kernel size is 613787
padded kernel is 00096000
Creating 6 MTD partitions on "raspi":
0x00000000-0x00010000 : "uboot"
0x00010000-0x00020000 : "boardconfig"
0x00020000-0x00200000 : "image"
0x00020000-0x000b6000 : "linux"
mtd: partition "linux" doesn't end on an erase block -- force read-only
0x000b6000-0x001f0000 : "rootfs"
mtd: partition "rootfs" doesn't start on an erase block boundary -- force read-only
mtd: partition "rootfs" set to be root filesystem
... シリアルFLASH でも MTD 使っているのか。
OpenMicroServer
49800円? (2006年 当時)
CPU Alchemy Au1550 400MHz
Memory 128MB(PC133 SDRAM), FLASH 16MB
... CPU 的には遜色ないようだ。(MIPS でも 高価なものだと GHz 以上の CPU とか SMP dual-core とかあるが、ここでは対象にしない。)
Jz47xx の 中華PMP はネットワークがないのが弱みだけれども、FLASH が多いのは嬉しい特徴なのかも知れない。
ホストがあれば、USB (Device) 経由でネットワークをホストにつなげられるのだが、スタンドアローンで動かすサーバ用途は厳しい。
メモリはどれも少なく開発マシンとしては厳しい。意外にも Jz47xx の Netbook (128MB)がまともな方かも。
-- 128M化改造は、意味がありそう。あきらめないでおこう。
ARMなら SheevaPlug とか 玄柴(SATAつきSheevaPlug) が 512MB 積んでいるから開発もできるのだが ...SDRAM で 256MB とか 512MB はコスト的にとても厳しそうだ。
一応 128MB + SWAP があれば、自力で (まともな)ディストリビューションをビルドできる。64MB だと無理かもしれない。
いま現在 MIPS で高性能かつ安価なマシンとして、Jz47xx の中華PMP , Netbook は有力な存在のようだ。
もうしばらくすれば、次世代の Jz476x とか Jz48xx とかが出てくる。(Linux に入っている)。Jz47xx は当面遊べそう。