うちにはCATVとB-Fletzの2つのインターネット接続経路があるので、 WAN側2ポート、LAN側1ポート+ハブみたいな構成のルータがほしいのです。 以前は、PCを使用していましたが、2005年夏に死んでしまいました。 新しく組み直そうと思ったのですが、小さく作ろうと思うと結構大変です。 miniITXでEther 3portのマザーボードは高価です。 使えそうな市販のルータは、C社の6万円のものや、Y社の10万のもの等、やや高額な上、 期待通りの機能があるとは限りません。 そこで、市販の安いルータを改造することにしました。
コンソールがないとなにも作業できないので、シリアルポートを使える状態にします。 USBメモリを使用できるようにし、オンボードフラッシュとは比較にならないほど楽にシステムを構築できるようにします。
オリジナルのモニタでは、プログラムはFlashメモリのCode領域からしかロードできません。この領域は512KBしかないのでカーネルを入れるのは困難です。ダウンロードもシリアルからしかできないので、linuxカーネルのデバッグ作業の効率が悪いです。そこでu-bootを移植することにしました。
u-bootはオリジナルのモニタを残す形で、実装します。オリジナルのモニタから、Code領域のプログラムとしてロードされるようにします。
OSとして、linuxを使用します。仕事でドライバいじったりして、慣れているのでlinuxにしました。
ユーザランドはbuildrootを使用して作成しました。CのライブラリにuClibcを使用しているため、glibcを使用する場合に比べて遙かにコンパクトになります。
フラッシュメモリの使い方は以下のようにしました。
Address | size | 元の使われ方 | 改造後 |
0xbfc00000 - 0xbfc20000 | 128K | Boot | ← |
0xbfc20000 - 0xbfc40000 | 128K | Configuration | U-boot env. |
0xbfc40000 - 0xbfc80000 | 256K | Web Image | 未使用 |
0xbfc80000 - 0xbfd00000 | 512K | Code Image | u-boot |
0xbfd00000 - 0xbfd10000 | 64K | Boot Params | ← |
0xbfd10000 - 0xbfe00000 | 960K | 未使用 | Linux Kernel |
ベースは buffaloのBBR-4MGです。
ADM5120P (MIPS 4Kc) | 175Mhz |
SDRAM | 8MB |
FlashROM | 2MB(intelのものとAMDのものがあるみたいです) |
Ether | 5 port |
Etherが5ポートあるのがすばらしいです。ADM5120は内部にプログラマブルなハブが入っていて、各portを自由に振り分けることができます。 たとえば、通常のBBR-4MGは、WAN1ポートとLAN4ポートをそれぞれ別の論理ハブに接続し、CPU側からは2つの論理ポートとして見えるような設定で動作しています。これを WANには1本づつの計2本の物理ポートを、LANにはハブでつながった3本の物理ポートを割り当てて、 WAN2本LAN1本の合計3本の論理ポートに見えるようにします。 (WAN2本+LAN1本+DMZ2本という強力な構成にもできるはずです。)
linuxを動かすことを考えるとRAMもROMも少ないです。 とくにROM 2MBにカーネルとユーザランド(とブートローダ)を入れるのは無理です。 (2MBにいれちゃったすごい人もいるようですが) USBポートを追加してUSBメモリを接続し、そこにユーザランドを入れることにします。
ちょっと気をつけなければいけないこととして、ADM5120のEther物理ポートの番号と、BBR-4MGに振ってあるポートの番号が一致しないということがあります。
BBR-4MGのWANがADM5120のport4, LANの1〜4がADM5120のport3〜1になっています。
油性ペンで番号を書いておきました。
ADMTek製の MIPS 4KcコアのSoCです。
シリアルポートの信号はピンヘッダ(J1)にでています。
+-+ CPU(123) DCD---1 6---DSR CPU(124) CPU(127) DIO---2 7-- CPU(129) DOO---3 8---CTS CPU(125) 4 9 VSS---5 10--VDD +-+DIO, DOOがそれぞれ、受信(RxD)、送信(TxD)です。
RS232Cレベルに変換してパソコンとつなげられるようにします。
秋月電子で買ったADM3202ANを使用しました。
万能基板にピンヘッダの受け側をつけて、直接本体に挿すようにしています。
DSUB 9pinコネクタを筐体を縦置きしたときに下になるところにつけました。 ど真ん中です。ど真ん中にすると付属の縦置きスタンドもつけられます。
ADM5120Pのピンをあげて、48Mhzのクロックを接続します。接続先は
168 CLK48M 167 VSSです。
小さな万能基板上に組んでCPUの上に両面テープで貼り付けました。 電源にフェライトビーズとパスコンを入れてあります。 電源は、C44の両端からとりました。
USBの信号線を引っ張りだします。
ADM5120PはUSBホストポートを2本持っていますが、1本だけ出しました。
使用したUSBの信号線は、
174 DPLS0 (D+) 175 DMNS0 (D-)です。
基板に穴をあけて、USBコネクタをつけてました。USBコネクタの位置にあわせて
筐体にも穴をあけてあります
USBの信号線は、直列に33オームの抵抗を入れ、15kオームでGNDに落とします
VBUSとGNDはACアダプタから入ってすぐのところから分岐して、フェライトビーズを入れて接続しています。
私は秋月で買った5V出力の小さなACアダプタを使用しているのですが、付属のACアダプタでは5.5vなのであまりよくないかもしれません。
USBメモリをつないでhdparmで速度を調べてみました。
620kB/secです。うーん。遅いけどまあこんなもんか。
カーネルメッセージの途中に
Start Init AHCI_INIT Sep 5 2006 USB AHCI at membase 0xb1200000, IRQ 11 usb.c: new USB bus registered, assigned bus number 1 hub.c: USB hub found hub.c: 2 ports detectedと出ました。
# hub.c: new USB device adm5120-hcd-1, assigned address 2 scsi0 : SCSI emulation for USB Mass Storage devices Vendor: Model: USB DISK 2.0 Rev: PMAP Type: Direct-Access ANSI SCSI revision: 02 Attached scsi removable disk sda at scsi0, channel 0, id 0, lun 0 SCSI device sda: 2009088 512-byte hdwr sectors (1029 MB) sda: Write Protect is off Partition check: sda: sda1 # hdparm -t /dev/sda /dev/sda: Timing buffered disk reads: 2 MB in 3.30 seconds = 620.61 kB/sec #
オリジナルのモニタでは不便なのでu-bootを移植します。
オリジナルのモニタを残す形でu-bootをインストールすることを考えます。 リセットベクタを書き換えると失敗して再起不能になってしまいますので、 JTAG-ICEを持っていない場合には、この方法がベストです。
u-bootにはADM5120用のコードはないようなので、ドライバ類を自分で作る必要があります。
とりあえず、シリアルとイーサネットだけは使えるようにしたいです。イーサが使えなければなんのためにu-boot移植するのかわからないので。
せっかくだからUSBからカーネルよめるようにしたいですが、これはちょっと大変なので後回しです。
MACアドレス、VLAN(仮想ハブ)の設定はu-bootの環境変数で設定し、それをlinuxに渡せるようにします。u-bootの環境変数はFlashに保存できるので、これらの設定も電源を切っても残すことができます。
UNEXPECTED LOAD ADDRESS!!! LOADED 0x80002000 EXPECTED 0x80001000
linuxカーネルを移植します。 ADM5120で動くlinuxカーネルはけっこうあちこちにありますが、 ADM5120のUSB hostのドライバは、最近のカーネルに対応したものはなかなか見つかりません。
linuxカーネルは2.4系を使用しました。 2.6系のカーネル用のUSBドライバがまともに動かなかったからです。 ほかに、2.6系はカーネルサイズが大きいのとコンパイルに時間がかかるという 問題があるので、2.4系の方がいいと思います。 2.6系でうまく動かなかったのはでかすぎたせいのような気がします。
buildrootを使用します。 uClibcを使用しており、glibcと比べてコンパクトになります。 USBを増設したことで、ルートファイルシステムのサイズが問題になることは ありませんが、RAM容量が非常に少ないので、依然、プログラムのサイズを気にする必要があります。
# mount /dev/root on / type ext3 (rw) proc on /proc type proc (rw) devpts on /dev/pts type devpts (rw) # ps ax PID Uid VmSize Stat Command 1 root 372 S init 2 root SW [keventd] 3 root SWN [ksoftirqd_CPU0] 4 root SW [kswapd] 5 root SW [bdflush] 6 root SW [kupdated] 14 root SW [khubd] 17 root SW [usb-storage-0] 18 root SW [scsi_eh_0] 20 root SW [kjournald] 57 root 360 S /sbin/syslogd -n -m 0 58 root 340 S /sbin/klogd -n 59 root 484 S /bin/sh 60 root 444 S /usr/sbin/dropbear 73 root 296 S udhcpc -i eth0 89 root 444 S ntpd 90 _ntp 444 S ntpd 99 root 728 S /usr/sbin/dropbear 100 root 572 S -sh 140 root 320 S udhcpd 143 root 352 R ps ax # free total used free shared buffers Mem: 6084 4964 1120 0 560 Swap: 0 0 0 Total: 6084 4964 1120 #ntpd, dhcp client/server(udhcpc,udhcpd), sshd(dropbear),syslogdを 動かした状態で、sshdでログインしてみました。 この状態で1120KB空いているのでRAM容量も足りそうです。
BBR-4MGに標準で書き込まれているbootloaderのUコマンドを使用して書き込みます。 プロトコルはX-MODEM CRCです。
linuxでkermitとsxを使用するとうまくいきませんでした。改行を入力すると中止するそうなので、そのせいかもしれません。 仕方がないのでwindowsでteratermを使用しました。
起動時にPress any key to enter command mode ...と表示されたら、すぐに何かキーを押します。
[BBR-4HG Boot]:が表示されたらUを押します
[BBR-4HG Boot]:U UPLOAD Flash -------------------------------------- Area Address Length -------------------------------------- [0] Boot 0xBFC00000 128K [1] Configuration 0xBFC20000 128K [2] Web Image 0xBFC40000 256K [3] Code Image 0xBFC80000 512K [4] Boot Params 0xBFD00000 64K -------------------------------------- Enter area to UPLOAD:3を入力します。
Upload area 3. Are you sure? (Y/n)大文字でYを入力します。
Starting XModem download...(press Enter to abort)と表示されたら、 XMODEMで、u-boot-bbr4-XXXXXXXX.zip を送信します。
u-bootの環境変数のethportsに設定し、linuxカーネルからもこれを使用します。 ethportsには、VLANのリストを16進数で設定します。各ビットが物理ポートに対応します。
ビット | 7 | 6 | 5 | 4 | 3 | 2 | 1 | 0 |
ポート | - | CPU | GMII | port4 | port3 | port2 | port1 | port0 |
port0,port1,port2をLAN, port3をWAN1, port4をWAN2になるように設定します。 それぞれのグループにCPUポートを加えると、0x47, 0x48, 0x50となります。 u-bootのコマンドで以下のように設定します。
BBR-4MG/HG # setenv ethports 0x47,0x48,0x50
MACアドレスは、group毎に振る必要があります。 一つ目のグループのMACアドレスは標準で割り振られているアドレスを環境変数ethaddr に自動的にセットするようにしてあります。 それ以外のグループのMACアドレスは設定を行う必要があります。 2つめ以降はeth1addr, eth2addrのように設定します。
BBR-4MG/HG # setenv eth1addr 00:0d:0b:08:06:51 BBR-4MG/HG # setenv eth2addr 00:0d:0b:08:06:51保存して再起動して確認します。
BBR-4MG/HG # saveenv BBR-4MG/HG # reset...略
Net: adm0, adm1, adm2 Flash: 2 MB In: serial Out: serial Err: serial Net: adm0, adm1, adm2 Hit any key to stop autoboot: 0 BBR-4MG/HG # printenv bootdelay=2 baudrate=115200 ethaddr=00:0d:0b:08:06:50 ethact=adm0 bootcmd=bootm 0xbfd10000 bootargs=ttyS0,115200 root=/dev/sda1 ethports=0x47,0x48,0x50 eth1addr=00:0d:0b:08:06:51 eth2addr=00:0d:0b:08:06:51 stdin=serial stdout=serial stderr=serial Environment size: 247/65532 bytes
TFTPでカーネルイメージを転送しました。 TFTPで転送するためには、自分のIPアドレスとサーバのIPアドレスを環境変数にセットしておく必要があります。それぞれ、ipaddr, serveripです。
もちろんサーバの準備も必要です。サーバの準備についてはここでは割愛します。
ファイルをRAMに転送した後、FlashROMに書き込みます。 FlashROMに書き込む前にprotectの解除とeraseを行う必要があります。
BBR-4MG/HG # setenv ipaddr 192.168.0.51 BBR-4MG/HG # setenv serverip 192.168.0.18 BBR-4MG/HG # tftp 0x80300000 vmlinux.img Using adm0 device TFTP from server 192.168.0.18; our IP address is 192.168.0.51 Filename 'vmlinux.img'. Load address: 0x80300000 Loading: ################################################################# ################################################################# ################################################ done Bytes transferred = 907800 (dda18 hex) ←この値を書き込み時のサイズに指定する BBR-4MG/HG # protect off 0xbfd10000 0xbfe00000 ............... Un-Protected 15 sectors BBR-4MG/HG # erase 0xbfd10000 0xbfe00000 ............... done Erased 15 sectors BBR-4MG/HG # cp.b 0x80300000 0xbfd10000 0xdda18 ←tftp転送時のメッセージのBytes transferred の値を指定 Copy to Flash... flash_write_cfiword, cnt=907800, src=80200000 done
上の例ではRAMの0x80300000〜を作業に使用しています。 u-bootが使用している、0x80500000〜80800000(ブートログのu-bootのメッセージ参照)とベクタエリアの0x80000000〜0x80001000をさければ、どこでも使用できます。 0x80300000〜にすると、展開後のカーネルがロードされる0x80001000〜が空くので、 Flashに書き込まずにそのままbootmコマンドで実行することができるので、テストするのに便利です。
USBメモリを他のlinuxマシンに接続してインストールを行います。
NFSサーバが用意できるならば、NFS rootでbootして 、BBR-4MG上で作業を行うこともできるかもしれません。
コンパイルする順番は、buildroot, u-boot, linux kernelです。
buildrootにクロスコンパイラが含まれているので、これを最初にコンパイルします。 また、u-bootにmkimageというツールが入っていて、これを使用してlinuxカーネルをu-boot イメージ形式に変換するので、u-bootをlinux kernelより先にコンパイルします。
$ make
$ export PATH=${PATH}:buildrootのディレクトリ/build_mipsel/staging_dir/bin $ make bbr4_config $ make $ zip u-boot.zip u-boot.bin
$ export PATH=${PATH}:buildrootのディレクトリ/build_mipsel/staging_dir/bin $ yes "" | make config $ make dep && make $ mipsel-linux-objdump -f vmlinux # start addressを確認(下のmkimageのエントリポイントとして入力) $ mipsel-linux-objcopy -O binary vmlinux vmlinux.bin $ bzip2 vmlinux.bin $ u-bootのディレクトリ/tools/mkimage -A mips -O linux -C bzip2 -a 0x80001000 -e エントリポイント -d vmlinux.bin.bz2 vmlinux.img
BBR-4MGのブートローダがu-bootを実行し、u-bootがlinuxを実行すると、 コンソールにはこんなメッセージが流れます。
FENIX/ MEMBERS/ thomas's HOME/ MEMO/bbr4
佐藤益弘 thomas@fenix.ne.jp