蟹さんのboot

HardOffのジャンクにで108円とか216円である、某有線ルーターV2の蟹さん(RTL8196C)が、純正のbootでなかったので、ビルドして焼いてみました。

ビルドはいつものようにFreeBSDのlinuxエミュレーションでSDKのgcc4を使います。

Bare Metalを試すときにやってもよかったですが、ビルドちゃんと通らないんじゃないかとおもってやってませんでした。

純正のbootはboot-sourceというディレクトリに入っているソースでビルドできます。設定はmenuでできるようですが、うまく動かないようだったので.configを直接いじりました。

2,3箇所修正してgmakeしたら、案外すんなりビルドが通りboot/Output/boot.binが出来上がりました。

~~コードで修正したところはbtcode/start.Sで何故か、.configのメモリサイズ(CONFIG_D8_16)が効かなかったので、コードの先頭でdefineしたくらいでした。後はMakefileの中のmakeをgmakeにするとかでした。~~autoconf.hを修正すれば良いようです。

このbootは以下のような構造になっています。

![RTL_BOOT.png](https://qiita-image-store.s3.amazonaws.com/0/104066/cfd482b2-6ad0-6395-c19d-886663fcba7b.png)

SOC内のROMコードがbtcodeのコードをSPI Flashからメモリにロードして実行して、btcodeがbootのイメージを解凍して実行を移します。

boot.binには先頭に16バイトのヘッダーが付いているので、[flashrom](https://qiita.com/yamori813/items/28c3fe71840c3277e409)で直接焼く時はここを落として焼く必要があります。このヘッダーはboot自体での焼き直しのための物です。boot自体で焼き直す場合はboot.binをtftpでputします。

```
% dd if=boot.bin of=boot.tmp bs=16 skip=1
% dd if=boot.tmp of=boot_2m.bin bs=2m conv=sync
```

8ピンのSPI Flashははがしやすいのだが、いろいろ試しているうちにパターンはがしてしまい、SOCの足からジャンパー張って直接つなぎました。基板によってパターンの強さが違うようです。またヒートガンで熱したときに、力をかけて取ろうとするとはがれるので、自然にはがれるまで待つのが良いです。

![RTL_SPI.png](https://qiita-image-store.s3.amazonaws.com/0/104066/02a0e4c7-9f92-c8e2-e018-7eb01bc63ba0.png)

なぜか律儀に6本もつないでいます。4本でもいけるはずなのですが。

boot/flash/spi_common.cに対応しているflashが定義されています。EN28QH16は定義されていなかったので、注意が必要です。

元々入っていたbootのコマンドオペレーションではboot領域の書き換えは出来ないようなので、一度flashを剥がすしかないようです。

RTL8196Cの純正のbootは0x6000からHardware settingというデータが入っていて、それぞれのMACアドレスもここに入っています。これを作るrubyスクリプトを書いてみました。MACアドレス以外は空で最後にチェックサムが入ります。

```ruby
# make realtek rtl8196c hardware setting block by ruby

magic = [0x48, 0x36, 0x30, 0x31] # H601
data = [0x04, 0x8e, 0x02]
zero = [0x00]

magic = [0x48, 0x36, 0x30, 0x31]
data = [0x04, 0x8e, 0x02]
zero = [0x00]

if ARGV.length != 2
  print "usage hwsetting [mac1] [mac2]¥n"
  exit!
end

macarr1 = ARGV[0].split(':')
macarr2 = ARGV[1].split(':')
if macarr1.length != 6 || macarr2.length != 6
  print "usage hwsetting [mac1] [mac2]¥n"
  exit!
end

macaddr1 = []
for h in macarr1 do
  macaddr1.push(h.hex)
end
macaddr2 = []
for h in macarr2 do
  macaddr2.push(h.hex)
end

f = open('tmp.bin', 'wb')
f.write(magic.pack('C*'))
f.write(data.pack('C*'))
f.write(macaddr1.pack('C*'))
f.write(macaddr2.pack('C*'))

i = 0
len = (data[0] * 0x100 + data[1]) - 1 - 6 - 6 - 1;
while i < len do
  f.write(zero.pack('C*'))
  i = i + 1
end

sum = data[2]
for var in macaddr1 do
  sum = sum + var
end

for var in macaddr2 do
  sum = sum + var
end

sum = 0xff & sum
sum = 0x100 - sum

f.write([sum].pack('C*'))
f.close
```

RTL8196Eを使ったモジュールでbootにパスワードがかかっていたので、bootをビルドして入れなおしました。RTL8196Eのbootのソースコードはbootcode_rtl8196dというディレクトリに入っているようです。.configとautoconf.hをモジュールの設定にあわせて修正してビルドしてflashromで焼いて、bootできました。

サポートしているSPI Flashの一覧はboot/flash/spi_common.cにあります。利用するflashがここにないと読み書きができないので、注意してください。

mrubyでmrbをイメージにするときにタイポして、アドレスを間違って0x1000にしてしまい、書き込んだらブートがつぶれました。プロテクトとか出来なさそうなので、注意するしかありません。

HOME SPOT CUBEのHardware settingは形式がちょっと違っていて0x8000からCOMPHSという文字列の後にデータがあります。このフォーマットはよく分かりません。

ブートのソースを眺めていて気がついたのですが、シリアルコンソールでエスケープで止める以外にGet_GPIO_SW_IN()というマクロもチェックしていました。RTL8196Cの場合5ビット目のスイッチが押されていたときに止まるようになっていました。RTL8196Eの方も同じようです。この機能を使えば、分解せずにファームの焼き替えができて便利です。

RTL8196Cは192.168.1.6のアドレスで設定されていましたが、RTL8198でカスタマイズされていて192.168.0.1のケースがありました。このモジュールはDOWNLOADコマンドを入力しないとtftpをうけつけないようです。当初IPアドレスがわからなかったのですが、DOWNLOADコマンドを実行したときにarpパケットを送っていて分かりました。

当初RTL8198はコマンドラインからもIPを特定できずブートをビルドして焼き直す事も考えたのですが、結局そのままでいけました。MACのEtherはランデブーとかでいろいろパケットを送るので、見逃しやすいです。

IPアドレス特定のためにarp-scanというコマンドも試してみたのですが、MACの雪豹だとパケットは受け取ってるけどコマンドでは
拾えないようで、コマンドの結果には出ずにarpコマンドで確認するしかないようでした。

ビルドはしてませんがRTL8197D+RTL8367のモジュールのbootのコードはbootcode_rtl8197d_8367r_20150724.tar.gzというファイルに入ってました。

蟹さんがよくないと思うのは同じ系統のチップのコードが別々に管理されてることや、ifdefが交錯して入っていたりすることがあります。