ComcertoでFreeBSD その参

なぜかブートしてシングルユーザーのshを起動するとsignal 4で終了しています。

signal 4はillegal instructionで1136で実行できないインストラクションが混じっている可能性が考えられます。

shが落ちてもカーネルデバッガには落とせるので、カーネルは動いているようです。

```
Enter full pathname of shell or RETURN for /bin/sh: 
pid 16 (sh), jid 0, uid 0: exited on signal 4
random: unblocking device.
KDB: enter: Break to debugger
[ thread pid 1 tid 100001 ]
Stopped at      kdb_break+0x58: ldrb    r15, [r15, r15, ror r15]!
db> c
```

armにはthumbという縮小命令セットがあります。これはarmv4tからサポートされてarmv6(1136,1176)までのthumbと、armv6t2(1156)以降のthumb2の二つのタイプがあります。4の時もそうでしたが、何故か同じバージョンの途中から仕様が変わっています。ネットで調べると情報が混乱しているので、よくないと思います。

Comcerto 1000は1136なのでthumbでFreeBSDで公式的にサポートされている1176もthumbになります。

clang 8.0.1で確認してみました。

```
% echo | arm.armv6/tmp/usr/bin/cc -dM -E - | grep thumb
```

thumbはありません。

```
% echo | arm.armv6/tmp/usr/bin/cc -mthumb -dM -E - | grep thumb
#define __thumb__ 1
```

thumbのサポートが入ります。

```
% echo | arm.armv6/tmp/usr/bin/cc -mthumb -march=armv6t2 -dM -E - | grep thumb
#define __thumb2__ 1
#define __thumb__ 1
```

thumb2もサポート入りました。

```
% echo | arm.armv6/tmp/usr/bin/cc -mthumb -mcpu=arm1176jzf-s -dM -E - | grep thumb
#define __thumb__ 1
```

arm1176jzf-sはarmv6でthumbです。armv6t2は11台では1152t2-sのみだったようです。ややっこしです。

ビルドされたELFでは以下の方法で確認できます。

```
% readelf -a sh | grep THUMB
  Tag_THUMB_ISA_use: 16-bit Thumb
```

thumb2の場合は32-bitになります。

イメージのバイナリとライブラリを確認してみましたが、すべて16-bitで問題なさそうです。

いろいろ調べていて気づいたのですが、arm1136j-sにはVFPV2がありません。おそらくこのインストラクションがユーザランドに入ってしまっているものと思われます。

```
% echo | arm.armv6/tmp/usr/bin/cc -mcpu=arm1136j-s -dM -E - | grep VFP
#define __ARM_PCS_VFP 1
% echo | arm.armv6/tmp/usr/bin/cc -dM -E - | grep VFP
#define __ARM_PCS_VFP 1
#define __ARM_VFPV2__ 1
#define __VFP_FP__ 1
```

CPUTYPE=armv6-softでビルドするとVFPなしでビルドできるようですが、lib/libc/arm/aeabi/aeabi_vfp.hに問題があって、パッチを当てたらビルドできました。

これでビルドしたバイナリを焼いてみたところ今度はlibedit.soが見つからないというエラーがでるようになりました。少し進んだようです。

libexec/rtld-elf/paths.hにsoft時のPATHがあり、これを書き換えたら、またsignal 4に戻ってしまいました。

ld-elf.so.1を逆アセンブラしてみると、

```
% tmp/usr/home/hiroki/freebsd/arm.armv6/tmp/usr/bin/objdump -D Softbank_E-WMTA22_rootfs_clean/libexec/ld-elf.so.1 | grep "[[:space:]]v"
   15a24:	ec828b10 	vstmia	r2, {d8-d15}
   15a5c:	ec9c8b10 	vldmia	ip, {d8-d15}
   15ab4:	ec828b10 	vstmia	r2, {d8-d15}
   15b04:	ec9c8b10 	vldmia	ip, {d8-d15}
   1b034:	4d4c4b4a 	vstrmi	d20, [ip, #-296]
   1b4dc:	6d203b74 	vstmdbvs	r0!, {d3-<overflow reg d60>}
```

後ろの二つはデーター部分と思われますが、VFP命令がまだ残っている様です。

念のためにarmv5tのバイナリを確認すると

```
% tmp/usr/home/hiroki/freebsd/arm.armv6/tmp/usr/bin/objdump -D Buffalo_WZR2-G300N_rootfs_clean/libexec/ld-elf.so.1 | grep "[[:space:]]v"
   19cb0:	4d4c4b4a 	vstrmi	d20, [ip, #-296]
   1a158:	6d203b74 	vstmdbvs	r0!, {d3-<overflow reg d60>}
```

ちゃんと使われていません。

rtld-elfのオブジェクトファイルでvstmiaが使われているファイルをobjdumpで探します。setjmp関連の様です。

```
% cd arm.armv6/libexec/rtld-elf
% ls *o | xargs -I'{}' sh -c 'C=`../../tmp/usr/bin/objdump -D {} | grep -c vstmia`;if [ $C  -ne 0 ];then echo {};fi'
_setjmp.nossppico
setjmp.nossppico
```

rtld-elfにはlibcのsetjmp.cと_setjmp.cが使われていてこのファイルのsoftの条件が抜けていました。

後日追記：レビュー出しました。https://reviews.freebsd.org/D22352

これでどうにかシングルユーザまでたどり着きましたが、まだ安定しません。

Comcerto 1000は1136J-S r1p5でラズパイの1176より後の製品で、r0のerrortaも直っている可能性が高く、動かない方がおかしいのですが。。。

シングルユーザでプロセスを実行するとプロセスが落ちたり、kernelがpanicしたりします。pmap周りのエラーが出る事があるのでpmapを疑っています。

* ラズパイの1176では動いていたし、おそらくいまだに動く
* 3年くらい前に試した時も同じだった
* 落ち方がpanicしたりプロセスが落ちたりさまざま
* プロセスが落ちた時はkernelはbreakが効き動き続けている
* シングルユーザーのshが落ちることもある
* KDBでshow irqするとtimerとuartの割り込みは正常に動作している
* dtsのメモリサイズを変更しても変化なし
* オリジナルのSDKを見ても特に気にかかるコードはない
* NetBSDのコードとは違った実装になっているので、正確には比較できないがとくに気になるコードはない
* 同じようにZRouterでビルドしているarmv7(A10)は問題なく動作している
* kernel内にarmv6kのインストラクション(clrex)が使われているところがあるが、1136 r1p5はarmv6kなので問題ない
* 


以下推測です。

* CFIとかDDRの初期化はu-bootがやっていて、不完全な可能性は低い
* 1136の後半のレビジョンなのでerrtaがある可能性は低い
* Multi CPUだが片方は止まっているので、影響しないはず
* ラズパイはセカンドブートローダーを使っているが関係ないはず
* NetBSDやSDKにはMCRRインストラクションを使っている箇所があるが、MCRでも同じ事ができるはず
* オリジナルのLinuxはメモリの先頭8Mを空けてkernelを読み込んでいるが、これはLinuxの実装によるものだと思われる
*