HardOffでRT1310かと思い524円で購入したルータがSTR9102で、FreeBSDの arm/cavium/cns11xxにコードがあるようなので、試してみる事にした。 このチップはもともとStar Semiconductorという会社の製品だったが、この会社は 2008年にCaviumに買収されたようだ。Star Semiconducto時代の製品名がSTR91XXで CaviumになってからはCNS11XXとなったようだ。 チップは2007年47週の製造でarm v4系(922)だがメモリが64Mでフラッシュが 8Mと十分な容量がある。シリアルはTX,RXなどのシルク印刷があり38400BPSだった。 ブートはARMboot 1.1.0 (Sep 13 2007 - 14:41:53)が入って いて起動時に^Cで止める事ができ、ネットワークもちゃんと使えた。ARMBootはU-Boot の元となったPPCBootから派生したプロジェクトだったみたいだ。 データーシートもネットで入手できる。 純正ファームブートログ
2008年くらいの製品だと思うが、この当時としては珍しいギガのスイッチのチップを 外付けにしている。ヒートシンクが貼られていて確認できないがVitesseという会社の VSC7385のようだ。
FreeBSDのコードはYohanes Nugrohoさんが作られて こちらにページがあった。 いまのところこのコードはeventtimerのサポートがなかったりFDTにも対応してない。 ページのコメントにFreeBSD 10でBootしないという書き込みがある。
メモリは0x00000000(0x20000000)からありフラッシュは0x10000000からあるようだ。
国内にも NetBSDを試されている方がいる模様。
RT1310の設定をコピーして書き換えイメージは数時間でできた。しかしイメージを tfpboot/bootmしても全く返事がないので、とりあえず得意のリセット作戦。 まずはBootでリセットしてみる。
STR9100>mw.b 0x77000004 0
アセンブラで書くとこんな感じ。
/* reset code */ ldr r0,=0x77000000 ldr r2,=0 strb r2, [r0, #+4] resetwait: nop b resetwait
当初、0x00000000なアドレスからのカーネルを作っていたところ、Bootがハングアップ してしまい、0x50000からのビルドにした。どうもこのボードのBootはメモリの先頭部分 を利用しているようだ。Bootが展開できて、とりあえずlocore-v4.Sが実行されている のは確認できたがtranslate_va_to_paで落ちる。何でだろう。
STR9100>bootm ## Booting image at 00800000 ... Image Name: FreeBSD Kernel Image Image Type: ARM Linux Kernel Image (gzip compressed) Data Size: 1263205 Bytes = 1233 kB = 1 MB Load Address: 000500e0 Entry Point: 000500e0 Verifying Checksum ... OK Uncompressing Kernel Image ... OK Starting kernel ... data abort pc : [<00000134>] lr : [<00050138>] sp : 0003b30c ip : 78000000 fp : 00000000 r10: 00800040 r9 : 00000000 r8 : 000000f2 r7 : 600000d3 r6 : 0003b63c r5 : 00000000 r4 : 000500e0 r3 : 00000000 r2 : c0000000 r1 : c0314000 r0 : 00314000 Flags: nZCv IRQs off FIQs off Mode UND_32 Resetting CPU ... ### ERROR ### Please RESET the board ###
ARMのアセンブラはここ が参考になる。
std.econaには"CONF_CFLAGS=-march=armv4"とあるが、gccでこのオプションを使うと geom_lavelなどでコンパイルが通らなくなる。CFLAGSに-mno-thumb-interworkの設定が 必要で環境変数にセットしておくと通った。sys/conf/Makefile.armにCFLAGS.gccと あるが、ZRouterではこれを元にコンパイルしているが効いていないようだ。 と思ったが、カーネル本体のビルドには効いていて、モジュールのビルドの時には 効いていないような気がする。
arm/locore-v4.Sは元々arm/locore.Sだったのを2014年にv4とv6に分けたみたいだ。
なんとデータシートには922互換とあるがTではなくてarmv4が正しいようだ。このため 4T以降でサポートされたRETで使われるbx命令が無くarmv4t以上でコンパイルすると この命令が使われるためRETURNできなくて落ちていた。
armv4なコード c005021c <translate_va_to_pa>: c005021c: e5901000 ldr r1, [r0] c0050220: e0412000 sub r2, r1, r0 c0050224: e5901004 ldr r1, [r0, #4] c0050228: e0410002 sub r0, r1, r2 c005022c: e1a0f00e mov pc, lr armv4tなコード c0000230 <translate_va_to_pa>: c0000230: e5901000 ldr r1, [r0] c0000234: e0412000 sub r2, r1, r0 c0000238: e5901004 ldr r1, [r0, #4] c000023c: e0410002 sub r0, r1, r2 c0000240: e12fff1e bx lr
このチップはFA526というタイプでFreeBSDにはMMUの設定などの専用のアセンブラコード が用意されている。
とりあえずブートログでました。(2016/05/23)
initを起動したところで落ちていたが、よくよく考えてみるとユーザランドも armv4でコンパイルしなければいけなかった。
initは実行されるようになったがシングルユーザのshを起動する前で "Jan 1 00:00:08"だけ出力して固まる。固まった後にUSBメモリの抜き差しを してもまったくメッセージが出ないので、完全に落ちているようだ。 DDBにも落ちないのは非常に困り果てる。
エクセプションが起きても拾えるはずなのだが、拾えずダブルフォルトすること あるのかな。。。
よくよくコードを追ってみると、uart_dev_ns8250.cの送信部分にbroken_txfifo という怪しげな変数がある。これを設定してみたところちゃんと文字の出力が されるようになった。この値はhints(sysctl)やFDTから設定できるようなのだが他の sdtを見てみると設定しているものがある。ただsysctlのメッセージはQUMEのバグの 多応のようなコメントだけでちょっと不親切かも。
UARTのコードはuart_cpu_hogeとuart_bus_hogeというコードで構成されているが、 これらは起動からinitさんの手前までがcpuでそれ以降がbusで処理されるよいう 流れになる。cpuの方はTXの割り込みは使わず、busになった時に割り込みを使い 始める。
シングルユーザのシェル選択のプロンプトまで進んだが、以前ハングアップする。 割り込みにデバッグライトを入れてみて、タイマーの割り込みも止まってしまうので、 またまた完全に落ちている模様。。。
試しにマルチユーザまで進めると、loginプロンプトまでたどり着くがやはりハング アップする。consoleのtty(uart)に対してreadを行ったタイミングで落ちているような 感じだ。ttyに対するreadは受信データがあればそれを返し無ければ空で返ることに なる。受信データは普通は割り込みで拾われている。
ttyは昔はsioというドライバだったがFreeBSD 8の頃にuartドライバに取り替えられた ようだ。uartのパラメータでshiftというのがあるが、これはレジスタのバウンダリ を設定するもので0であれば1バイト毎で1であれば2バイトで2で4バイト毎にレジスタが 並んでいる事を示す。
かなりはまりまくっているが、乗りかかった船なので、まだ調べている。シングル ユーザでシェルのところで落ちるが、マルチユーザまで進めると今度はログインの ところで落ちる。入力を開いたところで落ちているような気もする。落ちる前にログが 出ている時に入力するとエコーバックされるので、uartの入力がまったく機能して いないわけでもなさそう。
broken_txfifoは進んでいるように見えるが、実は根本的な問題を先送りしている だけでしかなさそう。initさんをWRITEONLYでコンソールをつかませると落ちない。 9-Currentでは実装した人以外にも試していたようで、ちゃんと動いていたような 感じだから何が影響しているのかな。。。
完全に落ちているのかUARTだけが死んでいるのかはこのデバイスではUSBデバイスを つないで、アクティブになるかどうかで判断できたりする。
kern/tty.cをwirteをダミーにして起動するとログインプロンプトの前まで進むが ログインプロンプトが出ない。なにか他に問題があるのかな。。。
どうもreadは確実に落ちるが、writeでも落ちる事があるみたい。。。こんなに不安定な UARTははじめてだ。uartのコードには8250系なはずなのにいろいろなデバイスのコード が用意されているのが、不具合対応の対応のためなんだろう。UARTは最も古い インターフェースなのでしかたがないのかな。
OSで問題が起きた時には、デバッガーに落ちる、リブートする、ハングアップするの ケースがある。ハングアップはあまり起きえないのだが、可能性は自分からhaltするとか クロックを止めてしまうとか、DMAがCPUを止めたままにするとか、メモリが見えなくなる とかかな。
JTAGのピンがあるので、UrJTAGでみてみたがdetectできない。。。
UARTのFIFOに16バイト突っ込んだ後ハングアップしているように見える。broken_txfifo をセットするとちょっと先まで進むのでUARTアクセスから戻った時に問題を起こしている ような感じ。
Yohanesさんのページにあるカーネルとrootfsだとちゃんとloginまで進む。この バイナリは9-CURRENTの時代に作られたようだ。cns11xxのポートは8-CURRENT時代から 初めて9-RELEASEには終わっていたようだ。9.0-RELEASEのコードでビルドすると ちゃんと動くようだ。
10.1-RELEASEのソースをビルドしても場所は違うがカーネル起動時にハングアップする。 考えられる可能性は、9から10でcns11xxのコードの修正が影響しているか、armサポート の修正が影響しているか、kernの修正が影響しているかのどれかだと思われる。
clangのバージョンが変わっていたので、試しにビルドしてみたがやはりarmv4での ビルドはうまくいかない。clangはarmv4t以降のサポートなんだと思われる。 (2017/04/14)
とりあえずgccでビルドしてカーネルを起動するとmountrootのところでハングする。 私がいじるまえの10Rでも同じところで、ハングしていたので、修正の問題では ないと思われる。とはいえなんでだろう。。。
このターゲットは遅いが、メモリ,Flashも大きいし、USB付いてるし、ネットワークも GIGAだったりして、結構気に入っているので、どうにか動くようにしたいのだが。。。
以前は日付を出力して行の途中でハングしていたのだが、今はハングのしかたが違う。
もとものとコードを実行するとuartが "Non-standard ns8250 class UART with FIFOs"となっていたのだが、これはtimer よりも前にロードされてDELAYがビジーループで実行されるためであった。dtsでuartを timerよりも前に書くと同じようになる。
rootfsがmountできないと、割り込みが上がらなくなり落ちている。なぜかrootfsが mount出来るとtimer割り込みは生きているのだが、ハングアップしたような状態に なる。ところが10分くらいたってから"random: unblocking device."が出力される。 別々の問題にも思えるがどうなのだろう。
この割り込みが上がらなくなるのは2015年の暮れに発生するようになったbcm/mips系 でハングしているのと同じ原因ではないのだろうか。
INTRNGがkernに入ったタイミングを疑っているのだが、原因が分からない。INTRNGで なくてもハングする。そもそもkern/subr_intr.cはarm/armから移された物で当初は armだけが対象だったはずなので、bcm/mipsに影響が出たとは考えにくいのだが。
rootfsがmount出来ないときにハングするのはkern/vfs_mountroot.cでpauseを2度呼んだ 時に起きているようだ。
割り込みが上がらなくなっているのか、そもそもCPUが落ちているのかは分からない。 デバッガーに落ちずにCPUが落ちているってありうるのかな。もしCPUが無権ループに 入っても割り込みは上がるはずなのだが。
armのintrの処理は cpsrというレジスタで制御できるみたい。 arm/include/cpufunc.hの中にintr_disable()があるが、これを誤って呼んでるのかな。
mizhkaさんの話ではbcm/mips74でも同じような現象があって、ワークアラウンドを 入れたという事であった。
こつこつデバッグしたところkern/vfs_mountroot.cのpauseで落ちている。 やはり直接的な不具合ではなさげだ。
do { pause("rmdev", delay); timeout -= delay; } while (timeout > 0 && !parse_mount_dev_present(dev));
mount出来る場合は直前のparse_mount_dev_present()で処理されるのでここのpause は通らないのでここでは落ちません。
各種カーネルデバッグオプションを設定してみてもなにも出てこない。。。
pauseを呼ぶ前のkdbのpsの結果
mountroot: waiting for device /dev/cfid0s.rootfs.uzip... KDB: enter: Break to debugger [ thread pid 1 tid 100001 ] Stopped at kdb_enter+0x40: ldrb r15, [r15, r15, ror r15]! db> ps pid ppid pgrp uid state wmesg wchan cmd 16 0 0 0 DL - 0xc039fa80 [soaiod4] 15 0 0 0 DL - 0xc039fa80 [soaiod3] 14 0 0 0 DL - 0xc039fa80 [soaiod2] 13 0 0 0 DL - 0xc039fa80 [soaiod1] 9 0 0 0 DL - 0xc033449c [schedcpu] 8 0 0 0 DL vlruwt 0xc0a68730 [vnlru] 7 0 0 0 DL syncer 0xc03a0cec [syncer] 6 0 0 0 DL psleep 0xc03a0080 [bufdaemon] 5 0 0 0 DL - 0xc03a0084 [bufspacedaemon] 4 0 0 0 DL pollid 0xc0333b5c [idlepoll] 3 0 0 0 DL (threaded) [pagedaemon] 100023 D psleep 0xc03a5310 [pagedaemon] 100031 D launds 0xc03a5318 [laundry: dom0] 100032 D umarcl 0xc03a4cc8 [uma] 2 0 0 0 RL [rand_harvestq] 12 0 0 0 DL (threaded) [geom] 100012 D - 0xc0330af8 [g_event] 100013 D - 0xc0330b00 [g_up] 100014 D - 0xc0330b04 [g_down] 11 0 0 0 RL (threaded) [intr] 100003 I [swi1: netisr 0] 100004 I [swi3: vm] 100005 RunQ [swi4: clock (0)] 100006 I [swi5: fast taskq] 100008 I [swi6: Giant taskq] 100009 I [swi6: task queue] 100016 I [swi0: uart] 100017 I [econaarm0,20: ece0] 100018 I [econaarm0,18: ece0] 100019 I [econaarm0,22: ece0] 100020 I [econaarm0,19: ece0] 10 0 0 0 RL [idle] 1 0 0 0 RL CPU 0 [kernel] 0 0 0 0 DLs (threaded) [kernel] 100000 D swapin 0xc0330f48 [swapper] 100007 D - 0xc0a4f580 [thread taskq] 100010 D - 0xc0a4f400 [aiod_kick taskq] 100011 D - 0xc0a4f380 [kqueue_ctx taskq] 100015 D - 0xc0a4d400 [cfid taskq] 100021 D - 0xc0a50600 [ece0 taskq] 100029 D - 0xc0b91580 [softirq_0]