ハードオフで324円で購入したVOIPなルーターにMINDSPEED社のComcerto 1000というSOCが入っていたのでちょっといじってみる事にしました。
MINDSPEEDという会社は2014年にMACOMに買収され、その後ARM部門はFreescaleに売却され、Freescaleもその後NXPに買収されました。NXPもQualcommに買収されました。
Comcertoシリーズは100,300,1000,2000というシリーズがあったようです。100,300,1000はARM11(armv6)で2000はCortex-A9でした。100はM821xxという型番で300はM823xxで1000がM83xxxとなるようです。100,300も1136だったようです。MINDSPEEDはVOIPに対応したSOCを作っていたメーカーのようです。以前いじっていた、5VTechnologies(5VT1310:RT1310)のコンペティタだったのかもしれません。
写真のSOCはM83261Gのようです。M83がComcerto1000シリーズで、その次がCore数で、6は650MHzのようです。最後は機能レベルかもしれません。クロックは650MHz,533MHz,450MHzがあったようです。
Comcertoのデーターシートは公式には公開されていなかったと思うのですが、100のデーターシートとNXPになってから編集されたLS102MAのデーターシートがネットで手に入りました。100のデーターシートには機能説明とレジスタの説明がありますが、LS102MAのデーターシートは機能説明だけのものになります。レジスタの説明は別のpdfで用意されているようなので、手に入りませんでした。
SDKはOpenWRT 6.0でlinuxは2.6だったようです。
Comcerto 1000はARM1136J-Sです。FreeBSDで1136を対象にしたサポートコードはsys/armにありませんが、arm/broadcom/bcm2835/とarm/versatileが1176を対象にしたコードです。
ヤマハのNVR500もComcerto 1000のようです。
bcm2835はラズパイの初期のモデルで使われていたようです。
1136を使ったSOCはFreescaleのimx31,35やTIのomap2くらいしか無いようです。これらは1136JF-Sで1136J-SはComcertoだけかもしれません。
ZRouterを使ってビルドするのですが、まずはsocにファイルを作ります。1136な設定はないのでとりあえず1176の設定で作りました。boardsの方にもファイルを作り、作ったsocを指定しておきます。
FreeBSDのソースですが、armはFDT化したことで、個別のmachdep.cはほとんどいじる必要がなくなりました。rebootコマンドなどから叩かれる、cpu_reset()だけは対応したコードが必要なのですが、このSOCのリセットは分からなかったのでとりあえず無限ループを入れておきました。u-bootでもresetが効かないようなのでresetが無いsocなのかもしれません。
あとはdtsファイルを適当に作ります。soc由来の構成はdtsiに入れて、それをincludeするようにしてターゲット用のdtsを用意します。フルビルドしてdtsファイルを確認するのは時間がかかるので以下のようなスクリプトでコンパイルして確認すると良いです。Sがソースツリーのsysなので適当に書き換えてください。
#!/bin/sh
S=/storage/home/hiroki/freebsd/sys
MACHINE=arm
$S/tools/fdt/make_dtb.sh $S $1 /tmp
machdep.cとdtsファイルがあればビルドはできるはずなのでfilesにmachdep.cとkern/kern_clocksource.cだけを入れてビルドを通しました。
u-bootのtftpbootでファイルを読み込んで、bootmすると展開途中で止まってしまいます。これはu-bootヘッターのloadアドレスやelfのentoryアドレスの問題なので調整します。
bootmで正しく展開されてると以下のメッセージが表示されます。
Uncompressing Kernel Image ... OK
Starting kernel ...
この後、いきなりメッセージが出てくる事はほぼないので、どこまで進んでいるかを確認するため、UART一文字デバッグです。まず最初にlocore-v6.Sの_startに以下のアセンブラを入れてビルドしてu-bootから実行がちゃんと移っているか確認します。
ldr r0,=0x10090000
ldr r2,=0x2a
strb r2, [r0]
UART一文字デバッグはconsoleが使えるようなるまで3つの方法をとる必要があります。この事はこちらに書きました。
locore-v6.Sの_startはちゃんと実行されているが、コンソールが出てきません。こつこつUART一文字でバッグをおこなって行きます。
arm/machdep.cのV6用のinitarm()のset_cpufuncs()で落ちていました。このコードはcpufunc.cにありますが、cputypeをCPU_ID_ARM1176JZSだけしかチェックしていなかったのでcpuが不明になっていたようです。このため、cputype == CPU_ID_ARM1136JSとcputype == CPU_ID_ARM1136JSR1を追加します。このSOCはCPU_ID_ARM1136JSR1のようです。
これを直して起動したら、あっけなくコンソール出力がでてきて、一瞬なにがおきたのか分かりませんでした。
思いのほか処理が進んでいて、eventtimerが無くて落ちている状態です。次はPICとTIMERのコードを用意します。
TIMERのコードはtimecounterとeventtimerの処理を作ります。100のデーターシートを見ると6本のタイマーがあり1000と同じですが、1000は6本の割り込みがありますが100は2本だけとちょっと違っていました。FreeBSDでは2つあればいいのでTimer0をEventtimerでTimer1をtimecounterとして使うコードを書きました。
割り込みの方はINTRNGベースのコードで、マスク処理と実際の割り込み処理だけです。
これだけ用意すればmountrootまでは到達できるはずです。ところがtimerの直後で固まります。
このSOCのタイマーはcount upのみのサポートでcount downで作られていたrt1310のコードをそのままつかったのがまずかったようです。これを直したら少し進みましたがまた固まります。いろいろ確認してみたら、bcm2835のeventtimerはET_FLAGS_PERIODICをサポートしていなくET_FLAGS_ONESHOTだけだったんで、同じようにしたら先に進みました。ET_FLAGS_PERIODICの処理はこちらに書いたのですが、なにか間違って理解しているところがあるのかもしれません。
これで、mountrootの直前まで進むようになりましたが、不正な割り込みでメッセージが出続けてしまいます。ところが割り込みをいっさいenableにしなければ、mountrootまです進みます。
この止まる箇所はcns11xxと同じ状態です。
割り込みは上がったがPICのレジスタを見ても、フラグが見当たらな状態のようです。状況的にUARTのFIFOが空になった割り込みなので、フラグが無い時はUARTの割り込みにするワークアラウンドを入れたら、先に進みました。なぜこのような状態になるか、ちゃんとデバッグしないとダメですね。
dtsに書いたcfiのエントリーでflashは見えているので、geom_mapのpartitionをdtsに書いたらrootfsがmountできて、シングルユーザーまで到達できました。
ところが、もう一度lsを実行するとpanicしてしまいます。oz_
# ls
pid 17 (sh), uid 0: exited on signal 11
pmap_remove_pages: pmap 0xc0439a6c va 0x20238000 pte2 0
panic: bad pte2
KDB: enter: panic
[ thread pid 19 tid 100032 ]
Stopped at kdb_enter+0x48: ldrb r15, [r15, r15, ror r15]!
db>