FreeBSDでRedBootをビルドしてみた

昨年年末に、ハードオフのジャンクで入手したAR2313を使ったWR6670SにBootを焼く事にした。Fonなどで実績があるRedBootを載せる事にした。

結論から書くと、Linux用のtoolchainをFreeBSDのlinuxエミュレーション機能で動作させてバイナリを作るのが現実的です。

WR6670SはRedBootは焼けたのですが、SDRAMが8Mでしか認識できず、あきらめて他のターゲットにしました。メモリは16Mだったのですが、RedBootの認識機能と相性が悪いか、そもそもハード的に8Mで使うようになっていたのかのどちらかかもしれません。

WR6670SのオリジナルのブートはRedBootでもU-BootでもなくVxWorksなbootでもなさそうでした。

ブートが持たなければいけない最低限の機能は次のようになります。

* SOCの初期化
* SDRAMの設定
* CFI/SPI FLASHの読み書き
* シリアルコンソール
* ネットワークアクセス

RedBootはeCosというビルドシステムを使っていて、Linuxで動作するコンフィフレーション用のコマンド（ELF)を使っている。手元の作業環境のFreeBSD9でこの仕組みを使うには[Linuxエミュレーション](https://www.freebsd.org/doc/handbook/linuxemu-lbc-install.html)を導入する事で動作するようになった。

元にするソースは同じSOCを使ったルータのGPLで公開されているものを適当に拾ってきた。

当初ZRouterで使っているgcc4.2でのクロスコンパイルを試していたのだが、AR2313のサポートされたRedBootのコードはgcc3の頃のコードになり、[エラー](http://blog.kmckk.com/archives/1810367.html)がでてコンパイルできなかった。

こつこつgcc4に直していこうかと思ったが心が折れて、gcc3を用意する事にした。

ところがeCosはC++を使っていてgcc3をC++を入れてFreeBSD9/gcc4.2でビルドするとライブラリのビルドでエラーでビルドできない。。。

とりあえずバイナリだけはできたのでビルドした物を使い、ライブラリはネットで拾ってきた物を使う事にしてみる。

RedBootのビルドにはgmakeがmakeとして使えtcl86(tclsh)が必要だったので、パッケージをインストールしてシンボリックリンクを作ってみた。FreeBSD 10.3ではbashのインストールも必要だった。これ以外は特に用意する物もなく、案外シンプルだ。

RedBootのビルドはFlashに焼くイメージ(ROM)とメモリ上で起動するイメージ(RAM)がビルドされる。元々ネットワークが使えるRedBootが焼いてあればRAMイメージが使えるが、それがない場合はROMイメージをJTAGでFlashに焼く必要がある。

JTAGでのFlash焼き込みはMac OS X上の[UrJTAG](http://urjtag.org/)を使っておこないましたが、160Kくらいを焼くのに2時間近くかかっていた。

8ビットの場合
```
cable ft2232
detect
include atheros/ar2312/ar2312
poke 0x58400000 0x000e3ce1
detectflash 0x1fc00000
flashmem 0x1fc00000 redboot.rom noverify
```

16ビットの場合
```
cable ft2232
detect
include atheros/ar2312/ar2312
poke 0x58400000 0x100e3ce1
detectflash 0x3fc00000
print
flashmem 0x3fc00000 redboot.rom noverify
```

書き込みが遅い理由を調べてみたところFlashがシングルでの書き込みしかできないのが、要因のようです。UrJTAGにFTDIのHiスピードmpsseのopcodeを追加してみて15MHz(30MHzでは認識せず)で動作させてみてもまったく焼き込み速度が変わらなかった。

AR23xxシリーズはAR2311-14がCFIでAR2315-28がSPIなFlashを使っているようです。

UrJTAGで書き込みができるのは対応しているSOCでCFIなFlashになります。SPIなFlashはUrJTAGでは書き込みできないので[FlashRom](https://flashrom.org/)というオープンソースを使う必要があります。

JTAGはFTとは信号線4本とGNDの接続でOKです。

![MIPS-JTAG.png](https://qiita-image-store.s3.amazonaws.com/0/104066/58fddb09-3bc9-53c3-69ad-d0d748505e3f.png)


AR2313はJTAGのTRSTを100ΩくらいでプルアップしないとJTAGが使えないが、プルアップしていると焼いた後に再起動してもFlashのコードが実行されず、はまってしまった。

何度もJTAGで焼いていたのだが、RedBootのポーティングはまずは、Networkを使えるROMイメージをFlashにJTAGで焼いて、後はネットワーク経由(TFTP)でRAMイメージをロードして実行して確認するのが効率的である。RAMにロードしたイメージでFlashが認識できていれば、ROMイメージをrowでメモリにloadして焼き直しもできます。ただ失敗するとJTAGに逆戻りです。

```
RedBoot> ip_address -l 10.10.10.180 -h 10.10.10.3
RedBoot> load redboot.elf
RedBoot> exec
```

![BOOT_SELFUPDATE.png](https://qiita-image-store.s3.amazonaws.com/0/104066/a21ce6bc-ce75-d13b-dced-1c416b29be54.png)

手順は、FLASHにネットワークが使えるROMイメージを焼きます。次にtftpでRAMイメージ(elf)をロードして動作確認をします。問題なければ、RAMイメージと同じビルドのROMイメージをローデータとしてロードしてFLASHのRedBootと入れ替えます。

これはよくあるケースとしてブートはするが、FLASHが見えてない場合に、RAMイメージでFLASHの確認をおこない、問題なければ入れ替えるってことになります。

また当初、無理矢理FreeBSD9上のクロス用のgcc3を用意したが、Linuxのバイナリがあったので、これを使う方が効率がいい。

余談だが、おそらくclangでgcc3を用意する事はほぼ不可能なのではないだろうか？

ここにAR2313のRedBootのソースとクロス用のgcc3などが入ったアーカイブがある。

http://downloads.openwrt.org/reference/redboot.tar.bz2

このソースはv2とか入っていて、他に転がっているソースに比べて大きめのコンフィグレーションで出来上がるバイナリは大きめです。

他で拾ったコードでFlashの認識できなかったのだが、上のアーカイブのコードでは対象のFlash(MX29LV320CT)のID(a7)を設定したらすんなり動いてくれた。

Flashは16ビットアクセスか8ビットアクセスかボードによって違うようです。今回のターゲットは8ビットアクセスなボードだったみたいです。

RedBootを焼いて起動後にfis initするとRedBoot configとFIS directoryがFlashに作られる。

![RedBootFlash.png](https://qiita-image-store.s3.amazonaws.com/0/104066/55d31a2d-5ea2-36f5-4f23-b9306c242c80.png)

Board config dataのサイズはhalのcdlファイルのCYGNUM_FLASH_END_RESERVED_BYTESで指定します。WIFIを使わない場合は無くても大丈夫だと思います。

# 後日談

調子にのってspiなap51,ap61なRedBootもビルドして焼いてみたのですが、いろいろはまりました。AtherosのRedBootはFlashの最後の0x10000にboardの情報が書き込まれていて、新しいFlashに焼くとこの部分がないので、kernelやドライバでチェックしているとうまく動きません。RedBoot自体では通常この部分の書き込みはできないようになっているので、ちょっとやっかいです。

ap51を焼いたら、なぜかMACアドレスが最上位ビットが立ったマルチキャストアドレスになってしまい、ホストと通信ができなくなりました。

spiなFlashはonboardでもflashromの様なツールで焼けるような話がネットにありますが、私が試したところではうまくできませんでした。ボードの回路にもよるものなのかもしれません。

RedBootでtftpでロードしたバイナリを上書きもおこないましたが、失敗すると元の木阿弥なので、かなり緊張しました。マルチキャストアドレスになって通信できなくなったのでxmodemでバイナリをloadして焼き直しました。これも一瞬失敗したかとおもいましたが、うまくいきました。

AR5312系の初期化のアセンブラにSDRAM設定のルーチンがあり、1バンク8Mまでしかサポートされていないので16Mでmakeするとおかしな動作になりました。AR2316系はコードが全く違っていて、大丈夫のようです。

上のopenwrtにあるアーカイブファイルはデフォルトのap43などをビルドはできますが、カスタムでビルドするとうまくビルドできないです。

当初はFreeBSD 9.3でビルドしていたのですが、FreeBSD 10.3でもビルドしてみて、少し追記してみました。

FON2201では60秒くらいでloginプロンプトが出るのだが、自分で焼いたREDBOOTだと150秒くらいかかる。PLLの初期化とも思ったのだが、起動後にベンチマークをとると特に変わりなく、なんでだろう。。。

AR531xのRedBootのソースはいろいろなところに落ちていますが、大きく分けると三種類になるようです。v1.xとv2_0とdd-wrtで修正されたものになります。v2_0はAtherosがv1.xの初期のコードを元に設定したものではないかと想像しています。

AtherosはSDKとしてAR2/5の頃にはRedBootを提供していた様なのですが、RedBoot本家にはマージされてなかったようです。

AR2313などの初期のルータにはVxWorksが使われている事があります。JTAGで焼くのは時間がかかるので、VxWorksのbootでもELFは実行できるので、VxWorksのbootからELFのredbootを実行してnetとflashのアクセスを確認して問題なければ、binなredbootを先頭部分に焼いてしまうのが良いです。

VxWorksのbootでのELF実行はcでアドレスとファイルを設定してflagを0x80にして@で実行します。

AR2312なルータで以下の設定で常にrootfsを焼いて、kernelをtftpでロードして実行するようにしてみたのですが、110秒位で起動できました。Flashの寿命もちょっと心配ですが10万回とか起動する事はたぶんないので大丈夫でしょう。

```
Boot script: 
.. fis init -f
.. load -r -v -b 0x80050000 Nec_WR7850S_rootfs_clean.iso.ulzma
.. fis create -e 0x00000000 rootfs
.. load Nec_WR7850S_kernel
.. exec
```

RedBootはtelnetでのアクセスがサポートされているので[リモートアップデート](http://qiita.com/yamori813/items/a880256d75f39ff258f5)をおこなえるようにしてみました。

スイッチに88E6065を使ったAR2318なWR1200用のビルドもしてみた。

ap61でビルドしたが、mvPhy.cが組み込まれなくて、何故かと調べたところ、ecos.dbのAP61のエントリーに無かったためでした。

mvPhy.cは6060用のコードで6065ではそのままでは動かず、MDIOのアドレスが0x10からではなく0x00からにしたところ、スイッチは見えたのですがpingが通らず、いろいろ試したところPort Base VLAN MapのForceMapをセットすると通信できるようになりました。

メモリのサイズはオプションにありますが、実はap61のコードではハードコードしてあって注意が必要です。ecos/packages/hal/mips/ar2316/current/include/ar2316reg.hのAR2316_SDRAM_ROW_WIDTHなどがそれにあたります。

urjtagはftdiの純正のライブラリとオープンソースのlibftdiのどちらかでftdiデバイスのサポートができます。libftdiでビルドした場合は以下のようにして使います。

FT2232Hの場合

```
jtag> cable ft2232 vid=0x0403 pid=0x6010 driver=ftdi-mpsse
```

FT232Hの場合

```
jtag> cable ft2232 vid=0x0403 pid=0x6014 driver=ftdi-mpsse
```

RAMビルドをloadして確認する時はfis initでflashへのアクセスが正常にできるかとpingでネットワークが使えるかを確認する。